blob: 0d5f3f3c0a1dca38e0cfa4a0d04f27804cf0e06b [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 Vasko004d3152020-06-11 19:59:22 +020028#include "tree_data_internal.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020029#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "tree_schema_internal.h"
31#include "xpath.h"
32
33/**
34 * @brief Check predicate syntax.
35 *
36 * @param[in] ctx libyang context.
37 * @param[in] exp Parsed predicate.
38 * @param[in,out] tok_idx Index in @p exp, is adjusted.
39 * @param[in] prefix Prefix option.
40 * @param[in] pred Predicate option.
41 * @return LY_ERR value.
42 */
43static LY_ERR
44ly_path_check_predicate(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, uint8_t prefix,
45 uint8_t pred)
46{
47 struct ly_set *set = NULL;
48 uint32_t i;
49 const char *name;
50 size_t name_len;
51
52 /* '[' */
53 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
54 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS))
55 && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
56 set = ly_set_new();
57 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
58
59 do {
60 /* NameTest is always expected here */
61 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
62
63 /* check prefix based on the options */
64 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
65 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
66 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
67 exp->expr + exp->tok_pos[*tok_idx]);
68 goto error;
69 }
70 if (!name) {
71 name = exp->expr + exp->tok_pos[*tok_idx];
72 name_len = exp->tok_len[*tok_idx];
73 } else {
74 ++name;
75 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
76 }
77
78 /* check whether it was not already specified */
79 for (i = 0; i < set->count; ++i) {
80 /* all the keys must be from the same module so this comparison should be fine */
81 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
82 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
83 name_len, name);
84 goto error;
85 }
86 }
87
88 /* add it into the set */
89 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
90
91 /* NameTest */
92 ++(*tok_idx);
93
94 /* '=' */
95 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
96
97 /* Literal */
98 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
99
100 /* ']' */
101 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
102
103 /* '[' */
104 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
105
106 /* '.' */
107 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
108 /* '=' */
109 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
110
111 /* Literal */
112 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
113
114 /* ']' */
115 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
116
117 /* Number */
118 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
119
120 /* ']' */
121 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
122
123 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
124 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
125 set = ly_set_new();
126 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
127
128 do {
129 /* NameTest is always expected here */
130 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
131
132 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
133 if (!name) {
134 name = exp->expr + exp->tok_pos[*tok_idx];
135 name_len = exp->tok_len[*tok_idx];
136 } else {
137 ++name;
138 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
139 }
140
141 /* check whether it was not already specified */
142 for (i = 0; i < set->count; ++i) {
143 /* all the keys must be from the same module so this comparison should be fine */
144 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
145 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.",
146 name_len, name);
147 goto error;
148 }
149 }
150
151 /* add it into the set */
152 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
153
154 /* NameTest */
155 ++(*tok_idx);
156
157 /* '=' */
158 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
159
160 /* FuncName */
161 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
162 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
163 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
164 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
165 goto error;
166 }
167 ++(*tok_idx);
168
169 /* '(' */
170 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), error);
171
172 /* ')' */
173 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), error);
174
175 /* '/' */
176 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
177
178 /* '..' */
179 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), error);
180 do {
181 /* '/' */
182 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
183 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
184
185 /* NameTest */
186 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
187
188 /* '/' */
189 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
190 /* NameTest */
191 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
192 }
193
194 /* ']' */
195 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
196
197 /* '[' */
198 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
199
200 } else {
201 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
202 exp->expr + exp->tok_pos[*tok_idx]);
203 goto error;
204 }
205 }
206
207 ly_set_free(set, NULL);
208 return LY_SUCCESS;
209
210error:
211 ly_set_free(set, NULL);
212 return LY_EVALID;
213}
214
215LY_ERR
216ly_path_parse(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t begin, uint8_t lref,
217 uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
218{
219 struct lyxp_expr *exp;
220 uint16_t tok_idx;
221
222 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
223 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
224 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
225 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
226
227 /* parse as a generic XPath expression */
228 exp = lyxp_expr_parse(ctx, str_path, path_len, 1);
229 LY_CHECK_GOTO(!exp, error);
230 tok_idx = 0;
231
232 if (begin == LY_PATH_BEGIN_EITHER) {
233 /* is the path relative? */
234 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
235 /* '..' */
236 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
237 /* '/' */
238 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
239 }
240 }
241 } else {
242 /* '/' */
243 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
244 }
245
246 do {
247 /* NameTest */
248 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
249
250 /* check prefix based on the options */
251 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !strnstr(exp->expr + exp->tok_pos[tok_idx], ":", exp->tok_len[tok_idx])) {
252 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[tok_idx],
253 exp->expr + exp->tok_pos[tok_idx]);
254 goto error;
255 }
256
257 ++tok_idx;
258
259 /* Predicate* */
260 LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
261
262 /* '/' */
263 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
264
265 /* trailing token check */
266 if (exp->used > tok_idx) {
267 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
268 exp->expr + exp->tok_pos[tok_idx]);
269 goto error;
270 }
271
272 *expr = exp;
273 return LY_SUCCESS;
274
275error:
276 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200277 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200278}
279
280LY_ERR
281ly_path_parse_predicate(const struct ly_ctx *ctx, const char *str_path, size_t path_len, uint8_t prefix, uint8_t pred,
282 struct lyxp_expr **expr)
283{
284 struct lyxp_expr *exp;
285 uint16_t tok_idx;
286
287 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
288 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
289
290 /* parse as a generic XPath expression */
291 exp = lyxp_expr_parse(ctx, str_path, path_len, 0);
292 LY_CHECK_GOTO(!exp, error);
293 tok_idx = 0;
294
295 LY_CHECK_GOTO(ly_path_check_predicate(ctx, exp, &tok_idx, prefix, pred), error);
296
297 /* trailing token check */
298 if (exp->used > tok_idx) {
299 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
300 exp->expr + exp->tok_pos[tok_idx]);
301 goto error;
302 }
303
304 *expr = exp;
305 return LY_SUCCESS;
306
307error:
308 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200309 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200310}
311
312/**
313 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
314 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200315 * @param[in] ctx libyang context.
Michal Vasko004d3152020-06-11 19:59:22 +0200316 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
317 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
318 * @param[in] expr Parsed path.
319 * @param[in] tok_idx Index in @p expr.
320 * @param[in] lref Lref option.
321 * @param[in] resolve_prefix Callback for prefix resolution.
322 * @param[in] prefix_data Data for @p resolve_prefix.
323 * @param[in] format Format of the path.
324 * @param[out] mod Resolved module.
325 * @param[out] name Parsed node name.
326 * @param[out] name_len Length of @p name.
327 * @return LY_ERR value.
328 */
329static LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200330ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *prev_ctx_node,
331 const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref, ly_clb_resolve_prefix resolve_prefix,
332 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 +0200333{
334 const char *ptr;
335 size_t len;
336
337 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
338
339 /* get prefix */
340 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
341 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
342
343 /* find next node module */
344 if (ptr) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200345 *mod = resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200346 if (!*mod) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200347 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200348 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200349 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200350 } else if (!(*mod)->implemented) {
351 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200352 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200353 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200354 }
355 lys_set_implemented_internal((struct lys_module *)*mod, 2);
356 }
357 } else {
358 switch (format) {
359 case LYD_SCHEMA:
360 *mod = cur_mod;
361 break;
362 case LYD_JSON:
363 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200364 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200365 }
366 *mod = prev_ctx_node->module;
367 break;
368 case LYD_XML:
Michal Vasko60ea6352020-06-29 13:39:39 +0200369 case LYD_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200370 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200371 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200372 }
373 }
374
375 /* set name */
376 if (ptr) {
377 *name = ptr + 1;
378 *name_len = expr->tok_len[tok_idx] - len - 1;
379 } else {
380 *name = expr->expr + expr->tok_pos[tok_idx];
381 *name_len = expr->tok_len[tok_idx];
382 }
383
384 return LY_SUCCESS;
385}
386
387LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200388ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
389 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
390 void *prefix_data, LYD_FORMAT format, struct ly_path_predicate **predicates,
391 enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200392{
393 struct ly_path_predicate *p;
394 const struct lysc_node *key;
395 const struct lys_module *mod;
396 const char *name;
397 size_t name_len, key_count;
398
Michal Vasko00cbf532020-06-15 13:58:47 +0200399 assert(ctx && ctx_node);
400
Michal Vasko004d3152020-06-11 19:59:22 +0200401 *pred_type = 0;
402
403 /* '[' */
404 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
405 /* no predicate */
406 return LY_SUCCESS;
407 }
408
409 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
410 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200411 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200412 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200413 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200414 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200415 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200416 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200417 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200418 }
419
420 do {
421 /* NameTest, find the key */
Michal Vasko00cbf532020-06-15 13:58:47 +0200422 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 +0200423 prefix_data, format, &mod, &name, &name_len));
424 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
425 if (!key) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200426 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200427 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200428 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200429 LOGVAL(ctx, LY_VLOG_LYSC, key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200430 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200431 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200432 }
433 ++(*tok_idx);
434
435 /* new predicate */
436 if (!*pred_type) {
437 *pred_type = LY_PATH_PREDTYPE_LIST;
438 }
439 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200440 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200441 p->key = key;
442
443 /* '=' */
444 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
445 ++(*tok_idx);
446
447 /* Literal */
448 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
449 LY_CHECK_RET(lyd_value_store(&p->value, key, expr->expr + expr->tok_pos[*tok_idx] + 1,
450 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
451 ++(*tok_idx);
452
453 /* ']' */
454 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
455 ++(*tok_idx);
456
457 /* another predicate follows? */
458 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
459
460 /* check that all keys were set */
461 key_count = 0;
462 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
463 ++key_count;
464 }
465 if (LY_ARRAY_SIZE(*predicates) != key_count) {
466 /* names (keys) are unique - it was checked when parsing */
Michal Vasko00cbf532020-06-15 13:58:47 +0200467 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 +0200468 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200469 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200470 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200471 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200472 }
473
474 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
475 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200476 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200477 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200478 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200479 }
480 ++(*tok_idx);
481
482 /* new predicate */
483 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200484 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200485
486 /* '=' */
487 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
488 ++(*tok_idx);
489
490 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
491 /* store the value */
492 LY_CHECK_RET(lyd_value_store(&p->value, ctx_node, expr->expr + expr->tok_pos[*tok_idx] + 1,
493 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
494 ++(*tok_idx);
495
496 /* ']' */
497 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
498 ++(*tok_idx);
499 } else {
500 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
501 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200502 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko004d3152020-06-11 19:59:22 +0200503 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200504 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200505 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200506 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Positional predicate defined for configuration"
Michal Vasko004d3152020-06-11 19:59:22 +0200507 " %s \"%s\" in path.", lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200508 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200509 }
Michal Vasko004d3152020-06-11 19:59:22 +0200510
511 /* new predicate */
512 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200513 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200514
515 /* syntax was already checked */
516 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200517 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200518
519 /* ']' */
520 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
521 ++(*tok_idx);
522 }
523
524 return LY_SUCCESS;
525}
526
527/**
528 * @brief Compile leafref predicate. Actually, it is only checked.
529 *
530 * @param[in] ctx_node Context node, node for which the predicate is defined.
531 * @param[in] cur_node Current (original context) node.
532 * @param[in] expr Parsed path.
533 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
534 * @param[in] resolve_prefix Callback for prefix resolution.
535 * @param[in] prefix_data Data for @p resolve_prefix.
536 * @param[in] format Format of the path.
537 * @return LY_ERR value.
538 */
539static LY_ERR
540ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
541 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
542 void *prefix_data, LYD_FORMAT format)
543{
544 const struct lysc_node *key, *node, *node2;
545 const struct lys_module *mod;
546 const char *name;
547 size_t name_len;
548
549 /* '[' */
550 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
551 /* no predicate */
552 return LY_SUCCESS;
553 }
554
555 if (ctx_node->nodetype != LYS_LIST) {
556 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
557 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200558 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200559 } else if (ctx_node->flags & LYS_KEYLESS) {
560 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
561 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200562 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200563 }
564
565 do {
566 /* NameTest, find the key */
Michal Vasko00cbf532020-06-15 13:58:47 +0200567 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, ctx_node, expr, *tok_idx,
568 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200569 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
570 if (!key) {
571 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 +0200572 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200573 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
574 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
575 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200576 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200577 }
578 ++(*tok_idx);
579
580 /* we are not actually compiling, throw the key away */
581 (void)key;
582
583 /* '=' */
584 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
585 ++(*tok_idx);
586
587 /* FuncName */
588 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
589 ++(*tok_idx);
590
591 /* evaluating from the "current()" node */
592 node = cur_node;
593
594 /* '(' */
595 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
596 ++(*tok_idx);
597
598 /* ')' */
599 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
600 ++(*tok_idx);
601
602 do {
603 /* '/' */
604 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
605 ++(*tok_idx);
606
607 /* go to parent */
608 if (!node) {
609 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200610 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200611 }
612 node = lysc_data_parent(node);
613
614 /* '..' */
615 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
616 ++(*tok_idx);
617 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
618
619 do {
620 /* '/' */
621 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
622 ++(*tok_idx);
623
624 /* NameTest */
625 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200626 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node->module, node, expr, *tok_idx,
627 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200628 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
629 if (!node2) {
630 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.",
631 name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200632 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200633 }
634 node = node2;
635 ++(*tok_idx);
636 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
637
638 /* check the last target node */
639 if (node->nodetype != LYS_LEAF) {
640 LOGVAL(cur_node->module->ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in"
641 " leafref predicate in path.", lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200642 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200643 }
644
645 /* we are not actually compiling, throw the rightside node away */
646 (void)node;
647
648 /* ']' */
649 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
650 ++(*tok_idx);
651
652 /* another predicate follows? */
653 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
654
655 return LY_SUCCESS;
656}
657
658LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200659ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
660 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
661 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200662{
663 LY_ERR ret = LY_SUCCESS;
664 uint16_t tok_idx = 0;
665 const struct lys_module *mod;
666 const struct lysc_node *node2, *cur_node;
Michal Vasko00cbf532020-06-15 13:58:47 +0200667 struct ly_path *p = NULL;
668 int getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200669 const char *name;
670 size_t name_len;
671
Michal Vasko00cbf532020-06-15 13:58:47 +0200672 assert(ctx);
673 assert((expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) || (lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200674 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200675 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
676 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200677
678 if (lref == LY_PATH_LREF_TRUE) {
679 /* remember original context node */
680 cur_node = ctx_node;
681 }
682 *path = NULL;
683
Michal Vasko00cbf532020-06-15 13:58:47 +0200684 if (oper == LY_PATH_OPER_OUTPUT) {
685 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
686 } else {
687 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
688 }
689
Michal Vasko004d3152020-06-11 19:59:22 +0200690 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
691 /* absolute path */
692 ctx_node = NULL;
693
694 ++tok_idx;
695 } else {
696 /* relative path */
697 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
698 if (!ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200699 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200700 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200701 }
702
703 /* get parent */
704 ctx_node = lysc_data_parent(ctx_node);
705
706 ++tok_idx;
707
708 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
709 ++tok_idx;
710 }
711
Michal Vasko00cbf532020-06-15 13:58:47 +0200712 /* we are not storing the parent */
713 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200714 }
715
716 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200717 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
718 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
719 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
720 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200721 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200722 }
723
Michal Vasko004d3152020-06-11 19:59:22 +0200724 /* get module and node name */
Michal Vasko00cbf532020-06-15 13:58:47 +0200725 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_mod, ctx_node, expr, tok_idx, lref, resolve_prefix,
726 prefix_data, format, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200727 ++tok_idx;
728
729 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200730 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200731 if (!node2) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200732 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200733 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200734 goto cleanup;
735 }
736 ctx_node = node2;
737
738 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200739 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200740 p->node = ctx_node;
741
742 /* compile any predicates */
743 if (lref == LY_PATH_LREF_TRUE) {
744 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, resolve_prefix, prefix_data, format);
745 } else {
Michal Vasko00cbf532020-06-15 13:58:47 +0200746 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 +0200747 &p->predicates, &p->pred_type);
748 }
749 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200750 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
751
Michal Vasko00cbf532020-06-15 13:58:47 +0200752 /* check last compiled node */
753 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
754 && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
755 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
756 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200757 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200758 }
759
Michal Vasko004d3152020-06-11 19:59:22 +0200760cleanup:
761 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200762 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200763 *path = NULL;
764 }
765 return ret;
766}
767
768LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200769ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_SIZE_TYPE *path_idx,
770 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200771{
772 LY_ARRAY_SIZE_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200773 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200774 uint64_t pos;
775
776 assert(path && start);
777
778 if (lysc_data_parent(path[0].node)) {
779 /* relative path, start from the parent children */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200780 start = lyd_node_children(start, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200781 } else {
782 /* absolute path, start from the first top-level sibling */
783 while (start->parent) {
784 start = (struct lyd_node *)start->parent;
785 }
786 while (start->prev->next) {
787 start = start->prev;
788 }
789 }
790
791 LY_ARRAY_FOR(path, u) {
792 switch (path[u].pred_type) {
793 case LY_PATH_PREDTYPE_POSITION:
794 /* we cannot use hashes and want an instance on a specific position */
795 pos = 1;
796 node = (struct lyd_node *)start;
797 while (!lyd_find_sibling_next2(node, path[u].node, NULL, 0, &node)) {
798 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{
891 LY_ARRAY_SIZE_TYPE u, v;
892
893 if (!path) {
894 return LY_SUCCESS;
895 }
896
897 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_SIZE(path), LY_EMEM);
898 LY_ARRAY_FOR(path, u) {
899 LY_ARRAY_INCREMENT(*dup);
900 (*dup)[u].node = path[u].node;
901 if (path[u].predicates) {
902 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_SIZE(path[u].predicates), LY_EMEM);
903 (*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{
934 LY_ARRAY_SIZE_TYPE u;
935
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{
960 LY_ARRAY_SIZE_TYPE u;
961
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}