blob: 9cbc7a7b01c7cc0af7a330a14a55cbc5554e9375 [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);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100173 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
174 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200175 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200176 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200177 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200178 }
179 ++(*tok_idx);
180
181 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200182 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200183
184 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200185 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200186
187 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200188 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200189
190 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200191 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200192 do {
193 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200194 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200195 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
196
197 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200198 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200199
200 /* '/' */
201 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
202 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200203 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200204 }
205
206 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200207 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200208
Radek Krejci0f969882020-08-21 16:56:47 +0200209 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200210 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
211
212 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200213 LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
Michal Vasko69730152020-10-09 16:30:07 +0200214 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200215 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200216 }
217 }
218
Radek Krejciba03a5a2020-08-27 14:40:41 +0200219cleanup:
Michal Vasko004d3152020-06-11 19:59:22 +0200220 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200221 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200222
Radek Krejciba03a5a2020-08-27 14:40:41 +0200223token_error:
Michal Vasko004d3152020-06-11 19:59:22 +0200224 ly_set_free(set, NULL);
225 return LY_EVALID;
226}
227
228LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200229ly_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 +0200230 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200231{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200232 LY_ERR ret = LY_SUCCESS;
233 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200234 uint16_t tok_idx, cur_len;
235 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200236
237 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
238 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko69730152020-10-09 16:30:07 +0200239 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
240 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200241 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
242
243 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200244 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200245 tok_idx = 0;
246
247 if (begin == LY_PATH_BEGIN_EITHER) {
248 /* is the path relative? */
249 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200250 /* relative path check specific to leafref */
251 if (lref == LY_PATH_LREF_TRUE) {
252 /* mandatory '..' */
253 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
254
255 do {
256 /* '/' */
257 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
258
259 /* optional '..' */
260 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200261 }
262 }
263 } else {
264 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200265 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 +0200266 }
267
268 do {
269 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200270 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 +0200271
272 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200273 cur_node = exp->expr + exp->tok_pos[tok_idx];
274 cur_len = exp->tok_len[tok_idx];
275 if (prefix == LY_PATH_PREFIX_MANDATORY) {
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 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
282 if (!prev_prefix) {
283 /* the first node must have a prefix */
284 if (!strnstr(cur_node, ":", cur_len)) {
285 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200286 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200287 goto error;
288 }
289
290 /* remember the first prefix */
291 prev_prefix = cur_node;
292 } else {
293 /* the prefix must be different, if any */
294 ptr = strnstr(cur_node, ":", cur_len);
295 if (ptr) {
296 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
297 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200298 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200299 goto error;
300 }
301
302 /* remember this next prefix */
303 prev_prefix = cur_node;
304 }
305 }
Michal Vasko004d3152020-06-11 19:59:22 +0200306 }
307
308 ++tok_idx;
309
310 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200311 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200312
Radek Krejci0f969882020-08-21 16:56:47 +0200313 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200314 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
315
316 /* trailing token check */
317 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200318 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
Michal Vasko69730152020-10-09 16:30:07 +0200319 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200320 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200321 goto error;
322 }
323
324 *expr = exp;
325 return LY_SUCCESS;
326
327error:
328 lyxp_expr_free(ctx, exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200329 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200330}
331
332LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200333ly_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 +0200334 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200335{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200336 LY_ERR ret = LY_SUCCESS;
337 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200338 uint16_t tok_idx;
339
340 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
341 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
342
343 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200344 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200345 tok_idx = 0;
346
Radek Krejcif03a9e22020-09-18 20:09:31 +0200347 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200348
349 /* trailing token check */
350 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200351 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200352 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200353 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200354 goto error;
355 }
356
357 *expr = exp;
358 return LY_SUCCESS;
359
360error:
361 lyxp_expr_free(ctx, exp);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200362 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200363}
364
365/**
366 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
367 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200368 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200369 * @param[in] cur_node Optional current (original context) node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200370 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_PREF_SCHEMA*.
371 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_PREF_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200372 * @param[in] expr Parsed path.
373 * @param[in] tok_idx Index in @p expr.
374 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200375 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200376 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200377 * @param[out] mod Resolved module.
378 * @param[out] name Parsed node name.
379 * @param[out] name_len Length of @p name.
380 * @return LY_ERR value.
381 */
382static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200383ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200384 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100385 LY_PREFIX_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
386 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200387{
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200388 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200389 size_t len;
390
391 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko405cc9e2020-12-01 12:01:27 +0100392 assert((lref != LY_PATH_LREF_TRUE) || unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200393
394 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200395 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
396 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
397 pref = expr->expr + expr->tok_pos[tok_idx];
398 } else {
399 len = 0;
400 }
Michal Vasko004d3152020-06-11 19:59:22 +0200401
402 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200403 if (pref) {
404 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200405 if (!*mod) {
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100406 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
407 len, pref, ly_format2str(format));
Radek Krejci8de005f2020-06-25 17:02:07 +0200408 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200409 } else if (!(*mod)->implemented) {
410 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200411 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200412 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200413 }
Michal Vasko405cc9e2020-12-01 12:01:27 +0100414 LY_CHECK_RET(lys_set_implemented_r((struct lys_module *)*mod, NULL, unres));
Michal Vasko004d3152020-06-11 19:59:22 +0200415 }
416 } else {
417 switch (format) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200418 case LY_PREF_SCHEMA:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200419 case LY_PREF_SCHEMA_RESOLVED:
420 if (!cur_mod) {
421 LOGINT_RET(ctx);
422 }
423 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200424 *mod = cur_mod;
425 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200426 case LY_PREF_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200427 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200428 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200429 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200430 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200431 *mod = prev_ctx_node->module;
432 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200433 case LY_PREF_XML:
Michal Vasko004d3152020-06-11 19:59:22 +0200434 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200435 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200436 }
437 }
438
439 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200440 if (pref) {
441 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200442 *name_len = expr->tok_len[tok_idx] - len - 1;
443 } else {
444 *name = expr->expr + expr->tok_pos[tok_idx];
445 *name_len = expr->tok_len[tok_idx];
446 }
447
448 return LY_SUCCESS;
449}
450
451LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200452ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200453 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format,
454 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200455{
456 struct ly_path_predicate *p;
457 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100458 const struct lys_module *mod = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200459 const char *name;
460 size_t name_len, key_count;
461
Michal Vasko00cbf532020-06-15 13:58:47 +0200462 assert(ctx && ctx_node);
463
Michal Vasko004d3152020-06-11 19:59:22 +0200464 *pred_type = 0;
465
Michal Vasko004d3152020-06-11 19:59:22 +0200466 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200467 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200468 return LY_SUCCESS;
469 }
470
471 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
472 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200473 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200474 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200475 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200476 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200477 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200478 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200479 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200480 }
481
482 do {
483 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200484 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100485 format, prefix_data, NULL, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100486 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200487 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200488 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200489 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200490 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200491 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 +0200492 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200493 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200494 }
495 ++(*tok_idx);
496
Michal Vasko004d3152020-06-11 19:59:22 +0200497 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200498 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200499 *pred_type = LY_PATH_PREDTYPE_LIST;
500 }
501 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200502 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200503 p->key = key;
504
505 /* '=' */
506 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
507 ++(*tok_idx);
508
509 /* Literal */
510 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200511 LY_CHECK_RET(lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
512 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
513 LYD_HINT_DATA, key, NULL, LY_VLOG_LYSC, key));
Michal Vasko004d3152020-06-11 19:59:22 +0200514 ++(*tok_idx);
515
Michal Vaskoae875662020-10-21 10:33:17 +0200516 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
517 ++((struct lysc_type *)p->value.realtype)->refcount;
518
Michal Vasko004d3152020-06-11 19:59:22 +0200519 /* ']' */
520 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
521 ++(*tok_idx);
522
523 /* another predicate follows? */
524 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
525
526 /* check that all keys were set */
527 key_count = 0;
528 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
529 ++key_count;
530 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200531 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200532 /* names (keys) are unique - it was checked when parsing */
Michal Vasko6b26e742020-07-17 15:02:10 +0200533 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200534 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200535 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200536 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200537 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200538 }
539
540 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
541 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200542 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200543 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200544 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200545 }
546 ++(*tok_idx);
547
548 /* new predicate */
549 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200550 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200551
552 /* '=' */
553 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
554 ++(*tok_idx);
555
556 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
557 /* store the value */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200558 LY_CHECK_RET(lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
559 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
560 LYD_HINT_DATA, ctx_node, NULL, LY_VLOG_LYSC, ctx_node));
Michal Vasko004d3152020-06-11 19:59:22 +0200561 ++(*tok_idx);
562
Michal Vaskoae875662020-10-21 10:33:17 +0200563 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
564 ++((struct lysc_type *)p->value.realtype)->refcount;
565
Michal Vasko004d3152020-06-11 19:59:22 +0200566 /* ']' */
567 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
568 ++(*tok_idx);
569 } else {
570 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
571 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200572 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200573 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200574 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200575 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200576 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200577 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200578 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200579 }
Michal Vasko004d3152020-06-11 19:59:22 +0200580
581 /* new predicate */
582 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200583 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200584
585 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100586 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200587 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200588
589 /* ']' */
590 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
591 ++(*tok_idx);
592 }
593
594 return LY_SUCCESS;
595}
596
597/**
598 * @brief Compile leafref predicate. Actually, it is only checked.
599 *
600 * @param[in] ctx_node Context node, node for which the predicate is defined.
601 * @param[in] cur_node Current (original context) node.
602 * @param[in] expr Parsed path.
603 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200604 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200605 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko405cc9e2020-12-01 12:01:27 +0100606 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko004d3152020-06-11 19:59:22 +0200607 * @return LY_ERR value.
608 */
609static LY_ERR
610ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100611 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format, void *prefix_data,
612 struct lys_glob_unres *unres)
Michal Vasko004d3152020-06-11 19:59:22 +0200613{
614 const struct lysc_node *key, *node, *node2;
615 const struct lys_module *mod;
616 const char *name;
617 size_t name_len;
618
Michal Vasko004d3152020-06-11 19:59:22 +0200619 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200620 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200621 return LY_SUCCESS;
622 }
623
624 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200625 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 +0200626 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200627 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200628 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200629 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 +0200630 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200631 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200632 }
633
634 do {
635 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200636 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100637 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100638 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200639 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200640 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 +0200641 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200642 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200643 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 +0200644 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200645 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200646 }
647 ++(*tok_idx);
648
649 /* we are not actually compiling, throw the key away */
650 (void)key;
651
652 /* '=' */
653 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
654 ++(*tok_idx);
655
656 /* FuncName */
657 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
658 ++(*tok_idx);
659
660 /* evaluating from the "current()" node */
661 node = cur_node;
662
663 /* '(' */
664 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
665 ++(*tok_idx);
666
667 /* ')' */
668 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
669 ++(*tok_idx);
670
671 do {
672 /* '/' */
673 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
674 ++(*tok_idx);
675
676 /* go to parent */
677 if (!node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200678 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200679 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200680 }
681 node = lysc_data_parent(node);
682
683 /* '..' */
684 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
685 ++(*tok_idx);
686 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
687
688 do {
689 /* '/' */
690 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
691 ++(*tok_idx);
692
693 /* NameTest */
694 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko6b26e742020-07-17 15:02:10 +0200695 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100696 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100697 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200698 if (!node2) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200699 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 +0200700 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200701 }
702 node = node2;
703 ++(*tok_idx);
704 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
705
706 /* check the last target node */
707 if (node->nodetype != LYS_LEAF) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200708 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
Michal Vasko69730152020-10-09 16:30:07 +0200709 "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
710 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200711 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200712 }
713
714 /* we are not actually compiling, throw the rightside node away */
715 (void)node;
716
717 /* ']' */
718 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
719 ++(*tok_idx);
720
Radek Krejci0f969882020-08-21 16:56:47 +0200721 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200722 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
723
724 return LY_SUCCESS;
725}
726
727LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200728ly_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 +0200729 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target, LY_PREFIX_FORMAT format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100730 void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200731{
732 LY_ERR ret = LY_SUCCESS;
733 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100734 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200735 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200736 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200737 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200738 const char *name;
739 size_t name_len;
740
Michal Vasko00cbf532020-06-15 13:58:47 +0200741 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200742 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200743 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200744 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
745 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200746
Michal Vasko6b26e742020-07-17 15:02:10 +0200747 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200748 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200749
750 /* remember original context node */
751 cur_node = ctx_node;
752
Michal Vasko004d3152020-06-11 19:59:22 +0200753 *path = NULL;
754
Michal Vasko00cbf532020-06-15 13:58:47 +0200755 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100756 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200757 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100758 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200759 }
760
Michal Vasko004d3152020-06-11 19:59:22 +0200761 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
762 /* absolute path */
763 ctx_node = NULL;
764
765 ++tok_idx;
766 } else {
767 /* relative path */
768 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
769 if (!ctx_node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200770 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200771 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200772 }
773
774 /* get parent */
775 ctx_node = lysc_data_parent(ctx_node);
776
777 ++tok_idx;
778
779 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
780 ++tok_idx;
781 }
782
Michal Vasko00cbf532020-06-15 13:58:47 +0200783 /* we are not storing the parent */
784 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200785 }
786
787 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200788 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskod456cf62020-11-23 16:48:43 +0100789 if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
790 (p->node->nodetype == LYS_LIST) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200791 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200792 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200793 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200794 }
795
Michal Vasko004d3152020-06-11 19:59:22 +0200796 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200797 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100798 prefix_data, unres, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200799 ++tok_idx;
800
801 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200802 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100803 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200804 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200805 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200806 goto cleanup;
807 }
808 ctx_node = node2;
809
810 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200811 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200812 p->node = ctx_node;
813
814 /* compile any predicates */
815 if (lref == LY_PATH_LREF_TRUE) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100816 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200817 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200818 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 +0200819 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200820 }
821 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200822 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
823
Michal Vasko00cbf532020-06-15 13:58:47 +0200824 /* check last compiled node */
Michal Vasko69730152020-10-09 16:30:07 +0200825 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
826 (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200827 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200828 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200829 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200830 }
831
Michal Vasko004d3152020-06-11 19:59:22 +0200832cleanup:
833 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200834 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200835 *path = NULL;
836 }
837 return ret;
838}
839
840LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200841ly_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 +0200842 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200843{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200844 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200845 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200846 uint64_t pos;
847
848 assert(path && start);
849
850 if (lysc_data_parent(path[0].node)) {
851 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200852 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200853 } else {
854 /* absolute path, start from the first top-level sibling */
855 while (start->parent) {
856 start = (struct lyd_node *)start->parent;
857 }
858 while (start->prev->next) {
859 start = start->prev;
860 }
861 }
862
863 LY_ARRAY_FOR(path, u) {
864 switch (path[u].pred_type) {
865 case LY_PATH_PREDTYPE_POSITION:
866 /* we cannot use hashes and want an instance on a specific position */
867 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200868 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200869 if (pos == path[u].predicates[0].position) {
870 break;
871 }
872 ++pos;
873 }
874 break;
875 case LY_PATH_PREDTYPE_LEAFLIST:
876 /* we will use hashes to find one leaf-list instance */
877 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
878 lyd_find_sibling_first(start, target, &node);
879 lyd_free_tree(target);
880 break;
881 case LY_PATH_PREDTYPE_LIST:
882 /* we will use hashes to find one list instance */
883 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
884 lyd_find_sibling_first(start, target, &node);
885 lyd_free_tree(target);
886 break;
887 case LY_PATH_PREDTYPE_NONE:
888 /* we will use hashes to find one any/container/leaf instance */
889 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
890 break;
891 }
892
893 if (!node) {
894 /* no matching nodes */
895 break;
896 }
897
Michal Vasko00cbf532020-06-15 13:58:47 +0200898 /* rememeber previous node */
899 prev_node = node;
900
Michal Vasko004d3152020-06-11 19:59:22 +0200901 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200902 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +0200903 }
904
Michal Vasko004d3152020-06-11 19:59:22 +0200905 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200906 /* we have found the full path */
907 if (path_idx) {
908 *path_idx = u;
909 }
910 if (match) {
911 *match = node;
912 }
Michal Vasko004d3152020-06-11 19:59:22 +0200913 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200914
915 } else if (prev_node) {
916 /* we have found only some partial match */
917 if (path_idx) {
918 *path_idx = u - 1;
919 }
920 if (match) {
921 *match = prev_node;
922 }
923 return LY_EINCOMPLETE;
924 }
925
926 /* we have not found any nodes */
927 if (path_idx) {
928 *path_idx = 0;
929 }
930 if (match) {
931 *match = NULL;
932 }
933 return LY_ENOTFOUND;
934}
935
936LY_ERR
937ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
938{
939 LY_ERR ret;
940 struct lyd_node *m;
941
942 ret = ly_path_eval_partial(path, start, NULL, &m);
943
944 if (ret == LY_SUCCESS) {
945 /* last node was found */
946 if (match) {
947 *match = m;
948 }
949 return LY_SUCCESS;
950 }
951
952 /* not a full match */
953 if (match) {
954 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200955 }
956 return LY_ENOTFOUND;
957}
958
959LY_ERR
960ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
961{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200962 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200963
964 if (!path) {
965 return LY_SUCCESS;
966 }
967
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200968 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200969 LY_ARRAY_FOR(path, u) {
970 LY_ARRAY_INCREMENT(*dup);
971 (*dup)[u].node = path[u].node;
972 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200973 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200974 (*dup)[u].pred_type = path[u].pred_type;
975 LY_ARRAY_FOR(path[u].predicates, v) {
976 struct ly_path_predicate *pred = &path[u].predicates[v];
977
978 LY_ARRAY_INCREMENT((*dup)[u].predicates);
979 switch (path[u].pred_type) {
980 case LY_PATH_PREDTYPE_POSITION:
981 /* position-predicate */
982 (*dup)[u].predicates[v].position = pred->position;
983 break;
984 case LY_PATH_PREDTYPE_LIST:
985 case LY_PATH_PREDTYPE_LEAFLIST:
986 /* key-predicate or leaf-list-predicate */
987 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +0200988 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vaskoae875662020-10-21 10:33:17 +0200989 ++((struct lysc_type *)pred->value.realtype)->refcount;
Michal Vasko004d3152020-06-11 19:59:22 +0200990 break;
991 case LY_PATH_PREDTYPE_NONE:
992 break;
993 }
994 }
995 }
996 }
997
998 return LY_SUCCESS;
999}
1000
1001void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001002ly_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 +02001003{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001004 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001005
1006 if (!predicates) {
1007 return;
1008 }
1009
1010 LY_ARRAY_FOR(predicates, u) {
1011 switch (pred_type) {
1012 case LY_PATH_PREDTYPE_POSITION:
1013 case LY_PATH_PREDTYPE_NONE:
1014 /* nothing to free */
1015 break;
1016 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001017 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001018 if (predicates[u].value.realtype) {
1019 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1020 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1021 }
Michal Vasko004d3152020-06-11 19:59:22 +02001022 break;
1023 }
1024 }
1025 LY_ARRAY_FREE(predicates);
1026}
1027
1028void
1029ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1030{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001031 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001032
1033 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001034 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001035 }
1036 LY_ARRAY_FREE(path);
1037}