blob: 0e787c4fd3cc685def1c41c83c30954d35736e9a [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
Michal Vasko4911eeb2021-06-28 11:23:05 +0200111 /* Literal or Number */
112 LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +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
Michal Vasko4911eeb2021-06-28 11:23:05 +0200126 /* Literal or Number */
127 LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +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,
Michal Vaskoed725d72021-06-23 12:03:45 +0200235 ly_bool lref, uint8_t begin, 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));
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 */
Michal Vaskoed725d72021-06-23 12:03:45 +0200257 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200258 /* 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.
Radek Krejci09c77442021-04-26 11:10:34 +0200383 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA*.
384 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200385 * @param[in] expr Parsed path.
386 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200387 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200388 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200389 * @param[out] mod Resolved module.
390 * @param[out] name Parsed node name.
391 * @param[out] name_len Length of @p name.
392 * @return LY_ERR value.
393 */
394static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200395ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskoed725d72021-06-23 12:03:45 +0200396 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
397 void *prefix_data, const struct lys_module **mod, const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200398{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100399 LY_ERR ret;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200400 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200401 size_t len;
402
403 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
404
405 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200406 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
407 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
408 pref = expr->expr + expr->tok_pos[tok_idx];
409 } else {
410 len = 0;
411 }
Michal Vasko004d3152020-06-11 19:59:22 +0200412
413 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200414 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100415 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100416
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200417 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200418 if (!*mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100419 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100420 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200421 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100422 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200423 } else if (!(*mod)->implemented) {
Michal Vaskoed725d72021-06-23 12:03:45 +0200424 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
425 ret = LY_EVALID;
426 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200427 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100428
Radek Krejciddace2c2021-01-08 11:30:56 +0100429 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200430 } else {
431 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200432 case LY_VALUE_SCHEMA:
433 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200434 if (!cur_mod) {
435 LOGINT_RET(ctx);
436 }
437 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200438 *mod = cur_mod;
439 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200440 case LY_VALUE_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200441 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200442 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200443 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200444 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200445 *mod = prev_ctx_node->module;
446 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200447 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200448 case LY_VALUE_XML:
Radek Krejcif9943642021-04-26 10:18:21 +0200449 case LY_VALUE_LYB:
450 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200451 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200452 }
453 }
454
455 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200456 if (pref) {
457 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200458 *name_len = expr->tok_len[tok_idx] - len - 1;
459 } else {
460 *name = expr->expr + expr->tok_pos[tok_idx];
461 *name_len = expr->tok_len[tok_idx];
462 }
463
464 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100465
466error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100467 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200468 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200469}
470
Michal Vaskoed725d72021-06-23 12:03:45 +0200471/**
472 * @brief Parse prefix from a NameTest in a leafref, if any, and node name, and return expected module of the node.
473 *
474 * @param[in] ctx libyang context.
475 * @param[in] cur_node Optional current (original context) node.
476 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
477 * @param[in] expr Parsed path.
478 * @param[in] tok_idx Index in @p expr.
479 * @param[in] format Format of the path.
480 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
481 * @param[in,out] unres Global unres to use.
482 * @param[out] mod Resolved module.
483 * @param[out] name Parsed node name.
484 * @param[out] name_len Length of @p name.
485 * @return LY_ERR value.
486 */
487static LY_ERR
488ly_path_compile_prefix_leafref(const struct ly_ctx *ctx, const struct lysc_node *cur_node,
489 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, LY_VALUE_FORMAT format,
490 void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod, const char **name,
491 size_t *name_len)
492{
493 LY_ERR ret;
494 const char *pref;
495 size_t len;
496
497 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
498
499 /* get prefix */
500 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
501 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
502 pref = expr->expr + expr->tok_pos[tok_idx];
503 } else {
504 len = 0;
505 }
506
507 /* find next node module */
508 if (pref) {
509 LOG_LOCSET(cur_node, NULL, NULL, NULL);
510
511 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
512 if (!*mod) {
513 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
514 (int)len, pref, ly_format2str(format));
515 ret = LY_EVALID;
516 goto error;
517 } else if (!(*mod)->implemented) {
518 assert(unres);
519 LY_CHECK_GOTO(ret = lys_implement((struct lys_module *)*mod, NULL, unres), error);
520 LY_CHECK_GOTO(ret = lys_compile((struct lys_module *)*mod, &unres->ds_unres), error);
521 }
522
523 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
524 } else {
525 switch (format) {
526 case LY_VALUE_SCHEMA:
527 case LY_VALUE_SCHEMA_RESOLVED:
528 /* use original context node module */
529 *mod = cur_node->module;
530 break;
531 case LY_VALUE_JSON:
532 if (!prev_ctx_node) {
533 LOGINT_RET(ctx);
534 }
535 /* inherit module of the previous node */
536 *mod = prev_ctx_node->module;
537 break;
538 case LY_VALUE_CANON:
539 case LY_VALUE_XML:
540 case LY_VALUE_LYB:
541 /* not really defined or accepted */
542 LOGINT_RET(ctx);
543 }
544 }
545
546 /* set name */
547 if (pref) {
548 *name = pref + len + 1;
549 *name_len = expr->tok_len[tok_idx] - len - 1;
550 } else {
551 *name = expr->expr + expr->tok_pos[tok_idx];
552 *name_len = expr->tok_len[tok_idx];
553 }
554
555 return LY_SUCCESS;
556
557error:
558 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
559 return ret;
560}
561
Michal Vasko004d3152020-06-11 19:59:22 +0200562LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200563ly_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 +0200564 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 +0200565 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200566{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100567 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200568 struct ly_path_predicate *p;
569 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100570 const struct lys_module *mod = NULL;
Michal Vasko4911eeb2021-06-28 11:23:05 +0200571 const char *name, *val;
572 size_t name_len, val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200573
Michal Vasko00cbf532020-06-15 13:58:47 +0200574 assert(ctx && ctx_node);
575
Radek Krejciddace2c2021-01-08 11:30:56 +0100576 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100577
Michal Vasko004d3152020-06-11 19:59:22 +0200578 *pred_type = 0;
579
Michal Vasko004d3152020-06-11 19:59:22 +0200580 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200581 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100582 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200583 }
584
585 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
586 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100587 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200588 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100589 ret = LY_EVALID;
590 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200591 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100592 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200593 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100594 ret = LY_EVALID;
595 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200596 }
597
598 do {
599 /* NameTest, find the key */
Michal Vaskoed725d72021-06-23 12:03:45 +0200600 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
601 &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100602 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200603 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100604 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100605 ret = LY_ENOTFOUND;
606 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200607 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100608 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
609 key->name);
610 ret = LY_EVALID;
611 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200612 }
613 ++(*tok_idx);
614
Michal Vasko004d3152020-06-11 19:59:22 +0200615 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200616 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200617 *pred_type = LY_PATH_PREDTYPE_LIST;
618 }
619 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100620 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200621 p->key = key;
622
623 /* '=' */
624 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
625 ++(*tok_idx);
626
Michal Vasko4911eeb2021-06-28 11:23:05 +0200627 /* Literal or Number */
628 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
629 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
630 /* skip quotes */
631 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
632 val_len = expr->tok_len[*tok_idx] - 2;
633 } else {
634 val = expr->expr + expr->tok_pos[*tok_idx];
635 val_len = expr->tok_len[*tok_idx];
636 }
637
638 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100639 LOG_LOCSET(key, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200640 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
641 prefix_data, LYD_HINT_DATA, key, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100642 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200643 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200644 ++(*tok_idx);
645
Michal Vaskoae875662020-10-21 10:33:17 +0200646 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
647 ++((struct lysc_type *)p->value.realtype)->refcount;
648
Michal Vasko004d3152020-06-11 19:59:22 +0200649 /* ']' */
650 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
651 ++(*tok_idx);
652
653 /* another predicate follows? */
654 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
655
656 /* check that all keys were set */
657 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100658 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200659 ++key_count;
660 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200661 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200662 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100663 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200664 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200665 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200666 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100667 ret = LY_EVALID;
668 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200669 }
670
671 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
672 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200674 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100675 ret = LY_EVALID;
676 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200677 }
678 ++(*tok_idx);
679
680 /* new predicate */
681 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100682 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200683
684 /* '=' */
685 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
686 ++(*tok_idx);
687
Michal Vasko4911eeb2021-06-28 11:23:05 +0200688 /* Literal or Number */
689 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
690 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
691 /* skip quotes */
692 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
693 val_len = expr->tok_len[*tok_idx] - 2;
694 } else {
695 val = expr->expr + expr->tok_pos[*tok_idx];
696 val_len = expr->tok_len[*tok_idx];
697 }
698
Michal Vasko004d3152020-06-11 19:59:22 +0200699 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100700 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200701 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
702 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100703 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200704 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200705 ++(*tok_idx);
706
Michal Vaskoae875662020-10-21 10:33:17 +0200707 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
708 ++((struct lysc_type *)p->value.realtype)->refcount;
709
Michal Vasko004d3152020-06-11 19:59:22 +0200710 /* ']' */
711 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
712 ++(*tok_idx);
713 } else {
714 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
715 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100716 ret = LY_EVALID;
717 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200718 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100719 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200720 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100721 ret = LY_EVALID;
722 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200723 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100724 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200725 }
Michal Vasko004d3152020-06-11 19:59:22 +0200726
727 /* new predicate */
728 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100729 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200730
731 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100732 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200733 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200734
735 /* ']' */
736 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
737 ++(*tok_idx);
738 }
739
Radek Krejci2efc45b2020-12-22 16:25:44 +0100740cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100741 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100742 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200743}
744
745/**
746 * @brief Compile leafref predicate. Actually, it is only checked.
747 *
748 * @param[in] ctx_node Context node, node for which the predicate is defined.
749 * @param[in] cur_node Current (original context) node.
750 * @param[in] expr Parsed path.
751 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200752 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200753 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko405cc9e2020-12-01 12:01:27 +0100754 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko004d3152020-06-11 19:59:22 +0200755 * @return LY_ERR value.
756 */
757static LY_ERR
758ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Radek Krejci8df109d2021-04-23 12:19:08 +0200759 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100760 struct lys_glob_unres *unres)
Michal Vasko004d3152020-06-11 19:59:22 +0200761{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100762 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200763 const struct lysc_node *key, *node, *node2;
764 const struct lys_module *mod;
765 const char *name;
766 size_t name_len;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100767 struct ly_ctx *ctx = cur_node->module->ctx;
768
Radek Krejciddace2c2021-01-08 11:30:56 +0100769 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200770
Michal Vasko004d3152020-06-11 19:59:22 +0200771 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200772 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100773 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200774 }
775
776 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100777 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200778 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100779 ret = LY_EVALID;
780 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200781 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100782 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200783 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100784 ret = LY_EVALID;
785 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200786 }
787
788 do {
789 /* NameTest, find the key */
Michal Vaskoed725d72021-06-23 12:03:45 +0200790 ret = ly_path_compile_prefix_leafref(ctx, cur_node, ctx_node, expr, *tok_idx, format, prefix_data, unres, &mod,
791 &name, &name_len);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100792 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100793 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200794 if (!key) {
Radek Krejci422afb12021-03-04 16:38:16 +0100795 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100796 ret = LY_EVALID;
797 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200798 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100799 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200800 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100801 ret = LY_EVALID;
802 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200803 }
804 ++(*tok_idx);
805
806 /* we are not actually compiling, throw the key away */
807 (void)key;
808
809 /* '=' */
810 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
811 ++(*tok_idx);
812
813 /* FuncName */
814 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
815 ++(*tok_idx);
816
817 /* evaluating from the "current()" node */
818 node = cur_node;
819
820 /* '(' */
821 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
822 ++(*tok_idx);
823
824 /* ')' */
825 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
826 ++(*tok_idx);
827
828 do {
829 /* '/' */
830 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
831 ++(*tok_idx);
832
833 /* go to parent */
834 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100835 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
836 ret = LY_EVALID;
837 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200838 }
839 node = lysc_data_parent(node);
840
841 /* '..' */
842 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
843 ++(*tok_idx);
844 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
845
846 do {
847 /* '/' */
848 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
849 ++(*tok_idx);
850
851 /* NameTest */
852 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vaskoed725d72021-06-23 12:03:45 +0200853 LY_CHECK_RET(ly_path_compile_prefix_leafref(ctx, cur_node, node, expr, *tok_idx, format, prefix_data, unres,
854 &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100855 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200856 if (!node2) {
Radek Krejci422afb12021-03-04 16:38:16 +0100857 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100858 ret = LY_EVALID;
859 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200860 }
861 node = node2;
862 ++(*tok_idx);
863 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
864
865 /* check the last target node */
866 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100867 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200868 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100869 ret = LY_EVALID;
870 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200871 }
872
873 /* we are not actually compiling, throw the rightside node away */
874 (void)node;
875
876 /* ']' */
877 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
878 ++(*tok_idx);
879
Radek Krejci0f969882020-08-21 16:56:47 +0200880 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200881 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
882
Radek Krejci2efc45b2020-12-22 16:25:44 +0100883cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100884 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100885 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200886}
887
Michal Vaskoed725d72021-06-23 12:03:45 +0200888/**
889 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
890 *
891 * @param[in] ctx libyang context.
892 * @param[in] cur_mod Current module of the path (where it was "instantiated"), ignored of @p lref. Used for nodes
893 * without a prefix for ::LY_PREF_SCHEMA* format.
894 * @param[in] ctx_node Optional context node, mandatory of @p lref.
895 * @param[in] ext Extension instance containing the definition of the data being created. It is used to find the top-level
896 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
897 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
898 * @param[in] expr Parsed path.
899 * @param[in] lref Whether leafref is being compiled or not.
900 * @param[in] oper Oper option (@ref path_oper_options).
901 * @param[in] target Target option (@ref path_target_options).
902 * @param[in] format Format of the path.
903 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
904 * @param[in,out] unres Global unres structure for newly implemented modules, needed only if @p lref.
905 * @param[out] path Compiled path.
906 * @return LY_ERECOMPILE, only if @p lref.
907 * @return LY_ERR value.
908 */
909static LY_ERR
910_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
911 const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target,
Radek Krejci8df109d2021-04-23 12:19:08 +0200912 LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200913{
914 LY_ERR ret = LY_SUCCESS;
915 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100916 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200917 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200918 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200919 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200920 const char *name;
921 size_t name_len;
922
Michal Vasko00cbf532020-06-15 13:58:47 +0200923 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200924 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200925 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
926 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200927
Michal Vasko6b26e742020-07-17 15:02:10 +0200928 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200929 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200930
Radek Krejci2efc45b2020-12-22 16:25:44 +0100931 *path = NULL;
932
Michal Vasko6b26e742020-07-17 15:02:10 +0200933 /* remember original context node */
934 cur_node = ctx_node;
Radek Krejciddace2c2021-01-08 11:30:56 +0100935 LOG_LOCINIT(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200936
Michal Vasko00cbf532020-06-15 13:58:47 +0200937 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100938 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200939 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100940 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200941 }
942
Michal Vasko004d3152020-06-11 19:59:22 +0200943 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
944 /* absolute path */
945 ctx_node = NULL;
946
947 ++tok_idx;
948 } else {
949 /* relative path */
Michal Vaskoed725d72021-06-23 12:03:45 +0200950 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200951 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100952 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100953 ret = LY_EVALID;
954 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200955 }
956
957 /* get parent */
958 ctx_node = lysc_data_parent(ctx_node);
959
960 ++tok_idx;
961
962 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
963 ++tok_idx;
964 }
965
Michal Vasko00cbf532020-06-15 13:58:47 +0200966 /* we are not storing the parent */
967 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200968 }
969
970 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200971 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200972 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100973 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200974 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100975 ret = LY_EVALID;
976 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200977 }
978
Michal Vasko14424ba2020-12-09 18:09:51 +0100979 /* NameTest */
980 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
981
Michal Vasko004d3152020-06-11 19:59:22 +0200982 /* get module and node name */
Michal Vaskoed725d72021-06-23 12:03:45 +0200983 if (lref) {
984 LY_CHECK_GOTO(ret = ly_path_compile_prefix_leafref(ctx, cur_node, ctx_node, expr, tok_idx, format,
985 prefix_data, unres, &mod, &name, &name_len), cleanup);
986 } else {
987 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format,
988 prefix_data, &mod, &name, &name_len), cleanup);
989 }
Michal Vasko004d3152020-06-11 19:59:22 +0200990 ++tok_idx;
991
992 /* find the next node */
Radek Krejcid5d37432021-03-12 13:46:40 +0100993 if (!ctx_node && ext) {
994 node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
995 } else {
996 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
997 }
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100998 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Radek Krejci422afb12021-03-04 16:38:16 +0100999 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +02001000 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02001001 goto cleanup;
1002 }
1003 ctx_node = node2;
1004
1005 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +02001006 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001007 p->node = ctx_node;
1008
1009 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +02001010 if (lref) {
Michal Vasko405cc9e2020-12-01 12:01:27 +01001011 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
Michal Vasko004d3152020-06-11 19:59:22 +02001012 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02001013 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 +02001014 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +02001015 }
1016 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02001017 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
1018
Michal Vasko14424ba2020-12-09 18:09:51 +01001019 /* check leftover tokens */
1020 if (tok_idx < expr->used) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001021 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 +01001022 ret = LY_EVALID;
1023 goto cleanup;
1024 }
1025
Michal Vasko00cbf532020-06-15 13:58:47 +02001026 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +02001027 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001028 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001029 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001030 ret = LY_EVALID;
1031 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001032 }
1033
Michal Vasko004d3152020-06-11 19:59:22 +02001034cleanup:
1035 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001036 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +02001037 *path = NULL;
1038 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001039 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +02001040 return ret;
1041}
1042
1043LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +02001044ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
1045 const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target,
1046 LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
1047{
1048 return _ly_path_compile(ctx, cur_mod, ctx_node, ext, expr, 0, oper, target, format, prefix_data, NULL, path);
1049}
1050
1051LY_ERR
1052ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *ext,
1053 const struct lyxp_expr *expr, uint8_t oper, uint8_t target, LY_VALUE_FORMAT format, void *prefix_data,
1054 struct lys_glob_unres *unres, struct ly_path **path)
1055{
1056 return _ly_path_compile(ctx, NULL, ctx_node, ext, expr, 1, oper, target, format, prefix_data, unres, path);
1057}
1058
1059LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001060ly_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 +02001061 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +02001062{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001063 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoacfc9282021-02-04 12:08:23 +01001064 struct lyd_node *prev_node = NULL, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +02001065 uint64_t pos;
1066
1067 assert(path && start);
1068
1069 if (lysc_data_parent(path[0].node)) {
1070 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001071 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001072 } else {
1073 /* absolute path, start from the first top-level sibling */
1074 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001075 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001076 }
1077 while (start->prev->next) {
1078 start = start->prev;
1079 }
1080 }
1081
1082 LY_ARRAY_FOR(path, u) {
1083 switch (path[u].pred_type) {
1084 case LY_PATH_PREDTYPE_POSITION:
1085 /* we cannot use hashes and want an instance on a specific position */
1086 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +02001087 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +02001088 if (pos == path[u].predicates[0].position) {
1089 break;
1090 }
1091 ++pos;
1092 }
1093 break;
1094 case LY_PATH_PREDTYPE_LEAFLIST:
1095 /* we will use hashes to find one leaf-list instance */
1096 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1097 lyd_find_sibling_first(start, target, &node);
1098 lyd_free_tree(target);
1099 break;
1100 case LY_PATH_PREDTYPE_LIST:
1101 /* we will use hashes to find one list instance */
1102 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
1103 lyd_find_sibling_first(start, target, &node);
1104 lyd_free_tree(target);
1105 break;
1106 case LY_PATH_PREDTYPE_NONE:
1107 /* we will use hashes to find one any/container/leaf instance */
1108 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
1109 break;
1110 }
1111
1112 if (!node) {
1113 /* no matching nodes */
1114 break;
1115 }
1116
Michal Vasko00cbf532020-06-15 13:58:47 +02001117 /* rememeber previous node */
1118 prev_node = node;
1119
Michal Vasko004d3152020-06-11 19:59:22 +02001120 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001121 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001122 }
1123
Michal Vasko004d3152020-06-11 19:59:22 +02001124 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001125 /* we have found the full path */
1126 if (path_idx) {
1127 *path_idx = u;
1128 }
1129 if (match) {
1130 *match = node;
1131 }
Michal Vasko004d3152020-06-11 19:59:22 +02001132 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001133
1134 } else if (prev_node) {
1135 /* we have found only some partial match */
1136 if (path_idx) {
1137 *path_idx = u - 1;
1138 }
1139 if (match) {
1140 *match = prev_node;
1141 }
1142 return LY_EINCOMPLETE;
1143 }
1144
1145 /* we have not found any nodes */
1146 if (path_idx) {
1147 *path_idx = 0;
1148 }
1149 if (match) {
1150 *match = NULL;
1151 }
1152 return LY_ENOTFOUND;
1153}
1154
1155LY_ERR
1156ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1157{
1158 LY_ERR ret;
1159 struct lyd_node *m;
1160
1161 ret = ly_path_eval_partial(path, start, NULL, &m);
1162
1163 if (ret == LY_SUCCESS) {
1164 /* last node was found */
1165 if (match) {
1166 *match = m;
1167 }
1168 return LY_SUCCESS;
1169 }
1170
1171 /* not a full match */
1172 if (match) {
1173 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001174 }
1175 return LY_ENOTFOUND;
1176}
1177
1178LY_ERR
1179ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1180{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001181 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001182
1183 if (!path) {
1184 return LY_SUCCESS;
1185 }
1186
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001187 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001188 LY_ARRAY_FOR(path, u) {
1189 LY_ARRAY_INCREMENT(*dup);
1190 (*dup)[u].node = path[u].node;
1191 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001192 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001193 (*dup)[u].pred_type = path[u].pred_type;
1194 LY_ARRAY_FOR(path[u].predicates, v) {
1195 struct ly_path_predicate *pred = &path[u].predicates[v];
1196
1197 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1198 switch (path[u].pred_type) {
1199 case LY_PATH_PREDTYPE_POSITION:
1200 /* position-predicate */
1201 (*dup)[u].predicates[v].position = pred->position;
1202 break;
1203 case LY_PATH_PREDTYPE_LIST:
1204 case LY_PATH_PREDTYPE_LEAFLIST:
1205 /* key-predicate or leaf-list-predicate */
1206 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001207 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vaskoae875662020-10-21 10:33:17 +02001208 ++((struct lysc_type *)pred->value.realtype)->refcount;
Michal Vasko004d3152020-06-11 19:59:22 +02001209 break;
1210 case LY_PATH_PREDTYPE_NONE:
1211 break;
1212 }
1213 }
1214 }
1215 }
1216
1217 return LY_SUCCESS;
1218}
1219
1220void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001221ly_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 +02001222{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001223 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001224
1225 if (!predicates) {
1226 return;
1227 }
1228
1229 LY_ARRAY_FOR(predicates, u) {
1230 switch (pred_type) {
1231 case LY_PATH_PREDTYPE_POSITION:
1232 case LY_PATH_PREDTYPE_NONE:
1233 /* nothing to free */
1234 break;
1235 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001236 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001237 if (predicates[u].value.realtype) {
1238 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1239 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1240 }
Michal Vasko004d3152020-06-11 19:59:22 +02001241 break;
1242 }
1243 }
1244 LY_ARRAY_FREE(predicates);
1245}
1246
1247void
1248ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1249{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001250 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001251
Michal Vasko55b84812021-05-11 09:23:58 +02001252 if (!path) {
1253 return;
1254 }
1255
Michal Vasko004d3152020-06-11 19:59:22 +02001256 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001257 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001258 }
1259 LY_ARRAY_FREE(path);
1260}