blob: 741d8d1fa7eb7340ed74e72fe1baa70917767a1a [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"
Michal Vasko40c158c2021-04-28 17:01:03 +020027#include "schema_compile.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020028#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020029#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010031#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020032#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020033#include "tree_schema_internal.h"
34#include "xpath.h"
35
Radek Krejcic0c66412020-08-21 13:53:50 +020036#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 +020037
Michal Vasko004d3152020-06-11 19:59:22 +020038/**
39 * @brief Check predicate syntax.
40 *
41 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020042 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020043 * @param[in] exp Parsed predicate.
44 * @param[in,out] tok_idx Index in @p exp, is adjusted.
45 * @param[in] prefix Prefix option.
46 * @param[in] pred Predicate option.
47 * @return LY_ERR value.
48 */
49static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020050ly_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 +020051 uint16_t *tok_idx, uint8_t prefix, uint8_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020052{
Radek Krejciba03a5a2020-08-27 14:40:41 +020053 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020054 struct ly_set *set = NULL;
55 uint32_t i;
56 const char *name;
57 size_t name_len;
58
Radek Krejciddace2c2021-01-08 11:30:56 +010059 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010060
Michal Vasko004d3152020-06-11 19:59:22 +020061 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020062 /* '[' */
63
Michal Vasko69730152020-10-09 16:30:07 +020064 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
65 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020066 ret = ly_set_new(&set);
67 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020068
69 do {
70 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020071 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020072
73 /* check prefix based on the options */
74 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
75 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010076 LOGVAL(ctx, LYVE_XPATH, "Prefix missing 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 Vasko8b06a5e2020-08-06 12:13:08 +020079 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010080 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020081 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020082 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020083 }
84 if (!name) {
85 name = exp->expr + exp->tok_pos[*tok_idx];
86 name_len = exp->tok_len[*tok_idx];
87 } else {
88 ++name;
89 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
90 }
91
92 /* check whether it was not already specified */
93 for (i = 0; i < set->count; ++i) {
94 /* all the keys must be from the same module so this comparison should be fine */
95 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci422afb12021-03-04 16:38:16 +010096 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020097 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020098 }
99 }
100
101 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200102 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200103 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200104
105 /* NameTest */
106 ++(*tok_idx);
107
108 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200109 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200110
111 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200112 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200113
114 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200115 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200116
Radek Krejci0f969882020-08-21 16:56:47 +0200117 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200118 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
119
Michal Vasko004d3152020-06-11 19:59:22 +0200120 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200121 /* '.' */
122
Michal Vasko004d3152020-06-11 19:59:22 +0200123 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200124 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200125
126 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200127 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200128
129 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200130 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200131
Michal Vasko004d3152020-06-11 19:59:22 +0200132 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200133 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200134
135 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200136 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200137
138 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
139 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200140 ret = ly_set_new(&set);
141 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200142
143 do {
144 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200145 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200146
147 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
148 if (!name) {
149 name = exp->expr + exp->tok_pos[*tok_idx];
150 name_len = exp->tok_len[*tok_idx];
151 } else {
152 ++name;
153 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
154 }
155
156 /* check whether it was not already specified */
157 for (i = 0; i < set->count; ++i) {
158 /* all the keys must be from the same module so this comparison should be fine */
159 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci422afb12021-03-04 16:38:16 +0100160 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200161 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200162 }
163 }
164
165 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200166 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200167 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200168
169 /* NameTest */
170 ++(*tok_idx);
171
172 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200173 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200174
175 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200176 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100177 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
178 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100179 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200180 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200181 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200182 }
183 ++(*tok_idx);
184
185 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200186 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200187
188 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200189 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200190
191 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200192 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200193
194 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200195 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200196 do {
197 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200198 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200199 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
200
201 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200202 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200203
204 /* '/' */
205 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
206 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200207 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200208 }
209
210 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200211 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200212
Radek Krejci0f969882020-08-21 16:56:47 +0200213 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200214 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
215
216 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100217 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 +0200218 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200219 }
220 }
221
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100223 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200224 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200226
Radek Krejciba03a5a2020-08-27 14:40:41 +0200227token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100228 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200229 ly_set_free(set, NULL);
230 return LY_EVALID;
231}
232
233LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200234ly_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 +0200235 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200236{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200237 LY_ERR ret = LY_SUCCESS;
238 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200239 uint16_t tok_idx, cur_len;
240 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200241
242 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
243 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko69730152020-10-09 16:30:07 +0200244 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
245 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200246 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
247
Radek Krejciddace2c2021-01-08 11:30:56 +0100248 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100249
Michal Vasko004d3152020-06-11 19:59:22 +0200250 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200251 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200252 tok_idx = 0;
253
254 if (begin == LY_PATH_BEGIN_EITHER) {
255 /* is the path relative? */
256 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200257 /* relative path check specific to leafref */
258 if (lref == LY_PATH_LREF_TRUE) {
259 /* mandatory '..' */
260 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
261
262 do {
263 /* '/' */
264 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
265
266 /* optional '..' */
267 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200268 }
269 }
270 } else {
271 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200272 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 +0200273 }
274
275 do {
276 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200277 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 +0200278
279 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200280 cur_node = exp->expr + exp->tok_pos[tok_idx];
281 cur_len = exp->tok_len[tok_idx];
282 if (prefix == LY_PATH_PREFIX_MANDATORY) {
283 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100284 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200285 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200286 goto error;
287 }
288 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
289 if (!prev_prefix) {
290 /* the first node must have a prefix */
291 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100292 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200293 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200294 goto error;
295 }
296
297 /* remember the first prefix */
298 prev_prefix = cur_node;
299 } else {
300 /* the prefix must be different, if any */
301 ptr = strnstr(cur_node, ":", cur_len);
302 if (ptr) {
303 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100304 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200305 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200306 goto error;
307 }
308
309 /* remember this next prefix */
310 prev_prefix = cur_node;
311 }
312 }
Michal Vasko004d3152020-06-11 19:59:22 +0200313 }
314
315 ++tok_idx;
316
317 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200318 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200319
Radek Krejci0f969882020-08-21 16:56:47 +0200320 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200321 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
322
323 /* trailing token check */
324 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100325 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 +0200326 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200327 goto error;
328 }
329
330 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100331
Radek Krejciddace2c2021-01-08 11:30:56 +0100332 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200333 return LY_SUCCESS;
334
335error:
336 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100337 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200338 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200339}
340
341LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200342ly_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 +0200343 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200344{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200345 LY_ERR ret = LY_SUCCESS;
346 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200347 uint16_t tok_idx;
348
349 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
350 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
351
Radek Krejciddace2c2021-01-08 11:30:56 +0100352 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100353
Michal Vasko004d3152020-06-11 19:59:22 +0200354 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200355 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200356 tok_idx = 0;
357
Radek Krejcif03a9e22020-09-18 20:09:31 +0200358 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200359
360 /* trailing token check */
361 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100362 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200363 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200364 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200365 goto error;
366 }
367
368 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100369
Radek Krejciddace2c2021-01-08 11:30:56 +0100370 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200371 return LY_SUCCESS;
372
373error:
374 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100375 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200376 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200377}
378
379/**
380 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
381 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200382 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200383 * @param[in] cur_node Optional current (original context) node.
Radek Krejci09c77442021-04-26 11:10:34 +0200384 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA*.
385 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200386 * @param[in] expr Parsed path.
387 * @param[in] tok_idx Index in @p expr.
388 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200389 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200390 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200391 * @param[out] mod Resolved module.
392 * @param[out] name Parsed node name.
393 * @param[out] name_len Length of @p name.
394 * @return LY_ERR value.
395 */
396static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200397ly_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 +0200398 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 +0200399 LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100400 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200401{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100402 LY_ERR ret;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200403 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200404 size_t len;
405
406 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
407
408 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200409 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
410 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
411 pref = expr->expr + expr->tok_pos[tok_idx];
412 } else {
413 len = 0;
414 }
Michal Vasko004d3152020-06-11 19:59:22 +0200415
416 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200417 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100418 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100419
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200420 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200421 if (!*mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100422 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100423 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200424 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100425 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200426 } else if (!(*mod)->implemented) {
427 if (lref == LY_PATH_LREF_FALSE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100428 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Michal Vasko825a0442021-04-16 16:11:53 +0200429 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100430 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200431 }
Michal Vasko825a0442021-04-16 16:11:53 +0200432
Michal Vaskob3e22532021-02-03 10:50:04 +0100433 assert(unres);
Michal Vasko4e205e82021-06-08 14:01:47 +0200434 LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200435 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100436
Radek Krejciddace2c2021-01-08 11:30:56 +0100437 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200438 } else {
439 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200440 case LY_VALUE_SCHEMA:
441 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200442 if (!cur_mod) {
443 LOGINT_RET(ctx);
444 }
445 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200446 *mod = cur_mod;
447 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200448 case LY_VALUE_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200449 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200450 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200451 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200452 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200453 *mod = prev_ctx_node->module;
454 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200455 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200456 case LY_VALUE_XML:
Radek Krejcif9943642021-04-26 10:18:21 +0200457 case LY_VALUE_LYB:
458 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200459 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200460 }
461 }
462
463 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200464 if (pref) {
465 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200466 *name_len = expr->tok_len[tok_idx] - len - 1;
467 } else {
468 *name = expr->expr + expr->tok_pos[tok_idx];
469 *name_len = expr->tok_len[tok_idx];
470 }
471
472 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100473
474error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100475 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200476 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200477}
478
479LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200480ly_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 +0200481 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 +0200482 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200483{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100484 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200485 struct ly_path_predicate *p;
486 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100487 const struct lys_module *mod = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200488 const char *name;
489 size_t name_len, key_count;
490
Michal Vasko00cbf532020-06-15 13:58:47 +0200491 assert(ctx && ctx_node);
492
Radek Krejciddace2c2021-01-08 11:30:56 +0100493 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100494
Michal Vasko004d3152020-06-11 19:59:22 +0200495 *pred_type = 0;
496
Michal Vasko004d3152020-06-11 19:59:22 +0200497 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200498 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100499 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200500 }
501
502 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
503 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100504 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200505 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100506 ret = LY_EVALID;
507 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200508 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100509 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200510 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100511 ret = LY_EVALID;
512 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200513 }
514
515 do {
516 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200517 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 +0100518 format, prefix_data, NULL, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100519 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200520 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100521 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100522 ret = LY_ENOTFOUND;
523 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200524 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100525 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
526 key->name);
527 ret = LY_EVALID;
528 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200529 }
530 ++(*tok_idx);
531
Michal Vasko004d3152020-06-11 19:59:22 +0200532 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200533 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200534 *pred_type = LY_PATH_PREDTYPE_LIST;
535 }
536 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100537 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200538 p->key = key;
539
540 /* '=' */
541 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
542 ++(*tok_idx);
543
544 /* Literal */
545 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100546 LOG_LOCSET(key, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100547 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200548 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 +0100549 LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100550 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200551 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200552 ++(*tok_idx);
553
Michal Vaskoae875662020-10-21 10:33:17 +0200554 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
555 ++((struct lysc_type *)p->value.realtype)->refcount;
556
Michal Vasko004d3152020-06-11 19:59:22 +0200557 /* ']' */
558 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
559 ++(*tok_idx);
560
561 /* another predicate follows? */
562 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
563
564 /* check that all keys were set */
565 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100566 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200567 ++key_count;
568 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200569 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200570 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100571 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200572 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200573 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200574 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100575 ret = LY_EVALID;
576 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200577 }
578
579 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
580 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100581 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200582 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100583 ret = LY_EVALID;
584 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200585 }
586 ++(*tok_idx);
587
588 /* new predicate */
589 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100590 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200591
592 /* '=' */
593 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
594 ++(*tok_idx);
595
596 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
597 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100598 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100599 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200600 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 +0100601 LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100602 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200603 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200604 ++(*tok_idx);
605
Michal Vaskoae875662020-10-21 10:33:17 +0200606 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
607 ++((struct lysc_type *)p->value.realtype)->refcount;
608
Michal Vasko004d3152020-06-11 19:59:22 +0200609 /* ']' */
610 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
611 ++(*tok_idx);
612 } else {
613 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
614 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100615 ret = LY_EVALID;
616 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200617 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100618 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200619 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100620 ret = LY_EVALID;
621 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200622 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100623 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200624 }
Michal Vasko004d3152020-06-11 19:59:22 +0200625
626 /* new predicate */
627 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100628 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200629
630 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100631 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200632 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200633
634 /* ']' */
635 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
636 ++(*tok_idx);
637 }
638
Radek Krejci2efc45b2020-12-22 16:25:44 +0100639cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100640 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100641 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200642}
643
644/**
645 * @brief Compile leafref predicate. Actually, it is only checked.
646 *
647 * @param[in] ctx_node Context node, node for which the predicate is defined.
648 * @param[in] cur_node Current (original context) node.
649 * @param[in] expr Parsed path.
650 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200651 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200652 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko405cc9e2020-12-01 12:01:27 +0100653 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko004d3152020-06-11 19:59:22 +0200654 * @return LY_ERR value.
655 */
656static LY_ERR
657ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Radek Krejci8df109d2021-04-23 12:19:08 +0200658 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100659 struct lys_glob_unres *unres)
Michal Vasko004d3152020-06-11 19:59:22 +0200660{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100661 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200662 const struct lysc_node *key, *node, *node2;
663 const struct lys_module *mod;
664 const char *name;
665 size_t name_len;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100666 struct ly_ctx *ctx = cur_node->module->ctx;
667
Radek Krejciddace2c2021-01-08 11:30:56 +0100668 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200669
Michal Vasko004d3152020-06-11 19:59:22 +0200670 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200671 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100672 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200673 }
674
675 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100676 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200677 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100678 ret = LY_EVALID;
679 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200680 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100681 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200682 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100683 ret = LY_EVALID;
684 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200685 }
686
687 do {
688 /* NameTest, find the key */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100689 ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
690 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len);
691 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100692 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200693 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100694 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 ret = LY_EVALID;
696 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200697 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100698 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200699 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100700 ret = LY_EVALID;
701 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200702 }
703 ++(*tok_idx);
704
705 /* we are not actually compiling, throw the key away */
706 (void)key;
707
708 /* '=' */
709 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
710 ++(*tok_idx);
711
712 /* FuncName */
713 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
714 ++(*tok_idx);
715
716 /* evaluating from the "current()" node */
717 node = cur_node;
718
719 /* '(' */
720 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
721 ++(*tok_idx);
722
723 /* ')' */
724 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
725 ++(*tok_idx);
726
727 do {
728 /* '/' */
729 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
730 ++(*tok_idx);
731
732 /* go to parent */
733 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100734 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
735 ret = LY_EVALID;
736 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200737 }
738 node = lysc_data_parent(node);
739
740 /* '..' */
741 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
742 ++(*tok_idx);
743 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
744
745 do {
746 /* '/' */
747 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
748 ++(*tok_idx);
749
750 /* NameTest */
751 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100752 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100753 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100754 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200755 if (!node2) {
Radek Krejci422afb12021-03-04 16:38:16 +0100756 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100757 ret = LY_EVALID;
758 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200759 }
760 node = node2;
761 ++(*tok_idx);
762 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
763
764 /* check the last target node */
765 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100766 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200767 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100768 ret = LY_EVALID;
769 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200770 }
771
772 /* we are not actually compiling, throw the rightside node away */
773 (void)node;
774
775 /* ']' */
776 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
777 ++(*tok_idx);
778
Radek Krejci0f969882020-08-21 16:56:47 +0200779 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200780 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
781
Radek Krejci2efc45b2020-12-22 16:25:44 +0100782cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100783 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100784 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200785}
786
787LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200788ly_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 +0100789 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 +0200790 LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200791{
792 LY_ERR ret = LY_SUCCESS;
793 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100794 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200795 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200796 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200797 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200798 const char *name;
799 size_t name_len;
800
Michal Vasko00cbf532020-06-15 13:58:47 +0200801 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200802 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200803 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200804 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
805 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200806
Michal Vasko6b26e742020-07-17 15:02:10 +0200807 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200808 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200809
Radek Krejci2efc45b2020-12-22 16:25:44 +0100810 *path = NULL;
811
Michal Vasko6b26e742020-07-17 15:02:10 +0200812 /* remember original context node */
813 cur_node = ctx_node;
Radek Krejciddace2c2021-01-08 11:30:56 +0100814 LOG_LOCINIT(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200815
Michal Vasko00cbf532020-06-15 13:58:47 +0200816 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100817 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200818 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100819 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200820 }
821
Michal Vasko004d3152020-06-11 19:59:22 +0200822 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
823 /* absolute path */
824 ctx_node = NULL;
825
826 ++tok_idx;
827 } else {
828 /* relative path */
829 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
830 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100831 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100832 ret = LY_EVALID;
833 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200834 }
835
836 /* get parent */
837 ctx_node = lysc_data_parent(ctx_node);
838
839 ++tok_idx;
840
841 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
842 ++tok_idx;
843 }
844
Michal Vasko00cbf532020-06-15 13:58:47 +0200845 /* we are not storing the parent */
846 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200847 }
848
849 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200850 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskod456cf62020-11-23 16:48:43 +0100851 if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
852 (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100853 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200854 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100855 ret = LY_EVALID;
856 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200857 }
858
Michal Vasko14424ba2020-12-09 18:09:51 +0100859 /* NameTest */
860 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
861
Michal Vasko004d3152020-06-11 19:59:22 +0200862 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200863 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 +0100864 prefix_data, unres, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200865 ++tok_idx;
866
867 /* find the next node */
Radek Krejcid5d37432021-03-12 13:46:40 +0100868 if (!ctx_node && ext) {
869 node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
870 } else {
871 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
872 }
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100873 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Radek Krejci422afb12021-03-04 16:38:16 +0100874 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200875 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200876 goto cleanup;
877 }
878 ctx_node = node2;
879
880 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200881 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200882 p->node = ctx_node;
883
884 /* compile any predicates */
885 if (lref == LY_PATH_LREF_TRUE) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100886 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200887 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200888 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 +0200889 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200890 }
891 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200892 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
893
Michal Vasko14424ba2020-12-09 18:09:51 +0100894 /* check leftover tokens */
895 if (tok_idx < expr->used) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100896 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 +0100897 ret = LY_EVALID;
898 goto cleanup;
899 }
900
Michal Vasko00cbf532020-06-15 13:58:47 +0200901 /* check last compiled node */
Michal Vasko69730152020-10-09 16:30:07 +0200902 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
903 (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100904 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200905 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100906 ret = LY_EVALID;
907 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200908 }
909
Michal Vasko004d3152020-06-11 19:59:22 +0200910cleanup:
911 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200912 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200913 *path = NULL;
914 }
Radek Krejciddace2c2021-01-08 11:30:56 +0100915 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200916 return ret;
917}
918
919LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200920ly_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 +0200921 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200922{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200923 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoacfc9282021-02-04 12:08:23 +0100924 struct lyd_node *prev_node = NULL, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200925 uint64_t pos;
926
927 assert(path && start);
928
929 if (lysc_data_parent(path[0].node)) {
930 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200931 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200932 } else {
933 /* absolute path, start from the first top-level sibling */
934 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +0100935 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200936 }
937 while (start->prev->next) {
938 start = start->prev;
939 }
940 }
941
942 LY_ARRAY_FOR(path, u) {
943 switch (path[u].pred_type) {
944 case LY_PATH_PREDTYPE_POSITION:
945 /* we cannot use hashes and want an instance on a specific position */
946 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200947 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200948 if (pos == path[u].predicates[0].position) {
949 break;
950 }
951 ++pos;
952 }
953 break;
954 case LY_PATH_PREDTYPE_LEAFLIST:
955 /* we will use hashes to find one leaf-list instance */
956 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
957 lyd_find_sibling_first(start, target, &node);
958 lyd_free_tree(target);
959 break;
960 case LY_PATH_PREDTYPE_LIST:
961 /* we will use hashes to find one list instance */
962 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
963 lyd_find_sibling_first(start, target, &node);
964 lyd_free_tree(target);
965 break;
966 case LY_PATH_PREDTYPE_NONE:
967 /* we will use hashes to find one any/container/leaf instance */
968 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
969 break;
970 }
971
972 if (!node) {
973 /* no matching nodes */
974 break;
975 }
976
Michal Vasko00cbf532020-06-15 13:58:47 +0200977 /* rememeber previous node */
978 prev_node = node;
979
Michal Vasko004d3152020-06-11 19:59:22 +0200980 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200981 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +0200982 }
983
Michal Vasko004d3152020-06-11 19:59:22 +0200984 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200985 /* we have found the full path */
986 if (path_idx) {
987 *path_idx = u;
988 }
989 if (match) {
990 *match = node;
991 }
Michal Vasko004d3152020-06-11 19:59:22 +0200992 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200993
994 } else if (prev_node) {
995 /* we have found only some partial match */
996 if (path_idx) {
997 *path_idx = u - 1;
998 }
999 if (match) {
1000 *match = prev_node;
1001 }
1002 return LY_EINCOMPLETE;
1003 }
1004
1005 /* we have not found any nodes */
1006 if (path_idx) {
1007 *path_idx = 0;
1008 }
1009 if (match) {
1010 *match = NULL;
1011 }
1012 return LY_ENOTFOUND;
1013}
1014
1015LY_ERR
1016ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1017{
1018 LY_ERR ret;
1019 struct lyd_node *m;
1020
1021 ret = ly_path_eval_partial(path, start, NULL, &m);
1022
1023 if (ret == LY_SUCCESS) {
1024 /* last node was found */
1025 if (match) {
1026 *match = m;
1027 }
1028 return LY_SUCCESS;
1029 }
1030
1031 /* not a full match */
1032 if (match) {
1033 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001034 }
1035 return LY_ENOTFOUND;
1036}
1037
1038LY_ERR
1039ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1040{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001041 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001042
1043 if (!path) {
1044 return LY_SUCCESS;
1045 }
1046
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001047 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001048 LY_ARRAY_FOR(path, u) {
1049 LY_ARRAY_INCREMENT(*dup);
1050 (*dup)[u].node = path[u].node;
1051 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001052 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001053 (*dup)[u].pred_type = path[u].pred_type;
1054 LY_ARRAY_FOR(path[u].predicates, v) {
1055 struct ly_path_predicate *pred = &path[u].predicates[v];
1056
1057 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1058 switch (path[u].pred_type) {
1059 case LY_PATH_PREDTYPE_POSITION:
1060 /* position-predicate */
1061 (*dup)[u].predicates[v].position = pred->position;
1062 break;
1063 case LY_PATH_PREDTYPE_LIST:
1064 case LY_PATH_PREDTYPE_LEAFLIST:
1065 /* key-predicate or leaf-list-predicate */
1066 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001067 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vaskoae875662020-10-21 10:33:17 +02001068 ++((struct lysc_type *)pred->value.realtype)->refcount;
Michal Vasko004d3152020-06-11 19:59:22 +02001069 break;
1070 case LY_PATH_PREDTYPE_NONE:
1071 break;
1072 }
1073 }
1074 }
1075 }
1076
1077 return LY_SUCCESS;
1078}
1079
1080void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001081ly_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 +02001082{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001083 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001084
1085 if (!predicates) {
1086 return;
1087 }
1088
1089 LY_ARRAY_FOR(predicates, u) {
1090 switch (pred_type) {
1091 case LY_PATH_PREDTYPE_POSITION:
1092 case LY_PATH_PREDTYPE_NONE:
1093 /* nothing to free */
1094 break;
1095 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001096 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001097 if (predicates[u].value.realtype) {
1098 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1099 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1100 }
Michal Vasko004d3152020-06-11 19:59:22 +02001101 break;
1102 }
1103 }
1104 LY_ARRAY_FREE(predicates);
1105}
1106
1107void
1108ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1109{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001110 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001111
Michal Vasko55b84812021-05-11 09:23:58 +02001112 if (!path) {
1113 return;
1114 }
1115
Michal Vasko004d3152020-06-11 19:59:22 +02001116 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001117 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001118 }
1119 LY_ARRAY_FREE(path);
1120}