blob: 7558f953e717530aef2f81ba0ef6ce9df47ad8d1 [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;
73 }
74 if (!name) {
75 name = exp->expr + exp->tok_pos[*tok_idx];
76 name_len = exp->tok_len[*tok_idx];
77 } else {
78 ++name;
79 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
80 }
81
82 /* check whether it was not already specified */
83 for (i = 0; i < set->count; ++i) {
84 /* all the keys must be from the same module so this comparison should be fine */
85 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +020086 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +020087 goto error;
88 }
89 }
90
91 /* add it into the set */
92 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
93
94 /* NameTest */
95 ++(*tok_idx);
96
97 /* '=' */
98 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
99
100 /* Literal */
101 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
102
103 /* ']' */
104 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
105
106 /* '[' */
107 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
108
109 /* '.' */
110 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
111 /* '=' */
112 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
113
114 /* Literal */
115 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
116
117 /* ']' */
118 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
119
120 /* Number */
121 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
122
123 /* ']' */
124 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
125
126 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
127 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
128 set = ly_set_new();
129 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
130
131 do {
132 /* NameTest is always expected here */
133 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
134
135 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
136 if (!name) {
137 name = exp->expr + exp->tok_pos[*tok_idx];
138 name_len = exp->tok_len[*tok_idx];
139 } else {
140 ++name;
141 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
142 }
143
144 /* check whether it was not already specified */
145 for (i = 0; i < set->count; ++i) {
146 /* all the keys must be from the same module so this comparison should be fine */
147 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200148 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +0200149 goto error;
150 }
151 }
152
153 /* add it into the set */
154 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
155
156 /* NameTest */
157 ++(*tok_idx);
158
159 /* '=' */
160 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
161
162 /* FuncName */
163 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
164 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200165 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
166 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200167 goto error;
168 }
169 ++(*tok_idx);
170
171 /* '(' */
172 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), error);
173
174 /* ')' */
175 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), error);
176
177 /* '/' */
178 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
179
180 /* '..' */
181 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), error);
182 do {
183 /* '/' */
184 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
185 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
186
187 /* NameTest */
188 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
189
190 /* '/' */
191 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
192 /* NameTest */
193 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
194 }
195
196 /* ']' */
197 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
198
199 /* '[' */
200 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
201
202 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200203 LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
204 exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200205 goto error;
206 }
207 }
208
209 ly_set_free(set, NULL);
210 return LY_SUCCESS;
211
212error:
213 ly_set_free(set, NULL);
214 return LY_EVALID;
215}
216
217LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200218ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
219 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200220{
221 struct lyxp_expr *exp;
222 uint16_t tok_idx;
223
224 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
225 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
226 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
227 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
228
229 /* parse as a generic XPath expression */
230 exp = lyxp_expr_parse(ctx, str_path, path_len, 1);
231 LY_CHECK_GOTO(!exp, error);
232 tok_idx = 0;
233
234 if (begin == LY_PATH_BEGIN_EITHER) {
235 /* is the path relative? */
236 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
237 /* '..' */
238 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
239 /* '/' */
240 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
241 }
242 }
243 } else {
244 /* '/' */
245 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
246 }
247
248 do {
249 /* NameTest */
250 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
251
252 /* check prefix based on the options */
253 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !strnstr(exp->expr + exp->tok_pos[tok_idx], ":", exp->tok_len[tok_idx])) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200254 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[tok_idx],
255 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200256 goto error;
257 }
258
259 ++tok_idx;
260
261 /* Predicate* */
Michal Vasko6b26e742020-07-17 15:02:10 +0200262 LY_CHECK_GOTO(ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200263
264 /* '/' */
265 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
266
267 /* trailing token check */
268 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200269 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
270 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200271 goto error;
272 }
273
274 *expr = exp;
275 return LY_SUCCESS;
276
277error:
278 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200279 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200280}
281
282LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200283ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
284 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200285{
286 struct lyxp_expr *exp;
287 uint16_t tok_idx;
288
289 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
290 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
291
292 /* parse as a generic XPath expression */
293 exp = lyxp_expr_parse(ctx, str_path, path_len, 0);
294 LY_CHECK_GOTO(!exp, error);
295 tok_idx = 0;
296
Michal Vasko6b26e742020-07-17 15:02:10 +0200297 LY_CHECK_GOTO(ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200298
299 /* trailing token check */
300 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200301 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
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
314/**
315 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
316 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200317 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200318 * @param[in] cur_node Optional current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +0200319 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
320 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
321 * @param[in] expr Parsed path.
322 * @param[in] tok_idx Index in @p expr.
323 * @param[in] lref Lref option.
324 * @param[in] resolve_prefix Callback for prefix resolution.
325 * @param[in] prefix_data Data for @p resolve_prefix.
326 * @param[in] format Format of the path.
327 * @param[out] mod Resolved module.
328 * @param[out] name Parsed node name.
329 * @param[out] name_len Length of @p name.
330 * @return LY_ERR value.
331 */
332static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200333ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
334 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
335 uint8_t lref, ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
336 const struct lys_module **mod, const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200337{
338 const char *ptr;
339 size_t len;
340
341 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
342
343 /* get prefix */
344 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
345 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
346
347 /* find next node module */
348 if (ptr) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200349 *mod = resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200350 if (!*mod) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200351 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
352 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200353 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200354 } else if (!(*mod)->implemented) {
355 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200356 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200357 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200358 }
359 lys_set_implemented_internal((struct lys_module *)*mod, 2);
360 }
361 } else {
362 switch (format) {
363 case LYD_SCHEMA:
364 *mod = cur_mod;
365 break;
366 case LYD_JSON:
367 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200368 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200369 }
370 *mod = prev_ctx_node->module;
371 break;
372 case LYD_XML:
Michal Vasko60ea6352020-06-29 13:39:39 +0200373 case LYD_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200374 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200375 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200376 }
377 }
378
379 /* set name */
380 if (ptr) {
381 *name = ptr + 1;
382 *name_len = expr->tok_len[tok_idx] - len - 1;
383 } else {
384 *name = expr->expr + expr->tok_pos[tok_idx];
385 *name_len = expr->tok_len[tok_idx];
386 }
387
388 return LY_SUCCESS;
389}
390
391LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200392ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
393 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
394 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format,
395 struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200396{
397 struct ly_path_predicate *p;
398 const struct lysc_node *key;
399 const struct lys_module *mod;
400 const char *name;
401 size_t name_len, key_count;
402
Michal Vasko00cbf532020-06-15 13:58:47 +0200403 assert(ctx && ctx_node);
404
Michal Vasko004d3152020-06-11 19:59:22 +0200405 *pred_type = 0;
406
407 /* '[' */
408 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
409 /* no predicate */
410 return LY_SUCCESS;
411 }
412
413 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
414 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200415 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
416 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 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200419 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
420 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200421 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200422 }
423
424 do {
425 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200426 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
427 resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200428 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
429 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200430 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200431 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200432 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200433 LOGVAL_P(ctx, cur_node ? cur_node : key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
434 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200435 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200436 }
437 ++(*tok_idx);
438
439 /* new predicate */
440 if (!*pred_type) {
441 *pred_type = LY_PATH_PREDTYPE_LIST;
442 }
443 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200444 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200445 p->key = key;
446
447 /* '=' */
448 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
449 ++(*tok_idx);
450
451 /* Literal */
452 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
453 LY_CHECK_RET(lyd_value_store(&p->value, key, expr->expr + expr->tok_pos[*tok_idx] + 1,
454 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
455 ++(*tok_idx);
456
457 /* ']' */
458 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
459 ++(*tok_idx);
460
461 /* another predicate follows? */
462 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
463
464 /* check that all keys were set */
465 key_count = 0;
466 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
467 ++key_count;
468 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200469 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200470 /* names (keys) are unique - it was checked when parsing */
Michal Vasko6b26e742020-07-17 15:02:10 +0200471 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
472 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200473 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200474 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200475 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200476 }
477
478 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
479 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200480 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
481 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200482 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200483 }
484 ++(*tok_idx);
485
486 /* new predicate */
487 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200488 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200489
490 /* '=' */
491 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
492 ++(*tok_idx);
493
494 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
495 /* store the value */
496 LY_CHECK_RET(lyd_value_store(&p->value, ctx_node, expr->expr + expr->tok_pos[*tok_idx] + 1,
497 expr->tok_len[*tok_idx] - 2, NULL, resolve_prefix, prefix_data, format));
498 ++(*tok_idx);
499
500 /* ']' */
501 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
502 ++(*tok_idx);
503 } else {
504 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
505 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200506 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
507 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 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200510 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
511 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200512 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200513 }
Michal Vasko004d3152020-06-11 19:59:22 +0200514
515 /* new predicate */
516 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200517 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200518
519 /* syntax was already checked */
520 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200521 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200522
523 /* ']' */
524 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
525 ++(*tok_idx);
526 }
527
528 return LY_SUCCESS;
529}
530
531/**
532 * @brief Compile leafref predicate. Actually, it is only checked.
533 *
534 * @param[in] ctx_node Context node, node for which the predicate is defined.
535 * @param[in] cur_node Current (original context) node.
536 * @param[in] expr Parsed path.
537 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
538 * @param[in] resolve_prefix Callback for prefix resolution.
539 * @param[in] prefix_data Data for @p resolve_prefix.
540 * @param[in] format Format of the path.
541 * @return LY_ERR value.
542 */
543static LY_ERR
544ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
545 const struct lyxp_expr *expr, uint16_t *tok_idx, ly_clb_resolve_prefix resolve_prefix,
546 void *prefix_data, LYD_FORMAT format)
547{
548 const struct lysc_node *key, *node, *node2;
549 const struct lys_module *mod;
550 const char *name;
551 size_t name_len;
552
553 /* '[' */
554 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
555 /* no predicate */
556 return LY_SUCCESS;
557 }
558
559 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200560 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for %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 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200564 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
565 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200566 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200567 }
568
569 do {
570 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200571 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 +0200572 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200573 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
574 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200575 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 +0200576 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200577 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200578 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
579 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200580 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200581 }
582 ++(*tok_idx);
583
584 /* we are not actually compiling, throw the key away */
585 (void)key;
586
587 /* '=' */
588 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
589 ++(*tok_idx);
590
591 /* FuncName */
592 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
593 ++(*tok_idx);
594
595 /* evaluating from the "current()" node */
596 node = cur_node;
597
598 /* '(' */
599 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
600 ++(*tok_idx);
601
602 /* ')' */
603 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
604 ++(*tok_idx);
605
606 do {
607 /* '/' */
608 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
609 ++(*tok_idx);
610
611 /* go to parent */
612 if (!node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200613 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200614 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200615 }
616 node = lysc_data_parent(node);
617
618 /* '..' */
619 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
620 ++(*tok_idx);
621 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
622
623 do {
624 /* '/' */
625 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
626 ++(*tok_idx);
627
628 /* NameTest */
629 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko6b26e742020-07-17 15:02:10 +0200630 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 +0200631 LY_PATH_LREF_TRUE, resolve_prefix, prefix_data, format, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200632 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
633 if (!node2) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200634 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 +0200635 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200636 }
637 node = node2;
638 ++(*tok_idx);
639 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
640
641 /* check the last target node */
642 if (node->nodetype != LYS_LEAF) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200643 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
644 "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
645 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200646 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200647 }
648
649 /* we are not actually compiling, throw the rightside node away */
650 (void)node;
651
652 /* ']' */
653 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
654 ++(*tok_idx);
655
656 /* another predicate follows? */
657 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
658
659 return LY_SUCCESS;
660}
661
662LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200663ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
664 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
665 ly_clb_resolve_prefix resolve_prefix, void *prefix_data, LYD_FORMAT format, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200666{
667 LY_ERR ret = LY_SUCCESS;
668 uint16_t tok_idx = 0;
669 const struct lys_module *mod;
Michal Vasko6b26e742020-07-17 15:02:10 +0200670 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200671 struct ly_path *p = NULL;
672 int getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200673 const char *name;
674 size_t name_len;
675
Michal Vasko00cbf532020-06-15 13:58:47 +0200676 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200677 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200678 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200679 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
680 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200681
Michal Vasko6b26e742020-07-17 15:02:10 +0200682 /* find operation, if we are in any */
683 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent);
684
685 /* remember original context node */
686 cur_node = ctx_node;
687
Michal Vasko004d3152020-06-11 19:59:22 +0200688 *path = NULL;
689
Michal Vasko00cbf532020-06-15 13:58:47 +0200690 if (oper == LY_PATH_OPER_OUTPUT) {
691 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
692 } else {
693 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
694 }
695
Michal Vasko004d3152020-06-11 19:59:22 +0200696 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
697 /* absolute path */
698 ctx_node = NULL;
699
700 ++tok_idx;
701 } else {
702 /* relative path */
703 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
704 if (!ctx_node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200705 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200706 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200707 }
708
709 /* get parent */
710 ctx_node = lysc_data_parent(ctx_node);
711
712 ++tok_idx;
713
714 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
715 ++tok_idx;
716 }
717
Michal Vasko00cbf532020-06-15 13:58:47 +0200718 /* we are not storing the parent */
719 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200720 }
721
722 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200723 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
724 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200725 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
726 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200727 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200728 }
729
Michal Vasko004d3152020-06-11 19:59:22 +0200730 /* get module and node name */
Michal Vasko6b26e742020-07-17 15:02:10 +0200731 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 +0200732 prefix_data, format, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200733 ++tok_idx;
734
735 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200736 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko6b26e742020-07-17 15:02:10 +0200737 if (!node2 || ((node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
738 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200739 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200740 goto cleanup;
741 }
742 ctx_node = node2;
743
744 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200745 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200746 p->node = ctx_node;
747
748 /* compile any predicates */
749 if (lref == LY_PATH_LREF_TRUE) {
750 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, resolve_prefix, prefix_data, format);
751 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200752 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, resolve_prefix,
753 prefix_data, format, &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200754 }
755 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200756 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
757
Michal Vasko00cbf532020-06-15 13:58:47 +0200758 /* check last compiled node */
759 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
760 && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200761 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
762 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200763 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200764 }
765
Michal Vasko004d3152020-06-11 19:59:22 +0200766cleanup:
767 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200768 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200769 *path = NULL;
770 }
771 return ret;
772}
773
774LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200775ly_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 +0200776 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200777{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200778 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200779 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200780 uint64_t pos;
781
782 assert(path && start);
783
784 if (lysc_data_parent(path[0].node)) {
785 /* relative path, start from the parent children */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200786 start = lyd_node_children(start, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200787 } else {
788 /* absolute path, start from the first top-level sibling */
789 while (start->parent) {
790 start = (struct lyd_node *)start->parent;
791 }
792 while (start->prev->next) {
793 start = start->prev;
794 }
795 }
796
797 LY_ARRAY_FOR(path, u) {
798 switch (path[u].pred_type) {
799 case LY_PATH_PREDTYPE_POSITION:
800 /* we cannot use hashes and want an instance on a specific position */
801 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200802 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200803 if (pos == path[u].predicates[0].position) {
804 break;
805 }
806 ++pos;
807 }
808 break;
809 case LY_PATH_PREDTYPE_LEAFLIST:
810 /* we will use hashes to find one leaf-list instance */
811 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
812 lyd_find_sibling_first(start, target, &node);
813 lyd_free_tree(target);
814 break;
815 case LY_PATH_PREDTYPE_LIST:
816 /* we will use hashes to find one list instance */
817 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
818 lyd_find_sibling_first(start, target, &node);
819 lyd_free_tree(target);
820 break;
821 case LY_PATH_PREDTYPE_NONE:
822 /* we will use hashes to find one any/container/leaf instance */
823 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
824 break;
825 }
826
827 if (!node) {
828 /* no matching nodes */
829 break;
830 }
831
Michal Vasko00cbf532020-06-15 13:58:47 +0200832 /* rememeber previous node */
833 prev_node = node;
834
Michal Vasko004d3152020-06-11 19:59:22 +0200835 /* next path segment, if any */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200836 start = lyd_node_children(node, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200837 }
838
Michal Vasko004d3152020-06-11 19:59:22 +0200839 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200840 /* we have found the full path */
841 if (path_idx) {
842 *path_idx = u;
843 }
844 if (match) {
845 *match = node;
846 }
Michal Vasko004d3152020-06-11 19:59:22 +0200847 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200848
849 } else if (prev_node) {
850 /* we have found only some partial match */
851 if (path_idx) {
852 *path_idx = u - 1;
853 }
854 if (match) {
855 *match = prev_node;
856 }
857 return LY_EINCOMPLETE;
858 }
859
860 /* we have not found any nodes */
861 if (path_idx) {
862 *path_idx = 0;
863 }
864 if (match) {
865 *match = NULL;
866 }
867 return LY_ENOTFOUND;
868}
869
870LY_ERR
871ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
872{
873 LY_ERR ret;
874 struct lyd_node *m;
875
876 ret = ly_path_eval_partial(path, start, NULL, &m);
877
878 if (ret == LY_SUCCESS) {
879 /* last node was found */
880 if (match) {
881 *match = m;
882 }
883 return LY_SUCCESS;
884 }
885
886 /* not a full match */
887 if (match) {
888 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200889 }
890 return LY_ENOTFOUND;
891}
892
893LY_ERR
894ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
895{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200896 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200897
898 if (!path) {
899 return LY_SUCCESS;
900 }
901
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200902 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200903 LY_ARRAY_FOR(path, u) {
904 LY_ARRAY_INCREMENT(*dup);
905 (*dup)[u].node = path[u].node;
906 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200907 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200908 (*dup)[u].pred_type = path[u].pred_type;
909 LY_ARRAY_FOR(path[u].predicates, v) {
910 struct ly_path_predicate *pred = &path[u].predicates[v];
911
912 LY_ARRAY_INCREMENT((*dup)[u].predicates);
913 switch (path[u].pred_type) {
914 case LY_PATH_PREDTYPE_POSITION:
915 /* position-predicate */
916 (*dup)[u].predicates[v].position = pred->position;
917 break;
918 case LY_PATH_PREDTYPE_LIST:
919 case LY_PATH_PREDTYPE_LEAFLIST:
920 /* key-predicate or leaf-list-predicate */
921 (*dup)[u].predicates[v].key = pred->key;
922 (*dup)[u].predicates[v].value.realtype = pred->value.realtype;
923 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
924 break;
925 case LY_PATH_PREDTYPE_NONE:
926 break;
927 }
928 }
929 }
930 }
931
932 return LY_SUCCESS;
933}
934
935void
936ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, const struct lysc_node *llist,
937 struct ly_path_predicate *predicates)
938{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200939 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200940
941 if (!predicates) {
942 return;
943 }
944
945 LY_ARRAY_FOR(predicates, u) {
946 switch (pred_type) {
947 case LY_PATH_PREDTYPE_POSITION:
948 case LY_PATH_PREDTYPE_NONE:
949 /* nothing to free */
950 break;
951 case LY_PATH_PREDTYPE_LIST:
952 ((struct lysc_node_leaf *)predicates[u].key)->type->plugin->free(ctx, &predicates[u].value);
953 break;
954 case LY_PATH_PREDTYPE_LEAFLIST:
955 ((struct lysc_node_leaflist *)llist)->type->plugin->free(ctx, &predicates[u].value);
956 break;
957 }
958 }
959 LY_ARRAY_FREE(predicates);
960}
961
962void
963ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
964{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200965 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200966
967 LY_ARRAY_FOR(path, u) {
968 ly_path_predicates_free(ctx, path[u].pred_type, path[u].node, path[u].predicates);
969 }
970 LY_ARRAY_FREE(path);
971}