blob: e631e3ac36ad6a2ccca12aac56bd2d0f4b55ad24 [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,
Radek Krejci0f969882020-08-21 16:56:47 +020049 uint16_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
214 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100215 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200216 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200217 }
218 }
219
Radek Krejciba03a5a2020-08-27 14:40:41 +0200220cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100221 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200222 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200223 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200224
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100226 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200227 ly_set_free(set, NULL);
228 return LY_EVALID;
229}
230
231LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200232ly_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 +0200233 ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200234{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200235 LY_ERR ret = LY_SUCCESS;
236 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200237 uint16_t tok_idx, cur_len;
238 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200239
240 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200241 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
242 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200243 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
244
Radek Krejciddace2c2021-01-08 11:30:56 +0100245 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100246
Michal Vasko004d3152020-06-11 19:59:22 +0200247 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200248 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200249 tok_idx = 0;
250
251 if (begin == LY_PATH_BEGIN_EITHER) {
252 /* is the path relative? */
253 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200254 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200255 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200256 /* mandatory '..' */
257 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
258
259 do {
260 /* '/' */
261 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
262
263 /* optional '..' */
264 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200265 }
266 }
267 } else {
268 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200269 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 +0200270 }
271
272 do {
273 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200274 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 +0200275
276 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200277 cur_node = exp->expr + exp->tok_pos[tok_idx];
278 cur_len = exp->tok_len[tok_idx];
279 if (prefix == LY_PATH_PREFIX_MANDATORY) {
280 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100281 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200282 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200283 goto error;
284 }
285 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
286 if (!prev_prefix) {
287 /* the first node must have a prefix */
288 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100289 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200290 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200291 goto error;
292 }
293
294 /* remember the first prefix */
295 prev_prefix = cur_node;
296 } else {
297 /* the prefix must be different, if any */
298 ptr = strnstr(cur_node, ":", cur_len);
299 if (ptr) {
300 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100301 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix 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 this next prefix */
307 prev_prefix = cur_node;
308 }
309 }
Michal Vasko004d3152020-06-11 19:59:22 +0200310 }
311
312 ++tok_idx;
313
314 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200315 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200316
Radek Krejci0f969882020-08-21 16:56:47 +0200317 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200318 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
319
320 /* trailing token check */
321 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100322 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 +0200323 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200324 goto error;
325 }
326
327 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100328
Radek Krejciddace2c2021-01-08 11:30:56 +0100329 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200330 return LY_SUCCESS;
331
332error:
333 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100334 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200335 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200336}
337
338LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200339ly_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 +0200340 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200341{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200342 LY_ERR ret = LY_SUCCESS;
343 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200344 uint16_t tok_idx;
345
346 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
347 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
348
Radek Krejciddace2c2021-01-08 11:30:56 +0100349 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100350
Michal Vasko004d3152020-06-11 19:59:22 +0200351 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200352 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200353 tok_idx = 0;
354
Radek Krejcif03a9e22020-09-18 20:09:31 +0200355 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200356
357 /* trailing token check */
358 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100359 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200360 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200361 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200362 goto error;
363 }
364
365 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100366
Radek Krejciddace2c2021-01-08 11:30:56 +0100367 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200368 return LY_SUCCESS;
369
370error:
371 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100372 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200373 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200374}
375
376/**
377 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
378 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200379 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200380 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200381 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
382 * and ::LY_VALUE_SCHEMA_RESOLVED.
Radek Krejci09c77442021-04-26 11:10:34 +0200383 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200384 * @param[in] expr Parsed path.
385 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200386 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200387 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200388 * @param[out] mod Resolved module.
389 * @param[out] name Parsed node name.
390 * @param[out] name_len Length of @p name.
391 * @return LY_ERR value.
392 */
393static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200394ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskoed725d72021-06-23 12:03:45 +0200395 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
396 void *prefix_data, const struct lys_module **mod, const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200397{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100398 LY_ERR ret;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200399 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200400 size_t len;
401
402 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
403
404 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200405 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
406 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
407 pref = expr->expr + expr->tok_pos[tok_idx];
408 } else {
409 len = 0;
410 }
Michal Vasko004d3152020-06-11 19:59:22 +0200411
412 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200413 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100414 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100415
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200416 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200417 if (!*mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100418 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100419 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200420 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100421 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200422 } else if (!(*mod)->implemented) {
Michal Vaskoed725d72021-06-23 12:03:45 +0200423 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
424 ret = LY_EVALID;
425 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200426 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100427
Radek Krejciddace2c2021-01-08 11:30:56 +0100428 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200429 } else {
430 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200431 case LY_VALUE_SCHEMA:
432 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200433 if (!cur_mod) {
434 LOGINT_RET(ctx);
435 }
436 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200437 *mod = cur_mod;
438 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200439 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200440 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200441 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200442 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200443 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200444 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200445 *mod = prev_ctx_node->module;
446 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200447 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200448 case LY_VALUE_XML:
Radek Krejcif9943642021-04-26 10:18:21 +0200449 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200450 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200451 }
452 }
453
454 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200455 if (pref) {
456 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200457 *name_len = expr->tok_len[tok_idx] - len - 1;
458 } else {
459 *name = expr->expr + expr->tok_pos[tok_idx];
460 *name_len = expr->tok_len[tok_idx];
461 }
462
463 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100464
465error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100466 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200467 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200468}
469
470LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200471ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci8df109d2021-04-23 12:19:08 +0200472 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200473 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200474{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100475 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200476 struct ly_path_predicate *p;
477 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100478 const struct lys_module *mod = NULL;
Michal Vasko4911eeb2021-06-28 11:23:05 +0200479 const char *name, *val;
480 size_t name_len, val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200481
Michal Vasko00cbf532020-06-15 13:58:47 +0200482 assert(ctx && ctx_node);
483
Radek Krejciddace2c2021-01-08 11:30:56 +0100484 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100485
Michal Vasko004d3152020-06-11 19:59:22 +0200486 *pred_type = 0;
487
Michal Vasko004d3152020-06-11 19:59:22 +0200488 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200489 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100490 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200491 }
492
493 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
494 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100495 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200496 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100497 ret = LY_EVALID;
498 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200499 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100500 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200501 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100502 ret = LY_EVALID;
503 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200504 }
505
506 do {
507 /* NameTest, find the key */
Michal Vaskoed725d72021-06-23 12:03:45 +0200508 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
509 &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100510 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200511 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100512 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100513 ret = LY_ENOTFOUND;
514 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200515 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100516 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
517 key->name);
518 ret = LY_EVALID;
519 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200520 }
521 ++(*tok_idx);
522
Michal Vasko004d3152020-06-11 19:59:22 +0200523 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200524 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200525 *pred_type = LY_PATH_PREDTYPE_LIST;
526 }
527 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100528 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200529 p->key = key;
530
531 /* '=' */
532 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
533 ++(*tok_idx);
534
Michal Vasko4911eeb2021-06-28 11:23:05 +0200535 /* Literal or Number */
536 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
537 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
538 /* skip quotes */
539 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
540 val_len = expr->tok_len[*tok_idx] - 2;
541 } else {
542 val = expr->expr + expr->tok_pos[*tok_idx];
543 val_len = expr->tok_len[*tok_idx];
544 }
545
546 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100547 LOG_LOCSET(key, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200548 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
549 prefix_data, LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100550 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200551 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200552 ++(*tok_idx);
553
Michal Vaskoae875662020-10-21 10:33:17 +0200554 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200555 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200556
Michal Vasko004d3152020-06-11 19:59:22 +0200557 /* ']' */
558 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
559 ++(*tok_idx);
560
561 /* another predicate follows? */
562 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
563
564 /* check that all keys were set */
565 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100566 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200567 ++key_count;
568 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200569 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200570 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100571 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200572 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200573 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200574 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100575 ret = LY_EVALID;
576 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200577 }
578
579 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
580 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100581 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200582 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100583 ret = LY_EVALID;
584 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200585 }
586 ++(*tok_idx);
587
588 /* new predicate */
589 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100590 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200591
592 /* '=' */
593 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
594 ++(*tok_idx);
595
Michal Vasko4911eeb2021-06-28 11:23:05 +0200596 /* Literal or Number */
597 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
598 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
599 /* skip quotes */
600 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
601 val_len = expr->tok_len[*tok_idx] - 2;
602 } else {
603 val = expr->expr + expr->tok_pos[*tok_idx];
604 val_len = expr->tok_len[*tok_idx];
605 }
606
Michal Vasko004d3152020-06-11 19:59:22 +0200607 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100608 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200609 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
610 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100611 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200612 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200613 ++(*tok_idx);
614
Michal Vaskoae875662020-10-21 10:33:17 +0200615 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200616 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200617
Michal Vasko004d3152020-06-11 19:59:22 +0200618 /* ']' */
619 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
620 ++(*tok_idx);
621 } else {
622 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
623 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100624 ret = LY_EVALID;
625 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200626 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100627 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200628 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100629 ret = LY_EVALID;
630 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200631 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100632 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200633 }
Michal Vasko004d3152020-06-11 19:59:22 +0200634
635 /* new predicate */
636 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100637 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200638
639 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100640 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200641 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200642
643 /* ']' */
644 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
645 ++(*tok_idx);
646 }
647
Radek Krejci2efc45b2020-12-22 16:25:44 +0100648cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100649 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100650 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200651}
652
653/**
654 * @brief Compile leafref predicate. Actually, it is only checked.
655 *
656 * @param[in] ctx_node Context node, node for which the predicate is defined.
657 * @param[in] cur_node Current (original context) node.
658 * @param[in] expr Parsed path.
659 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200660 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200661 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200662 * @return LY_ERR value.
663 */
664static LY_ERR
665ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vasko24fc4d12021-07-12 14:41:20 +0200666 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200667{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100668 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200669 const struct lysc_node *key, *node, *node2;
670 const struct lys_module *mod;
671 const char *name;
672 size_t name_len;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 struct ly_ctx *ctx = cur_node->module->ctx;
674
Radek Krejciddace2c2021-01-08 11:30:56 +0100675 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200676
Michal Vasko004d3152020-06-11 19:59:22 +0200677 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200678 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100679 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200680 }
681
682 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100683 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200684 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100685 ret = LY_EVALID;
686 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200687 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100688 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200689 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100690 ret = LY_EVALID;
691 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200692 }
693
694 do {
695 /* NameTest, find the key */
Michal Vasko24fc4d12021-07-12 14:41:20 +0200696 ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
697 &mod, &name, &name_len);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100698 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100699 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200700 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100701 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100702 ret = LY_EVALID;
703 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200704 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100705 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200706 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100707 ret = LY_EVALID;
708 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200709 }
710 ++(*tok_idx);
711
712 /* we are not actually compiling, throw the key away */
713 (void)key;
714
715 /* '=' */
716 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
717 ++(*tok_idx);
718
719 /* FuncName */
720 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
721 ++(*tok_idx);
722
723 /* evaluating from the "current()" node */
724 node = cur_node;
725
726 /* '(' */
727 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
728 ++(*tok_idx);
729
730 /* ')' */
731 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
732 ++(*tok_idx);
733
734 do {
735 /* '/' */
736 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
737 ++(*tok_idx);
738
739 /* go to parent */
740 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100741 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
742 ret = LY_EVALID;
743 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200744 }
745 node = lysc_data_parent(node);
746
747 /* '..' */
748 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
749 ++(*tok_idx);
750 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
751
752 do {
753 /* '/' */
754 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
755 ++(*tok_idx);
756
757 /* NameTest */
758 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko24fc4d12021-07-12 14:41:20 +0200759 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
760 prefix_data, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100761 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200762 if (!node2) {
Radek Krejci422afb12021-03-04 16:38:16 +0100763 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100764 ret = LY_EVALID;
765 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200766 }
767 node = node2;
768 ++(*tok_idx);
769 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
770
771 /* check the last target node */
772 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100773 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200774 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100775 ret = LY_EVALID;
776 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200777 }
778
779 /* we are not actually compiling, throw the rightside node away */
780 (void)node;
781
782 /* ']' */
783 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
784 ++(*tok_idx);
785
Radek Krejci0f969882020-08-21 16:56:47 +0200786 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200787 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
788
Radek Krejci2efc45b2020-12-22 16:25:44 +0100789cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100790 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100791 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200792}
793
Michal Vaskoed725d72021-06-23 12:03:45 +0200794/**
795 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
796 *
797 * @param[in] ctx libyang context.
798 * @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 +0200799 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +0200800 * @param[in] ctx_node Optional context node, mandatory of @p lref.
801 * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
802 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
803 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
804 * @param[in] expr Parsed path.
805 * @param[in] lref Whether leafref is being compiled or not.
806 * @param[in] oper Oper option (@ref path_oper_options).
807 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +0200808 * @param[in] limit_access_tree Whether to limit accessible tree as described in
809 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +0200810 * @param[in] format Format of the path.
811 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +0200812 * @param[out] path Compiled path.
813 * @return LY_ERECOMPILE, only if @p lref.
814 * @return LY_ERR value.
815 */
816static LY_ERR
817_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
818 const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
Michal Vasko0884d212021-10-14 09:21:46 +0200819 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200820{
821 LY_ERR ret = LY_SUCCESS;
822 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100823 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200824 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200825 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200826 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200827 const char *name;
828 size_t name_len;
829
Michal Vasko00cbf532020-06-15 13:58:47 +0200830 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200831 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200832 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
833 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200834
Michal Vasko0884d212021-10-14 09:21:46 +0200835 if (!limit_access_tree) {
836 op = NULL;
837 } else {
838 /* find operation, if we are in any */
839 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
840 }
Michal Vasko6b26e742020-07-17 15:02:10 +0200841
Radek Krejci2efc45b2020-12-22 16:25:44 +0100842 *path = NULL;
843
Michal Vasko6b26e742020-07-17 15:02:10 +0200844 /* remember original context node */
845 cur_node = ctx_node;
Radek Krejciddace2c2021-01-08 11:30:56 +0100846 LOG_LOCINIT(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200847
Michal Vasko00cbf532020-06-15 13:58:47 +0200848 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100849 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200850 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100851 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200852 }
853
Michal Vasko004d3152020-06-11 19:59:22 +0200854 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
855 /* absolute path */
856 ctx_node = NULL;
857
858 ++tok_idx;
859 } else {
860 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +0100861 if (!ctx_node) {
862 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
863 ret = LY_EVALID;
864 goto cleanup;
865 }
866
867 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200868 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200869 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100870 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100871 ret = LY_EVALID;
872 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200873 }
874
875 /* get parent */
876 ctx_node = lysc_data_parent(ctx_node);
877
878 ++tok_idx;
879
880 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
881 ++tok_idx;
882 }
Michal Vasko004d3152020-06-11 19:59:22 +0200883 }
884
885 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200886 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200887 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100888 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200889 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100890 ret = LY_EVALID;
891 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200892 }
893
Michal Vasko14424ba2020-12-09 18:09:51 +0100894 /* NameTest */
895 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
896
Michal Vasko004d3152020-06-11 19:59:22 +0200897 /* get module and node name */
Michal Vasko24fc4d12021-07-12 14:41:20 +0200898 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
899 &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200900 ++tok_idx;
901
902 /* find the next node */
Radek Krejcid5d37432021-03-12 13:46:40 +0100903 if (!ctx_node && ext) {
904 node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
905 } else {
906 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
907 }
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100908 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Radek Krejci422afb12021-03-04 16:38:16 +0100909 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200910 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200911 goto cleanup;
912 }
913 ctx_node = node2;
914
915 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200916 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200917 p->node = ctx_node;
918
919 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +0200920 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +0200921 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200922 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200923 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 +0200924 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200925 }
926 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200927 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
928
Michal Vasko14424ba2020-12-09 18:09:51 +0100929 /* check leftover tokens */
930 if (tok_idx < expr->used) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100931 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
Michal Vasko14424ba2020-12-09 18:09:51 +0100932 ret = LY_EVALID;
933 goto cleanup;
934 }
935
Michal Vasko00cbf532020-06-15 13:58:47 +0200936 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +0200937 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100938 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200939 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100940 ret = LY_EVALID;
941 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200942 }
943
Michal Vasko004d3152020-06-11 19:59:22 +0200944cleanup:
945 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200946 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200947 *path = NULL;
948 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100949 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200950 return ret;
951}
952
953LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +0200954ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
955 const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
Michal Vasko0884d212021-10-14 09:21:46 +0200956 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200957{
Michal Vasko0884d212021-10-14 09:21:46 +0200958 return _ly_path_compile(ctx, cur_mod, ctx_node, ext, expr, 0, oper, target, limit_access_tree, format, prefix_data,
959 path);
Michal Vaskoed725d72021-06-23 12:03:45 +0200960}
961
962LY_ERR
963ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *ext,
964 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 +0200965 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +0200966{
Michal Vasko0884d212021-10-14 09:21:46 +0200967 return _ly_path_compile(ctx, ctx_node->module, ctx_node, ext, expr, 1, oper, target, 1, format, prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +0200968}
969
970LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200971ly_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 +0200972 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200973{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200974 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoacfc9282021-02-04 12:08:23 +0100975 struct lyd_node *prev_node = NULL, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200976 uint64_t pos;
977
978 assert(path && start);
979
980 if (lysc_data_parent(path[0].node)) {
981 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200982 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200983 } else {
984 /* absolute path, start from the first top-level sibling */
985 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +0100986 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200987 }
988 while (start->prev->next) {
989 start = start->prev;
990 }
991 }
992
993 LY_ARRAY_FOR(path, u) {
994 switch (path[u].pred_type) {
995 case LY_PATH_PREDTYPE_POSITION:
996 /* we cannot use hashes and want an instance on a specific position */
997 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200998 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200999 if (pos == path[u].predicates[0].position) {
1000 break;
1001 }
1002 ++pos;
1003 }
1004 break;
1005 case LY_PATH_PREDTYPE_LEAFLIST:
1006 /* we will use hashes to find one leaf-list instance */
1007 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1008 lyd_find_sibling_first(start, target, &node);
1009 lyd_free_tree(target);
1010 break;
1011 case LY_PATH_PREDTYPE_LIST:
1012 /* we will use hashes to find one list instance */
1013 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
1014 lyd_find_sibling_first(start, target, &node);
1015 lyd_free_tree(target);
1016 break;
1017 case LY_PATH_PREDTYPE_NONE:
1018 /* we will use hashes to find one any/container/leaf instance */
1019 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
1020 break;
1021 }
1022
1023 if (!node) {
1024 /* no matching nodes */
1025 break;
1026 }
1027
Michal Vasko00cbf532020-06-15 13:58:47 +02001028 /* rememeber previous node */
1029 prev_node = node;
1030
Michal Vasko004d3152020-06-11 19:59:22 +02001031 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001032 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001033 }
1034
Michal Vasko004d3152020-06-11 19:59:22 +02001035 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001036 /* we have found the full path */
1037 if (path_idx) {
1038 *path_idx = u;
1039 }
1040 if (match) {
1041 *match = node;
1042 }
Michal Vasko004d3152020-06-11 19:59:22 +02001043 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001044
1045 } else if (prev_node) {
1046 /* we have found only some partial match */
1047 if (path_idx) {
1048 *path_idx = u - 1;
1049 }
1050 if (match) {
1051 *match = prev_node;
1052 }
1053 return LY_EINCOMPLETE;
1054 }
1055
1056 /* we have not found any nodes */
1057 if (path_idx) {
1058 *path_idx = 0;
1059 }
1060 if (match) {
1061 *match = NULL;
1062 }
1063 return LY_ENOTFOUND;
1064}
1065
1066LY_ERR
1067ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1068{
1069 LY_ERR ret;
1070 struct lyd_node *m;
1071
1072 ret = ly_path_eval_partial(path, start, NULL, &m);
1073
1074 if (ret == LY_SUCCESS) {
1075 /* last node was found */
1076 if (match) {
1077 *match = m;
1078 }
1079 return LY_SUCCESS;
1080 }
1081
1082 /* not a full match */
1083 if (match) {
1084 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001085 }
1086 return LY_ENOTFOUND;
1087}
1088
1089LY_ERR
1090ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1091{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001092 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001093
1094 if (!path) {
1095 return LY_SUCCESS;
1096 }
1097
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001098 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001099 LY_ARRAY_FOR(path, u) {
1100 LY_ARRAY_INCREMENT(*dup);
1101 (*dup)[u].node = path[u].node;
1102 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001103 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001104 (*dup)[u].pred_type = path[u].pred_type;
1105 LY_ARRAY_FOR(path[u].predicates, v) {
1106 struct ly_path_predicate *pred = &path[u].predicates[v];
1107
1108 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1109 switch (path[u].pred_type) {
1110 case LY_PATH_PREDTYPE_POSITION:
1111 /* position-predicate */
1112 (*dup)[u].predicates[v].position = pred->position;
1113 break;
1114 case LY_PATH_PREDTYPE_LIST:
1115 case LY_PATH_PREDTYPE_LEAFLIST:
1116 /* key-predicate or leaf-list-predicate */
1117 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001118 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vasko04338d92021-09-01 07:58:14 +02001119 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
Michal Vasko004d3152020-06-11 19:59:22 +02001120 break;
1121 case LY_PATH_PREDTYPE_NONE:
1122 break;
1123 }
1124 }
1125 }
1126 }
1127
1128 return LY_SUCCESS;
1129}
1130
1131void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001132ly_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 +02001133{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001134 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001135
1136 if (!predicates) {
1137 return;
1138 }
1139
1140 LY_ARRAY_FOR(predicates, u) {
1141 switch (pred_type) {
1142 case LY_PATH_PREDTYPE_POSITION:
1143 case LY_PATH_PREDTYPE_NONE:
1144 /* nothing to free */
1145 break;
1146 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001147 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001148 if (predicates[u].value.realtype) {
1149 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1150 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1151 }
Michal Vasko004d3152020-06-11 19:59:22 +02001152 break;
1153 }
1154 }
1155 LY_ARRAY_FREE(predicates);
1156}
1157
1158void
1159ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1160{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001161 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001162
Michal Vasko55b84812021-05-11 09:23:58 +02001163 if (!path) {
1164 return;
1165 }
1166
Michal Vasko004d3152020-06-11 19:59:22 +02001167 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001168 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001169 }
1170 LY_ARRAY_FREE(path);
1171}