blob: 4ee9832225d6de83846d7849d6854c8af3cdf98b [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
23#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020024#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020025#include "log.h"
26#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) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010076 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", 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) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010080 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", 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 Vasko90189962023-02-28 12:10:34 +0100112 /* Literal, Number, or VariableReference */
113 if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
114 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
115 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
116 /* error */
117 lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
118 goto token_error;
119 }
Michal Vasko004d3152020-06-11 19:59:22 +0200120
121 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200122 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200123
Radek Krejci0f969882020-08-21 16:56:47 +0200124 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200125 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
126
Michal Vasko004d3152020-06-11 19:59:22 +0200127 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200128 /* '.' */
129
Michal Vasko004d3152020-06-11 19:59:22 +0200130 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200131 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200132
Michal Vasko4911eeb2021-06-28 11:23:05 +0200133 /* Literal or Number */
134 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 +0200135
136 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200137 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200138
Michal Vasko004d3152020-06-11 19:59:22 +0200139 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200140 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200141
Michal Vasko2261dfa2022-09-29 12:29:20 +0200142 /* check for index 0 */
143 if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
144 LOGVAL(ctx, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
145 exp->expr + exp->tok_pos[*tok_idx - 1]);
146 goto token_error;
147 }
148
Michal Vasko004d3152020-06-11 19:59:22 +0200149 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200150 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200151
152 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
153 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200154 ret = ly_set_new(&set);
155 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200156
157 do {
158 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200159 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200160
161 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
162 if (!name) {
163 name = exp->expr + exp->tok_pos[*tok_idx];
164 name_len = exp->tok_len[*tok_idx];
165 } else {
166 ++name;
167 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
168 }
169
170 /* check whether it was not already specified */
171 for (i = 0; i < set->count; ++i) {
172 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +0200173 if (!strncmp(set->objs[i], name, name_len) &&
174 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +0100175 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200176 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200177 }
178 }
179
180 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200181 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200182 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200183
184 /* NameTest */
185 ++(*tok_idx);
186
187 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200188 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200189
190 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200191 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100192 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
193 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100194 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200195 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200196 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200197 }
198 ++(*tok_idx);
199
200 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200201 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200202
203 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200204 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200205
206 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200207 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200208
209 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200210 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200211 do {
212 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200213 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200214 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
215
216 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200217 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200218
219 /* '/' */
220 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
221 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200223 }
224
225 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200226 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200227
Radek Krejci0f969882020-08-21 16:56:47 +0200228 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200229 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
230
Michal Vasko3c19b492022-09-05 08:48:10 +0200231 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
232 /* unexpected EOF */
233 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200234 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200235 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200236 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 +0200237 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200238 }
239 }
240
Radek Krejciba03a5a2020-08-27 14:40:41 +0200241cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100242 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200243 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200244 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200245
Radek Krejciba03a5a2020-08-27 14:40:41 +0200246token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100247 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200248 ly_set_free(set, NULL);
249 return LY_EVALID;
250}
251
252LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200253ly_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 +0100254 ly_bool lref, uint16_t begin, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200255{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200256 LY_ERR ret = LY_SUCCESS;
257 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200258 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200259 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100260 ly_bool is_abs;
Michal Vasko004d3152020-06-11 19:59:22 +0200261
262 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200263 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
Michal Vasko32ca49b2023-02-17 15:11:35 +0100264 (prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200265 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
266
Radek Krejciddace2c2021-01-08 11:30:56 +0100267 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100268
Michal Vasko004d3152020-06-11 19:59:22 +0200269 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200270 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200271 tok_idx = 0;
272
273 if (begin == LY_PATH_BEGIN_EITHER) {
274 /* is the path relative? */
275 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200276 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200277 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200278 /* mandatory '..' */
279 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
280
281 do {
282 /* '/' */
283 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
284
285 /* optional '..' */
286 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200287 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100288
289 is_abs = 0;
290 } else {
291 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200292 }
293 } else {
294 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200295 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 +0100296
297 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200298 }
299
300 do {
301 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200302 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 +0200303
304 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200305 cur_node = exp->expr + exp->tok_pos[tok_idx];
306 cur_len = exp->tok_len[tok_idx];
307 if (prefix == LY_PATH_PREFIX_MANDATORY) {
308 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100309 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200310 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200311 goto error;
312 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100313 } else if ((prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
314 if (!prev_prefix && is_abs) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200315 /* the first node must have a prefix */
316 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100317 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200318 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200319 goto error;
320 }
321
322 /* remember the first prefix */
323 prev_prefix = cur_node;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100324 } else if (prev_prefix && (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200325 /* the prefix must be different, if any */
326 ptr = strnstr(cur_node, ":", cur_len);
327 if (ptr) {
328 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100329 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200330 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200331 goto error;
332 }
333
334 /* remember this next prefix */
335 prev_prefix = cur_node;
336 }
337 }
Michal Vasko004d3152020-06-11 19:59:22 +0200338 }
339
340 ++tok_idx;
341
342 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200343 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200344
Radek Krejci0f969882020-08-21 16:56:47 +0200345 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200346 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
347
348 /* trailing token check */
349 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100350 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 +0200351 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200352 goto error;
353 }
354
355 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100356
Radek Krejciddace2c2021-01-08 11:30:56 +0100357 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200358 return LY_SUCCESS;
359
360error:
361 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100362 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200363 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200364}
365
366LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200367ly_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 +0100368 size_t path_len, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200369{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200370 LY_ERR ret = LY_SUCCESS;
371 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200372 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200373
374 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
375 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
376
Radek Krejciddace2c2021-01-08 11:30:56 +0100377 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100378
Michal Vasko004d3152020-06-11 19:59:22 +0200379 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200380 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200381 tok_idx = 0;
382
Radek Krejcif03a9e22020-09-18 20:09:31 +0200383 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200384
385 /* trailing token check */
386 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100387 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200388 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200389 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200390 goto error;
391 }
392
393 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100394
Radek Krejciddace2c2021-01-08 11:30:56 +0100395 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200396 return LY_SUCCESS;
397
398error:
399 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100400 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200401 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200402}
403
404/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200405 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200406 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200407 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200408 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200409 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
410 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200411 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200412 * @param[in] expr Parsed path.
413 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200414 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200415 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200416 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
417 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
418 * @param[out] snode Resolved schema node.
419 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200420 * @return LY_ERR value.
421 */
422static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200423ly_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 +0200424 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 +0200425 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
426 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200427{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100428 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200429 const struct lys_module *mod = NULL;
430 struct lysc_ext_instance *e = NULL;
431 const char *pref, *name;
432 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200433
434 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
435
Michal Vasko8cc3f662022-03-29 11:25:51 +0200436 *snode = NULL;
437 if (ext) {
438 *ext = NULL;
439 }
440
Michal Vasko004d3152020-06-11 19:59:22 +0200441 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200442 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
443 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
444 pref = expr->expr + expr->tok_pos[tok_idx];
445 } else {
446 len = 0;
447 }
Michal Vasko004d3152020-06-11 19:59:22 +0200448
Michal Vasko8cc3f662022-03-29 11:25:51 +0200449 /* set name */
450 if (pref) {
451 name = pref + len + 1;
452 name_len = expr->tok_len[tok_idx] - len - 1;
453 } else {
454 name = expr->expr + expr->tok_pos[tok_idx];
455 name_len = expr->tok_len[tok_idx];
456 }
457
458 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200459 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100460 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100461
Michal Vasko35b29622022-07-22 14:12:56 +0200462 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 +0200463 if ((!mod || !mod->implemented) && prev_ctx_node) {
464 /* check for nested ext data */
465 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
466 if (!ret) {
467 goto success;
468 } else if (ret != LY_ENOT) {
469 goto error;
470 }
471 }
472
473 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100474 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100475 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200476 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100477 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200478 } else if (!mod->implemented) {
479 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200480 ret = LY_EVALID;
481 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200482 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100483
Radek Krejciddace2c2021-01-08 11:30:56 +0100484 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200485 } else {
486 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200487 case LY_VALUE_SCHEMA:
488 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200489 if (!cur_mod) {
490 LOGINT_RET(ctx);
491 }
492 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200493 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200494 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200495 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200496 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200497 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200498 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200499 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200500 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200501 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200502 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200503 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200504 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100505 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200506 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200507 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200508 }
509 }
510
Michal Vasko8cc3f662022-03-29 11:25:51 +0200511 /* find schema node */
512 if (!prev_ctx_node && top_ext) {
513 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200514 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200515 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
516 if (!(*snode) && prev_ctx_node) {
517 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
518 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
519 }
520 }
521 if (!(*snode)) {
522 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
523 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200524 }
525
Michal Vasko8cc3f662022-03-29 11:25:51 +0200526success:
527 if (ext) {
528 *ext = e;
529 }
Michal Vasko004d3152020-06-11 19:59:22 +0200530 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100531
532error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100533 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200534 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200535}
536
537LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200538ly_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 +0200539 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 +0100540 void *prefix_data, struct ly_path_predicate **predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200541{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100542 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200543 struct ly_path_predicate *p;
544 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200545 const char *val;
546 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200547
Michal Vasko00cbf532020-06-15 13:58:47 +0200548 assert(ctx && ctx_node);
549
Radek Krejciddace2c2021-01-08 11:30:56 +0100550 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100551
Michal Vasko90189962023-02-28 12:10:34 +0100552 *predicates = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200553
Michal Vasko004d3152020-06-11 19:59:22 +0200554 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200555 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100556 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200557 }
558
559 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
560 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100561 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200562 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100563 ret = LY_EVALID;
564 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200565 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100566 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200567 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100568 ret = LY_EVALID;
569 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200570 }
571
572 do {
573 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200574 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
575 NULL, 0, &key, NULL));
576 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100577 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
578 key->name);
579 ret = LY_EVALID;
580 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200581 }
582 ++(*tok_idx);
583
Michal Vasko90189962023-02-28 12:10:34 +0100584 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100585 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200586 p->key = key;
587
588 /* '=' */
589 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
590 ++(*tok_idx);
591
Michal Vasko90189962023-02-28 12:10:34 +0100592 /* Literal, Number, or VariableReference */
593 if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
594 /* store the variable name */
595 p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
596 LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
597
598 p->type = LY_PATH_PREDTYPE_LIST_VAR;
599 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200600 } else {
Michal Vasko90189962023-02-28 12:10:34 +0100601 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
602 /* skip quotes */
603 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
604 val_len = expr->tok_len[*tok_idx] - 2;
605 } else {
606 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
607 val = expr->expr + expr->tok_pos[*tok_idx];
608 val_len = expr->tok_len[*tok_idx];
609 }
610
611 /* store the value */
612 LOG_LOCSET(key, NULL, NULL, NULL);
613 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
614 prefix_data, LYD_HINT_DATA, key, NULL);
615 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
616 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
617
618 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
619 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
620
621 p->type = LY_PATH_PREDTYPE_LIST;
622 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200623 }
624
Michal Vasko004d3152020-06-11 19:59:22 +0200625 /* ']' */
626 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
627 ++(*tok_idx);
628
629 /* another predicate follows? */
630 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
631
632 /* check that all keys were set */
633 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100634 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200635 ++key_count;
636 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200637 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200638 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100639 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200640 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko90189962023-02-28 12:10:34 +0100641 ly_path_predicates_free(ctx, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200642 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100643 ret = LY_EVALID;
644 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200645 }
646
647 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
648 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100649 LOGVAL(ctx, LYVE_XPATH, "Leaf-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 }
654 ++(*tok_idx);
655
656 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100657 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100658 p->type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko004d3152020-06-11 19:59:22 +0200659
660 /* '=' */
661 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
662 ++(*tok_idx);
663
Michal Vasko4911eeb2021-06-28 11:23:05 +0200664 /* Literal or Number */
665 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
666 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
667 /* skip quotes */
668 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
669 val_len = expr->tok_len[*tok_idx] - 2;
670 } else {
671 val = expr->expr + expr->tok_pos[*tok_idx];
672 val_len = expr->tok_len[*tok_idx];
673 }
674
Michal Vasko004d3152020-06-11 19:59:22 +0200675 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100676 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200677 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
678 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100679 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200680 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200681 ++(*tok_idx);
682
Michal Vaskoae875662020-10-21 10:33:17 +0200683 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200684 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200685
Michal Vasko004d3152020-06-11 19:59:22 +0200686 /* ']' */
687 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
688 ++(*tok_idx);
689 } else {
690 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
691 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100692 ret = LY_EVALID;
693 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200694 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200696 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100697 ret = LY_EVALID;
698 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200699 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100700 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200701 }
Michal Vasko004d3152020-06-11 19:59:22 +0200702
703 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100704 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100705 p->type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko004d3152020-06-11 19:59:22 +0200706
707 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200708 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200709 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200710
711 /* ']' */
712 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
713 ++(*tok_idx);
714 }
715
Radek Krejci2efc45b2020-12-22 16:25:44 +0100716cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100717 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100718 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200719}
720
721/**
722 * @brief Compile leafref predicate. Actually, it is only checked.
723 *
724 * @param[in] ctx_node Context node, node for which the predicate is defined.
725 * @param[in] cur_node Current (original context) node.
726 * @param[in] expr Parsed path.
727 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200728 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200729 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200730 * @return LY_ERR value.
731 */
732static LY_ERR
733ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200734 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200735{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100736 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200737 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100738 struct ly_ctx *ctx = cur_node->module->ctx;
739
Michal Vasko004d3152020-06-11 19:59:22 +0200740 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200741 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100742 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200743 }
744
745 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100746 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200747 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100748 ret = LY_EVALID;
749 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200750 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100751 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200752 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100753 ret = LY_EVALID;
754 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200755 }
756
757 do {
758 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200759 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
760 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100761 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200762 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100763 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200764 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100765 ret = LY_EVALID;
766 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200767 }
768 ++(*tok_idx);
769
770 /* we are not actually compiling, throw the key away */
771 (void)key;
772
773 /* '=' */
774 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
775 ++(*tok_idx);
776
777 /* FuncName */
778 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
779 ++(*tok_idx);
780
781 /* evaluating from the "current()" node */
782 node = cur_node;
783
784 /* '(' */
785 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
786 ++(*tok_idx);
787
788 /* ')' */
789 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
790 ++(*tok_idx);
791
792 do {
793 /* '/' */
794 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
795 ++(*tok_idx);
796
797 /* go to parent */
798 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100799 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
800 ret = LY_EVALID;
801 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200802 }
803 node = lysc_data_parent(node);
804
805 /* '..' */
806 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
807 ++(*tok_idx);
808 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
809
810 do {
811 /* '/' */
812 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
813 ++(*tok_idx);
814
815 /* NameTest */
816 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200817 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
818 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200819 node = node2;
820 ++(*tok_idx);
821 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
822
823 /* check the last target node */
824 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100825 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200826 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100827 ret = LY_EVALID;
828 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200829 }
830
831 /* we are not actually compiling, throw the rightside node away */
832 (void)node;
833
834 /* ']' */
835 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
836 ++(*tok_idx);
837
Radek Krejci0f969882020-08-21 16:56:47 +0200838 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200839 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
840
Radek Krejci2efc45b2020-12-22 16:25:44 +0100841cleanup:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200842 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200843}
844
Michal Vaskoed725d72021-06-23 12:03:45 +0200845/**
846 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
847 *
848 * @param[in] ctx libyang context.
849 * @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 +0200850 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +0200851 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200852 * @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 +0200853 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
854 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
855 * @param[in] expr Parsed path.
856 * @param[in] lref Whether leafref is being compiled or not.
857 * @param[in] oper Oper option (@ref path_oper_options).
858 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +0200859 * @param[in] limit_access_tree Whether to limit accessible tree as described in
860 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +0200861 * @param[in] format Format of the path.
862 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +0200863 * @param[out] path Compiled path.
864 * @return LY_ERECOMPILE, only if @p lref.
865 * @return LY_ERR value.
866 */
867static LY_ERR
868_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 +0100869 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 +0200870 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200871{
872 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +0200873 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +0200874 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200875 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200876 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200877
Michal Vasko00cbf532020-06-15 13:58:47 +0200878 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200879 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200880 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
881 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200882
Michal Vasko0884d212021-10-14 09:21:46 +0200883 if (!limit_access_tree) {
884 op = NULL;
885 } else {
886 /* find operation, if we are in any */
887 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
888 }
Michal Vasko6b26e742020-07-17 15:02:10 +0200889
Radek Krejci2efc45b2020-12-22 16:25:44 +0100890 *path = NULL;
891
Michal Vasko6b26e742020-07-17 15:02:10 +0200892 /* remember original context node */
893 cur_node = ctx_node;
Michal Vasko62225e22022-08-05 10:06:50 +0200894 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200895
Michal Vasko00cbf532020-06-15 13:58:47 +0200896 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100897 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200898 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100899 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200900 }
901
Michal Vasko004d3152020-06-11 19:59:22 +0200902 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
903 /* absolute path */
904 ctx_node = NULL;
905
906 ++tok_idx;
907 } else {
908 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +0100909 if (!ctx_node) {
910 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
911 ret = LY_EVALID;
912 goto cleanup;
913 }
914
915 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200916 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200917 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100918 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100919 ret = LY_EVALID;
920 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200921 }
922
923 /* get parent */
924 ctx_node = lysc_data_parent(ctx_node);
925
926 ++tok_idx;
927
928 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
929 ++tok_idx;
930 }
Michal Vasko004d3152020-06-11 19:59:22 +0200931 }
932
933 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200934 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200935 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100936 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200937 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100938 ret = LY_EVALID;
939 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200940 }
941
Michal Vasko14424ba2020-12-09 18:09:51 +0100942 /* NameTest */
943 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
944
Michal Vasko8cc3f662022-03-29 11:25:51 +0200945 /* get schema node */
946 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
947 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200948 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200949 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
950 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200951 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200952 goto cleanup;
953 }
954 ctx_node = node2;
955
956 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200957 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200958 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200959 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +0200960
961 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +0200962 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +0200963 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200964 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200965 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 +0100966 &p->predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200967 }
968 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200969 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
970
Michal Vasko14424ba2020-12-09 18:09:51 +0100971 /* check leftover tokens */
972 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +0200973 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 +0100974 ret = LY_EVALID;
975 goto cleanup;
976 }
977
Michal Vasko00cbf532020-06-15 13:58:47 +0200978 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +0200979 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100980 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200981 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100982 ret = LY_EVALID;
983 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200984 }
985
Michal Vasko004d3152020-06-11 19:59:22 +0200986cleanup:
987 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200988 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200989 *path = NULL;
990 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100991 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200992 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200993}
994
995LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +0200996ly_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 +0100997 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 +0200998 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200999{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001000 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
1001 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001002}
1003
1004LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +02001005ly_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 +01001006 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 +02001007 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001008{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001009 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 +02001010}
1011
1012LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001013ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
1014 LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +02001015{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001016 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001017 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +02001018 uint64_t pos;
1019
1020 assert(path && start);
1021
1022 if (lysc_data_parent(path[0].node)) {
1023 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001024 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001025 } else {
1026 /* absolute path, start from the first top-level sibling */
1027 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001028 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001029 }
1030 while (start->prev->next) {
1031 start = start->prev;
1032 }
1033 }
1034
1035 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001036 if (path[u].predicates) {
1037 switch (path[u].predicates[0].type) {
1038 case LY_PATH_PREDTYPE_POSITION:
1039 /* we cannot use hashes and want an instance on a specific position */
1040 pos = 1;
1041 node = NULL;
1042 LYD_LIST_FOR_INST(start, path[u].node, elem) {
1043 if (pos == path[u].predicates[0].position) {
1044 node = elem;
1045 break;
1046 }
1047 ++pos;
Michal Vasko004d3152020-06-11 19:59:22 +02001048 }
Michal Vasko90189962023-02-28 12:10:34 +01001049 break;
1050 case LY_PATH_PREDTYPE_LEAFLIST:
1051 /* we will use hashes to find one leaf-list instance */
1052 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1053 lyd_find_sibling_first(start, target, &node);
1054 lyd_free_tree(target);
1055 break;
1056 case LY_PATH_PREDTYPE_LIST_VAR:
1057 case LY_PATH_PREDTYPE_LIST:
1058 /* we will use hashes to find one list instance */
1059 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
1060 lyd_find_sibling_first(start, target, &node);
1061 lyd_free_tree(target);
1062 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001063 }
Michal Vasko90189962023-02-28 12:10:34 +01001064 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001065 /* we will use hashes to find one any/container/leaf instance */
1066 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
Michal Vasko004d3152020-06-11 19:59:22 +02001067 }
1068
1069 if (!node) {
1070 /* no matching nodes */
1071 break;
1072 }
1073
Michal Vasko00cbf532020-06-15 13:58:47 +02001074 /* rememeber previous node */
1075 prev_node = node;
1076
Michal Vasko004d3152020-06-11 19:59:22 +02001077 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001078 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001079 }
1080
Michal Vasko004d3152020-06-11 19:59:22 +02001081 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001082 /* we have found the full path */
1083 if (path_idx) {
1084 *path_idx = u;
1085 }
1086 if (match) {
1087 *match = node;
1088 }
Michal Vasko004d3152020-06-11 19:59:22 +02001089 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001090
1091 } else if (prev_node) {
1092 /* we have found only some partial match */
1093 if (path_idx) {
1094 *path_idx = u - 1;
1095 }
1096 if (match) {
1097 *match = prev_node;
1098 }
1099 return LY_EINCOMPLETE;
1100 }
1101
1102 /* we have not found any nodes */
1103 if (path_idx) {
1104 *path_idx = 0;
1105 }
1106 if (match) {
1107 *match = NULL;
1108 }
1109 return LY_ENOTFOUND;
1110}
1111
1112LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001113ly_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 +02001114{
1115 LY_ERR ret;
1116 struct lyd_node *m;
1117
Michal Vasko90189962023-02-28 12:10:34 +01001118 ret = ly_path_eval_partial(path, start, vars, NULL, &m);
Michal Vasko00cbf532020-06-15 13:58:47 +02001119
1120 if (ret == LY_SUCCESS) {
1121 /* last node was found */
1122 if (match) {
1123 *match = m;
1124 }
1125 return LY_SUCCESS;
1126 }
1127
1128 /* not a full match */
1129 if (match) {
1130 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001131 }
1132 return LY_ENOTFOUND;
1133}
1134
1135LY_ERR
1136ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1137{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001138 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001139
1140 if (!path) {
1141 return LY_SUCCESS;
1142 }
1143
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001144 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001145 LY_ARRAY_FOR(path, u) {
1146 LY_ARRAY_INCREMENT(*dup);
1147 (*dup)[u].node = path[u].node;
1148 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001149 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001150 LY_ARRAY_FOR(path[u].predicates, v) {
1151 struct ly_path_predicate *pred = &path[u].predicates[v];
1152
1153 LY_ARRAY_INCREMENT((*dup)[u].predicates);
Michal Vasko90189962023-02-28 12:10:34 +01001154 (*dup)[u].predicates[v].type = pred->type;
1155
1156 switch (pred->type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001157 case LY_PATH_PREDTYPE_POSITION:
1158 /* position-predicate */
1159 (*dup)[u].predicates[v].position = pred->position;
1160 break;
1161 case LY_PATH_PREDTYPE_LIST:
1162 case LY_PATH_PREDTYPE_LEAFLIST:
1163 /* key-predicate or leaf-list-predicate */
1164 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001165 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vasko04338d92021-09-01 07:58:14 +02001166 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
Michal Vasko004d3152020-06-11 19:59:22 +02001167 break;
Michal Vasko90189962023-02-28 12:10:34 +01001168 case LY_PATH_PREDTYPE_LIST_VAR:
1169 /* key-predicate with a variable */
1170 (*dup)[u].predicates[v].key = pred->key;
1171 (*dup)[u].predicates[v].variable = strdup(pred->variable);
Michal Vasko004d3152020-06-11 19:59:22 +02001172 break;
1173 }
1174 }
1175 }
1176 }
1177
1178 return LY_SUCCESS;
1179}
1180
1181void
Michal Vasko90189962023-02-28 12:10:34 +01001182ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001183{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001184 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001185 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001186
1187 if (!predicates) {
1188 return;
1189 }
1190
1191 LY_ARRAY_FOR(predicates, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001192 switch (predicates[u].type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001193 case LY_PATH_PREDTYPE_POSITION:
Michal Vasko004d3152020-06-11 19:59:22 +02001194 /* nothing to free */
1195 break;
1196 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001197 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001198 if (predicates[u].value.realtype) {
1199 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001200 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001201 }
Michal Vasko004d3152020-06-11 19:59:22 +02001202 break;
Michal Vasko90189962023-02-28 12:10:34 +01001203 case LY_PATH_PREDTYPE_LIST_VAR:
1204 free(predicates[u].variable);
1205 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001206 }
1207 }
1208 LY_ARRAY_FREE(predicates);
1209}
1210
1211void
1212ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1213{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001214 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001215
Michal Vasko55b84812021-05-11 09:23:58 +02001216 if (!path) {
1217 return;
1218 }
1219
Michal Vasko004d3152020-06-11 19:59:22 +02001220 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001221 ly_path_predicates_free(ctx, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001222 }
1223 LY_ARRAY_FREE(path);
1224}