blob: 3a299ae8544f3b00efd931e08b9b050672915c07 [file] [log] [blame]
Michal Vasko004d3152020-06-11 19:59:22 +02001/**
2 * @file path.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief Path functions
5 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14#define _ISOC99_SOURCE /* strtoull */
15
16#include "path.h"
17
18#include <assert.h>
19#include <ctype.h>
20#include <stdlib.h>
Radek Krejciad97c5f2020-06-30 09:19:28 +020021#include <string.h>
Michal Vasko004d3152020-06-11 19:59:22 +020022
23#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020024#include "compat.h"
Michal Vasko004d3152020-06-11 19:59:22 +020025#include "log.h"
26#include "plugins_types.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020027#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020028#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020029#include "tree_data_internal.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020030#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020031#include "tree_schema_internal.h"
32#include "xpath.h"
33
Michal Vasko6b26e742020-07-17 15:02:10 +020034#define LOGVAL_P(CTX, CUR_NODE, CODE, FORMAT...) ly_vlog(CTX, (CUR_NODE) ? LY_VLOG_LYSC : LY_VLOG_NONE, CUR_NODE, CODE, ##FORMAT)
35
Michal Vasko004d3152020-06-11 19:59:22 +020036/**
37 * @brief Check predicate syntax.
38 *
39 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020040 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020041 * @param[in] exp Parsed predicate.
42 * @param[in,out] tok_idx Index in @p exp, is adjusted.
43 * @param[in] prefix Prefix option.
44 * @param[in] pred Predicate option.
45 * @return LY_ERR value.
46 */
47static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020048ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
49 uint16_t *tok_idx, uint8_t prefix, uint8_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020050{
51 struct ly_set *set = NULL;
52 uint32_t i;
53 const char *name;
54 size_t name_len;
55
56 /* '[' */
57 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
58 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS))
59 && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
60 set = ly_set_new();
61 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
62
63 do {
64 /* NameTest is always expected here */
65 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
66
67 /* check prefix based on the options */
68 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
69 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Michal Vasko6b26e742020-07-17 15:02:10 +020070 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
71 exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +020072 goto error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020073 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
74 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
75 exp->expr + exp->tok_pos[*tok_idx]);
76 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +020077 }
78 if (!name) {
79 name = exp->expr + exp->tok_pos[*tok_idx];
80 name_len = exp->tok_len[*tok_idx];
81 } else {
82 ++name;
83 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
84 }
85
86 /* check whether it was not already specified */
87 for (i = 0; i < set->count; ++i) {
88 /* all the keys must be from the same module so this comparison should be fine */
89 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +020090 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +020091 goto error;
92 }
93 }
94
95 /* add it into the set */
96 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
97
98 /* NameTest */
99 ++(*tok_idx);
100
101 /* '=' */
102 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
103
104 /* Literal */
105 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
106
107 /* ']' */
108 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
109
110 /* '[' */
111 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
112
113 /* '.' */
114 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
115 /* '=' */
116 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
117
118 /* Literal */
119 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
120
121 /* ']' */
122 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
123
124 /* Number */
125 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
126
127 /* ']' */
128 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
129
130 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
131 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
132 set = ly_set_new();
133 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
134
135 do {
136 /* NameTest is always expected here */
137 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
138
139 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
140 if (!name) {
141 name = exp->expr + exp->tok_pos[*tok_idx];
142 name_len = exp->tok_len[*tok_idx];
143 } else {
144 ++name;
145 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
146 }
147
148 /* check whether it was not already specified */
149 for (i = 0; i < set->count; ++i) {
150 /* all the keys must be from the same module so this comparison should be fine */
151 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200152 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +0200153 goto error;
154 }
155 }
156
157 /* add it into the set */
158 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
159
160 /* NameTest */
161 ++(*tok_idx);
162
163 /* '=' */
164 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
165
166 /* FuncName */
167 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
168 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200169 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
170 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200171 goto error;
172 }
173 ++(*tok_idx);
174
175 /* '(' */
176 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), error);
177
178 /* ')' */
179 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), error);
180
181 /* '/' */
182 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
183
184 /* '..' */
185 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), error);
186 do {
187 /* '/' */
188 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
189 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
190
191 /* NameTest */
192 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
193
194 /* '/' */
195 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
196 /* NameTest */
197 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
198 }
199
200 /* ']' */
201 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
202
203 /* '[' */
204 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
205
206 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200207 LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
208 exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200209 goto error;
210 }
211 }
212
213 ly_set_free(set, NULL);
214 return LY_SUCCESS;
215
216error:
217 ly_set_free(set, NULL);
218 return LY_EVALID;
219}
220
221LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200222ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
223 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200224{
225 struct lyxp_expr *exp;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200226 uint16_t tok_idx, cur_len;
227 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200228
229 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
230 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200231 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY)
232 || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200233 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
234
235 /* parse as a generic XPath expression */
236 exp = lyxp_expr_parse(ctx, str_path, path_len, 1);
237 LY_CHECK_GOTO(!exp, error);
238 tok_idx = 0;
239
240 if (begin == LY_PATH_BEGIN_EITHER) {
241 /* is the path relative? */
242 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
243 /* '..' */
244 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
245 /* '/' */
246 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
247 }
248 }
249 } else {
250 /* '/' */
251 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
252 }
253
254 do {
255 /* NameTest */
256 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
257
258 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200259 cur_node = exp->expr + exp->tok_pos[tok_idx];
260 cur_len = exp->tok_len[tok_idx];
261 if (prefix == LY_PATH_PREFIX_MANDATORY) {
262 if (!strnstr(cur_node, ":", cur_len)) {
263 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
264 goto error;
265 }
266 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
267 if (!prev_prefix) {
268 /* the first node must have a prefix */
269 if (!strnstr(cur_node, ":", cur_len)) {
270 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
271 goto error;
272 }
273
274 /* remember the first prefix */
275 prev_prefix = cur_node;
276 } else {
277 /* the prefix must be different, if any */
278 ptr = strnstr(cur_node, ":", cur_len);
279 if (ptr) {
280 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
281 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
282 goto error;
283 }
284
285 /* remember this next prefix */
286 prev_prefix = cur_node;
287 }
288 }
Michal Vasko004d3152020-06-11 19:59:22 +0200289 }
290
291 ++tok_idx;
292
293 /* Predicate* */
Michal Vasko6b26e742020-07-17 15:02:10 +0200294 LY_CHECK_GOTO(ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200295
296 /* '/' */
297 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
298
299 /* trailing token check */
300 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200301 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
302 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200303 goto error;
304 }
305
306 *expr = exp;
307 return LY_SUCCESS;
308
309error:
310 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200311 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200312}
313
314LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200315ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
316 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200317{
318 struct lyxp_expr *exp;
319 uint16_t tok_idx;
320
321 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
322 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
323
324 /* parse as a generic XPath expression */
325 exp = lyxp_expr_parse(ctx, str_path, path_len, 0);
326 LY_CHECK_GOTO(!exp, error);
327 tok_idx = 0;
328
Michal Vasko6b26e742020-07-17 15:02:10 +0200329 LY_CHECK_GOTO(ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200330
331 /* trailing token check */
332 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200333 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
334 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200335 goto error;
336 }
337
338 *expr = exp;
339 return LY_SUCCESS;
340
341error:
342 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200343 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200344}
345
346/**
347 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
348 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200349 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200350 * @param[in] cur_node Optional current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +0200351 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
352 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
353 * @param[in] expr Parsed path.
354 * @param[in] tok_idx Index in @p expr.
355 * @param[in] lref Lref option.
356 * @param[in] resolve_prefix Callback for prefix resolution.
357 * @param[in] prefix_data Data for @p resolve_prefix.
358 * @param[in] format Format of the path.
359 * @param[out] mod Resolved module.
360 * @param[out] name Parsed node name.
361 * @param[out] name_len Length of @p name.
362 * @return LY_ERR value.
363 */
364static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200365ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
366 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
367 uint8_t lref, ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
368 const struct lys_module **mod, const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200369{
370 const char *ptr;
371 size_t len;
372
373 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
374
375 /* get prefix */
376 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
377 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
378
379 /* find next node module */
380 if (ptr) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200381 *mod = resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200382 if (!*mod) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200383 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
384 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200385 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200386 } else if (!(*mod)->implemented) {
387 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200388 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200389 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200390 }
391 lys_set_implemented_internal((struct lys_module *)*mod, 2);
392 }
393 } else {
394 switch (format) {
395 case LYD_SCHEMA:
396 *mod = cur_mod;
397 break;
398 case LYD_JSON:
399 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200400 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200401 }
402 *mod = prev_ctx_node->module;
403 break;
404 case LYD_XML:
Michal Vasko60ea6352020-06-29 13:39:39 +0200405 case LYD_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200406 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200407 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200408 }
409 }
410
411 /* set name */
412 if (ptr) {
413 *name = ptr + 1;
414 *name_len = expr->tok_len[tok_idx] - len - 1;
415 } else {
416 *name = expr->expr + expr->tok_pos[tok_idx];
417 *name_len = expr->tok_len[tok_idx];
418 }
419
420 return LY_SUCCESS;
421}
422
423LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200424ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
425 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
426 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
427 struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200428{
429 struct ly_path_predicate *p;
430 const struct lysc_node *key;
431 const struct lys_module *mod;
432 const char *name;
433 size_t name_len, key_count;
434
Michal Vasko00cbf532020-06-15 13:58:47 +0200435 assert(ctx && ctx_node);
436
Michal Vasko004d3152020-06-11 19:59:22 +0200437 *pred_type = 0;
438
439 /* '[' */
440 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
441 /* no predicate */
442 return LY_SUCCESS;
443 }
444
445 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
446 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200447 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
448 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200449 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200450 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200451 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
452 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200453 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200454 }
455
456 do {
457 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200458 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
459 resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200460 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
461 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200462 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200463 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200464 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200465 LOGVAL_P(ctx, cur_node ? cur_node : key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
466 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200467 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200468 }
469 ++(*tok_idx);
470
471 /* new predicate */
472 if (!*pred_type) {
473 *pred_type = LY_PATH_PREDTYPE_LIST;
474 }
475 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200476 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200477 p->key = key;
478
479 /* '=' */
480 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
481 ++(*tok_idx);
482
483 /* Literal */
484 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
485 LY_CHECK_RET(lyd_value_store(&p->value, key, expr->expr + expr->tok_pos[*tok_idx] + 1,
486 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
487 ++(*tok_idx);
488
489 /* ']' */
490 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
491 ++(*tok_idx);
492
493 /* another predicate follows? */
494 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
495
496 /* check that all keys were set */
497 key_count = 0;
498 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
499 ++key_count;
500 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200501 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200502 /* names (keys) are unique - it was checked when parsing */
Michal Vasko6b26e742020-07-17 15:02:10 +0200503 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
504 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200505 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200506 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200507 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200508 }
509
510 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
511 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200512 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
513 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200514 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200515 }
516 ++(*tok_idx);
517
518 /* new predicate */
519 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200520 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200521
522 /* '=' */
523 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
524 ++(*tok_idx);
525
526 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
527 /* store the value */
528 LY_CHECK_RET(lyd_value_store(&p->value, ctx_node, expr->expr + expr->tok_pos[*tok_idx] + 1,
529 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
530 ++(*tok_idx);
531
532 /* ']' */
533 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
534 ++(*tok_idx);
535 } else {
536 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
537 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200538 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
539 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200540 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200541 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200542 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
543 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200544 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200545 }
Michal Vasko004d3152020-06-11 19:59:22 +0200546
547 /* new predicate */
548 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200549 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200550
551 /* syntax was already checked */
552 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200553 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200554
555 /* ']' */
556 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
557 ++(*tok_idx);
558 }
559
560 return LY_SUCCESS;
561}
562
563/**
564 * @brief Compile leafref predicate. Actually, it is only checked.
565 *
566 * @param[in] ctx_node Context node, node for which the predicate is defined.
567 * @param[in] cur_node Current (original context) node.
568 * @param[in] expr Parsed path.
569 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
570 * @param[in] resolve_prefix Callback for prefix resolution.
571 * @param[in] prefix_data Data for @p resolve_prefix.
572 * @param[in] format Format of the path.
573 * @return LY_ERR value.
574 */
575static LY_ERR
576ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
577 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
578 void *prefix_data, LYD_FORMAT format)
579{
580 const struct lysc_node *key, *node, *node2;
581 const struct lys_module *mod;
582 const char *name;
583 size_t name_len;
584
585 /* '[' */
586 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
587 /* no predicate */
588 return LY_SUCCESS;
589 }
590
591 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200592 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
593 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200594 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200595 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200596 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
597 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200598 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200599 }
600
601 do {
602 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200603 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
Michal Vasko00cbf532020-06-15 13:58:47 +0200604 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200605 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
606 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200607 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200608 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200609 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200610 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
611 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200612 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200613 }
614 ++(*tok_idx);
615
616 /* we are not actually compiling, throw the key away */
617 (void)key;
618
619 /* '=' */
620 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
621 ++(*tok_idx);
622
623 /* FuncName */
624 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
625 ++(*tok_idx);
626
627 /* evaluating from the "current()" node */
628 node = cur_node;
629
630 /* '(' */
631 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
632 ++(*tok_idx);
633
634 /* ')' */
635 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
636 ++(*tok_idx);
637
638 do {
639 /* '/' */
640 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
641 ++(*tok_idx);
642
643 /* go to parent */
644 if (!node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200645 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200646 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200647 }
648 node = lysc_data_parent(node);
649
650 /* '..' */
651 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
652 ++(*tok_idx);
653 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
654
655 do {
656 /* '/' */
657 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
658 ++(*tok_idx);
659
660 /* NameTest */
661 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko6b26e742020-07-17 15:02:10 +0200662 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko00cbf532020-06-15 13:58:47 +0200663 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200664 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
665 if (!node2) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200666 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200667 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200668 }
669 node = node2;
670 ++(*tok_idx);
671 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
672
673 /* check the last target node */
674 if (node->nodetype != LYS_LEAF) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200675 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
676 "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
677 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200678 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200679 }
680
681 /* we are not actually compiling, throw the rightside node away */
682 (void)node;
683
684 /* ']' */
685 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
686 ++(*tok_idx);
687
688 /* another predicate follows? */
689 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
690
691 return LY_SUCCESS;
692}
693
694LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200695ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
696 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
697 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200698{
699 LY_ERR ret = LY_SUCCESS;
700 uint16_t tok_idx = 0;
701 const struct lys_module *mod;
Michal Vasko6b26e742020-07-17 15:02:10 +0200702 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200703 struct ly_path *p = NULL;
704 int getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200705 const char *name;
706 size_t name_len;
707
Michal Vasko00cbf532020-06-15 13:58:47 +0200708 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200709 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200710 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200711 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
712 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200713
Michal Vasko6b26e742020-07-17 15:02:10 +0200714 /* find operation, if we are in any */
715 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent);
716
717 /* remember original context node */
718 cur_node = ctx_node;
719
Michal Vasko004d3152020-06-11 19:59:22 +0200720 *path = NULL;
721
Michal Vasko00cbf532020-06-15 13:58:47 +0200722 if (oper == LY_PATH_OPER_OUTPUT) {
723 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
724 } else {
725 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
726 }
727
Michal Vasko004d3152020-06-11 19:59:22 +0200728 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
729 /* absolute path */
730 ctx_node = NULL;
731
732 ++tok_idx;
733 } else {
734 /* relative path */
735 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
736 if (!ctx_node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200737 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200738 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200739 }
740
741 /* get parent */
742 ctx_node = lysc_data_parent(ctx_node);
743
744 ++tok_idx;
745
746 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
747 ++tok_idx;
748 }
749
Michal Vasko00cbf532020-06-15 13:58:47 +0200750 /* we are not storing the parent */
751 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200752 }
753
754 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200755 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
756 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200757 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
758 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200759 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200760 }
761
Michal Vasko004d3152020-06-11 19:59:22 +0200762 /* get module and node name */
Michal Vasko6b26e742020-07-17 15:02:10 +0200763 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, resolve_prefix,
Michal Vasko00cbf532020-06-15 13:58:47 +0200764 prefix_data, format, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200765 ++tok_idx;
766
767 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200768 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko6b26e742020-07-17 15:02:10 +0200769 if (!node2 || ((node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
770 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200771 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200772 goto cleanup;
773 }
774 ctx_node = node2;
775
776 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200777 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200778 p->node = ctx_node;
779
780 /* compile any predicates */
781 if (lref == LY_PATH_LREF_TRUE) {
782 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, resolve_prefix, prefix_data, format);
783 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200784 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, resolve_prefix,
785 prefix_data, format, &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200786 }
787 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200788 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
789
Michal Vasko00cbf532020-06-15 13:58:47 +0200790 /* check last compiled node */
791 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
792 && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200793 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
794 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200795 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200796 }
797
Michal Vasko004d3152020-06-11 19:59:22 +0200798cleanup:
799 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200800 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200801 *path = NULL;
802 }
803 return ret;
804}
805
806LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200807ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
Michal Vasko00cbf532020-06-15 13:58:47 +0200808 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200809{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200810 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200811 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200812 uint64_t pos;
813
814 assert(path && start);
815
816 if (lysc_data_parent(path[0].node)) {
817 /* relative path, start from the parent children */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200818 start = lyd_node_children(start, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200819 } else {
820 /* absolute path, start from the first top-level sibling */
821 while (start->parent) {
822 start = (struct lyd_node *)start->parent;
823 }
824 while (start->prev->next) {
825 start = start->prev;
826 }
827 }
828
829 LY_ARRAY_FOR(path, u) {
830 switch (path[u].pred_type) {
831 case LY_PATH_PREDTYPE_POSITION:
832 /* we cannot use hashes and want an instance on a specific position */
833 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200834 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200835 if (pos == path[u].predicates[0].position) {
836 break;
837 }
838 ++pos;
839 }
840 break;
841 case LY_PATH_PREDTYPE_LEAFLIST:
842 /* we will use hashes to find one leaf-list instance */
843 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
844 lyd_find_sibling_first(start, target, &node);
845 lyd_free_tree(target);
846 break;
847 case LY_PATH_PREDTYPE_LIST:
848 /* we will use hashes to find one list instance */
849 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
850 lyd_find_sibling_first(start, target, &node);
851 lyd_free_tree(target);
852 break;
853 case LY_PATH_PREDTYPE_NONE:
854 /* we will use hashes to find one any/container/leaf instance */
855 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
856 break;
857 }
858
859 if (!node) {
860 /* no matching nodes */
861 break;
862 }
863
Michal Vasko00cbf532020-06-15 13:58:47 +0200864 /* rememeber previous node */
865 prev_node = node;
866
Michal Vasko004d3152020-06-11 19:59:22 +0200867 /* next path segment, if any */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200868 start = lyd_node_children(node, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200869 }
870
Michal Vasko004d3152020-06-11 19:59:22 +0200871 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200872 /* we have found the full path */
873 if (path_idx) {
874 *path_idx = u;
875 }
876 if (match) {
877 *match = node;
878 }
Michal Vasko004d3152020-06-11 19:59:22 +0200879 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200880
881 } else if (prev_node) {
882 /* we have found only some partial match */
883 if (path_idx) {
884 *path_idx = u - 1;
885 }
886 if (match) {
887 *match = prev_node;
888 }
889 return LY_EINCOMPLETE;
890 }
891
892 /* we have not found any nodes */
893 if (path_idx) {
894 *path_idx = 0;
895 }
896 if (match) {
897 *match = NULL;
898 }
899 return LY_ENOTFOUND;
900}
901
902LY_ERR
903ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
904{
905 LY_ERR ret;
906 struct lyd_node *m;
907
908 ret = ly_path_eval_partial(path, start, NULL, &m);
909
910 if (ret == LY_SUCCESS) {
911 /* last node was found */
912 if (match) {
913 *match = m;
914 }
915 return LY_SUCCESS;
916 }
917
918 /* not a full match */
919 if (match) {
920 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200921 }
922 return LY_ENOTFOUND;
923}
924
925LY_ERR
926ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
927{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200928 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200929
930 if (!path) {
931 return LY_SUCCESS;
932 }
933
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200934 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200935 LY_ARRAY_FOR(path, u) {
936 LY_ARRAY_INCREMENT(*dup);
937 (*dup)[u].node = path[u].node;
938 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200939 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200940 (*dup)[u].pred_type = path[u].pred_type;
941 LY_ARRAY_FOR(path[u].predicates, v) {
942 struct ly_path_predicate *pred = &path[u].predicates[v];
943
944 LY_ARRAY_INCREMENT((*dup)[u].predicates);
945 switch (path[u].pred_type) {
946 case LY_PATH_PREDTYPE_POSITION:
947 /* position-predicate */
948 (*dup)[u].predicates[v].position = pred->position;
949 break;
950 case LY_PATH_PREDTYPE_LIST:
951 case LY_PATH_PREDTYPE_LEAFLIST:
952 /* key-predicate or leaf-list-predicate */
953 (*dup)[u].predicates[v].key = pred->key;
954 (*dup)[u].predicates[v].value.realtype = pred->value.realtype;
955 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
956 break;
957 case LY_PATH_PREDTYPE_NONE:
958 break;
959 }
960 }
961 }
962 }
963
964 return LY_SUCCESS;
965}
966
967void
968ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, const struct lysc_node *llist,
969 struct ly_path_predicate *predicates)
970{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200971 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200972
973 if (!predicates) {
974 return;
975 }
976
977 LY_ARRAY_FOR(predicates, u) {
978 switch (pred_type) {
979 case LY_PATH_PREDTYPE_POSITION:
980 case LY_PATH_PREDTYPE_NONE:
981 /* nothing to free */
982 break;
983 case LY_PATH_PREDTYPE_LIST:
984 ((struct lysc_node_leaf *)predicates[u].key)->type->plugin->free(ctx, &predicates[u].value);
985 break;
986 case LY_PATH_PREDTYPE_LEAFLIST:
987 ((struct lysc_node_leaflist *)llist)->type->plugin->free(ctx, &predicates[u].value);
988 break;
989 }
990 }
991 LY_ARRAY_FREE(predicates);
992}
993
994void
995ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
996{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200997 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200998
999 LY_ARRAY_FOR(path, u) {
1000 ly_path_predicates_free(ctx, path[u].pred_type, path[u].node, path[u].predicates);
1001 }
1002 LY_ARRAY_FREE(path);
1003}