blob: 88f24a987d9a85ddc24c90c3f6fe87f07dc42786 [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
Radek Krejcic0c66412020-08-21 13:53:50 +020034#define LOGVAL_P(CTX, CUR_NODE, CODE, ...) ly_vlog(CTX, (CUR_NODE) ? LY_VLOG_LYSC : LY_VLOG_NONE, CUR_NODE, CODE, ##__VA_ARGS__)
Michal Vasko6b26e742020-07-17 15:02:10 +020035
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,
Radek Krejci0f969882020-08-21 16:56:47 +020049 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
Michal Vasko004d3152020-06-11 19:59:22 +020056 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020057 /* '[' */
58
Michal Vasko004d3152020-06-11 19:59:22 +020059 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS))
60 && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
61 set = ly_set_new();
62 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
63
64 do {
65 /* NameTest is always expected here */
66 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
67
68 /* check prefix based on the options */
69 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
70 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Michal Vasko6b26e742020-07-17 15:02:10 +020071 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
72 exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +020073 goto error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020074 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
75 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
76 exp->expr + exp->tok_pos[*tok_idx]);
77 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +020078 }
79 if (!name) {
80 name = exp->expr + exp->tok_pos[*tok_idx];
81 name_len = exp->tok_len[*tok_idx];
82 } else {
83 ++name;
84 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
85 }
86
87 /* check whether it was not already specified */
88 for (i = 0; i < set->count; ++i) {
89 /* all the keys must be from the same module so this comparison should be fine */
90 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +020091 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +020092 goto error;
93 }
94 }
95
96 /* add it into the set */
97 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
98
99 /* NameTest */
100 ++(*tok_idx);
101
102 /* '=' */
103 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
104
105 /* Literal */
106 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
107
108 /* ']' */
109 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
110
Radek Krejci0f969882020-08-21 16:56:47 +0200111 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200112 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
113
Michal Vasko004d3152020-06-11 19:59:22 +0200114 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200115 /* '.' */
116
Michal Vasko004d3152020-06-11 19:59:22 +0200117 /* '=' */
118 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
119
120 /* Literal */
121 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), error);
122
123 /* ']' */
124 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
125
Michal Vasko004d3152020-06-11 19:59:22 +0200126 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200127 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200128
129 /* ']' */
130 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
131
132 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
133 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
134 set = ly_set_new();
135 LY_CHECK_ERR_GOTO(!set, LOGMEM(ctx), error);
136
137 do {
138 /* NameTest is always expected here */
139 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), error);
140
141 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
142 if (!name) {
143 name = exp->expr + exp->tok_pos[*tok_idx];
144 name_len = exp->tok_len[*tok_idx];
145 } else {
146 ++name;
147 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
148 }
149
150 /* check whether it was not already specified */
151 for (i = 0; i < set->count; ++i) {
152 /* all the keys must be from the same module so this comparison should be fine */
153 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200154 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Michal Vasko004d3152020-06-11 19:59:22 +0200155 goto error;
156 }
157 }
158
159 /* add it into the set */
160 ly_set_add(set, (void *)name, LY_SET_OPT_USEASLIST);
161
162 /* NameTest */
163 ++(*tok_idx);
164
165 /* '=' */
166 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), error);
167
168 /* FuncName */
169 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), error);
170 if ((exp->tok_len[*tok_idx] != 7) || strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", 7)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200171 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
172 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200173 goto error;
174 }
175 ++(*tok_idx);
176
177 /* '(' */
178 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), error);
179
180 /* ')' */
181 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), error);
182
183 /* '/' */
184 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
185
186 /* '..' */
187 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), error);
188 do {
189 /* '/' */
190 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), error);
191 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
192
193 /* NameTest */
194 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
195
196 /* '/' */
197 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
198 /* NameTest */
199 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
200 }
201
202 /* ']' */
203 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), error);
204
Radek Krejci0f969882020-08-21 16:56:47 +0200205 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200206 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
207
208 } else {
Michal Vasko6b26e742020-07-17 15:02:10 +0200209 LOGVAL_P(ctx, cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
210 exp->expr + exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200211 goto error;
212 }
213 }
214
215 ly_set_free(set, NULL);
216 return LY_SUCCESS;
217
218error:
219 ly_set_free(set, NULL);
220 return LY_EVALID;
221}
222
223LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200224ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
Radek Krejci0f969882020-08-21 16:56:47 +0200225 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200226{
227 struct lyxp_expr *exp;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200228 uint16_t tok_idx, cur_len;
229 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200230
231 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
232 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200233 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY)
234 || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200235 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
236
237 /* parse as a generic XPath expression */
238 exp = lyxp_expr_parse(ctx, str_path, path_len, 1);
239 LY_CHECK_GOTO(!exp, error);
240 tok_idx = 0;
241
242 if (begin == LY_PATH_BEGIN_EITHER) {
243 /* is the path relative? */
244 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
245 /* '..' */
246 while ((lref == LY_PATH_LREF_TRUE) && !lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)) {
247 /* '/' */
248 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
249 }
250 }
251 } else {
252 /* '/' */
253 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), error);
254 }
255
256 do {
257 /* NameTest */
258 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), error);
259
260 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200261 cur_node = exp->expr + exp->tok_pos[tok_idx];
262 cur_len = exp->tok_len[tok_idx];
263 if (prefix == LY_PATH_PREFIX_MANDATORY) {
264 if (!strnstr(cur_node, ":", cur_len)) {
265 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
266 goto error;
267 }
268 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
269 if (!prev_prefix) {
270 /* the first node must have a prefix */
271 if (!strnstr(cur_node, ":", cur_len)) {
272 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
273 goto error;
274 }
275
276 /* remember the first prefix */
277 prev_prefix = cur_node;
278 } else {
279 /* the prefix must be different, if any */
280 ptr = strnstr(cur_node, ":", cur_len);
281 if (ptr) {
282 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
283 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
284 goto error;
285 }
286
287 /* remember this next prefix */
288 prev_prefix = cur_node;
289 }
290 }
Michal Vasko004d3152020-06-11 19:59:22 +0200291 }
292
293 ++tok_idx;
294
295 /* Predicate* */
Michal Vasko6b26e742020-07-17 15:02:10 +0200296 LY_CHECK_GOTO(ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200297
Radek Krejci0f969882020-08-21 16:56:47 +0200298 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200299 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
300
301 /* trailing token check */
302 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200303 LOGVAL_P(ctx, ctx_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.",
304 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200305 goto error;
306 }
307
308 *expr = exp;
309 return LY_SUCCESS;
310
311error:
312 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200313 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200314}
315
316LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200317ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
Radek Krejci0f969882020-08-21 16:56:47 +0200318 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200319{
320 struct lyxp_expr *exp;
321 uint16_t tok_idx;
322
323 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
324 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
325
326 /* parse as a generic XPath expression */
327 exp = lyxp_expr_parse(ctx, str_path, path_len, 0);
328 LY_CHECK_GOTO(!exp, error);
329 tok_idx = 0;
330
Michal Vasko6b26e742020-07-17 15:02:10 +0200331 LY_CHECK_GOTO(ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200332
333 /* trailing token check */
334 if (exp->used > tok_idx) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200335 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
336 exp->expr + exp->tok_pos[tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +0200337 goto error;
338 }
339
340 *expr = exp;
341 return LY_SUCCESS;
342
343error:
344 lyxp_expr_free(ctx, exp);
Radek Krejci8de005f2020-06-25 17:02:07 +0200345 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200346}
347
348/**
349 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
350 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200351 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200352 * @param[in] cur_node Optional current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +0200353 * @param[in] cur_mod Module of the current (original context) node. Needed for ::LYD_SCHEMA.
354 * @param[in] prev_ctx_node Previous context node. Needed for ::LYD_JSON.
355 * @param[in] expr Parsed path.
356 * @param[in] tok_idx Index in @p expr.
357 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200358 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200359 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200360 * @param[out] mod Resolved module.
361 * @param[out] name Parsed node name.
362 * @param[out] name_len Length of @p name.
363 * @return LY_ERR value.
364 */
365static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200366ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci0f969882020-08-21 16:56:47 +0200367 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx,
368 uint8_t lref, LY_PREFIX_FORMAT format, void *prefix_data, const struct lys_module **mod,
369 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200370{
371 const char *ptr;
372 size_t len;
373
374 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
375
376 /* get prefix */
377 ptr = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]);
378 len = ptr ? ptr - (expr->expr + expr->tok_pos[tok_idx]) : 0;
379
380 /* find next node module */
381 if (ptr) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200382 *mod = ly_resolve_prefix(ctx, expr->expr + expr->tok_pos[tok_idx], len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200383 if (!*mod) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200384 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Prefix \"%.*s\" not found of a module in path.",
385 len, expr->expr + expr->tok_pos[tok_idx]);
Radek Krejci8de005f2020-06-25 17:02:07 +0200386 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200387 } else if (!(*mod)->implemented) {
388 if (lref == LY_PATH_LREF_FALSE) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200389 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200390 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200391 }
Radek Krejci03fa8e82020-08-12 16:57:25 +0200392 LY_CHECK_RET(lys_set_implemented_internal((struct lys_module *)*mod, ctx->module_set_id));
Michal Vasko004d3152020-06-11 19:59:22 +0200393 }
394 } else {
395 switch (format) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200396 case LY_PREF_SCHEMA:
Michal Vasko004d3152020-06-11 19:59:22 +0200397 *mod = cur_mod;
398 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200399 case LY_PREF_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200400 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200401 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200402 }
403 *mod = prev_ctx_node->module;
404 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200405 case LY_PREF_XML:
Michal Vasko004d3152020-06-11 19:59:22 +0200406 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200407 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200408 }
409 }
410
411 /* set name */
412 if (ptr) {
413 *name = ptr + 1;
414 *name_len = expr->tok_len[tok_idx] - len - 1;
415 } else {
416 *name = expr->expr + expr->tok_pos[tok_idx];
417 *name_len = expr->tok_len[tok_idx];
418 }
419
420 return LY_SUCCESS;
421}
422
423LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200424ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Radek Krejci0f969882020-08-21 16:56:47 +0200425 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx,
426 LY_PREFIX_FORMAT format, void *prefix_data, struct ly_path_predicate **predicates,
427 enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200428{
429 struct ly_path_predicate *p;
430 const struct lysc_node *key;
431 const struct lys_module *mod;
432 const char *name;
433 size_t name_len, key_count;
434
Michal Vasko00cbf532020-06-15 13:58:47 +0200435 assert(ctx && ctx_node);
436
Michal Vasko004d3152020-06-11 19:59:22 +0200437 *pred_type = 0;
438
Michal Vasko004d3152020-06-11 19:59:22 +0200439 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200440 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200441 return LY_SUCCESS;
442 }
443
444 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
445 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200446 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
447 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200448 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200449 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200450 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
451 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200452 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200453 }
454
455 do {
456 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200457 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200458 format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200459 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
460 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200461 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200462 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200463 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200464 LOGVAL_P(ctx, cur_node ? cur_node : key, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
465 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200466 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200467 }
468 ++(*tok_idx);
469
Michal Vasko004d3152020-06-11 19:59:22 +0200470 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200471 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200472 *pred_type = LY_PATH_PREDTYPE_LIST;
473 }
474 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Michal Vasko00cbf532020-06-15 13:58:47 +0200475 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200476 p->key = key;
477
478 /* '=' */
479 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
480 ++(*tok_idx);
481
482 /* Literal */
483 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
484 LY_CHECK_RET(lyd_value_store(&p->value, key, expr->expr + expr->tok_pos[*tok_idx] + 1,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200485 expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data));
Michal Vasko004d3152020-06-11 19:59:22 +0200486 ++(*tok_idx);
487
488 /* ']' */
489 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
490 ++(*tok_idx);
491
492 /* another predicate follows? */
493 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
494
495 /* check that all keys were set */
496 key_count = 0;
497 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
498 ++key_count;
499 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200500 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200501 /* names (keys) are unique - it was checked when parsing */
Michal Vasko6b26e742020-07-17 15:02:10 +0200502 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
503 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko00cbf532020-06-15 13:58:47 +0200504 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, NULL, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200505 *predicates = NULL;
Radek Krejci8de005f2020-06-25 17:02:07 +0200506 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200507 }
508
509 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
510 if (ctx_node->nodetype != LYS_LEAFLIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200511 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
512 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200513 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200514 }
515 ++(*tok_idx);
516
517 /* new predicate */
518 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko00cbf532020-06-15 13:58:47 +0200519 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200520
521 /* '=' */
522 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
523 ++(*tok_idx);
524
525 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
526 /* store the value */
527 LY_CHECK_RET(lyd_value_store(&p->value, ctx_node, expr->expr + expr->tok_pos[*tok_idx] + 1,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200528 expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data));
Michal Vasko004d3152020-06-11 19:59:22 +0200529 ++(*tok_idx);
530
531 /* ']' */
532 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
533 ++(*tok_idx);
534 } else {
535 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
536 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200537 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
538 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200539 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200540 } else if (ctx_node->flags & LYS_CONFIG_W) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200541 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
542 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200543 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200544 }
Michal Vasko004d3152020-06-11 19:59:22 +0200545
546 /* new predicate */
547 *pred_type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko00cbf532020-06-15 13:58:47 +0200548 LY_ARRAY_NEW_RET(ctx, *predicates, p, LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200549
550 /* syntax was already checked */
551 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, 10);
Michal Vasko00cbf532020-06-15 13:58:47 +0200552 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200553
554 /* ']' */
555 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
556 ++(*tok_idx);
557 }
558
559 return LY_SUCCESS;
560}
561
562/**
563 * @brief Compile leafref predicate. Actually, it is only checked.
564 *
565 * @param[in] ctx_node Context node, node for which the predicate is defined.
566 * @param[in] cur_node Current (original context) node.
567 * @param[in] expr Parsed path.
568 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200569 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200570 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200571 * @return LY_ERR value.
572 */
573static LY_ERR
574ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Radek Krejci0f969882020-08-21 16:56:47 +0200575 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200576{
577 const struct lysc_node *key, *node, *node2;
578 const struct lys_module *mod;
579 const char *name;
580 size_t name_len;
581
Michal Vasko004d3152020-06-11 19:59:22 +0200582 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200583 /* '[', no predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200584 return LY_SUCCESS;
585 }
586
587 if (ctx_node->nodetype != LYS_LIST) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200588 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
589 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200590 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200591 } else if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200592 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
593 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200594 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200595 }
596
597 do {
598 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200599 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200600 LY_PATH_LREF_TRUE, format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200601 key = lys_find_child(ctx_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
602 if (!key) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200603 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 +0200604 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200605 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200606 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
607 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200608 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200609 }
610 ++(*tok_idx);
611
612 /* we are not actually compiling, throw the key away */
613 (void)key;
614
615 /* '=' */
616 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
617 ++(*tok_idx);
618
619 /* FuncName */
620 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
621 ++(*tok_idx);
622
623 /* evaluating from the "current()" node */
624 node = cur_node;
625
626 /* '(' */
627 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
628 ++(*tok_idx);
629
630 /* ')' */
631 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
632 ++(*tok_idx);
633
634 do {
635 /* '/' */
636 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
637 ++(*tok_idx);
638
639 /* go to parent */
640 if (!node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200641 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200642 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200643 }
644 node = lysc_data_parent(node);
645
646 /* '..' */
647 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
648 ++(*tok_idx);
649 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
650
651 do {
652 /* '/' */
653 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
654 ++(*tok_idx);
655
656 /* NameTest */
657 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko6b26e742020-07-17 15:02:10 +0200658 LY_CHECK_RET(ly_path_compile_prefix(cur_node->module->ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200659 LY_PATH_LREF_TRUE, format, prefix_data, &mod, &name, &name_len));
Michal Vasko004d3152020-06-11 19:59:22 +0200660 node2 = lys_find_child(node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
661 if (!node2) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200662 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 +0200663 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200664 }
665 node = node2;
666 ++(*tok_idx);
667 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
668
669 /* check the last target node */
670 if (node->nodetype != LYS_LEAF) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200671 LOGVAL_P(cur_node->module->ctx, cur_node, LYVE_XPATH,
672 "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
673 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200674 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200675 }
676
677 /* we are not actually compiling, throw the rightside node away */
678 (void)node;
679
680 /* ']' */
681 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
682 ++(*tok_idx);
683
Radek Krejci0f969882020-08-21 16:56:47 +0200684 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200685 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
686
687 return LY_SUCCESS;
688}
689
690LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200691ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Radek Krejci0f969882020-08-21 16:56:47 +0200692 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target, LY_PREFIX_FORMAT format,
693 void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200694{
695 LY_ERR ret = LY_SUCCESS;
696 uint16_t tok_idx = 0;
697 const struct lys_module *mod;
Michal Vasko6b26e742020-07-17 15:02:10 +0200698 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200699 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200700 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200701 const char *name;
702 size_t name_len;
703
Michal Vasko00cbf532020-06-15 13:58:47 +0200704 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200705 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200706 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200707 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
708 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200709
Michal Vasko6b26e742020-07-17 15:02:10 +0200710 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200711 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200712
713 /* remember original context node */
714 cur_node = ctx_node;
715
Michal Vasko004d3152020-06-11 19:59:22 +0200716 *path = NULL;
717
Michal Vasko00cbf532020-06-15 13:58:47 +0200718 if (oper == LY_PATH_OPER_OUTPUT) {
719 getnext_opts = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_OUTPUT;
720 } else {
721 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
722 }
723
Michal Vasko004d3152020-06-11 19:59:22 +0200724 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
725 /* absolute path */
726 ctx_node = NULL;
727
728 ++tok_idx;
729 } else {
730 /* relative path */
731 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
732 if (!ctx_node) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200733 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Too many parent references in path.");
Radek Krejci8de005f2020-06-25 17:02:07 +0200734 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200735 }
736
737 /* get parent */
738 ctx_node = lysc_data_parent(ctx_node);
739
740 ++tok_idx;
741
742 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
743 ++tok_idx;
744 }
745
Michal Vasko00cbf532020-06-15 13:58:47 +0200746 /* we are not storing the parent */
747 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200748 }
749
750 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200751 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
752 if (p && (lref == LY_PATH_LREF_FALSE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200753 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
754 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200755 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200756 }
757
Michal Vasko004d3152020-06-11 19:59:22 +0200758 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200759 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
760 prefix_data, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200761 ++tok_idx;
762
763 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200764 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Michal Vasko6b26e742020-07-17 15:02:10 +0200765 if (!node2 || ((node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
766 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200767 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200768 goto cleanup;
769 }
770 ctx_node = node2;
771
772 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200773 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200774 p->node = ctx_node;
775
776 /* compile any predicates */
777 if (lref == LY_PATH_LREF_TRUE) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200778 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200779 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200780 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
781 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200782 }
783 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200784 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
785
Michal Vasko00cbf532020-06-15 13:58:47 +0200786 /* check last compiled node */
787 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE)
788 && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Michal Vasko6b26e742020-07-17 15:02:10 +0200789 LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
790 lys_nodetype2str(p->node->nodetype), p->node->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200791 return LY_EVALID;
Michal Vasko00cbf532020-06-15 13:58:47 +0200792 }
793
Michal Vasko004d3152020-06-11 19:59:22 +0200794cleanup:
795 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200796 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200797 *path = NULL;
798 }
799 return ret;
800}
801
802LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200803ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
Radek Krejci0f969882020-08-21 16:56:47 +0200804 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200805{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200806 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200807 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200808 uint64_t pos;
809
810 assert(path && start);
811
812 if (lysc_data_parent(path[0].node)) {
813 /* relative path, start from the parent children */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200814 start = lyd_node_children(start, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200815 } else {
816 /* absolute path, start from the first top-level sibling */
817 while (start->parent) {
818 start = (struct lyd_node *)start->parent;
819 }
820 while (start->prev->next) {
821 start = start->prev;
822 }
823 }
824
825 LY_ARRAY_FOR(path, u) {
826 switch (path[u].pred_type) {
827 case LY_PATH_PREDTYPE_POSITION:
828 /* we cannot use hashes and want an instance on a specific position */
829 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200830 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200831 if (pos == path[u].predicates[0].position) {
832 break;
833 }
834 ++pos;
835 }
836 break;
837 case LY_PATH_PREDTYPE_LEAFLIST:
838 /* we will use hashes to find one leaf-list instance */
839 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
840 lyd_find_sibling_first(start, target, &node);
841 lyd_free_tree(target);
842 break;
843 case LY_PATH_PREDTYPE_LIST:
844 /* we will use hashes to find one list instance */
845 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
846 lyd_find_sibling_first(start, target, &node);
847 lyd_free_tree(target);
848 break;
849 case LY_PATH_PREDTYPE_NONE:
850 /* we will use hashes to find one any/container/leaf instance */
851 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
852 break;
853 }
854
855 if (!node) {
856 /* no matching nodes */
857 break;
858 }
859
Michal Vasko00cbf532020-06-15 13:58:47 +0200860 /* rememeber previous node */
861 prev_node = node;
862
Michal Vasko004d3152020-06-11 19:59:22 +0200863 /* next path segment, if any */
Michal Vasko5bfd4be2020-06-23 13:26:19 +0200864 start = lyd_node_children(node, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200865 }
866
Michal Vasko004d3152020-06-11 19:59:22 +0200867 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200868 /* we have found the full path */
869 if (path_idx) {
870 *path_idx = u;
871 }
872 if (match) {
873 *match = node;
874 }
Michal Vasko004d3152020-06-11 19:59:22 +0200875 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200876
877 } else if (prev_node) {
878 /* we have found only some partial match */
879 if (path_idx) {
880 *path_idx = u - 1;
881 }
882 if (match) {
883 *match = prev_node;
884 }
885 return LY_EINCOMPLETE;
886 }
887
888 /* we have not found any nodes */
889 if (path_idx) {
890 *path_idx = 0;
891 }
892 if (match) {
893 *match = NULL;
894 }
895 return LY_ENOTFOUND;
896}
897
898LY_ERR
899ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
900{
901 LY_ERR ret;
902 struct lyd_node *m;
903
904 ret = ly_path_eval_partial(path, start, NULL, &m);
905
906 if (ret == LY_SUCCESS) {
907 /* last node was found */
908 if (match) {
909 *match = m;
910 }
911 return LY_SUCCESS;
912 }
913
914 /* not a full match */
915 if (match) {
916 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200917 }
918 return LY_ENOTFOUND;
919}
920
921LY_ERR
922ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
923{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200924 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +0200925
926 if (!path) {
927 return LY_SUCCESS;
928 }
929
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200930 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200931 LY_ARRAY_FOR(path, u) {
932 LY_ARRAY_INCREMENT(*dup);
933 (*dup)[u].node = path[u].node;
934 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200935 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +0200936 (*dup)[u].pred_type = path[u].pred_type;
937 LY_ARRAY_FOR(path[u].predicates, v) {
938 struct ly_path_predicate *pred = &path[u].predicates[v];
939
940 LY_ARRAY_INCREMENT((*dup)[u].predicates);
941 switch (path[u].pred_type) {
942 case LY_PATH_PREDTYPE_POSITION:
943 /* position-predicate */
944 (*dup)[u].predicates[v].position = pred->position;
945 break;
946 case LY_PATH_PREDTYPE_LIST:
947 case LY_PATH_PREDTYPE_LEAFLIST:
948 /* key-predicate or leaf-list-predicate */
949 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +0200950 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
951 break;
952 case LY_PATH_PREDTYPE_NONE:
953 break;
954 }
955 }
956 }
957 }
958
959 return LY_SUCCESS;
960}
961
962void
963ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, const struct lysc_node *llist,
Radek Krejci0f969882020-08-21 16:56:47 +0200964 struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200965{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200966 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200967
968 if (!predicates) {
969 return;
970 }
971
972 LY_ARRAY_FOR(predicates, u) {
973 switch (pred_type) {
974 case LY_PATH_PREDTYPE_POSITION:
975 case LY_PATH_PREDTYPE_NONE:
976 /* nothing to free */
977 break;
978 case LY_PATH_PREDTYPE_LIST:
979 ((struct lysc_node_leaf *)predicates[u].key)->type->plugin->free(ctx, &predicates[u].value);
980 break;
981 case LY_PATH_PREDTYPE_LEAFLIST:
982 ((struct lysc_node_leaflist *)llist)->type->plugin->free(ctx, &predicates[u].value);
983 break;
984 }
985 }
986 LY_ARRAY_FREE(predicates);
987}
988
989void
990ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
991{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200992 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +0200993
994 LY_ARRAY_FOR(path, u) {
995 ly_path_predicates_free(ctx, path[u].pred_type, path[u].node, path[u].predicates);
996 }
997 LY_ARRAY_FREE(path);
998}