blob: b6dc04aab528fa5ece369978612acc11e2e05df8 [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>
17#include <ctype.h>
18#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020019#include <string.h>
Michal Vasko004d3152020-06-11 19:59:22 +020020
21#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020022#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020023#include "log.h"
24#include "plugins_types.h"
Michal Vasko40c158c2021-04-28 17:01:03 +020025#include "schema_compile.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020026#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020027#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020028#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010029#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020031#include "tree_schema_internal.h"
32#include "xpath.h"
33
Radek Krejcic0c66412020-08-21 13:53:50 +020034#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 +020035
Michal Vasko004d3152020-06-11 19:59:22 +020036/**
37 * @brief Check predicate syntax.
38 *
39 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020040 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020041 * @param[in] exp Parsed predicate.
42 * @param[in,out] tok_idx Index in @p exp, is adjusted.
43 * @param[in] prefix Prefix option.
44 * @param[in] pred Predicate option.
45 * @return LY_ERR value.
46 */
47static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020048ly_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 +020049 uint32_t *tok_idx, uint8_t prefix, uint8_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020050{
Radek Krejciba03a5a2020-08-27 14:40:41 +020051 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020052 struct ly_set *set = NULL;
53 uint32_t i;
54 const char *name;
55 size_t name_len;
56
Radek Krejciddace2c2021-01-08 11:30:56 +010057 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010058
Michal Vasko004d3152020-06-11 19:59:22 +020059 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020060 /* '[' */
61
Michal Vasko69730152020-10-09 16:30:07 +020062 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
63 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020064 ret = ly_set_new(&set);
65 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020066
67 do {
68 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020069 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020070
71 /* check prefix based on the options */
72 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
73 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010074 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020075 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020076 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020077 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010078 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020079 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020080 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020081 }
82 if (!name) {
83 name = exp->expr + exp->tok_pos[*tok_idx];
84 name_len = exp->tok_len[*tok_idx];
85 } else {
86 ++name;
87 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
88 }
89
90 /* check whether it was not already specified */
91 for (i = 0; i < set->count; ++i) {
92 /* all the keys must be from the same module so this comparison should be fine */
93 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
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
133 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200134 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200135
136 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
137 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200138 ret = ly_set_new(&set);
139 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200140
141 do {
142 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200143 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200144
145 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
146 if (!name) {
147 name = exp->expr + exp->tok_pos[*tok_idx];
148 name_len = exp->tok_len[*tok_idx];
149 } else {
150 ++name;
151 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
152 }
153
154 /* check whether it was not already specified */
155 for (i = 0; i < set->count; ++i) {
156 /* all the keys must be from the same module so this comparison should be fine */
157 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci422afb12021-03-04 16:38:16 +0100158 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200159 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200160 }
161 }
162
163 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200164 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200165 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200166
167 /* NameTest */
168 ++(*tok_idx);
169
170 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200171 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200172
173 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200174 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100175 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
176 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100177 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200178 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200179 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200180 }
181 ++(*tok_idx);
182
183 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200184 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200185
186 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200187 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200188
189 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200190 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200191
192 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200193 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200194 do {
195 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200196 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200197 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
198
199 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200200 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200201
202 /* '/' */
203 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
204 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200205 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200206 }
207
208 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200209 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200210
Radek Krejci0f969882020-08-21 16:56:47 +0200211 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200212 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
213
Michal Vasko3c19b492022-09-05 08:48:10 +0200214 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
215 /* unexpected EOF */
216 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200217 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200218 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200219 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 +0200220 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200221 }
222 }
223
Radek Krejciba03a5a2020-08-27 14:40:41 +0200224cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100225 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200226 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200227 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200228
Radek Krejciba03a5a2020-08-27 14:40:41 +0200229token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100230 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200231 ly_set_free(set, NULL);
232 return LY_EVALID;
233}
234
235LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200236ly_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 +0200237 ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200238{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200239 LY_ERR ret = LY_SUCCESS;
240 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200241 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200242 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200243
244 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200245 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
246 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200247 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
248
Radek Krejciddace2c2021-01-08 11:30:56 +0100249 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100250
Michal Vasko004d3152020-06-11 19:59:22 +0200251 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200252 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200253 tok_idx = 0;
254
255 if (begin == LY_PATH_BEGIN_EITHER) {
256 /* is the path relative? */
257 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200258 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200259 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200260 /* mandatory '..' */
261 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
262
263 do {
264 /* '/' */
265 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
266
267 /* optional '..' */
268 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200269 }
270 }
271 } else {
272 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200273 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 +0200274 }
275
276 do {
277 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200278 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 +0200279
280 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200281 cur_node = exp->expr + exp->tok_pos[tok_idx];
282 cur_len = exp->tok_len[tok_idx];
283 if (prefix == LY_PATH_PREFIX_MANDATORY) {
284 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100285 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200286 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200287 goto error;
288 }
289 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
290 if (!prev_prefix) {
291 /* the first node must have a prefix */
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
298 /* remember the first prefix */
299 prev_prefix = cur_node;
300 } else {
301 /* the prefix must be different, if any */
302 ptr = strnstr(cur_node, ":", cur_len);
303 if (ptr) {
304 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100305 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200306 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200307 goto error;
308 }
309
310 /* remember this next prefix */
311 prev_prefix = cur_node;
312 }
313 }
Michal Vasko004d3152020-06-11 19:59:22 +0200314 }
315
316 ++tok_idx;
317
318 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200319 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200320
Radek Krejci0f969882020-08-21 16:56:47 +0200321 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200322 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
323
324 /* trailing token check */
325 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100326 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 +0200327 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200328 goto error;
329 }
330
331 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100332
Radek Krejciddace2c2021-01-08 11:30:56 +0100333 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200334 return LY_SUCCESS;
335
336error:
337 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100338 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200339 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200340}
341
342LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200343ly_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 +0200344 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200345{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200346 LY_ERR ret = LY_SUCCESS;
347 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200348 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200349
350 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
351 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
352
Radek Krejciddace2c2021-01-08 11:30:56 +0100353 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100354
Michal Vasko004d3152020-06-11 19:59:22 +0200355 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200356 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200357 tok_idx = 0;
358
Radek Krejcif03a9e22020-09-18 20:09:31 +0200359 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200360
361 /* trailing token check */
362 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100363 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200364 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200365 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200366 goto error;
367 }
368
369 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100370
Radek Krejciddace2c2021-01-08 11:30:56 +0100371 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200372 return LY_SUCCESS;
373
374error:
375 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100376 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200377 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200378}
379
380/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200381 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200382 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200383 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200384 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200385 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
386 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200387 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200388 * @param[in] expr Parsed path.
389 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200390 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200391 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200392 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
393 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
394 * @param[out] snode Resolved schema node.
395 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200396 * @return LY_ERR value.
397 */
398static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200399ly_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 +0200400 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 +0200401 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
402 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200403{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100404 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200405 const struct lys_module *mod = NULL;
406 struct lysc_ext_instance *e = NULL;
407 const char *pref, *name;
408 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200409
410 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
411
Michal Vasko8cc3f662022-03-29 11:25:51 +0200412 *snode = NULL;
413 if (ext) {
414 *ext = NULL;
415 }
416
Michal Vasko004d3152020-06-11 19:59:22 +0200417 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200418 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
419 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
420 pref = expr->expr + expr->tok_pos[tok_idx];
421 } else {
422 len = 0;
423 }
Michal Vasko004d3152020-06-11 19:59:22 +0200424
Michal Vasko8cc3f662022-03-29 11:25:51 +0200425 /* set name */
426 if (pref) {
427 name = pref + len + 1;
428 name_len = expr->tok_len[tok_idx] - len - 1;
429 } else {
430 name = expr->expr + expr->tok_pos[tok_idx];
431 name_len = expr->tok_len[tok_idx];
432 }
433
434 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200435 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100436 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100437
Michal Vasko35b29622022-07-22 14:12:56 +0200438 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 +0200439 if ((!mod || !mod->implemented) && prev_ctx_node) {
440 /* check for nested ext data */
441 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
442 if (!ret) {
443 goto success;
444 } else if (ret != LY_ENOT) {
445 goto error;
446 }
447 }
448
449 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100450 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100451 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200452 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100453 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200454 } else if (!mod->implemented) {
455 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200456 ret = LY_EVALID;
457 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200458 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100459
Radek Krejciddace2c2021-01-08 11:30:56 +0100460 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200461 } else {
462 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200463 case LY_VALUE_SCHEMA:
464 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200465 if (!cur_mod) {
466 LOGINT_RET(ctx);
467 }
468 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200469 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200470 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200471 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200472 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200473 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200474 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200475 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200476 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200477 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200478 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200479 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200480 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100481 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200482 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200483 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200484 }
485 }
486
Michal Vasko8cc3f662022-03-29 11:25:51 +0200487 /* find schema node */
488 if (!prev_ctx_node && top_ext) {
489 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200490 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200491 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
492 if (!(*snode) && prev_ctx_node) {
493 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
494 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
495 }
496 }
497 if (!(*snode)) {
498 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
499 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200500 }
501
Michal Vasko8cc3f662022-03-29 11:25:51 +0200502success:
503 if (ext) {
504 *ext = e;
505 }
Michal Vasko004d3152020-06-11 19:59:22 +0200506 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100507
508error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100509 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200510 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200511}
512
513LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200514ly_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 +0200515 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 +0200516 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200517{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100518 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200519 struct ly_path_predicate *p;
520 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200521 const char *val;
522 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200523
Michal Vasko00cbf532020-06-15 13:58:47 +0200524 assert(ctx && ctx_node);
525
Radek Krejciddace2c2021-01-08 11:30:56 +0100526 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100527
Michal Vasko004d3152020-06-11 19:59:22 +0200528 *pred_type = 0;
529
Michal Vasko004d3152020-06-11 19:59:22 +0200530 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200531 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100532 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200533 }
534
535 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
536 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100537 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200538 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100539 ret = LY_EVALID;
540 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200541 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100542 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200543 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100544 ret = LY_EVALID;
545 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200546 }
547
548 do {
549 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200550 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
551 NULL, 0, &key, NULL));
552 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100553 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
554 key->name);
555 ret = LY_EVALID;
556 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200557 }
558 ++(*tok_idx);
559
Michal Vasko004d3152020-06-11 19:59:22 +0200560 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200561 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200562 *pred_type = LY_PATH_PREDTYPE_LIST;
563 }
564 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100565 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200566 p->key = key;
567
568 /* '=' */
569 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
570 ++(*tok_idx);
571
Michal Vasko4911eeb2021-06-28 11:23:05 +0200572 /* Literal or Number */
573 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
574 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
575 /* skip quotes */
576 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
577 val_len = expr->tok_len[*tok_idx] - 2;
578 } else {
579 val = expr->expr + expr->tok_pos[*tok_idx];
580 val_len = expr->tok_len[*tok_idx];
581 }
582
583 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100584 LOG_LOCSET(key, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200585 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
586 prefix_data, LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100587 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200588 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200589 ++(*tok_idx);
590
Michal Vaskoae875662020-10-21 10:33:17 +0200591 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200592 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200593
Michal Vasko004d3152020-06-11 19:59:22 +0200594 /* ']' */
595 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
596 ++(*tok_idx);
597
598 /* another predicate follows? */
599 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
600
601 /* check that all keys were set */
602 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100603 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200604 ++key_count;
605 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200606 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200607 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100608 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200609 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200610 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200611 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100612 ret = LY_EVALID;
613 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200614 }
615
616 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
617 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100618 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200619 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100620 ret = LY_EVALID;
621 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200622 }
623 ++(*tok_idx);
624
625 /* new predicate */
626 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100627 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200628
629 /* '=' */
630 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
631 ++(*tok_idx);
632
Michal Vasko4911eeb2021-06-28 11:23:05 +0200633 /* Literal or Number */
634 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
635 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
636 /* skip quotes */
637 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
638 val_len = expr->tok_len[*tok_idx] - 2;
639 } else {
640 val = expr->expr + expr->tok_pos[*tok_idx];
641 val_len = expr->tok_len[*tok_idx];
642 }
643
Michal Vasko004d3152020-06-11 19:59:22 +0200644 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100645 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200646 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
647 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100648 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200649 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200650 ++(*tok_idx);
651
Michal Vaskoae875662020-10-21 10:33:17 +0200652 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200653 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200654
Michal Vasko004d3152020-06-11 19:59:22 +0200655 /* ']' */
656 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
657 ++(*tok_idx);
658 } else {
659 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
660 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100661 ret = LY_EVALID;
662 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200663 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100664 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200665 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100666 ret = LY_EVALID;
667 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200668 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100669 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200670 }
Michal Vasko004d3152020-06-11 19:59:22 +0200671
672 /* new predicate */
673 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100674 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200675
676 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200677 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200678 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200679
680 /* ']' */
681 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
682 ++(*tok_idx);
683 }
684
Radek Krejci2efc45b2020-12-22 16:25:44 +0100685cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100686 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100687 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200688}
689
690/**
691 * @brief Compile leafref predicate. Actually, it is only checked.
692 *
693 * @param[in] ctx_node Context node, node for which the predicate is defined.
694 * @param[in] cur_node Current (original context) node.
695 * @param[in] expr Parsed path.
696 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200697 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200698 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200699 * @return LY_ERR value.
700 */
701static LY_ERR
702ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200703 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200704{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100705 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200706 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100707 struct ly_ctx *ctx = cur_node->module->ctx;
708
Radek Krejciddace2c2021-01-08 11:30:56 +0100709 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200710
Michal Vasko004d3152020-06-11 19:59:22 +0200711 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200712 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100713 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200714 }
715
716 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100717 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200718 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100719 ret = LY_EVALID;
720 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200721 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100722 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200723 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100724 ret = LY_EVALID;
725 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200726 }
727
728 do {
729 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200730 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
731 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100732 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200733 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100734 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200735 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100736 ret = LY_EVALID;
737 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200738 }
739 ++(*tok_idx);
740
741 /* we are not actually compiling, throw the key away */
742 (void)key;
743
744 /* '=' */
745 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
746 ++(*tok_idx);
747
748 /* FuncName */
749 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
750 ++(*tok_idx);
751
752 /* evaluating from the "current()" node */
753 node = cur_node;
754
755 /* '(' */
756 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
757 ++(*tok_idx);
758
759 /* ')' */
760 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
761 ++(*tok_idx);
762
763 do {
764 /* '/' */
765 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
766 ++(*tok_idx);
767
768 /* go to parent */
769 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100770 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
771 ret = LY_EVALID;
772 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200773 }
774 node = lysc_data_parent(node);
775
776 /* '..' */
777 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
778 ++(*tok_idx);
779 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
780
781 do {
782 /* '/' */
783 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
784 ++(*tok_idx);
785
786 /* NameTest */
787 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200788 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
789 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200790 node = node2;
791 ++(*tok_idx);
792 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
793
794 /* check the last target node */
795 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100796 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200797 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100798 ret = LY_EVALID;
799 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200800 }
801
802 /* we are not actually compiling, throw the rightside node away */
803 (void)node;
804
805 /* ']' */
806 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
807 ++(*tok_idx);
808
Radek Krejci0f969882020-08-21 16:56:47 +0200809 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200810 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
811
Radek Krejci2efc45b2020-12-22 16:25:44 +0100812cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100813 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200814 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200815}
816
Michal Vaskoed725d72021-06-23 12:03:45 +0200817/**
818 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
819 *
820 * @param[in] ctx libyang context.
821 * @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 +0200822 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +0200823 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200824 * @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 +0200825 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
826 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
827 * @param[in] expr Parsed path.
828 * @param[in] lref Whether leafref is being compiled or not.
829 * @param[in] oper Oper option (@ref path_oper_options).
830 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +0200831 * @param[in] limit_access_tree Whether to limit accessible tree as described in
832 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +0200833 * @param[in] format Format of the path.
834 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +0200835 * @param[out] path Compiled path.
836 * @return LY_ERECOMPILE, only if @p lref.
837 * @return LY_ERR value.
838 */
839static LY_ERR
840_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 +0200841 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 +0200842 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200843{
844 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +0200845 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +0200846 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200847 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200848 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200849
Michal Vasko00cbf532020-06-15 13:58:47 +0200850 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200851 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200852 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
853 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200854
Michal Vasko0884d212021-10-14 09:21:46 +0200855 if (!limit_access_tree) {
856 op = NULL;
857 } else {
858 /* find operation, if we are in any */
859 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
860 }
Michal Vasko6b26e742020-07-17 15:02:10 +0200861
Radek Krejci2efc45b2020-12-22 16:25:44 +0100862 *path = NULL;
863
Michal Vasko6b26e742020-07-17 15:02:10 +0200864 /* remember original context node */
865 cur_node = ctx_node;
Michal Vasko62225e22022-08-05 10:06:50 +0200866 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200867
Michal Vasko00cbf532020-06-15 13:58:47 +0200868 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100869 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200870 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100871 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200872 }
873
Michal Vasko004d3152020-06-11 19:59:22 +0200874 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
875 /* absolute path */
876 ctx_node = NULL;
877
878 ++tok_idx;
879 } else {
880 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +0100881 if (!ctx_node) {
882 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
883 ret = LY_EVALID;
884 goto cleanup;
885 }
886
887 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200888 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200889 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100890 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100891 ret = LY_EVALID;
892 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200893 }
894
895 /* get parent */
896 ctx_node = lysc_data_parent(ctx_node);
897
898 ++tok_idx;
899
900 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
901 ++tok_idx;
902 }
Michal Vasko004d3152020-06-11 19:59:22 +0200903 }
904
905 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200906 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200907 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100908 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200909 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100910 ret = LY_EVALID;
911 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200912 }
913
Michal Vasko14424ba2020-12-09 18:09:51 +0100914 /* NameTest */
915 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
916
Michal Vasko8cc3f662022-03-29 11:25:51 +0200917 /* get schema node */
918 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
919 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200920 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200921 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
922 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200923 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200924 goto cleanup;
925 }
926 ctx_node = node2;
927
928 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200929 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200930 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200931 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +0200932
933 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +0200934 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +0200935 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200936 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200937 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 +0200938 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200939 }
940 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200941 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
942
Michal Vasko14424ba2020-12-09 18:09:51 +0100943 /* check leftover tokens */
944 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +0200945 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 +0100946 ret = LY_EVALID;
947 goto cleanup;
948 }
949
Michal Vasko00cbf532020-06-15 13:58:47 +0200950 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +0200951 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100952 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200953 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100954 ret = LY_EVALID;
955 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200956 }
957
Michal Vasko004d3152020-06-11 19:59:22 +0200958cleanup:
959 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200960 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200961 *path = NULL;
962 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100963 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200964 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200965}
966
967LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +0200968ly_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 +0200969 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 +0200970 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200971{
Michal Vasko8cc3f662022-03-29 11:25:51 +0200972 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
973 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +0200974}
975
976LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200977ly_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 +0200978 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 +0200979 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200980{
Michal Vasko8cc3f662022-03-29 11:25:51 +0200981 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 +0200982}
983
984LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200985ly_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 +0200986 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200987{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200988 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +0200989 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200990 uint64_t pos;
991
992 assert(path && start);
993
994 if (lysc_data_parent(path[0].node)) {
995 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200996 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200997 } else {
998 /* absolute path, start from the first top-level sibling */
999 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001000 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001001 }
1002 while (start->prev->next) {
1003 start = start->prev;
1004 }
1005 }
1006
1007 LY_ARRAY_FOR(path, u) {
1008 switch (path[u].pred_type) {
1009 case LY_PATH_PREDTYPE_POSITION:
1010 /* we cannot use hashes and want an instance on a specific position */
1011 pos = 1;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001012 node = NULL;
1013 LYD_LIST_FOR_INST(start, path[u].node, elem) {
Michal Vasko004d3152020-06-11 19:59:22 +02001014 if (pos == path[u].predicates[0].position) {
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001015 node = elem;
Michal Vasko004d3152020-06-11 19:59:22 +02001016 break;
1017 }
1018 ++pos;
1019 }
1020 break;
1021 case LY_PATH_PREDTYPE_LEAFLIST:
1022 /* we will use hashes to find one leaf-list instance */
1023 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1024 lyd_find_sibling_first(start, target, &node);
1025 lyd_free_tree(target);
1026 break;
1027 case LY_PATH_PREDTYPE_LIST:
1028 /* we will use hashes to find one list instance */
1029 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
1030 lyd_find_sibling_first(start, target, &node);
1031 lyd_free_tree(target);
1032 break;
1033 case LY_PATH_PREDTYPE_NONE:
1034 /* we will use hashes to find one any/container/leaf instance */
1035 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
1036 break;
1037 }
1038
1039 if (!node) {
1040 /* no matching nodes */
1041 break;
1042 }
1043
Michal Vasko00cbf532020-06-15 13:58:47 +02001044 /* rememeber previous node */
1045 prev_node = node;
1046
Michal Vasko004d3152020-06-11 19:59:22 +02001047 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001048 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001049 }
1050
Michal Vasko004d3152020-06-11 19:59:22 +02001051 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001052 /* we have found the full path */
1053 if (path_idx) {
1054 *path_idx = u;
1055 }
1056 if (match) {
1057 *match = node;
1058 }
Michal Vasko004d3152020-06-11 19:59:22 +02001059 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001060
1061 } else if (prev_node) {
1062 /* we have found only some partial match */
1063 if (path_idx) {
1064 *path_idx = u - 1;
1065 }
1066 if (match) {
1067 *match = prev_node;
1068 }
1069 return LY_EINCOMPLETE;
1070 }
1071
1072 /* we have not found any nodes */
1073 if (path_idx) {
1074 *path_idx = 0;
1075 }
1076 if (match) {
1077 *match = NULL;
1078 }
1079 return LY_ENOTFOUND;
1080}
1081
1082LY_ERR
1083ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1084{
1085 LY_ERR ret;
1086 struct lyd_node *m;
1087
1088 ret = ly_path_eval_partial(path, start, NULL, &m);
1089
1090 if (ret == LY_SUCCESS) {
1091 /* last node was found */
1092 if (match) {
1093 *match = m;
1094 }
1095 return LY_SUCCESS;
1096 }
1097
1098 /* not a full match */
1099 if (match) {
1100 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001101 }
1102 return LY_ENOTFOUND;
1103}
1104
1105LY_ERR
1106ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1107{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001108 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001109
1110 if (!path) {
1111 return LY_SUCCESS;
1112 }
1113
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001114 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001115 LY_ARRAY_FOR(path, u) {
1116 LY_ARRAY_INCREMENT(*dup);
1117 (*dup)[u].node = path[u].node;
1118 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001119 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001120 (*dup)[u].pred_type = path[u].pred_type;
1121 LY_ARRAY_FOR(path[u].predicates, v) {
1122 struct ly_path_predicate *pred = &path[u].predicates[v];
1123
1124 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1125 switch (path[u].pred_type) {
1126 case LY_PATH_PREDTYPE_POSITION:
1127 /* position-predicate */
1128 (*dup)[u].predicates[v].position = pred->position;
1129 break;
1130 case LY_PATH_PREDTYPE_LIST:
1131 case LY_PATH_PREDTYPE_LEAFLIST:
1132 /* key-predicate or leaf-list-predicate */
1133 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001134 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vasko04338d92021-09-01 07:58:14 +02001135 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
Michal Vasko004d3152020-06-11 19:59:22 +02001136 break;
1137 case LY_PATH_PREDTYPE_NONE:
1138 break;
1139 }
1140 }
1141 }
1142 }
1143
1144 return LY_SUCCESS;
1145}
1146
1147void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001148ly_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 +02001149{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001150 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001151 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001152
1153 if (!predicates) {
1154 return;
1155 }
1156
1157 LY_ARRAY_FOR(predicates, u) {
1158 switch (pred_type) {
1159 case LY_PATH_PREDTYPE_POSITION:
1160 case LY_PATH_PREDTYPE_NONE:
1161 /* nothing to free */
1162 break;
1163 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001164 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001165 if (predicates[u].value.realtype) {
1166 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001167 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001168 }
Michal Vasko004d3152020-06-11 19:59:22 +02001169 break;
1170 }
1171 }
1172 LY_ARRAY_FREE(predicates);
1173}
1174
1175void
1176ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1177{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001178 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001179
Michal Vasko55b84812021-05-11 09:23:58 +02001180 if (!path) {
1181 return;
1182 }
1183
Michal Vasko004d3152020-06-11 19:59:22 +02001184 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001185 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001186 }
1187 LY_ARRAY_FREE(path);
1188}