blob: 4017be7dd5cddb95c6c5dae674059c9b78664ea1 [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
34/**
35 * @brief Check predicate syntax.
36 *
37 * @param[in] ctx libyang context.
38 * @param[in] exp Parsed predicate.
39 * @param[in,out] tok_idx Index in @p exp, is adjusted.
40 * @param[in] prefix Prefix option.
41 * @param[in] pred Predicate option.
42 * @return LY_ERR value.
43 */
44static LY_ERR
45ly_path_check_predicate(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, uint8_t prefix,
46 uint8_t pred)
47{
48 struct ly_set *set = NULL;
49 uint32_t i;
50 const char *name;
51 size_t name_len;
52
53 /* '[' */
54 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
55 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS))
56 && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
57 set = ly_set_new();
58 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
59
60 do {
61 /* NameTest is always expected here */
62 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
63
64 /* check prefix based on the options */
65 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
66 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
67 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
68 exp->expr + exp->tok_pos[*tok_idx]);
69 goto error;
70 }
71 if (!name) {
72 name = exp->expr + exp->tok_pos[*tok_idx];
73 name_len = exp->tok_len[*tok_idx];
74 } else {
75 ++name;
76 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
77 }
78
79 /* check whether it was not already specified */
80 for (i = 0; i < set->count; ++i) {
81 /* all the keys must be from the same module so this comparison should be fine */
82 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
83 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
84 name_len, name);
85 goto error;
86 }
87 }
88
89 /* add it into the set */
90 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
91
92 /* NameTest */
93 ++(*tok_idx);
94
95 /* '=' */
96 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
97
98 /* Literal */
99 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
100
101 /* ']' */
102 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
103
104 /* '[' */
105 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
106
107 /* '.' */
108 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
109 /* '=' */
110 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
111
112 /* Literal */
113 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
114
115 /* ']' */
116 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
117
118 /* Number */
119 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
120
121 /* ']' */
122 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
123
124 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
125 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
126 set = ly_set_new();
127 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
128
129 do {
130 /* NameTest is always expected here */
131 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
132
133 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
134 if (!name) {
135 name = exp->expr + exp->tok_pos[*tok_idx];
136 name_len = exp->tok_len[*tok_idx];
137 } else {
138 ++name;
139 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
140 }
141
142 /* check whether it was not already specified */
143 for (i = 0; i < set->count; ++i) {
144 /* all the keys must be from the same module so this comparison should be fine */
145 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
146 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
147 name_len, name);
148 goto error;
149 }
150 }
151
152 /* add it into the set */
153 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
154
155 /* NameTest */
156 ++(*tok_idx);
157
158 /* '=' */
159 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
160
161 /* FuncName */
162 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
163 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
164 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
165 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
166 goto error;
167 }
168 ++(*tok_idx);
169
170 /* '(' */
171 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), error);
172
173 /* ')' */
174 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), error);
175
176 /* '/' */
177 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
178
179 /* '..' */
180 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), error);
181 do {
182 /* '/' */
183 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
184 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
185
186 /* NameTest */
187 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
188
189 /* '/' */
190 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
191 /* NameTest */
192 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
193 }
194
195 /* ']' */
196 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
197
198 /* '[' */
199 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
200
201 } else {
202 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
203 exp->expr + exp->tok_pos[*tok_idx]);
204 goto error;
205 }
206 }
207
208 ly_set_free(set, NULL);
209 return LY_SUCCESS;
210
211error:
212 ly_set_free(set, NULL);
213 return LY_EVALID;
214}
215
216LY_ERR
217ly_path_parse(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t begin, uint8_t lref,
218 uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
219{
220 struct lyxp_expr *exp;
221 uint16_t tok_idx;
222
223 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
224 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
225 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
226 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
227
228 /* parse as a generic XPath expression */
229 exp = lyxp_expr_parse(ctx, str_path, path_len, 1);
230 LY_CHECK_GOTO(!exp, error);
231 tok_idx = 0;
232
233 if (begin == LY_PATH_BEGIN_EITHER) {
234 /* is the path relative? */
235 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
236 /* '..' */
237 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
238 /* '/' */
239 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
240 }
241 }
242 } else {
243 /* '/' */
244 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
245 }
246
247 do {
248 /* NameTest */
249 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
250
251 /* check prefix based on the options */
252 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !strnstr(exp->expr + exp->tok_pos[tok_idx], ":", exp->tok_len[tok_idx])) {
253 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[tok_idx],
254 exp->expr + exp->tok_pos[tok_idx]);
255 goto error;
256 }
257
258 ++tok_idx;
259
260 /* Predicate* */
261 LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
262
263 /* '/' */
264 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
265
266 /* trailing token check */
267 if (exp->used > tok_idx) {
268 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
269 exp->expr + exp->tok_pos[tok_idx]);
270 goto error;
271 }
272
273 *expr = exp;
274 return LY_SUCCESS;
275
276error:
277 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200278 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200279}
280
281LY_ERR
282ly_path_parse_predicate(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t prefix, uint8_t pred,
283 struct lyxp_expr **expr)
284{
285 struct lyxp_expr *exp;
286 uint16_t tok_idx;
287
288 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
289 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
290
291 /* parse as a generic XPath expression */
292 exp = lyxp_expr_parse(ctx, str_path, path_len, 0);
293 LY_CHECK_GOTO(!exp, error);
294 tok_idx = 0;
295
296 LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
297
298 /* trailing token check */
299 if (exp->used > tok_idx) {
300 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
301 exp->expr + exp->tok_pos[tok_idx]);
302 goto error;
303 }
304
305 *expr = exp;
306 return LY_SUCCESS;
307
308error:
309 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200310 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200311}
312
313/**
314 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
315 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200316 * @param[in] ctx libyang context.
Michal Vasko004d3152020-06-11 19:59:22 +0200317 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
318 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
319 * @param[in] expr Parsed path.
320 * @param[in] tok_idx Index in @p expr.
321 * @param[in] lref Lref option.
322 * @param[in] resolve_prefix Callback for prefix resolution.
323 * @param[in] prefix_data Data for @p resolve_prefix.
324 * @param[in] format Format of the path.
325 * @param[out] mod Resolved module.
326 * @param[out] name Parsed node name.
327 * @param[out] name_len Length of @p name.
328 * @return LY_ERR value.
329 */
330static LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200331ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *prev_ctx_node,
332 const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref, ly_clb_resolve_prefix resolve_prefix,
333 void *prefix_data, LYD_FORMAT format, const struct lys_module **mod, const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200334{
335 const char *ptr;
336 size_t len;
337
338 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
339
340 /* get prefix */
341 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
342 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
343
344 /* find next node module */
345 if (ptr) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200346 *mod = resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200347 if (!*mod) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200348 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200349 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200350 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200351 } else if (!(*mod)->implemented) {
352 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200353 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200354 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200355 }
356 lys_set_implemented_internal((struct lys_module *)*mod, 2);
357 }
358 } else {
359 switch (format) {
360 case LYD_SCHEMA:
361 *mod = cur_mod;
362 break;
363 case LYD_JSON:
364 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200365 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200366 }
367 *mod = prev_ctx_node->module;
368 break;
369 case LYD_XML:
Michal Vasko60ea6352020-06-29 13:39:39 +0200370 case LYD_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200371 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200372 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200373 }
374 }
375
376 /* set name */
377 if (ptr) {
378 *name = ptr + 1;
379 *name_len = expr->tok_len[tok_idx] - len - 1;
380 } else {
381 *name = expr->expr + expr->tok_pos[tok_idx];
382 *name_len = expr->tok_len[tok_idx];
383 }
384
385 return LY_SUCCESS;
386}
387
388LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200389ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
390 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
391 void *prefix_data, LYD_FORMAT format, struct ly_path_predicate **predicates,
392 enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200393{
394 struct ly_path_predicate *p;
395 const struct lysc_node *key;
396 const struct lys_module *mod;
397 const char *name;
398 size_t name_len, key_count;
399
Michal Vasko00cbf532020-06-15 13:58:47 +0200400 assert(ctx && ctx_node);
401
Michal Vasko004d3152020-06-11 19:59:22 +0200402 *pred_type = 0;
403
404 /* '[' */
405 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
406 /* no predicate */
407 return LY_SUCCESS;
408 }
409
410 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
411 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200412 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200413 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200414 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200415 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200416 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200417 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200418 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200419 }
420
421 do {
422 /* NameTest, find the key */
Michal Vasko00cbf532020-06-15 13:58:47 +0200423 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE, resolve_prefix,
Michal Vasko004d3152020-06-11 19:59:22 +0200424 prefix_data, format, &mod, &name, &name_len));
425 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
426 if (!key) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200427 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200428 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200429 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200430 LOGVAL(ctx, LY_VLOG_LYSC, key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200431 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200432 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200433 }
434 ++(*tok_idx);
435
436 /* new predicate */
437 if (!*pred_type) {
438 *pred_type = LY_PATH_PREDTYPE_LIST;
439 }
440 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200441 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200442 p->key = key;
443
444 /* '=' */
445 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
446 ++(*tok_idx);
447
448 /* Literal */
449 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
450 LY_CHECK_RET(lyd_value_store(&p->value, key, expr->expr + expr->tok_pos[*tok_idx] + 1,
451 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
452 ++(*tok_idx);
453
454 /* ']' */
455 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
456 ++(*tok_idx);
457
458 /* another predicate follows? */
459 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
460
461 /* check that all keys were set */
462 key_count = 0;
463 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
464 ++key_count;
465 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200466 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200467 /* names (keys) are unique - it was checked when parsing */
Michal Vasko00cbf532020-06-15 13:58:47 +0200468 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200469 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200470 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200471 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200472 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200473 }
474
475 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
476 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200477 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200478 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200479 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200480 }
481 ++(*tok_idx);
482
483 /* new predicate */
484 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200485 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200486
487 /* '=' */
488 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
489 ++(*tok_idx);
490
491 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
492 /* store the value */
493 LY_CHECK_RET(lyd_value_store(&p->value, ctx_node, expr->expr + expr->tok_pos[*tok_idx] + 1,
494 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
495 ++(*tok_idx);
496
497 /* ']' */
498 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
499 ++(*tok_idx);
500 } else {
501 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
502 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200503 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200504 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200505 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200506 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200507 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for configuration"
Michal Vasko004d3152020-06-11 19:59:22 +0200508 " %s \"%s\" in path.", lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200509 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200510 }
Michal Vasko004d3152020-06-11 19:59:22 +0200511
512 /* new predicate */
513 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200514 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200515
516 /* syntax was already checked */
517 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200518 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200519
520 /* ']' */
521 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
522 ++(*tok_idx);
523 }
524
525 return LY_SUCCESS;
526}
527
528/**
529 * @brief Compile leafref predicate. Actually, it is only checked.
530 *
531 * @param[in] ctx_node Context node, node for which the predicate is defined.
532 * @param[in] cur_node Current (original context) node.
533 * @param[in] expr Parsed path.
534 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
535 * @param[in] resolve_prefix Callback for prefix resolution.
536 * @param[in] prefix_data Data for @p resolve_prefix.
537 * @param[in] format Format of the path.
538 * @return LY_ERR value.
539 */
540static LY_ERR
541ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
542 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
543 void *prefix_data, LYD_FORMAT format)
544{
545 const struct lysc_node *key, *node, *node2;
546 const struct lys_module *mod;
547 const char *name;
548 size_t name_len;
549
550 /* '[' */
551 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
552 /* no predicate */
553 return LY_SUCCESS;
554 }
555
556 if (ctx_node->nodetype != LYS_LIST) {
557 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
558 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200559 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200560 } else if (ctx_node->flags & LYS_KEYLESS) {
561 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
562 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200563 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200564 }
565
566 do {
567 /* NameTest, find the key */
Michal Vasko00cbf532020-06-15 13:58:47 +0200568 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, ctx_node, expr, *tok_idx,
569 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200570 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
571 if (!key) {
572 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200573 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200574 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
575 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
576 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200577 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200578 }
579 ++(*tok_idx);
580
581 /* we are not actually compiling, throw the key away */
582 (void)key;
583
584 /* '=' */
585 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
586 ++(*tok_idx);
587
588 /* FuncName */
589 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
590 ++(*tok_idx);
591
592 /* evaluating from the "current()" node */
593 node = cur_node;
594
595 /* '(' */
596 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
597 ++(*tok_idx);
598
599 /* ')' */
600 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
601 ++(*tok_idx);
602
603 do {
604 /* '/' */
605 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
606 ++(*tok_idx);
607
608 /* go to parent */
609 if (!node) {
610 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200611 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200612 }
613 node = lysc_data_parent(node);
614
615 /* '..' */
616 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
617 ++(*tok_idx);
618 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
619
620 do {
621 /* '/' */
622 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
623 ++(*tok_idx);
624
625 /* NameTest */
626 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200627 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, node, expr, *tok_idx,
628 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200629 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
630 if (!node2) {
631 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.",
632 name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200633 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200634 }
635 node = node2;
636 ++(*tok_idx);
637 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
638
639 /* check the last target node */
640 if (node->nodetype != LYS_LEAF) {
641 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in"
642 " leafref predicate in path.", lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200643 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200644 }
645
646 /* we are not actually compiling, throw the rightside node away */
647 (void)node;
648
649 /* ']' */
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 return LY_SUCCESS;
657}
658
659LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200660ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
661 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
662 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200663{
664 LY_ERR ret = LY_SUCCESS;
665 uint16_t tok_idx = 0;
666 const struct lys_module *mod;
667 const struct lysc_node *node2, *cur_node;
Michal Vasko00cbf532020-06-15 13:58:47 +0200668 struct ly_path *p = NULL;
669 int getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200670 const char *name;
671 size_t name_len;
672
Michal Vasko00cbf532020-06-15 13:58:47 +0200673 assert(ctx);
674 assert((expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) || (lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200675 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200676 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
677 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200678
679 if (lref == LY_PATH_LREF_TRUE) {
680 /* remember original context node */
681 cur_node = ctx_node;
682 }
683 *path = NULL;
684
Michal Vasko00cbf532020-06-15 13:58:47 +0200685 if (oper == LY_PATH_OPER_OUTPUT) {
686 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
687 } else {
688 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
689 }
690
Michal Vasko004d3152020-06-11 19:59:22 +0200691 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
692 /* absolute path */
693 ctx_node = NULL;
694
695 ++tok_idx;
696 } else {
697 /* relative path */
698 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
699 if (!ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200700 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200701 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200702 }
703
704 /* get parent */
705 ctx_node = lysc_data_parent(ctx_node);
706
707 ++tok_idx;
708
709 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
710 ++tok_idx;
711 }
712
Michal Vasko00cbf532020-06-15 13:58:47 +0200713 /* we are not storing the parent */
714 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200715 }
716
717 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200718 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
719 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
720 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
721 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200722 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200723 }
724
Michal Vasko004d3152020-06-11 19:59:22 +0200725 /* get module and node name */
Michal Vasko00cbf532020-06-15 13:58:47 +0200726 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_mod, ctx_node, expr, tok_idx, lref, resolve_prefix,
727 prefix_data, format, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200728 ++tok_idx;
729
730 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200731 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200732 if (!node2) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200733 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200734 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200735 goto cleanup;
736 }
737 ctx_node = node2;
738
739 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200740 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200741 p->node = ctx_node;
742
743 /* compile any predicates */
744 if (lref == LY_PATH_LREF_TRUE) {
745 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, resolve_prefix, prefix_data, format);
746 } else {
Michal Vasko00cbf532020-06-15 13:58:47 +0200747 ret = ly_path_compile_predicate(ctx, cur_mod, ctx_node, expr, &tok_idx, resolve_prefix, prefix_data, format,
Michal Vasko004d3152020-06-11 19:59:22 +0200748 &p->predicates, &p->pred_type);
749 }
750 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200751 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
752
Michal Vasko00cbf532020-06-15 13:58:47 +0200753 /* check last compiled node */
754 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
755 && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
756 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
757 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200758 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200759 }
760
Michal Vasko004d3152020-06-11 19:59:22 +0200761cleanup:
762 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200763 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200764 *path = NULL;
765 }
766 return ret;
767}
768
769LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200770ly_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 +0200771 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200772{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200773 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200774 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200775 uint64_t pos;
776
777 assert(path && start);
778
779 if (lysc_data_parent(path[0].node)) {
780 /* relative path, start from the parent children */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200781 start = lyd_node_children(start, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200782 } else {
783 /* absolute path, start from the first top-level sibling */
784 while (start->parent) {
785 start = (struct lyd_node *)start->parent;
786 }
787 while (start->prev->next) {
788 start = start->prev;
789 }
790 }
791
792 LY_ARRAY_FOR(path, u) {
793 switch (path[u].pred_type) {
794 case LY_PATH_PREDTYPE_POSITION:
795 /* we cannot use hashes and want an instance on a specific position */
796 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200797 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200798 if (pos == path[u].predicates[0].position) {
799 break;
800 }
801 ++pos;
802 }
803 break;
804 case LY_PATH_PREDTYPE_LEAFLIST:
805 /* we will use hashes to find one leaf-list instance */
806 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
807 lyd_find_sibling_first(start, target, &node);
808 lyd_free_tree(target);
809 break;
810 case LY_PATH_PREDTYPE_LIST:
811 /* we will use hashes to find one list instance */
812 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
813 lyd_find_sibling_first(start, target, &node);
814 lyd_free_tree(target);
815 break;
816 case LY_PATH_PREDTYPE_NONE:
817 /* we will use hashes to find one any/container/leaf instance */
818 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
819 break;
820 }
821
822 if (!node) {
823 /* no matching nodes */
824 break;
825 }
826
Michal Vasko00cbf532020-06-15 13:58:47 +0200827 /* rememeber previous node */
828 prev_node = node;
829
Michal Vasko004d3152020-06-11 19:59:22 +0200830 /* next path segment, if any */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200831 start = lyd_node_children(node, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200832 }
833
Michal Vasko004d3152020-06-11 19:59:22 +0200834 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200835 /* we have found the full path */
836 if (path_idx) {
837 *path_idx = u;
838 }
839 if (match) {
840 *match = node;
841 }
Michal Vasko004d3152020-06-11 19:59:22 +0200842 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200843
844 } else if (prev_node) {
845 /* we have found only some partial match */
846 if (path_idx) {
847 *path_idx = u - 1;
848 }
849 if (match) {
850 *match = prev_node;
851 }
852 return LY_EINCOMPLETE;
853 }
854
855 /* we have not found any nodes */
856 if (path_idx) {
857 *path_idx = 0;
858 }
859 if (match) {
860 *match = NULL;
861 }
862 return LY_ENOTFOUND;
863}
864
865LY_ERR
866ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
867{
868 LY_ERR ret;
869 struct lyd_node *m;
870
871 ret = ly_path_eval_partial(path, start, NULL, &m);
872
873 if (ret == LY_SUCCESS) {
874 /* last node was found */
875 if (match) {
876 *match = m;
877 }
878 return LY_SUCCESS;
879 }
880
881 /* not a full match */
882 if (match) {
883 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200884 }
885 return LY_ENOTFOUND;
886}
887
888LY_ERR
889ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
890{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200891 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200892
893 if (!path) {
894 return LY_SUCCESS;
895 }
896
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200897 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200898 LY_ARRAY_FOR(path, u) {
899 LY_ARRAY_INCREMENT(*dup);
900 (*dup)[u].node = path[u].node;
901 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200902 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200903 (*dup)[u].pred_type = path[u].pred_type;
904 LY_ARRAY_FOR(path[u].predicates, v) {
905 struct ly_path_predicate *pred = &path[u].predicates[v];
906
907 LY_ARRAY_INCREMENT((*dup)[u].predicates);
908 switch (path[u].pred_type) {
909 case LY_PATH_PREDTYPE_POSITION:
910 /* position-predicate */
911 (*dup)[u].predicates[v].position = pred->position;
912 break;
913 case LY_PATH_PREDTYPE_LIST:
914 case LY_PATH_PREDTYPE_LEAFLIST:
915 /* key-predicate or leaf-list-predicate */
916 (*dup)[u].predicates[v].key = pred->key;
917 (*dup)[u].predicates[v].value.realtype = pred->value.realtype;
918 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
919 break;
920 case LY_PATH_PREDTYPE_NONE:
921 break;
922 }
923 }
924 }
925 }
926
927 return LY_SUCCESS;
928}
929
930void
931ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, const struct lysc_node *llist,
932 struct ly_path_predicate *predicates)
933{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200934 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200935
936 if (!predicates) {
937 return;
938 }
939
940 LY_ARRAY_FOR(predicates, u) {
941 switch (pred_type) {
942 case LY_PATH_PREDTYPE_POSITION:
943 case LY_PATH_PREDTYPE_NONE:
944 /* nothing to free */
945 break;
946 case LY_PATH_PREDTYPE_LIST:
947 ((struct lysc_node_leaf *)predicates[u].key)->type->plugin->free(ctx, &predicates[u].value);
948 break;
949 case LY_PATH_PREDTYPE_LEAFLIST:
950 ((struct lysc_node_leaflist *)llist)->type->plugin->free(ctx, &predicates[u].value);
951 break;
952 }
953 }
954 LY_ARRAY_FREE(predicates);
955}
956
957void
958ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
959{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200960 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200961
962 LY_ARRAY_FOR(path, u) {
963 ly_path_predicates_free(ctx, path[u].pred_type, path[u].node, path[u].predicates);
964 }
965 LY_ARRAY_FREE(path);
966}