blob: a4db50c9dbbafd8af30dca400a59d4b9223151b7 [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 Krejci859a15a2021-03-05 20:56:59 +010030#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020031#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020032#include "tree_schema_internal.h"
33#include "xpath.h"
34
Radek Krejcic0c66412020-08-21 13:53:50 +020035#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 +020036
Michal Vasko004d3152020-06-11 19:59:22 +020037/**
38 * @brief Check predicate syntax.
39 *
40 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020041 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020042 * @param[in] exp Parsed predicate.
43 * @param[in,out] tok_idx Index in @p exp, is adjusted.
44 * @param[in] prefix Prefix option.
45 * @param[in] pred Predicate option.
46 * @return LY_ERR value.
47 */
48static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020049ly_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 +020050 uint16_t *tok_idx, uint8_t prefix, uint8_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020051{
Radek Krejciba03a5a2020-08-27 14:40:41 +020052 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020053 struct ly_set *set = NULL;
54 uint32_t i;
55 const char *name;
56 size_t name_len;
57
Radek Krejciddace2c2021-01-08 11:30:56 +010058 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010059
Michal Vasko004d3152020-06-11 19:59:22 +020060 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020061 /* '[' */
62
Michal Vasko69730152020-10-09 16:30:07 +020063 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
64 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020065 ret = ly_set_new(&set);
66 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020067
68 do {
69 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020070 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020071
72 /* check prefix based on the options */
73 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
74 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010075 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020076 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020077 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020078 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010079 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020080 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020081 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020082 }
83 if (!name) {
84 name = exp->expr + exp->tok_pos[*tok_idx];
85 name_len = exp->tok_len[*tok_idx];
86 } else {
87 ++name;
88 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
89 }
90
91 /* check whether it was not already specified */
92 for (i = 0; i < set->count; ++i) {
93 /* all the keys must be from the same module so this comparison should be fine */
94 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci422afb12021-03-04 16:38:16 +010095 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020096 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020097 }
98 }
99
100 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200101 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200102 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200103
104 /* NameTest */
105 ++(*tok_idx);
106
107 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200108 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200109
110 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200111 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200112
113 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200114 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200115
Radek Krejci0f969882020-08-21 16:56:47 +0200116 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200117 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
118
Michal Vasko004d3152020-06-11 19:59:22 +0200119 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200120 /* '.' */
121
Michal Vasko004d3152020-06-11 19:59:22 +0200122 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200123 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200124
125 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200126 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200127
128 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200129 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200130
Michal Vasko004d3152020-06-11 19:59:22 +0200131 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200132 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200133
134 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200135 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200136
137 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
138 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200139 ret = ly_set_new(&set);
140 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200141
142 do {
143 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200144 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200145
146 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
147 if (!name) {
148 name = exp->expr + exp->tok_pos[*tok_idx];
149 name_len = exp->tok_len[*tok_idx];
150 } else {
151 ++name;
152 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
153 }
154
155 /* check whether it was not already specified */
156 for (i = 0; i < set->count; ++i) {
157 /* all the keys must be from the same module so this comparison should be fine */
158 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci422afb12021-03-04 16:38:16 +0100159 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200160 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200161 }
162 }
163
164 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200165 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200166 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200167
168 /* NameTest */
169 ++(*tok_idx);
170
171 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200172 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200173
174 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200175 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100176 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
177 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100178 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200179 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200180 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200181 }
182 ++(*tok_idx);
183
184 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200185 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), 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_PAR2), 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_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200192
193 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200194 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200195 do {
196 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200197 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200198 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
199
200 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200201 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200202
203 /* '/' */
204 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
205 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200206 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200207 }
208
209 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200210 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200211
Radek Krejci0f969882020-08-21 16:56:47 +0200212 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200213 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
214
215 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100216 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200217 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200218 }
219 }
220
Radek Krejciba03a5a2020-08-27 14:40:41 +0200221cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100222 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200223 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200224 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200225
Radek Krejciba03a5a2020-08-27 14:40:41 +0200226token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100227 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200228 ly_set_free(set, NULL);
229 return LY_EVALID;
230}
231
232LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200233ly_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 +0200234 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200235{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200236 LY_ERR ret = LY_SUCCESS;
237 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200238 uint16_t tok_idx, cur_len;
239 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200240
241 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
242 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko69730152020-10-09 16:30:07 +0200243 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
244 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200245 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
246
Radek Krejciddace2c2021-01-08 11:30:56 +0100247 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100248
Michal Vasko004d3152020-06-11 19:59:22 +0200249 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200250 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200251 tok_idx = 0;
252
253 if (begin == LY_PATH_BEGIN_EITHER) {
254 /* is the path relative? */
255 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200256 /* relative path check specific to leafref */
257 if (lref == LY_PATH_LREF_TRUE) {
258 /* mandatory '..' */
259 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
260
261 do {
262 /* '/' */
263 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
264
265 /* optional '..' */
266 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200267 }
268 }
269 } else {
270 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200271 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 +0200272 }
273
274 do {
275 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200276 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 +0200277
278 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200279 cur_node = exp->expr + exp->tok_pos[tok_idx];
280 cur_len = exp->tok_len[tok_idx];
281 if (prefix == LY_PATH_PREFIX_MANDATORY) {
282 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100283 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200284 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200285 goto error;
286 }
287 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
288 if (!prev_prefix) {
289 /* the first node must have a prefix */
290 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100291 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200292 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200293 goto error;
294 }
295
296 /* remember the first prefix */
297 prev_prefix = cur_node;
298 } else {
299 /* the prefix must be different, if any */
300 ptr = strnstr(cur_node, ":", cur_len);
301 if (ptr) {
302 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100303 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200304 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200305 goto error;
306 }
307
308 /* remember this next prefix */
309 prev_prefix = cur_node;
310 }
311 }
Michal Vasko004d3152020-06-11 19:59:22 +0200312 }
313
314 ++tok_idx;
315
316 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200317 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200318
Radek Krejci0f969882020-08-21 16:56:47 +0200319 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200320 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
321
322 /* trailing token check */
323 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100324 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.", exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200325 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200326 goto error;
327 }
328
329 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100330
Radek Krejciddace2c2021-01-08 11:30:56 +0100331 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200332 return LY_SUCCESS;
333
334error:
335 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100336 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200337 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200338}
339
340LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200341ly_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 +0200342 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200343{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200344 LY_ERR ret = LY_SUCCESS;
345 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200346 uint16_t tok_idx;
347
348 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
349 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
350
Radek Krejciddace2c2021-01-08 11:30:56 +0100351 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100352
Michal Vasko004d3152020-06-11 19:59:22 +0200353 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200354 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200355 tok_idx = 0;
356
Radek Krejcif03a9e22020-09-18 20:09:31 +0200357 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200358
359 /* trailing token check */
360 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100361 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200362 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200363 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200364 goto error;
365 }
366
367 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100368
Radek Krejciddace2c2021-01-08 11:30:56 +0100369 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200370 return LY_SUCCESS;
371
372error:
373 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100374 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200375 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200376}
377
378/**
379 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
380 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200381 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200382 * @param[in] cur_node Optional current (original context) node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200383 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_PREF_SCHEMA*.
384 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_PREF_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200385 * @param[in] expr Parsed path.
386 * @param[in] tok_idx Index in @p expr.
387 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200388 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200389 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200390 * @param[out] mod Resolved module.
391 * @param[out] name Parsed node name.
392 * @param[out] name_len Length of @p name.
393 * @return LY_ERR value.
394 */
395static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200396ly_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 +0200397 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref,
Radek Krejci8df109d2021-04-23 12:19:08 +0200398 LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100399 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200400{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100401 LY_ERR ret;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200402 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200403 size_t len;
404
405 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
406
407 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200408 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
409 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
410 pref = expr->expr + expr->tok_pos[tok_idx];
411 } else {
412 len = 0;
413 }
Michal Vasko004d3152020-06-11 19:59:22 +0200414
415 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200416 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100417 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100418
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200419 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200420 if (!*mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100421 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100422 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200423 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100424 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200425 } else if (!(*mod)->implemented) {
426 if (lref == LY_PATH_LREF_FALSE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100427 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Michal Vasko825a0442021-04-16 16:11:53 +0200428 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100429 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200430 }
Michal Vasko825a0442021-04-16 16:11:53 +0200431
Michal Vaskob3e22532021-02-03 10:50:04 +0100432 assert(unres);
Michal Vasko69827502021-04-22 09:15:23 +0200433 LY_CHECK_GOTO(ret = lys_set_implemented_r((struct lys_module *)*mod, NULL, unres), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200434 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100435
Radek Krejciddace2c2021-01-08 11:30:56 +0100436 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200437 } else {
438 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200439 case LY_VALUE_SCHEMA:
440 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200441 if (!cur_mod) {
442 LOGINT_RET(ctx);
443 }
444 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200445 *mod = cur_mod;
446 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200447 case LY_VALUE_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200448 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200449 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200450 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200451 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200452 *mod = prev_ctx_node->module;
453 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200454 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200455 case LY_VALUE_XML:
Radek Krejcif9943642021-04-26 10:18:21 +0200456 case LY_VALUE_LYB:
457 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200458 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200459 }
460 }
461
462 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200463 if (pref) {
464 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200465 *name_len = expr->tok_len[tok_idx] - len - 1;
466 } else {
467 *name = expr->expr + expr->tok_pos[tok_idx];
468 *name_len = expr->tok_len[tok_idx];
469 }
470
471 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100472
473error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100474 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200475 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200476}
477
478LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200479ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci8df109d2021-04-23 12:19:08 +0200480 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200481 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200482{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100483 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200484 struct ly_path_predicate *p;
485 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100486 const struct lys_module *mod = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200487 const char *name;
488 size_t name_len, key_count;
489
Michal Vasko00cbf532020-06-15 13:58:47 +0200490 assert(ctx && ctx_node);
491
Radek Krejciddace2c2021-01-08 11:30:56 +0100492 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100493
Michal Vasko004d3152020-06-11 19:59:22 +0200494 *pred_type = 0;
495
Michal Vasko004d3152020-06-11 19:59:22 +0200496 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200497 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100498 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200499 }
500
501 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
502 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100503 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200504 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100505 ret = LY_EVALID;
506 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200507 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100508 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200509 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100510 ret = LY_EVALID;
511 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200512 }
513
514 do {
515 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200516 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 +0100517 format, prefix_data, NULL, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100518 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200519 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100520 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521 ret = LY_ENOTFOUND;
522 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200523 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100524 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
525 key->name);
526 ret = LY_EVALID;
527 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200528 }
529 ++(*tok_idx);
530
Michal Vasko004d3152020-06-11 19:59:22 +0200531 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200532 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200533 *pred_type = LY_PATH_PREDTYPE_LIST;
534 }
535 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100536 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200537 p->key = key;
538
539 /* '=' */
540 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
541 ++(*tok_idx);
542
543 /* Literal */
544 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100545 LOG_LOCSET(key, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100546 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200547 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
Radek Krejci2efc45b2020-12-22 16:25:44 +0100548 LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100549 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100550 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200551 ++(*tok_idx);
552
Michal Vaskoae875662020-10-21 10:33:17 +0200553 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
554 ++((struct lysc_type *)p->value.realtype)->refcount;
555
Michal Vasko004d3152020-06-11 19:59:22 +0200556 /* ']' */
557 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
558 ++(*tok_idx);
559
560 /* another predicate follows? */
561 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
562
563 /* check that all keys were set */
564 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100565 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200566 ++key_count;
567 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200568 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200569 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100570 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200571 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200572 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200573 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100574 ret = LY_EVALID;
575 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200576 }
577
578 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
579 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100580 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200581 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100582 ret = LY_EVALID;
583 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200584 }
585 ++(*tok_idx);
586
587 /* new predicate */
588 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100589 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200590
591 /* '=' */
592 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
593 ++(*tok_idx);
594
595 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
596 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100597 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100598 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200599 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
Radek Krejci2efc45b2020-12-22 16:25:44 +0100600 LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100601 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100602 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200603 ++(*tok_idx);
604
Michal Vaskoae875662020-10-21 10:33:17 +0200605 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
606 ++((struct lysc_type *)p->value.realtype)->refcount;
607
Michal Vasko004d3152020-06-11 19:59:22 +0200608 /* ']' */
609 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
610 ++(*tok_idx);
611 } else {
612 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
613 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100614 ret = LY_EVALID;
615 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200616 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100617 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200618 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100619 ret = LY_EVALID;
620 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200621 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100622 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200623 }
Michal Vasko004d3152020-06-11 19:59:22 +0200624
625 /* new predicate */
626 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100627 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200628
629 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100630 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200631 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200632
633 /* ']' */
634 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
635 ++(*tok_idx);
636 }
637
Radek Krejci2efc45b2020-12-22 16:25:44 +0100638cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100639 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100640 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200641}
642
643/**
644 * @brief Compile leafref predicate. Actually, it is only checked.
645 *
646 * @param[in] ctx_node Context node, node for which the predicate is defined.
647 * @param[in] cur_node Current (original context) node.
648 * @param[in] expr Parsed path.
649 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200650 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200651 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko405cc9e2020-12-01 12:01:27 +0100652 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko004d3152020-06-11 19:59:22 +0200653 * @return LY_ERR value.
654 */
655static LY_ERR
656ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Radek Krejci8df109d2021-04-23 12:19:08 +0200657 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100658 struct lys_glob_unres *unres)
Michal Vasko004d3152020-06-11 19:59:22 +0200659{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100660 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200661 const struct lysc_node *key, *node, *node2;
662 const struct lys_module *mod;
663 const char *name;
664 size_t name_len;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100665 struct ly_ctx *ctx = cur_node->module->ctx;
666
Radek Krejciddace2c2021-01-08 11:30:56 +0100667 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200668
Michal Vasko004d3152020-06-11 19:59:22 +0200669 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200670 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100671 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200672 }
673
674 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100675 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200676 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100677 ret = LY_EVALID;
678 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200679 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100680 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200681 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100682 ret = LY_EVALID;
683 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200684 }
685
686 do {
687 /* NameTest, find the key */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100688 ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
689 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len);
690 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100691 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200692 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100693 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100694 ret = LY_EVALID;
695 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200696 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100697 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200698 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100699 ret = LY_EVALID;
700 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200701 }
702 ++(*tok_idx);
703
704 /* we are not actually compiling, throw the key away */
705 (void)key;
706
707 /* '=' */
708 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
709 ++(*tok_idx);
710
711 /* FuncName */
712 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
713 ++(*tok_idx);
714
715 /* evaluating from the "current()" node */
716 node = cur_node;
717
718 /* '(' */
719 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
720 ++(*tok_idx);
721
722 /* ')' */
723 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
724 ++(*tok_idx);
725
726 do {
727 /* '/' */
728 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
729 ++(*tok_idx);
730
731 /* go to parent */
732 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100733 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
734 ret = LY_EVALID;
735 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200736 }
737 node = lysc_data_parent(node);
738
739 /* '..' */
740 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
741 ++(*tok_idx);
742 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
743
744 do {
745 /* '/' */
746 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
747 ++(*tok_idx);
748
749 /* NameTest */
750 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100751 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100752 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100753 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200754 if (!node2) {
Radek Krejci422afb12021-03-04 16:38:16 +0100755 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100756 ret = LY_EVALID;
757 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200758 }
759 node = node2;
760 ++(*tok_idx);
761 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
762
763 /* check the last target node */
764 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100765 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200766 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100767 ret = LY_EVALID;
768 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200769 }
770
771 /* we are not actually compiling, throw the rightside node away */
772 (void)node;
773
774 /* ']' */
775 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
776 ++(*tok_idx);
777
Radek Krejci0f969882020-08-21 16:56:47 +0200778 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200779 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
780
Radek Krejci2efc45b2020-12-22 16:25:44 +0100781cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100782 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100783 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200784}
785
786LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200787ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Radek Krejcid5d37432021-03-12 13:46:40 +0100788 const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
Radek Krejci8df109d2021-04-23 12:19:08 +0200789 LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200790{
791 LY_ERR ret = LY_SUCCESS;
792 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100793 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200794 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200795 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200796 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200797 const char *name;
798 size_t name_len;
799
Michal Vasko00cbf532020-06-15 13:58:47 +0200800 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200801 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200802 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200803 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
804 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200805
Michal Vasko6b26e742020-07-17 15:02:10 +0200806 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200807 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200808
Radek Krejci2efc45b2020-12-22 16:25:44 +0100809 *path = NULL;
810
Michal Vasko6b26e742020-07-17 15:02:10 +0200811 /* remember original context node */
812 cur_node = ctx_node;
Radek Krejciddace2c2021-01-08 11:30:56 +0100813 LOG_LOCINIT(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200814
Michal Vasko00cbf532020-06-15 13:58:47 +0200815 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100816 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200817 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100818 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200819 }
820
Michal Vasko004d3152020-06-11 19:59:22 +0200821 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
822 /* absolute path */
823 ctx_node = NULL;
824
825 ++tok_idx;
826 } else {
827 /* relative path */
828 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
829 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100830 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100831 ret = LY_EVALID;
832 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200833 }
834
835 /* get parent */
836 ctx_node = lysc_data_parent(ctx_node);
837
838 ++tok_idx;
839
840 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
841 ++tok_idx;
842 }
843
Michal Vasko00cbf532020-06-15 13:58:47 +0200844 /* we are not storing the parent */
845 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200846 }
847
848 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200849 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskod456cf62020-11-23 16:48:43 +0100850 if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
851 (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100852 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200853 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100854 ret = LY_EVALID;
855 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200856 }
857
Michal Vasko14424ba2020-12-09 18:09:51 +0100858 /* NameTest */
859 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
860
Michal Vasko004d3152020-06-11 19:59:22 +0200861 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200862 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 +0100863 prefix_data, unres, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200864 ++tok_idx;
865
866 /* find the next node */
Radek Krejcid5d37432021-03-12 13:46:40 +0100867 if (!ctx_node && ext) {
868 node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
869 } else {
870 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
871 }
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100872 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Radek Krejci422afb12021-03-04 16:38:16 +0100873 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200874 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200875 goto cleanup;
876 }
877 ctx_node = node2;
878
879 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200880 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200881 p->node = ctx_node;
882
883 /* compile any predicates */
884 if (lref == LY_PATH_LREF_TRUE) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100885 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200886 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200887 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 +0200888 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200889 }
890 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200891 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
892
Michal Vasko14424ba2020-12-09 18:09:51 +0100893 /* check leftover tokens */
894 if (tok_idx < expr->used) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100895 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
Michal Vasko14424ba2020-12-09 18:09:51 +0100896 ret = LY_EVALID;
897 goto cleanup;
898 }
899
Michal Vasko00cbf532020-06-15 13:58:47 +0200900 /* check last compiled node */
Michal Vasko69730152020-10-09 16:30:07 +0200901 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
902 (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100903 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200904 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100905 ret = LY_EVALID;
906 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200907 }
908
Michal Vasko004d3152020-06-11 19:59:22 +0200909cleanup:
910 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200911 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200912 *path = NULL;
913 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100914 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200915 return ret;
916}
917
918LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200919ly_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 +0200920 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200921{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200922 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoacfc9282021-02-04 12:08:23 +0100923 struct lyd_node *prev_node = NULL, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200924 uint64_t pos;
925
926 assert(path && start);
927
928 if (lysc_data_parent(path[0].node)) {
929 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200930 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200931 } else {
932 /* absolute path, start from the first top-level sibling */
933 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +0100934 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200935 }
936 while (start->prev->next) {
937 start = start->prev;
938 }
939 }
940
941 LY_ARRAY_FOR(path, u) {
942 switch (path[u].pred_type) {
943 case LY_PATH_PREDTYPE_POSITION:
944 /* we cannot use hashes and want an instance on a specific position */
945 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200946 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200947 if (pos == path[u].predicates[0].position) {
948 break;
949 }
950 ++pos;
951 }
952 break;
953 case LY_PATH_PREDTYPE_LEAFLIST:
954 /* we will use hashes to find one leaf-list instance */
955 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
956 lyd_find_sibling_first(start, target, &node);
957 lyd_free_tree(target);
958 break;
959 case LY_PATH_PREDTYPE_LIST:
960 /* we will use hashes to find one list instance */
961 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
962 lyd_find_sibling_first(start, target, &node);
963 lyd_free_tree(target);
964 break;
965 case LY_PATH_PREDTYPE_NONE:
966 /* we will use hashes to find one any/container/leaf instance */
967 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
968 break;
969 }
970
971 if (!node) {
972 /* no matching nodes */
973 break;
974 }
975
Michal Vasko00cbf532020-06-15 13:58:47 +0200976 /* rememeber previous node */
977 prev_node = node;
978
Michal Vasko004d3152020-06-11 19:59:22 +0200979 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200980 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +0200981 }
982
Michal Vasko004d3152020-06-11 19:59:22 +0200983 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200984 /* we have found the full path */
985 if (path_idx) {
986 *path_idx = u;
987 }
988 if (match) {
989 *match = node;
990 }
Michal Vasko004d3152020-06-11 19:59:22 +0200991 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200992
993 } else if (prev_node) {
994 /* we have found only some partial match */
995 if (path_idx) {
996 *path_idx = u - 1;
997 }
998 if (match) {
999 *match = prev_node;
1000 }
1001 return LY_EINCOMPLETE;
1002 }
1003
1004 /* we have not found any nodes */
1005 if (path_idx) {
1006 *path_idx = 0;
1007 }
1008 if (match) {
1009 *match = NULL;
1010 }
1011 return LY_ENOTFOUND;
1012}
1013
1014LY_ERR
1015ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1016{
1017 LY_ERR ret;
1018 struct lyd_node *m;
1019
1020 ret = ly_path_eval_partial(path, start, NULL, &m);
1021
1022 if (ret == LY_SUCCESS) {
1023 /* last node was found */
1024 if (match) {
1025 *match = m;
1026 }
1027 return LY_SUCCESS;
1028 }
1029
1030 /* not a full match */
1031 if (match) {
1032 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001033 }
1034 return LY_ENOTFOUND;
1035}
1036
1037LY_ERR
1038ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1039{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001040 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001041
1042 if (!path) {
1043 return LY_SUCCESS;
1044 }
1045
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001046 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001047 LY_ARRAY_FOR(path, u) {
1048 LY_ARRAY_INCREMENT(*dup);
1049 (*dup)[u].node = path[u].node;
1050 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001051 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001052 (*dup)[u].pred_type = path[u].pred_type;
1053 LY_ARRAY_FOR(path[u].predicates, v) {
1054 struct ly_path_predicate *pred = &path[u].predicates[v];
1055
1056 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1057 switch (path[u].pred_type) {
1058 case LY_PATH_PREDTYPE_POSITION:
1059 /* position-predicate */
1060 (*dup)[u].predicates[v].position = pred->position;
1061 break;
1062 case LY_PATH_PREDTYPE_LIST:
1063 case LY_PATH_PREDTYPE_LEAFLIST:
1064 /* key-predicate or leaf-list-predicate */
1065 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001066 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vaskoae875662020-10-21 10:33:17 +02001067 ++((struct lysc_type *)pred->value.realtype)->refcount;
Michal Vasko004d3152020-06-11 19:59:22 +02001068 break;
1069 case LY_PATH_PREDTYPE_NONE:
1070 break;
1071 }
1072 }
1073 }
1074 }
1075
1076 return LY_SUCCESS;
1077}
1078
1079void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001080ly_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 +02001081{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001082 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001083
1084 if (!predicates) {
1085 return;
1086 }
1087
1088 LY_ARRAY_FOR(predicates, u) {
1089 switch (pred_type) {
1090 case LY_PATH_PREDTYPE_POSITION:
1091 case LY_PATH_PREDTYPE_NONE:
1092 /* nothing to free */
1093 break;
1094 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001095 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001096 if (predicates[u].value.realtype) {
1097 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1098 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1099 }
Michal Vasko004d3152020-06-11 19:59:22 +02001100 break;
1101 }
1102 }
1103 LY_ARRAY_FREE(predicates);
1104}
1105
1106void
1107ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1108{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001109 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001110
1111 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001112 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001113 }
1114 LY_ARRAY_FREE(path);
1115}