blob: 4d94da4665d7dbd883444cc0f8560480af3a9c5e [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 */
14#define _ISOC99_SOURCE /* strtoull */
15
16#include "path.h"
17
18#include <assert.h>
19#include <ctype.h>
20#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020021#include <string.h>
Michal Vasko004d3152020-06-11 19:59:22 +020022
23#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020024#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020025#include "log.h"
26#include "plugins_types.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020027#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020028#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020029#include "tree_data_internal.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
Michal Vasko004d3152020-06-11 19:59:22 +020057 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020058 /* '[' */
59
Michal Vasko69730152020-10-09 16:30:07 +020060 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
61 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020062 ret = ly_set_new(&set);
63 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020064
65 do {
66 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020067 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020068
69 /* check prefix based on the options */
70 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
71 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Michal Vasko6b26e742020-07-17 15:02:10 +020072 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020073 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020074 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020075 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
76 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020077 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020078 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020079 }
80 if (!name) {
81 name = exp->expr + exp->tok_pos[*tok_idx];
82 name_len = exp->tok_len[*tok_idx];
83 } else {
84 ++name;
85 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
86 }
87
88 /* check whether it was not already specified */
89 for (i = 0; i < set->count; ++i) {
90 /* all the keys must be from the same module so this comparison should be fine */
91 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +020092 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020093 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020094 }
95 }
96
97 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +020098 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +020099 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200100
101 /* NameTest */
102 ++(*tok_idx);
103
104 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200105 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200106
107 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200108 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200109
110 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200111 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200112
Radek Krejci0f969882020-08-21 16:56:47 +0200113 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200114 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
115
Michal Vasko004d3152020-06-11 19:59:22 +0200116 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200117 /* '.' */
118
Michal Vasko004d3152020-06-11 19:59:22 +0200119 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200120 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200121
122 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200123 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200124
125 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200126 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200127
Michal Vasko004d3152020-06-11 19:59:22 +0200128 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200129 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200130
131 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200132 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200133
134 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
135 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200136 ret = ly_set_new(&set);
137 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200138
139 do {
140 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200141 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200142
143 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
144 if (!name) {
145 name = exp->expr + exp->tok_pos[*tok_idx];
146 name_len = exp->tok_len[*tok_idx];
147 } else {
148 ++name;
149 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
150 }
151
152 /* check whether it was not already specified */
153 for (i = 0; i < set->count; ++i) {
154 /* all the keys must be from the same module so this comparison should be fine */
155 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200156 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200157 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200158 }
159 }
160
161 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200162 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200163 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200164
165 /* NameTest */
166 ++(*tok_idx);
167
168 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200169 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200170
171 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200172 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200173 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200174 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200175 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200176 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200177 }
178 ++(*tok_idx);
179
180 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200181 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200182
183 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200184 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), 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_OPER_PATH), 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_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200191 do {
192 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200193 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200194 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
195
196 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200197 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200198
199 /* '/' */
200 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
201 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200202 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200203 }
204
205 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200206 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200207
Radek Krejci0f969882020-08-21 16:56:47 +0200208 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200209 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
210
211 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200212 LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
Michal Vasko69730152020-10-09 16:30:07 +0200213 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200214 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200215 }
216 }
217
Radek Krejciba03a5a2020-08-27 14:40:41 +0200218cleanup:
Michal Vasko004d3152020-06-11 19:59:22 +0200219 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200220 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200221
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222token_error:
Michal Vasko004d3152020-06-11 19:59:22 +0200223 ly_set_free(set, NULL);
224 return LY_EVALID;
225}
226
227LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200228ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
Radek Krejci0f969882020-08-21 16:56:47 +0200229 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200230{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200231 LY_ERR ret = LY_SUCCESS;
232 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200233 uint16_t tok_idx, cur_len;
234 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200235
236 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
237 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko69730152020-10-09 16:30:07 +0200238 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
239 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200240 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
241
242 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200243 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200244 tok_idx = 0;
245
246 if (begin == LY_PATH_BEGIN_EITHER) {
247 /* is the path relative? */
248 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
249 /* '..' */
250 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
251 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200252 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 +0200253 }
254 }
255 } else {
256 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200257 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 +0200258 }
259
260 do {
261 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200262 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 +0200263
264 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200265 cur_node = exp->expr + exp->tok_pos[tok_idx];
266 cur_len = exp->tok_len[tok_idx];
267 if (prefix == LY_PATH_PREFIX_MANDATORY) {
268 if (!strnstr(cur_node, ":", cur_len)) {
269 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200270 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200271 goto error;
272 }
273 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
274 if (!prev_prefix) {
275 /* the first node must have a prefix */
276 if (!strnstr(cur_node, ":", cur_len)) {
277 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200278 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200279 goto error;
280 }
281
282 /* remember the first prefix */
283 prev_prefix = cur_node;
284 } else {
285 /* the prefix must be different, if any */
286 ptr = strnstr(cur_node, ":", cur_len);
287 if (ptr) {
288 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
289 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Duplicate prefix 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 this next prefix */
295 prev_prefix = cur_node;
296 }
297 }
Michal Vasko004d3152020-06-11 19:59:22 +0200298 }
299
300 ++tok_idx;
301
302 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200303 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200304
Radek Krejci0f969882020-08-21 16:56:47 +0200305 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200306 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
307
308 /* trailing token check */
309 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200310 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
Michal Vasko69730152020-10-09 16:30:07 +0200311 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200312 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200313 goto error;
314 }
315
316 *expr = exp;
317 return LY_SUCCESS;
318
319error:
320 lyxp_expr_free(ctx, exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200321 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200322}
323
324LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200325ly_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 +0200326 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200327{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200328 LY_ERR ret = LY_SUCCESS;
329 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200330 uint16_t tok_idx;
331
332 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
333 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
334
335 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200336 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200337 tok_idx = 0;
338
Radek Krejcif03a9e22020-09-18 20:09:31 +0200339 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200340
341 /* trailing token check */
342 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200343 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200344 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200345 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200346 goto error;
347 }
348
349 *expr = exp;
350 return LY_SUCCESS;
351
352error:
353 lyxp_expr_free(ctx, exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200354 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200355}
356
357/**
358 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
359 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200360 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200361 * @param[in] cur_node Optional current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +0200362 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
363 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
364 * @param[in] expr Parsed path.
365 * @param[in] tok_idx Index in @p expr.
366 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200367 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200368 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200369 * @param[out] mod Resolved module.
370 * @param[out] name Parsed node name.
371 * @param[out] name_len Length of @p name.
372 * @return LY_ERR value.
373 */
374static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200375ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci0f969882020-08-21 16:56:47 +0200376 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
377 uint8_t lref, LY_PREFIX_FORMAT format, void *prefix_data, const struct lys_module **mod,
378 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200379{
380 const char *ptr;
381 size_t len;
382
383 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
384
385 /* get prefix */
386 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
387 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
388
389 /* find next node module */
390 if (ptr) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200391 *mod = ly_resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200392 if (!*mod) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200393 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200394 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200395 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200396 } else if (!(*mod)->implemented) {
397 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200398 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200399 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200400 }
Michal Vasko89b5c072020-10-06 13:52:44 +0200401 LY_CHECK_RET(lys_set_implemented((struct lys_module *)*mod));
Michal Vasko004d3152020-06-11 19:59:22 +0200402 }
403 } else {
404 switch (format) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200405 case LY_PREF_SCHEMA:
Michal Vasko004d3152020-06-11 19:59:22 +0200406 *mod = cur_mod;
407 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200408 case LY_PREF_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200409 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200410 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200411 }
412 *mod = prev_ctx_node->module;
413 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200414 case LY_PREF_XML:
Michal Vaskoc9795582020-10-08 16:22:17 +0200415 case LY_PREF_SCHEMA_RESOLVED:
Michal Vasko004d3152020-06-11 19:59:22 +0200416 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200417 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200418 }
419 }
420
421 /* set name */
422 if (ptr) {
423 *name = ptr + 1;
424 *name_len = expr->tok_len[tok_idx] - len - 1;
425 } else {
426 *name = expr->expr + expr->tok_pos[tok_idx];
427 *name_len = expr->tok_len[tok_idx];
428 }
429
430 return LY_SUCCESS;
431}
432
433LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200434ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci0f969882020-08-21 16:56:47 +0200435 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
436 LY_PREFIX_FORMAT format, void *prefix_data, struct ly_path_predicate **predicates,
437 enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200438{
439 struct ly_path_predicate *p;
440 const struct lysc_node *key;
441 const struct lys_module *mod;
442 const char *name;
443 size_t name_len, key_count;
444
Michal Vasko00cbf532020-06-15 13:58:47 +0200445 assert(ctx && ctx_node);
446
Michal Vasko004d3152020-06-11 19:59:22 +0200447 *pred_type = 0;
448
Michal Vasko004d3152020-06-11 19:59:22 +0200449 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200450 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200451 return LY_SUCCESS;
452 }
453
454 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
455 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200456 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200457 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200458 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200459 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200460 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200461 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200462 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200463 }
464
465 do {
466 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200467 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
Michal Vasko69730152020-10-09 16:30:07 +0200468 format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200469 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
470 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200471 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200472 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200473 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200474 LOGVAL_P(ctx, cur_node ? cur_node : key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200475 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200476 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200477 }
478 ++(*tok_idx);
479
Michal Vasko004d3152020-06-11 19:59:22 +0200480 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200481 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200482 *pred_type = LY_PATH_PREDTYPE_LIST;
483 }
484 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200485 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200486 p->key = key;
487
488 /* '=' */
489 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
490 ++(*tok_idx);
491
492 /* Literal */
493 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200494 LY_CHECK_RET(lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
495 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
496 LYD_HINT_DATA, key, NULL, LY_VLOG_LYSC, key));
Michal Vasko004d3152020-06-11 19:59:22 +0200497 ++(*tok_idx);
498
499 /* ']' */
500 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
501 ++(*tok_idx);
502
503 /* another predicate follows? */
504 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
505
506 /* check that all keys were set */
507 key_count = 0;
508 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
509 ++key_count;
510 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200511 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200512 /* names (keys) are unique - it was checked when parsing */
Michal Vasko6b26e742020-07-17 15:02:10 +0200513 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200514 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200515 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200516 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200517 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200518 }
519
520 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
521 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200522 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200523 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200524 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200525 }
526 ++(*tok_idx);
527
528 /* new predicate */
529 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200530 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200531
532 /* '=' */
533 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
534 ++(*tok_idx);
535
536 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
537 /* store the value */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200538 LY_CHECK_RET(lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
539 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
540 LYD_HINT_DATA, ctx_node, NULL, LY_VLOG_LYSC, ctx_node));
Michal Vasko004d3152020-06-11 19:59:22 +0200541 ++(*tok_idx);
542
543 /* ']' */
544 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
545 ++(*tok_idx);
546 } else {
547 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
548 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200549 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200550 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200551 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200552 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200553 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200554 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200555 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200556 }
Michal Vasko004d3152020-06-11 19:59:22 +0200557
558 /* new predicate */
559 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200560 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200561
562 /* syntax was already checked */
563 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200564 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200565
566 /* ']' */
567 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
568 ++(*tok_idx);
569 }
570
571 return LY_SUCCESS;
572}
573
574/**
575 * @brief Compile leafref predicate. Actually, it is only checked.
576 *
577 * @param[in] ctx_node Context node, node for which the predicate is defined.
578 * @param[in] cur_node Current (original context) node.
579 * @param[in] expr Parsed path.
580 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200581 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200582 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200583 * @return LY_ERR value.
584 */
585static LY_ERR
586ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Radek Krejci0f969882020-08-21 16:56:47 +0200587 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200588{
589 const struct lysc_node *key, *node, *node2;
590 const struct lys_module *mod;
591 const char *name;
592 size_t name_len;
593
Michal Vasko004d3152020-06-11 19:59:22 +0200594 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200595 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200596 return LY_SUCCESS;
597 }
598
599 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200600 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200601 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200602 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200603 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200604 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200605 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200606 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200607 }
608
609 do {
610 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200611 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
Michal Vasko69730152020-10-09 16:30:07 +0200612 LY_PATH_LREF_TRUE, format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200613 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
614 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200615 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200616 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200617 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200618 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200619 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200620 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200621 }
622 ++(*tok_idx);
623
624 /* we are not actually compiling, throw the key away */
625 (void)key;
626
627 /* '=' */
628 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
629 ++(*tok_idx);
630
631 /* FuncName */
632 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
633 ++(*tok_idx);
634
635 /* evaluating from the "current()" node */
636 node = cur_node;
637
638 /* '(' */
639 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
640 ++(*tok_idx);
641
642 /* ')' */
643 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
644 ++(*tok_idx);
645
646 do {
647 /* '/' */
648 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
649 ++(*tok_idx);
650
651 /* go to parent */
652 if (!node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200653 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200654 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200655 }
656 node = lysc_data_parent(node);
657
658 /* '..' */
659 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
660 ++(*tok_idx);
661 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
662
663 do {
664 /* '/' */
665 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
666 ++(*tok_idx);
667
668 /* NameTest */
669 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko6b26e742020-07-17 15:02:10 +0200670 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko69730152020-10-09 16:30:07 +0200671 LY_PATH_LREF_TRUE, format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200672 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
673 if (!node2) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200674 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200675 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200676 }
677 node = node2;
678 ++(*tok_idx);
679 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
680
681 /* check the last target node */
682 if (node->nodetype != LYS_LEAF) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200683 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
Michal Vasko69730152020-10-09 16:30:07 +0200684 "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
685 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200686 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200687 }
688
689 /* we are not actually compiling, throw the rightside node away */
690 (void)node;
691
692 /* ']' */
693 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
694 ++(*tok_idx);
695
Radek Krejci0f969882020-08-21 16:56:47 +0200696 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200697 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
698
699 return LY_SUCCESS;
700}
701
702LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200703ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Radek Krejci0f969882020-08-21 16:56:47 +0200704 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target, LY_PREFIX_FORMAT format,
705 void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200706{
707 LY_ERR ret = LY_SUCCESS;
708 uint16_t tok_idx = 0;
709 const struct lys_module *mod;
Michal Vasko6b26e742020-07-17 15:02:10 +0200710 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200711 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200712 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200713 const char *name;
714 size_t name_len;
715
Michal Vasko00cbf532020-06-15 13:58:47 +0200716 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200717 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200718 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200719 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
720 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200721
Michal Vasko6b26e742020-07-17 15:02:10 +0200722 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200723 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200724
725 /* remember original context node */
726 cur_node = ctx_node;
727
Michal Vasko004d3152020-06-11 19:59:22 +0200728 *path = NULL;
729
Michal Vasko00cbf532020-06-15 13:58:47 +0200730 if (oper == LY_PATH_OPER_OUTPUT) {
731 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
732 } else {
733 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
734 }
735
Michal Vasko004d3152020-06-11 19:59:22 +0200736 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
737 /* absolute path */
738 ctx_node = NULL;
739
740 ++tok_idx;
741 } else {
742 /* relative path */
743 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
744 if (!ctx_node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200745 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200746 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200747 }
748
749 /* get parent */
750 ctx_node = lysc_data_parent(ctx_node);
751
752 ++tok_idx;
753
754 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
755 ++tok_idx;
756 }
757
Michal Vasko00cbf532020-06-15 13:58:47 +0200758 /* we are not storing the parent */
759 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200760 }
761
762 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200763 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
764 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200765 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200766 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200767 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200768 }
769
Michal Vasko004d3152020-06-11 19:59:22 +0200770 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200771 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
Michal Vasko69730152020-10-09 16:30:07 +0200772 prefix_data, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200773 ++tok_idx;
774
775 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200776 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko6b26e742020-07-17 15:02:10 +0200777 if (!node2 || ((node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
778 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200779 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200780 goto cleanup;
781 }
782 ctx_node = node2;
783
784 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200785 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200786 p->node = ctx_node;
787
788 /* compile any predicates */
789 if (lref == LY_PATH_LREF_TRUE) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200790 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200791 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200792 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 +0200793 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200794 }
795 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200796 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
797
Michal Vasko00cbf532020-06-15 13:58:47 +0200798 /* check last compiled node */
Michal Vasko69730152020-10-09 16:30:07 +0200799 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
800 (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200801 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200802 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200803 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200804 }
805
Michal Vasko004d3152020-06-11 19:59:22 +0200806cleanup:
807 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200808 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200809 *path = NULL;
810 }
811 return ret;
812}
813
814LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200815ly_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 +0200816 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200817{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200818 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200819 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200820 uint64_t pos;
821
822 assert(path && start);
823
824 if (lysc_data_parent(path[0].node)) {
825 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200826 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200827 } else {
828 /* absolute path, start from the first top-level sibling */
829 while (start->parent) {
830 start = (struct lyd_node *)start->parent;
831 }
832 while (start->prev->next) {
833 start = start->prev;
834 }
835 }
836
837 LY_ARRAY_FOR(path, u) {
838 switch (path[u].pred_type) {
839 case LY_PATH_PREDTYPE_POSITION:
840 /* we cannot use hashes and want an instance on a specific position */
841 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200842 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200843 if (pos == path[u].predicates[0].position) {
844 break;
845 }
846 ++pos;
847 }
848 break;
849 case LY_PATH_PREDTYPE_LEAFLIST:
850 /* we will use hashes to find one leaf-list instance */
851 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
852 lyd_find_sibling_first(start, target, &node);
853 lyd_free_tree(target);
854 break;
855 case LY_PATH_PREDTYPE_LIST:
856 /* we will use hashes to find one list instance */
857 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
858 lyd_find_sibling_first(start, target, &node);
859 lyd_free_tree(target);
860 break;
861 case LY_PATH_PREDTYPE_NONE:
862 /* we will use hashes to find one any/container/leaf instance */
863 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
864 break;
865 }
866
867 if (!node) {
868 /* no matching nodes */
869 break;
870 }
871
Michal Vasko00cbf532020-06-15 13:58:47 +0200872 /* rememeber previous node */
873 prev_node = node;
874
Michal Vasko004d3152020-06-11 19:59:22 +0200875 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200876 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +0200877 }
878
Michal Vasko004d3152020-06-11 19:59:22 +0200879 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200880 /* we have found the full path */
881 if (path_idx) {
882 *path_idx = u;
883 }
884 if (match) {
885 *match = node;
886 }
Michal Vasko004d3152020-06-11 19:59:22 +0200887 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200888
889 } else if (prev_node) {
890 /* we have found only some partial match */
891 if (path_idx) {
892 *path_idx = u - 1;
893 }
894 if (match) {
895 *match = prev_node;
896 }
897 return LY_EINCOMPLETE;
898 }
899
900 /* we have not found any nodes */
901 if (path_idx) {
902 *path_idx = 0;
903 }
904 if (match) {
905 *match = NULL;
906 }
907 return LY_ENOTFOUND;
908}
909
910LY_ERR
911ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
912{
913 LY_ERR ret;
914 struct lyd_node *m;
915
916 ret = ly_path_eval_partial(path, start, NULL, &m);
917
918 if (ret == LY_SUCCESS) {
919 /* last node was found */
920 if (match) {
921 *match = m;
922 }
923 return LY_SUCCESS;
924 }
925
926 /* not a full match */
927 if (match) {
928 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200929 }
930 return LY_ENOTFOUND;
931}
932
933LY_ERR
934ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
935{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200936 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200937
938 if (!path) {
939 return LY_SUCCESS;
940 }
941
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200942 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200943 LY_ARRAY_FOR(path, u) {
944 LY_ARRAY_INCREMENT(*dup);
945 (*dup)[u].node = path[u].node;
946 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200947 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200948 (*dup)[u].pred_type = path[u].pred_type;
949 LY_ARRAY_FOR(path[u].predicates, v) {
950 struct ly_path_predicate *pred = &path[u].predicates[v];
951
952 LY_ARRAY_INCREMENT((*dup)[u].predicates);
953 switch (path[u].pred_type) {
954 case LY_PATH_PREDTYPE_POSITION:
955 /* position-predicate */
956 (*dup)[u].predicates[v].position = pred->position;
957 break;
958 case LY_PATH_PREDTYPE_LIST:
959 case LY_PATH_PREDTYPE_LEAFLIST:
960 /* key-predicate or leaf-list-predicate */
961 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +0200962 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
963 break;
964 case LY_PATH_PREDTYPE_NONE:
965 break;
966 }
967 }
968 }
969 }
970
971 return LY_SUCCESS;
972}
973
974void
975ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, const struct lysc_node *llist,
Radek Krejci0f969882020-08-21 16:56:47 +0200976 struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200977{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200978 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200979
980 if (!predicates) {
981 return;
982 }
983
984 LY_ARRAY_FOR(predicates, u) {
985 switch (pred_type) {
986 case LY_PATH_PREDTYPE_POSITION:
987 case LY_PATH_PREDTYPE_NONE:
988 /* nothing to free */
989 break;
990 case LY_PATH_PREDTYPE_LIST:
991 ((struct lysc_node_leaf *)predicates[u].key)->type->plugin->free(ctx, &predicates[u].value);
992 break;
993 case LY_PATH_PREDTYPE_LEAFLIST:
994 ((struct lysc_node_leaflist *)llist)->type->plugin->free(ctx, &predicates[u].value);
995 break;
996 }
997 }
998 LY_ARRAY_FREE(predicates);
999}
1000
1001void
1002ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1003{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001004 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001005
1006 LY_ARRAY_FOR(path, u) {
1007 ly_path_predicates_free(ctx, path[u].pred_type, path[u].node, path[u].predicates);
1008 }
1009 LY_ARRAY_FREE(path);
1010}