blob: 2d4d95cc894f8f098fa436763611e3f5a78df417 [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 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Michal Vasko004d3152020-06-11 19:59:22 +020014#include "path.h"
15
16#include <assert.h>
Michal Vasko004d3152020-06-11 19:59:22 +020017#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020018#include <string.h>
Michal Vasko004d3152020-06-11 19:59:22 +020019
20#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020021#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020022#include "log.h"
23#include "plugins_types.h"
Michal Vasko40c158c2021-04-28 17:01:03 +020024#include "schema_compile.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020025#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020026#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020027#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010028#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020029#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "tree_schema_internal.h"
31#include "xpath.h"
32
Radek Krejcic0c66412020-08-21 13:53:50 +020033#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 +020034
Michal Vasko004d3152020-06-11 19:59:22 +020035/**
36 * @brief Check predicate syntax.
37 *
38 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020039 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020040 * @param[in] exp Parsed predicate.
41 * @param[in,out] tok_idx Index in @p exp, is adjusted.
42 * @param[in] prefix Prefix option.
43 * @param[in] pred Predicate option.
44 * @return LY_ERR value.
45 */
46static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020047ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
Michal Vaskodd528af2022-08-08 14:35:07 +020048 uint32_t *tok_idx, uint8_t prefix, uint8_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020049{
Radek Krejciba03a5a2020-08-27 14:40:41 +020050 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020051 struct ly_set *set = NULL;
52 uint32_t i;
53 const char *name;
54 size_t name_len;
55
Radek Krejciddace2c2021-01-08 11:30:56 +010056 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010057
Michal Vasko004d3152020-06-11 19:59:22 +020058 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020059 /* '[' */
60
Michal Vasko69730152020-10-09 16:30:07 +020061 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
62 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020063 ret = ly_set_new(&set);
64 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020065
66 do {
67 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020068 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020069
70 /* check prefix based on the options */
71 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
72 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010073 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020074 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020075 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020076 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010077 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020078 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020079 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020080 }
81 if (!name) {
82 name = exp->expr + exp->tok_pos[*tok_idx];
83 name_len = exp->tok_len[*tok_idx];
84 } else {
85 ++name;
86 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
87 }
88
89 /* check whether it was not already specified */
90 for (i = 0; i < set->count; ++i) {
91 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +020092 if (!strncmp(set->objs[i], name, name_len) &&
93 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +010094 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020095 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020096 }
97 }
98
99 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200100 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200101 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200102
103 /* NameTest */
104 ++(*tok_idx);
105
106 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200107 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200108
Michal Vasko4911eeb2021-06-28 11:23:05 +0200109 /* Literal or Number */
110 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 +0200111
112 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200113 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200114
Radek Krejci0f969882020-08-21 16:56:47 +0200115 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200116 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
117
Michal Vasko004d3152020-06-11 19:59:22 +0200118 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200119 /* '.' */
120
Michal Vasko004d3152020-06-11 19:59:22 +0200121 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200122 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200123
Michal Vasko4911eeb2021-06-28 11:23:05 +0200124 /* Literal or Number */
125 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 +0200126
127 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200128 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200129
Michal Vasko004d3152020-06-11 19:59:22 +0200130 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200131 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200132
Michal Vasko2261dfa2022-09-29 12:29:20 +0200133 /* check for index 0 */
134 if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
135 LOGVAL(ctx, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
136 exp->expr + exp->tok_pos[*tok_idx - 1]);
137 goto token_error;
138 }
139
Michal Vasko004d3152020-06-11 19:59:22 +0200140 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200141 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200142
143 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
144 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200145 ret = ly_set_new(&set);
146 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200147
148 do {
149 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200150 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200151
152 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
153 if (!name) {
154 name = exp->expr + exp->tok_pos[*tok_idx];
155 name_len = exp->tok_len[*tok_idx];
156 } else {
157 ++name;
158 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
159 }
160
161 /* check whether it was not already specified */
162 for (i = 0; i < set->count; ++i) {
163 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +0200164 if (!strncmp(set->objs[i], name, name_len) &&
165 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +0100166 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200167 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200168 }
169 }
170
171 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200172 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200173 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200174
175 /* NameTest */
176 ++(*tok_idx);
177
178 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200179 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200180
181 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200182 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100183 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
184 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100185 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200186 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200187 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200188 }
189 ++(*tok_idx);
190
191 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200192 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200193
194 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200195 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200196
197 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200198 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200199
200 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200201 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200202 do {
203 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200204 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200205 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
206
207 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200208 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200209
210 /* '/' */
211 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
212 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200213 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200214 }
215
216 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200217 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200218
Radek Krejci0f969882020-08-21 16:56:47 +0200219 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200220 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
221
Michal Vasko3c19b492022-09-05 08:48:10 +0200222 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
223 /* unexpected EOF */
224 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200225 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200226 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200227 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 +0200228 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200229 }
230 }
231
Radek Krejciba03a5a2020-08-27 14:40:41 +0200232cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100233 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200234 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200235 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200236
Radek Krejciba03a5a2020-08-27 14:40:41 +0200237token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100238 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200239 ly_set_free(set, NULL);
240 return LY_EVALID;
241}
242
243LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200244ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
Michal Vaskoed725d72021-06-23 12:03:45 +0200245 ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200246{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200247 LY_ERR ret = LY_SUCCESS;
248 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200249 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200250 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200251
252 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200253 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
254 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200255 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
256
Radek Krejciddace2c2021-01-08 11:30:56 +0100257 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100258
Michal Vasko004d3152020-06-11 19:59:22 +0200259 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200260 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200261 tok_idx = 0;
262
263 if (begin == LY_PATH_BEGIN_EITHER) {
264 /* is the path relative? */
265 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200266 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200267 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200268 /* mandatory '..' */
269 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
270
271 do {
272 /* '/' */
273 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
274
275 /* optional '..' */
276 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200277 }
278 }
279 } else {
280 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200281 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
Michal Vasko004d3152020-06-11 19:59:22 +0200282 }
283
284 do {
285 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200286 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 +0200287
288 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200289 cur_node = exp->expr + exp->tok_pos[tok_idx];
290 cur_len = exp->tok_len[tok_idx];
291 if (prefix == LY_PATH_PREFIX_MANDATORY) {
292 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100293 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200294 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200295 goto error;
296 }
297 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
298 if (!prev_prefix) {
299 /* the first node must have a prefix */
300 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100301 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200302 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200303 goto error;
304 }
305
306 /* remember the first prefix */
307 prev_prefix = cur_node;
308 } else {
309 /* the prefix must be different, if any */
310 ptr = strnstr(cur_node, ":", cur_len);
311 if (ptr) {
312 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100313 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200314 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200315 goto error;
316 }
317
318 /* remember this next prefix */
319 prev_prefix = cur_node;
320 }
321 }
Michal Vasko004d3152020-06-11 19:59:22 +0200322 }
323
324 ++tok_idx;
325
326 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200327 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200328
Radek Krejci0f969882020-08-21 16:56:47 +0200329 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200330 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
331
332 /* trailing token check */
333 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100334 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 +0200335 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200336 goto error;
337 }
338
339 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100340
Radek Krejciddace2c2021-01-08 11:30:56 +0100341 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200342 return LY_SUCCESS;
343
344error:
345 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100346 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200347 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200348}
349
350LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200351ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
Radek Krejci0f969882020-08-21 16:56:47 +0200352 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200353{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200354 LY_ERR ret = LY_SUCCESS;
355 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200356 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200357
358 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
359 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
360
Radek Krejciddace2c2021-01-08 11:30:56 +0100361 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100362
Michal Vasko004d3152020-06-11 19:59:22 +0200363 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200364 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200365 tok_idx = 0;
366
Radek Krejcif03a9e22020-09-18 20:09:31 +0200367 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200368
369 /* trailing token check */
370 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100371 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200372 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200373 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200374 goto error;
375 }
376
377 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100378
Radek Krejciddace2c2021-01-08 11:30:56 +0100379 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200380 return LY_SUCCESS;
381
382error:
383 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100384 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200385 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200386}
387
388/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200389 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200390 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200391 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200392 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200393 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
394 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200395 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200396 * @param[in] expr Parsed path.
397 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200398 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200399 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200400 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
401 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
402 * @param[out] snode Resolved schema node.
403 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200404 * @return LY_ERR value.
405 */
406static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200407ly_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 +0200408 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 +0200409 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
410 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200411{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100412 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200413 const struct lys_module *mod = NULL;
414 struct lysc_ext_instance *e = NULL;
415 const char *pref, *name;
416 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200417
418 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
419
Michal Vasko8cc3f662022-03-29 11:25:51 +0200420 *snode = NULL;
421 if (ext) {
422 *ext = NULL;
423 }
424
Michal Vasko004d3152020-06-11 19:59:22 +0200425 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200426 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
427 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
428 pref = expr->expr + expr->tok_pos[tok_idx];
429 } else {
430 len = 0;
431 }
Michal Vasko004d3152020-06-11 19:59:22 +0200432
Michal Vasko8cc3f662022-03-29 11:25:51 +0200433 /* set name */
434 if (pref) {
435 name = pref + len + 1;
436 name_len = expr->tok_len[tok_idx] - len - 1;
437 } else {
438 name = expr->expr + expr->tok_pos[tok_idx];
439 name_len = expr->tok_len[tok_idx];
440 }
441
442 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200443 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100444 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100445
Michal Vasko35b29622022-07-22 14:12:56 +0200446 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 +0200447 if ((!mod || !mod->implemented) && prev_ctx_node) {
448 /* check for nested ext data */
449 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
450 if (!ret) {
451 goto success;
452 } else if (ret != LY_ENOT) {
453 goto error;
454 }
455 }
456
457 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100458 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100459 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200460 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100461 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200462 } else if (!mod->implemented) {
463 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200464 ret = LY_EVALID;
465 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200466 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100467
Radek Krejciddace2c2021-01-08 11:30:56 +0100468 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200469 } else {
470 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200471 case LY_VALUE_SCHEMA:
472 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200473 if (!cur_mod) {
474 LOGINT_RET(ctx);
475 }
476 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200477 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200478 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200479 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200480 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200481 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200482 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200483 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200484 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200485 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200486 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200487 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200488 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100489 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200490 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200491 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200492 }
493 }
494
Michal Vasko8cc3f662022-03-29 11:25:51 +0200495 /* find schema node */
496 if (!prev_ctx_node && top_ext) {
497 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200498 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200499 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
500 if (!(*snode) && prev_ctx_node) {
501 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
502 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
503 }
504 }
505 if (!(*snode)) {
506 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
507 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200508 }
509
Michal Vasko8cc3f662022-03-29 11:25:51 +0200510success:
511 if (ext) {
512 *ext = e;
513 }
Michal Vasko004d3152020-06-11 19:59:22 +0200514 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100515
516error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100517 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200518 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200519}
520
521LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200522ly_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 +0200523 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200524 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200525{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100526 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200527 struct ly_path_predicate *p;
528 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200529 const char *val;
530 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200531
Michal Vasko00cbf532020-06-15 13:58:47 +0200532 assert(ctx && ctx_node);
533
Radek Krejciddace2c2021-01-08 11:30:56 +0100534 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100535
Michal Vasko004d3152020-06-11 19:59:22 +0200536 *pred_type = 0;
537
Michal Vasko004d3152020-06-11 19:59:22 +0200538 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200539 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200541 }
542
543 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
544 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100545 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200546 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100547 ret = LY_EVALID;
548 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200549 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100550 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200551 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100552 ret = LY_EVALID;
553 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200554 }
555
556 do {
557 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200558 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
559 NULL, 0, &key, NULL));
560 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100561 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
562 key->name);
563 ret = LY_EVALID;
564 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200565 }
566 ++(*tok_idx);
567
Michal Vasko004d3152020-06-11 19:59:22 +0200568 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200569 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200570 *pred_type = LY_PATH_PREDTYPE_LIST;
571 }
572 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100573 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200574 p->key = key;
575
576 /* '=' */
577 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
578 ++(*tok_idx);
579
Michal Vasko4911eeb2021-06-28 11:23:05 +0200580 /* Literal or Number */
581 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
582 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
583 /* skip quotes */
584 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
585 val_len = expr->tok_len[*tok_idx] - 2;
586 } else {
587 val = expr->expr + expr->tok_pos[*tok_idx];
588 val_len = expr->tok_len[*tok_idx];
589 }
590
591 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100592 LOG_LOCSET(key, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200593 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
594 prefix_data, LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100595 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200596 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200597 ++(*tok_idx);
598
Michal Vaskoae875662020-10-21 10:33:17 +0200599 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200600 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200601
Michal Vasko004d3152020-06-11 19:59:22 +0200602 /* ']' */
603 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
604 ++(*tok_idx);
605
606 /* another predicate follows? */
607 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
608
609 /* check that all keys were set */
610 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100611 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200612 ++key_count;
613 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200614 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200615 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100616 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200617 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200618 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200619 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100620 ret = LY_EVALID;
621 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200622 }
623
624 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
625 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100626 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200627 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100628 ret = LY_EVALID;
629 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200630 }
631 ++(*tok_idx);
632
633 /* new predicate */
634 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100635 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200636
637 /* '=' */
638 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
639 ++(*tok_idx);
640
Michal Vasko4911eeb2021-06-28 11:23:05 +0200641 /* Literal or Number */
642 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
643 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
644 /* skip quotes */
645 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
646 val_len = expr->tok_len[*tok_idx] - 2;
647 } else {
648 val = expr->expr + expr->tok_pos[*tok_idx];
649 val_len = expr->tok_len[*tok_idx];
650 }
651
Michal Vasko004d3152020-06-11 19:59:22 +0200652 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100653 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200654 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
655 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100656 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200657 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200658 ++(*tok_idx);
659
Michal Vaskoae875662020-10-21 10:33:17 +0200660 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200661 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200662
Michal Vasko004d3152020-06-11 19:59:22 +0200663 /* ']' */
664 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
665 ++(*tok_idx);
666 } else {
667 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
668 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100669 ret = LY_EVALID;
670 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200671 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100672 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200673 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100674 ret = LY_EVALID;
675 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200676 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100677 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200678 }
Michal Vasko004d3152020-06-11 19:59:22 +0200679
680 /* new predicate */
681 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100682 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200683
684 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200685 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200686 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200687
688 /* ']' */
689 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
690 ++(*tok_idx);
691 }
692
Radek Krejci2efc45b2020-12-22 16:25:44 +0100693cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100694 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200696}
697
698/**
699 * @brief Compile leafref predicate. Actually, it is only checked.
700 *
701 * @param[in] ctx_node Context node, node for which the predicate is defined.
702 * @param[in] cur_node Current (original context) node.
703 * @param[in] expr Parsed path.
704 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200705 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200706 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200707 * @return LY_ERR value.
708 */
709static LY_ERR
710ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200711 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200712{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100713 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200714 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100715 struct ly_ctx *ctx = cur_node->module->ctx;
716
Radek Krejciddace2c2021-01-08 11:30:56 +0100717 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200718
Michal Vasko004d3152020-06-11 19:59:22 +0200719 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200720 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100721 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200722 }
723
724 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100725 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200726 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100727 ret = LY_EVALID;
728 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200729 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100730 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200731 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100732 ret = LY_EVALID;
733 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200734 }
735
736 do {
737 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200738 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
739 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100740 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200741 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100742 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200743 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100744 ret = LY_EVALID;
745 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200746 }
747 ++(*tok_idx);
748
749 /* we are not actually compiling, throw the key away */
750 (void)key;
751
752 /* '=' */
753 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
754 ++(*tok_idx);
755
756 /* FuncName */
757 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
758 ++(*tok_idx);
759
760 /* evaluating from the "current()" node */
761 node = cur_node;
762
763 /* '(' */
764 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
765 ++(*tok_idx);
766
767 /* ')' */
768 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
769 ++(*tok_idx);
770
771 do {
772 /* '/' */
773 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
774 ++(*tok_idx);
775
776 /* go to parent */
777 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100778 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
779 ret = LY_EVALID;
780 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200781 }
782 node = lysc_data_parent(node);
783
784 /* '..' */
785 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
786 ++(*tok_idx);
787 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
788
789 do {
790 /* '/' */
791 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
792 ++(*tok_idx);
793
794 /* NameTest */
795 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200796 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
797 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200798 node = node2;
799 ++(*tok_idx);
800 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
801
802 /* check the last target node */
803 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100804 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200805 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100806 ret = LY_EVALID;
807 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200808 }
809
810 /* we are not actually compiling, throw the rightside node away */
811 (void)node;
812
813 /* ']' */
814 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
815 ++(*tok_idx);
816
Radek Krejci0f969882020-08-21 16:56:47 +0200817 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200818 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
819
Radek Krejci2efc45b2020-12-22 16:25:44 +0100820cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100821 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200822 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200823}
824
Michal Vaskoed725d72021-06-23 12:03:45 +0200825/**
826 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
827 *
828 * @param[in] ctx libyang context.
829 * @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 +0200830 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +0200831 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200832 * @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 +0200833 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
834 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
835 * @param[in] expr Parsed path.
836 * @param[in] lref Whether leafref is being compiled or not.
837 * @param[in] oper Oper option (@ref path_oper_options).
838 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +0200839 * @param[in] limit_access_tree Whether to limit accessible tree as described in
840 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +0200841 * @param[in] format Format of the path.
842 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +0200843 * @param[out] path Compiled path.
844 * @return LY_ERECOMPILE, only if @p lref.
845 * @return LY_ERR value.
846 */
847static LY_ERR
848_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko8cc3f662022-03-29 11:25:51 +0200849 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
Michal Vasko0884d212021-10-14 09:21:46 +0200850 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200851{
852 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +0200853 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +0200854 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200855 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200856 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200857
Michal Vasko00cbf532020-06-15 13:58:47 +0200858 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200859 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200860 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
861 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200862
Michal Vasko0884d212021-10-14 09:21:46 +0200863 if (!limit_access_tree) {
864 op = NULL;
865 } else {
866 /* find operation, if we are in any */
867 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
868 }
Michal Vasko6b26e742020-07-17 15:02:10 +0200869
Radek Krejci2efc45b2020-12-22 16:25:44 +0100870 *path = NULL;
871
Michal Vasko6b26e742020-07-17 15:02:10 +0200872 /* remember original context node */
873 cur_node = ctx_node;
Michal Vasko62225e22022-08-05 10:06:50 +0200874 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200875
Michal Vasko00cbf532020-06-15 13:58:47 +0200876 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100877 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200878 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100879 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200880 }
881
Michal Vasko004d3152020-06-11 19:59:22 +0200882 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
883 /* absolute path */
884 ctx_node = NULL;
885
886 ++tok_idx;
887 } else {
888 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +0100889 if (!ctx_node) {
890 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
891 ret = LY_EVALID;
892 goto cleanup;
893 }
894
895 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200896 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200897 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100898 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100899 ret = LY_EVALID;
900 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200901 }
902
903 /* get parent */
904 ctx_node = lysc_data_parent(ctx_node);
905
906 ++tok_idx;
907
908 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
909 ++tok_idx;
910 }
Michal Vasko004d3152020-06-11 19:59:22 +0200911 }
912
913 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200914 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200915 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100916 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200917 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100918 ret = LY_EVALID;
919 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200920 }
921
Michal Vasko14424ba2020-12-09 18:09:51 +0100922 /* NameTest */
923 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
924
Michal Vasko8cc3f662022-03-29 11:25:51 +0200925 /* get schema node */
926 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
927 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200928 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200929 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
930 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200931 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200932 goto cleanup;
933 }
934 ctx_node = node2;
935
936 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200937 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200938 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200939 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +0200940
941 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +0200942 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +0200943 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200944 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200945 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
Michal Vasko69730152020-10-09 16:30:07 +0200946 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200947 }
948 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200949 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
950
Michal Vasko14424ba2020-12-09 18:09:51 +0100951 /* check leftover tokens */
952 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +0200953 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 +0100954 ret = LY_EVALID;
955 goto cleanup;
956 }
957
Michal Vasko00cbf532020-06-15 13:58:47 +0200958 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +0200959 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100960 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200961 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100962 ret = LY_EVALID;
963 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200964 }
965
Michal Vasko004d3152020-06-11 19:59:22 +0200966cleanup:
967 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200968 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200969 *path = NULL;
970 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100971 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200972 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200973}
974
975LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +0200976ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko8cc3f662022-03-29 11:25:51 +0200977 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
Michal Vasko0884d212021-10-14 09:21:46 +0200978 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200979{
Michal Vasko8cc3f662022-03-29 11:25:51 +0200980 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
981 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +0200982}
983
984LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200985ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *top_ext,
Michal Vaskoed725d72021-06-23 12:03:45 +0200986 const struct lyxp_expr *expr, uint8_t oper, uint8_t target, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko24fc4d12021-07-12 14:41:20 +0200987 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200988{
Michal Vasko8cc3f662022-03-29 11:25:51 +0200989 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 +0200990}
991
992LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200993ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
Radek Krejci0f969882020-08-21 16:56:47 +0200994 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200995{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200996 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +0200997 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200998 uint64_t pos;
999
1000 assert(path && start);
1001
1002 if (lysc_data_parent(path[0].node)) {
1003 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001004 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001005 } else {
1006 /* absolute path, start from the first top-level sibling */
1007 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001008 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001009 }
1010 while (start->prev->next) {
1011 start = start->prev;
1012 }
1013 }
1014
1015 LY_ARRAY_FOR(path, u) {
1016 switch (path[u].pred_type) {
1017 case LY_PATH_PREDTYPE_POSITION:
1018 /* we cannot use hashes and want an instance on a specific position */
1019 pos = 1;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001020 node = NULL;
1021 LYD_LIST_FOR_INST(start, path[u].node, elem) {
Michal Vasko004d3152020-06-11 19:59:22 +02001022 if (pos == path[u].predicates[0].position) {
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001023 node = elem;
Michal Vasko004d3152020-06-11 19:59:22 +02001024 break;
1025 }
1026 ++pos;
1027 }
1028 break;
1029 case LY_PATH_PREDTYPE_LEAFLIST:
1030 /* we will use hashes to find one leaf-list instance */
1031 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1032 lyd_find_sibling_first(start, target, &node);
1033 lyd_free_tree(target);
1034 break;
1035 case LY_PATH_PREDTYPE_LIST:
1036 /* we will use hashes to find one list instance */
1037 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
1038 lyd_find_sibling_first(start, target, &node);
1039 lyd_free_tree(target);
1040 break;
1041 case LY_PATH_PREDTYPE_NONE:
1042 /* we will use hashes to find one any/container/leaf instance */
1043 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
1044 break;
1045 }
1046
1047 if (!node) {
1048 /* no matching nodes */
1049 break;
1050 }
1051
Michal Vasko00cbf532020-06-15 13:58:47 +02001052 /* rememeber previous node */
1053 prev_node = node;
1054
Michal Vasko004d3152020-06-11 19:59:22 +02001055 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001056 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001057 }
1058
Michal Vasko004d3152020-06-11 19:59:22 +02001059 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001060 /* we have found the full path */
1061 if (path_idx) {
1062 *path_idx = u;
1063 }
1064 if (match) {
1065 *match = node;
1066 }
Michal Vasko004d3152020-06-11 19:59:22 +02001067 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001068
1069 } else if (prev_node) {
1070 /* we have found only some partial match */
1071 if (path_idx) {
1072 *path_idx = u - 1;
1073 }
1074 if (match) {
1075 *match = prev_node;
1076 }
1077 return LY_EINCOMPLETE;
1078 }
1079
1080 /* we have not found any nodes */
1081 if (path_idx) {
1082 *path_idx = 0;
1083 }
1084 if (match) {
1085 *match = NULL;
1086 }
1087 return LY_ENOTFOUND;
1088}
1089
1090LY_ERR
1091ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1092{
1093 LY_ERR ret;
1094 struct lyd_node *m;
1095
1096 ret = ly_path_eval_partial(path, start, NULL, &m);
1097
1098 if (ret == LY_SUCCESS) {
1099 /* last node was found */
1100 if (match) {
1101 *match = m;
1102 }
1103 return LY_SUCCESS;
1104 }
1105
1106 /* not a full match */
1107 if (match) {
1108 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001109 }
1110 return LY_ENOTFOUND;
1111}
1112
1113LY_ERR
1114ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1115{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001116 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001117
1118 if (!path) {
1119 return LY_SUCCESS;
1120 }
1121
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001122 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001123 LY_ARRAY_FOR(path, u) {
1124 LY_ARRAY_INCREMENT(*dup);
1125 (*dup)[u].node = path[u].node;
1126 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001127 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001128 (*dup)[u].pred_type = path[u].pred_type;
1129 LY_ARRAY_FOR(path[u].predicates, v) {
1130 struct ly_path_predicate *pred = &path[u].predicates[v];
1131
1132 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1133 switch (path[u].pred_type) {
1134 case LY_PATH_PREDTYPE_POSITION:
1135 /* position-predicate */
1136 (*dup)[u].predicates[v].position = pred->position;
1137 break;
1138 case LY_PATH_PREDTYPE_LIST:
1139 case LY_PATH_PREDTYPE_LEAFLIST:
1140 /* key-predicate or leaf-list-predicate */
1141 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001142 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vasko04338d92021-09-01 07:58:14 +02001143 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
Michal Vasko004d3152020-06-11 19:59:22 +02001144 break;
1145 case LY_PATH_PREDTYPE_NONE:
1146 break;
1147 }
1148 }
1149 }
1150 }
1151
1152 return LY_SUCCESS;
1153}
1154
1155void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001156ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001157{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001158 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001159 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001160
1161 if (!predicates) {
1162 return;
1163 }
1164
1165 LY_ARRAY_FOR(predicates, u) {
1166 switch (pred_type) {
1167 case LY_PATH_PREDTYPE_POSITION:
1168 case LY_PATH_PREDTYPE_NONE:
1169 /* nothing to free */
1170 break;
1171 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001172 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001173 if (predicates[u].value.realtype) {
1174 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001175 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001176 }
Michal Vasko004d3152020-06-11 19:59:22 +02001177 break;
1178 }
1179 }
1180 LY_ARRAY_FREE(predicates);
1181}
1182
1183void
1184ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1185{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001186 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001187
Michal Vasko55b84812021-05-11 09:23:58 +02001188 if (!path) {
1189 return;
1190 }
1191
Michal Vasko004d3152020-06-11 19:59:22 +02001192 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001193 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001194 }
1195 LY_ARRAY_FREE(path);
1196}