blob: df3abc3a9372bce6cb4d1fbf1bdaa97d48c8b120 [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{
Radek Krejciba03a5a2020-08-27 14:40:41 +020051 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020052 struct ly_set *set = NULL;
53 uint32_t i;
54 const char *name;
55 size_t name_len;
56
Radek Krejci2efc45b2020-12-22 16:25:44 +010057 LOG_LOCSET(ctx, cur_node, NULL, NULL, NULL);
58
Michal Vasko004d3152020-06-11 19:59:22 +020059 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020060 /* '[' */
61
Michal Vasko69730152020-10-09 16:30:07 +020062 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
63 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020064 ret = ly_set_new(&set);
65 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020066
67 do {
68 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020069 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020070
71 /* check prefix based on the options */
72 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
73 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010074 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020075 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020076 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020077 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010078 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020079 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020080 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020081 }
82 if (!name) {
83 name = exp->expr + exp->tok_pos[*tok_idx];
84 name_len = exp->tok_len[*tok_idx];
85 } else {
86 ++name;
87 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
88 }
89
90 /* check whether it was not already specified */
91 for (i = 0; i < set->count; ++i) {
92 /* all the keys must be from the same module so this comparison should be fine */
93 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010094 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020095 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020096 }
97 }
98
99 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200100 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200101 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200102
103 /* NameTest */
104 ++(*tok_idx);
105
106 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200107 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200108
109 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200110 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200111
112 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200113 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200114
Radek Krejci0f969882020-08-21 16:56:47 +0200115 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200116 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
117
Michal Vasko004d3152020-06-11 19:59:22 +0200118 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200119 /* '.' */
120
Michal Vasko004d3152020-06-11 19:59:22 +0200121 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200122 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200123
124 /* Literal */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200125 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200126
127 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200128 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200129
Michal Vasko004d3152020-06-11 19:59:22 +0200130 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200131 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200132
133 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200134 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200135
136 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
137 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200138 ret = ly_set_new(&set);
139 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200140
141 do {
142 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200143 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200144
145 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
146 if (!name) {
147 name = exp->expr + exp->tok_pos[*tok_idx];
148 name_len = exp->tok_len[*tok_idx];
149 } else {
150 ++name;
151 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
152 }
153
154 /* check whether it was not already specified */
155 for (i = 0; i < set->count; ++i) {
156 /* all the keys must be from the same module so this comparison should be fine */
157 if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100158 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200159 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200160 }
161 }
162
163 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200164 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200165 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200166
167 /* NameTest */
168 ++(*tok_idx);
169
170 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200171 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200172
173 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200174 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100175 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
176 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100177 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200178 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200179 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200180 }
181 ++(*tok_idx);
182
183 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200184 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200185
186 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200187 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200188
189 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200190 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200191
192 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200193 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200194 do {
195 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200196 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200197 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
198
199 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200200 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200201
202 /* '/' */
203 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
204 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200205 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200206 }
207
208 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200209 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200210
Radek Krejci0f969882020-08-21 16:56:47 +0200211 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200212 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
213
214 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100215 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200216 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200217 }
218 }
219
Radek Krejciba03a5a2020-08-27 14:40:41 +0200220cleanup:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100221 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200222 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200223 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200224
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225token_error:
Radek Krejci2efc45b2020-12-22 16:25:44 +0100226 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200227 ly_set_free(set, NULL);
228 return LY_EVALID;
229}
230
231LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200232ly_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 +0200233 uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200234{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200235 LY_ERR ret = LY_SUCCESS;
236 struct lyxp_expr *exp = NULL;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200237 uint16_t tok_idx, cur_len;
238 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko004d3152020-06-11 19:59:22 +0200239
240 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
241 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko69730152020-10-09 16:30:07 +0200242 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
243 (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200244 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
245
Radek Krejci2efc45b2020-12-22 16:25:44 +0100246 LOG_LOCSET(ctx, ctx_node, NULL, NULL, NULL);
247
Michal Vasko004d3152020-06-11 19:59:22 +0200248 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200249 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200250 tok_idx = 0;
251
252 if (begin == LY_PATH_BEGIN_EITHER) {
253 /* is the path relative? */
254 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200255 /* relative path check specific to leafref */
256 if (lref == LY_PATH_LREF_TRUE) {
257 /* mandatory '..' */
258 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
259
260 do {
261 /* '/' */
262 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
263
264 /* optional '..' */
265 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200266 }
267 }
268 } else {
269 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200270 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
Michal Vasko004d3152020-06-11 19:59:22 +0200271 }
272
273 do {
274 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200275 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, error);
Michal Vasko004d3152020-06-11 19:59:22 +0200276
277 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200278 cur_node = exp->expr + exp->tok_pos[tok_idx];
279 cur_len = exp->tok_len[tok_idx];
280 if (prefix == LY_PATH_PREFIX_MANDATORY) {
281 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100282 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200283 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200284 goto error;
285 }
286 } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
287 if (!prev_prefix) {
288 /* the first node must have a prefix */
289 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100290 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200291 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200292 goto error;
293 }
294
295 /* remember the first prefix */
296 prev_prefix = cur_node;
297 } else {
298 /* the prefix must be different, if any */
299 ptr = strnstr(cur_node, ":", cur_len);
300 if (ptr) {
301 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100302 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200303 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200304 goto error;
305 }
306
307 /* remember this next prefix */
308 prev_prefix = cur_node;
309 }
310 }
Michal Vasko004d3152020-06-11 19:59:22 +0200311 }
312
313 ++tok_idx;
314
315 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200316 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200317
Radek Krejci0f969882020-08-21 16:56:47 +0200318 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200319 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
320
321 /* trailing token check */
322 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100323 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.", exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200324 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200325 goto error;
326 }
327
328 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100329
330 LOG_LOCBACK(ctx, ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200331 return LY_SUCCESS;
332
333error:
334 lyxp_expr_free(ctx, exp);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100335 LOG_LOCBACK(ctx, ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200336 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200337}
338
339LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200340ly_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 +0200341 size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200342{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200343 LY_ERR ret = LY_SUCCESS;
344 struct lyxp_expr *exp = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200345 uint16_t tok_idx;
346
347 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
348 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
349
Radek Krejci2efc45b2020-12-22 16:25:44 +0100350 LOG_LOCSET(ctx, cur_node, NULL, NULL, NULL);
351
Michal Vasko004d3152020-06-11 19:59:22 +0200352 /* parse as a generic XPath expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200353 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200354 tok_idx = 0;
355
Radek Krejcif03a9e22020-09-18 20:09:31 +0200356 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200357
358 /* trailing token check */
359 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100360 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200361 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200362 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200363 goto error;
364 }
365
366 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100367
368 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200369 return LY_SUCCESS;
370
371error:
372 lyxp_expr_free(ctx, exp);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100373 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200374 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200375}
376
377/**
378 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
379 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200380 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200381 * @param[in] cur_node Optional current (original context) node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200382 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_PREF_SCHEMA*.
383 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_PREF_JSON.
Michal Vasko004d3152020-06-11 19:59:22 +0200384 * @param[in] expr Parsed path.
385 * @param[in] tok_idx Index in @p expr.
386 * @param[in] lref Lref option.
Michal Vasko004d3152020-06-11 19:59:22 +0200387 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200388 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200389 * @param[out] mod Resolved module.
390 * @param[out] name Parsed node name.
391 * @param[out] name_len Length of @p name.
392 * @return LY_ERR value.
393 */
394static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200395ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200396 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100397 LY_PREFIX_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
398 const char **name, size_t *name_len)
Michal Vasko004d3152020-06-11 19:59:22 +0200399{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100400 LY_ERR ret;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200401 const char *pref;
Michal Vasko004d3152020-06-11 19:59:22 +0200402 size_t len;
403
404 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko405cc9e2020-12-01 12:01:27 +0100405 assert((lref != LY_PATH_LREF_TRUE) || unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200406
407 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200408 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
409 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
410 pref = expr->expr + expr->tok_pos[tok_idx];
411 } else {
412 len = 0;
413 }
Michal Vasko004d3152020-06-11 19:59:22 +0200414
415 /* find next node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200416 if (pref) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100417 ret = LY_EVALID;
418
419 LOG_LOCSET(ctx, cur_node, NULL, NULL, NULL);
420
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200421 *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200422 if (!*mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100423 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Michal Vasko7ed1fcb2020-12-03 14:15:22 +0100424 len, pref, ly_format2str(format));
Radek Krejci2efc45b2020-12-22 16:25:44 +0100425 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200426 } else if (!(*mod)->implemented) {
427 if (lref == LY_PATH_LREF_FALSE) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100428 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
429 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200430 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100431 LY_CHECK_GOTO(ret = lys_set_implemented_r((struct lys_module *)*mod, NULL, unres), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200432 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100433
434 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200435 } else {
436 switch (format) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200437 case LY_PREF_SCHEMA:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200438 case LY_PREF_SCHEMA_RESOLVED:
439 if (!cur_mod) {
440 LOGINT_RET(ctx);
441 }
442 /* use current module */
Michal Vasko004d3152020-06-11 19:59:22 +0200443 *mod = cur_mod;
444 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200445 case LY_PREF_JSON:
Michal Vasko004d3152020-06-11 19:59:22 +0200446 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200447 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200448 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200449 /* inherit module of the previous node */
Michal Vasko004d3152020-06-11 19:59:22 +0200450 *mod = prev_ctx_node->module;
451 break;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200452 case LY_PREF_XML:
Michal Vasko004d3152020-06-11 19:59:22 +0200453 /* not really defined */
Michal Vasko00cbf532020-06-15 13:58:47 +0200454 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200455 }
456 }
457
458 /* set name */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200459 if (pref) {
460 *name = pref + len + 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200461 *name_len = expr->tok_len[tok_idx] - len - 1;
462 } else {
463 *name = expr->expr + expr->tok_pos[tok_idx];
464 *name_len = expr->tok_len[tok_idx];
465 }
466
467 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100468
469error:
470 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
471 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200472}
473
474LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200475ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200476 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format,
477 void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vasko004d3152020-06-11 19:59:22 +0200478{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100479 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200480 struct ly_path_predicate *p;
481 const struct lysc_node *key;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100482 const struct lys_module *mod = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200483 const char *name;
484 size_t name_len, key_count;
485
Michal Vasko00cbf532020-06-15 13:58:47 +0200486 assert(ctx && ctx_node);
487
Radek Krejci2efc45b2020-12-22 16:25:44 +0100488 LOG_LOCSET(ctx, cur_node, NULL, NULL, NULL);
489
Michal Vasko004d3152020-06-11 19:59:22 +0200490 *pred_type = 0;
491
Michal Vasko004d3152020-06-11 19:59:22 +0200492 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200493 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100494 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200495 }
496
497 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
498 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100499 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200500 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100501 ret = LY_EVALID;
502 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200503 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100504 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200505 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100506 ret = LY_EVALID;
507 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200508 }
509
510 do {
511 /* NameTest, find the key */
Michal Vasko6b26e742020-07-17 15:02:10 +0200512 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100513 format, prefix_data, NULL, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100514 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200515 if (!key) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100516 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
517 ret = LY_ENOTFOUND;
518 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200519 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100520 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
521 key->name);
522 ret = LY_EVALID;
523 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200524 }
525 ++(*tok_idx);
526
Michal Vasko004d3152020-06-11 19:59:22 +0200527 if (!*pred_type) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200528 /* new predicate */
Michal Vasko004d3152020-06-11 19:59:22 +0200529 *pred_type = LY_PATH_PREDTYPE_LIST;
530 }
531 assert(*pred_type == LY_PATH_PREDTYPE_LIST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100532 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200533 p->key = key;
534
535 /* '=' */
536 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
537 ++(*tok_idx);
538
539 /* Literal */
540 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100541 LOG_LOCSET(ctx, key, NULL, NULL, NULL);
542 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200543 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
Radek Krejci2efc45b2020-12-22 16:25:44 +0100544 LYD_HINT_DATA, key, NULL);
545 LOG_LOCBACK(ctx, key ? 1 : 0, 0, 0, 0);
546 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200547 ++(*tok_idx);
548
Michal Vaskoae875662020-10-21 10:33:17 +0200549 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
550 ++((struct lysc_type *)p->value.realtype)->refcount;
551
Michal Vasko004d3152020-06-11 19:59:22 +0200552 /* ']' */
553 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
554 ++(*tok_idx);
555
556 /* another predicate follows? */
557 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
558
559 /* check that all keys were set */
560 key_count = 0;
561 for (key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next) {
562 ++key_count;
563 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200564 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200565 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100566 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200567 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vaskof7e16e22020-10-21 09:24:39 +0200568 ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200569 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100570 ret = LY_EVALID;
571 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200572 }
573
574 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
575 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100576 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200577 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100578 ret = LY_EVALID;
579 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200580 }
581 ++(*tok_idx);
582
583 /* new predicate */
584 *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100585 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200586
587 /* '=' */
588 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
589 ++(*tok_idx);
590
591 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
592 /* store the value */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100593 LOG_LOCSET(ctx, ctx_node, NULL, NULL, NULL);
594 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200595 expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
Radek Krejci2efc45b2020-12-22 16:25:44 +0100596 LYD_HINT_DATA, ctx_node, NULL);
597 LOG_LOCBACK(ctx, ctx_node ? 1 : 0, 0, 0, 0);
598 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200599 ++(*tok_idx);
600
Michal Vaskoae875662020-10-21 10:33:17 +0200601 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
602 ++((struct lysc_type *)p->value.realtype)->refcount;
603
Michal Vasko004d3152020-06-11 19:59:22 +0200604 /* ']' */
605 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
606 ++(*tok_idx);
607 } else {
608 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
609 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100610 ret = LY_EVALID;
611 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200612 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100613 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200614 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100615 ret = LY_EVALID;
616 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200617 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100618 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200619 }
Michal Vasko004d3152020-06-11 19:59:22 +0200620
621 /* new predicate */
622 *pred_type = LY_PATH_PREDTYPE_POSITION;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100623 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200624
625 /* syntax was already checked */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100626 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200627 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200628
629 /* ']' */
630 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
631 ++(*tok_idx);
632 }
633
Radek Krejci2efc45b2020-12-22 16:25:44 +0100634cleanup:
635 LOG_LOCBACK(ctx, cur_node ? 1 : 0, 0, 0, 0);
636 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200637}
638
639/**
640 * @brief Compile leafref predicate. Actually, it is only checked.
641 *
642 * @param[in] ctx_node Context node, node for which the predicate is defined.
643 * @param[in] cur_node Current (original context) node.
644 * @param[in] expr Parsed path.
645 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200646 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200647 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko405cc9e2020-12-01 12:01:27 +0100648 * @param[in,out] unres Global unres structure for newly implemented modules.
Michal Vasko004d3152020-06-11 19:59:22 +0200649 * @return LY_ERR value.
650 */
651static LY_ERR
652ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100653 const struct lyxp_expr *expr, uint16_t *tok_idx, LY_PREFIX_FORMAT format, void *prefix_data,
654 struct lys_glob_unres *unres)
Michal Vasko004d3152020-06-11 19:59:22 +0200655{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100656 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200657 const struct lysc_node *key, *node, *node2;
658 const struct lys_module *mod;
659 const char *name;
660 size_t name_len;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100661 struct ly_ctx *ctx = cur_node->module->ctx;
662
663 LOG_LOCSET(ctx, cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200664
Michal Vasko004d3152020-06-11 19:59:22 +0200665 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200666 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100667 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200668 }
669
670 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100671 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200672 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100673 ret = LY_EVALID;
674 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200675 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100676 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200677 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100678 ret = LY_EVALID;
679 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200680 }
681
682 do {
683 /* NameTest, find the key */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100684 ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
685 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len);
686 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100687 key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200688 if (!key) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100689 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
690 ret = LY_EVALID;
691 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200692 } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100693 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200694 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 ret = LY_EVALID;
696 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200697 }
698 ++(*tok_idx);
699
700 /* we are not actually compiling, throw the key away */
701 (void)key;
702
703 /* '=' */
704 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
705 ++(*tok_idx);
706
707 /* FuncName */
708 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
709 ++(*tok_idx);
710
711 /* evaluating from the "current()" node */
712 node = cur_node;
713
714 /* '(' */
715 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
716 ++(*tok_idx);
717
718 /* ')' */
719 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
720 ++(*tok_idx);
721
722 do {
723 /* '/' */
724 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
725 ++(*tok_idx);
726
727 /* go to parent */
728 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100729 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
730 ret = LY_EVALID;
731 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200732 }
733 node = lysc_data_parent(node);
734
735 /* '..' */
736 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
737 ++(*tok_idx);
738 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
739
740 do {
741 /* '/' */
742 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
743 ++(*tok_idx);
744
745 /* NameTest */
746 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100747 LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100748 LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100749 node2 = lys_find_child(node, mod, name, name_len, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200750 if (!node2) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100751 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
752 ret = LY_EVALID;
753 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200754 }
755 node = node2;
756 ++(*tok_idx);
757 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
758
759 /* check the last target node */
760 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100761 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200762 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100763 ret = LY_EVALID;
764 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200765 }
766
767 /* we are not actually compiling, throw the rightside node away */
768 (void)node;
769
770 /* ']' */
771 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
772 ++(*tok_idx);
773
Radek Krejci0f969882020-08-21 16:56:47 +0200774 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200775 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
776
Radek Krejci2efc45b2020-12-22 16:25:44 +0100777cleanup:
778 LOG_LOCBACK(ctx, 1, 0, 0, 0);
779 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200780}
781
782LY_ERR
Michal Vasko00cbf532020-06-15 13:58:47 +0200783ly_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 +0200784 const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target, LY_PREFIX_FORMAT format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100785 void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200786{
787 LY_ERR ret = LY_SUCCESS;
788 uint16_t tok_idx = 0;
Radek Krejci2b18bf12020-11-06 11:20:20 +0100789 const struct lys_module *mod = NULL;
Michal Vasko6b26e742020-07-17 15:02:10 +0200790 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200791 struct ly_path *p = NULL;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200792 uint32_t getnext_opts;
Michal Vasko004d3152020-06-11 19:59:22 +0200793 const char *name;
794 size_t name_len;
795
Michal Vasko00cbf532020-06-15 13:58:47 +0200796 assert(ctx);
Michal Vasko6b26e742020-07-17 15:02:10 +0200797 assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
Michal Vasko004d3152020-06-11 19:59:22 +0200798 assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
Michal Vasko00cbf532020-06-15 13:58:47 +0200799 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
800 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200801
Michal Vasko6b26e742020-07-17 15:02:10 +0200802 /* find operation, if we are in any */
Radek Krejci1e008d22020-08-17 11:37:37 +0200803 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +0200804
Radek Krejci2efc45b2020-12-22 16:25:44 +0100805 *path = NULL;
806
Michal Vasko6b26e742020-07-17 15:02:10 +0200807 /* remember original context node */
808 cur_node = ctx_node;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100809 LOG_LOCINIT(ctx, cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200810
Michal Vasko00cbf532020-06-15 13:58:47 +0200811 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100812 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200813 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100814 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200815 }
816
Michal Vasko004d3152020-06-11 19:59:22 +0200817 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
818 /* absolute path */
819 ctx_node = NULL;
820
821 ++tok_idx;
822 } else {
823 /* relative path */
824 while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
825 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100826 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100827 ret = LY_EVALID;
828 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200829 }
830
831 /* get parent */
832 ctx_node = lysc_data_parent(ctx_node);
833
834 ++tok_idx;
835
836 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
837 ++tok_idx;
838 }
839
Michal Vasko00cbf532020-06-15 13:58:47 +0200840 /* we are not storing the parent */
841 (void)ctx_node;
Michal Vasko004d3152020-06-11 19:59:22 +0200842 }
843
844 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200845 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskod456cf62020-11-23 16:48:43 +0100846 if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
847 (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100848 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200849 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100850 ret = LY_EVALID;
851 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200852 }
853
Michal Vasko14424ba2020-12-09 18:09:51 +0100854 /* NameTest */
855 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
856
Michal Vasko004d3152020-06-11 19:59:22 +0200857 /* get module and node name */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200858 LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
Michal Vasko405cc9e2020-12-01 12:01:27 +0100859 prefix_data, unres, &mod, &name, &name_len), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200860 ++tok_idx;
861
862 /* find the next node */
Michal Vasko00cbf532020-06-15 13:58:47 +0200863 node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
Radek Krejci25fe3dd2020-11-10 22:02:26 +0100864 if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100865 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", name_len, name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200866 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200867 goto cleanup;
868 }
869 ctx_node = node2;
870
871 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200872 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200873 p->node = ctx_node;
874
875 /* compile any predicates */
876 if (lref == LY_PATH_LREF_TRUE) {
Michal Vasko405cc9e2020-12-01 12:01:27 +0100877 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
Michal Vasko004d3152020-06-11 19:59:22 +0200878 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200879 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
Michal Vasko69730152020-10-09 16:30:07 +0200880 &p->predicates, &p->pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +0200881 }
882 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200883 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
884
Michal Vasko14424ba2020-12-09 18:09:51 +0100885 /* check leftover tokens */
886 if (tok_idx < expr->used) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100887 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
Michal Vasko14424ba2020-12-09 18:09:51 +0100888 ret = LY_EVALID;
889 goto cleanup;
890 }
891
Michal Vasko00cbf532020-06-15 13:58:47 +0200892 /* check last compiled node */
Michal Vasko69730152020-10-09 16:30:07 +0200893 if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
894 (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100895 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200896 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100897 ret = LY_EVALID;
898 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200899 }
900
Michal Vasko004d3152020-06-11 19:59:22 +0200901cleanup:
902 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200903 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +0200904 *path = NULL;
905 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100906 LOG_LOCBACK(ctx, 1, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200907 return ret;
908}
909
910LY_ERR
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200911ly_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 +0200912 struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +0200913{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200914 LY_ARRAY_COUNT_TYPE u;
Michal Vasko00cbf532020-06-15 13:58:47 +0200915 struct lyd_node *prev_node = NULL, *node, *target;
Michal Vasko004d3152020-06-11 19:59:22 +0200916 uint64_t pos;
917
918 assert(path && start);
919
920 if (lysc_data_parent(path[0].node)) {
921 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200922 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +0200923 } else {
924 /* absolute path, start from the first top-level sibling */
925 while (start->parent) {
926 start = (struct lyd_node *)start->parent;
927 }
928 while (start->prev->next) {
929 start = start->prev;
930 }
931 }
932
933 LY_ARRAY_FOR(path, u) {
934 switch (path[u].pred_type) {
935 case LY_PATH_PREDTYPE_POSITION:
936 /* we cannot use hashes and want an instance on a specific position */
937 pos = 1;
Michal Vasko4c583e82020-07-17 12:16:14 +0200938 LYD_LIST_FOR_INST(start, path[u].node, node) {
Michal Vasko004d3152020-06-11 19:59:22 +0200939 if (pos == path[u].predicates[0].position) {
940 break;
941 }
942 ++pos;
943 }
944 break;
945 case LY_PATH_PREDTYPE_LEAFLIST:
946 /* we will use hashes to find one leaf-list instance */
947 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
948 lyd_find_sibling_first(start, target, &node);
949 lyd_free_tree(target);
950 break;
951 case LY_PATH_PREDTYPE_LIST:
952 /* we will use hashes to find one list instance */
953 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
954 lyd_find_sibling_first(start, target, &node);
955 lyd_free_tree(target);
956 break;
957 case LY_PATH_PREDTYPE_NONE:
958 /* we will use hashes to find one any/container/leaf instance */
959 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
960 break;
961 }
962
963 if (!node) {
964 /* no matching nodes */
965 break;
966 }
967
Michal Vasko00cbf532020-06-15 13:58:47 +0200968 /* rememeber previous node */
969 prev_node = node;
970
Michal Vasko004d3152020-06-11 19:59:22 +0200971 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +0200972 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +0200973 }
974
Michal Vasko004d3152020-06-11 19:59:22 +0200975 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200976 /* we have found the full path */
977 if (path_idx) {
978 *path_idx = u;
979 }
980 if (match) {
981 *match = node;
982 }
Michal Vasko004d3152020-06-11 19:59:22 +0200983 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +0200984
985 } else if (prev_node) {
986 /* we have found only some partial match */
987 if (path_idx) {
988 *path_idx = u - 1;
989 }
990 if (match) {
991 *match = prev_node;
992 }
993 return LY_EINCOMPLETE;
994 }
995
996 /* we have not found any nodes */
997 if (path_idx) {
998 *path_idx = 0;
999 }
1000 if (match) {
1001 *match = NULL;
1002 }
1003 return LY_ENOTFOUND;
1004}
1005
1006LY_ERR
1007ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1008{
1009 LY_ERR ret;
1010 struct lyd_node *m;
1011
1012 ret = ly_path_eval_partial(path, start, NULL, &m);
1013
1014 if (ret == LY_SUCCESS) {
1015 /* last node was found */
1016 if (match) {
1017 *match = m;
1018 }
1019 return LY_SUCCESS;
1020 }
1021
1022 /* not a full match */
1023 if (match) {
1024 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001025 }
1026 return LY_ENOTFOUND;
1027}
1028
1029LY_ERR
1030ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1031{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001032 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001033
1034 if (!path) {
1035 return LY_SUCCESS;
1036 }
1037
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001038 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001039 LY_ARRAY_FOR(path, u) {
1040 LY_ARRAY_INCREMENT(*dup);
1041 (*dup)[u].node = path[u].node;
1042 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001043 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001044 (*dup)[u].pred_type = path[u].pred_type;
1045 LY_ARRAY_FOR(path[u].predicates, v) {
1046 struct ly_path_predicate *pred = &path[u].predicates[v];
1047
1048 LY_ARRAY_INCREMENT((*dup)[u].predicates);
1049 switch (path[u].pred_type) {
1050 case LY_PATH_PREDTYPE_POSITION:
1051 /* position-predicate */
1052 (*dup)[u].predicates[v].position = pred->position;
1053 break;
1054 case LY_PATH_PREDTYPE_LIST:
1055 case LY_PATH_PREDTYPE_LEAFLIST:
1056 /* key-predicate or leaf-list-predicate */
1057 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001058 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vaskoae875662020-10-21 10:33:17 +02001059 ++((struct lysc_type *)pred->value.realtype)->refcount;
Michal Vasko004d3152020-06-11 19:59:22 +02001060 break;
1061 case LY_PATH_PREDTYPE_NONE:
1062 break;
1063 }
1064 }
1065 }
1066 }
1067
1068 return LY_SUCCESS;
1069}
1070
1071void
Michal Vaskof7e16e22020-10-21 09:24:39 +02001072ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001073{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001074 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001075
1076 if (!predicates) {
1077 return;
1078 }
1079
1080 LY_ARRAY_FOR(predicates, u) {
1081 switch (pred_type) {
1082 case LY_PATH_PREDTYPE_POSITION:
1083 case LY_PATH_PREDTYPE_NONE:
1084 /* nothing to free */
1085 break;
1086 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001087 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001088 if (predicates[u].value.realtype) {
1089 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1090 lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1091 }
Michal Vasko004d3152020-06-11 19:59:22 +02001092 break;
1093 }
1094 }
1095 LY_ARRAY_FREE(predicates);
1096}
1097
1098void
1099ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1100{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001101 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001102
1103 LY_ARRAY_FOR(path, u) {
Michal Vaskof7e16e22020-10-21 09:24:39 +02001104 ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001105 }
1106 LY_ARRAY_FREE(path);
1107}