blob: cfa934f4e804d34382479c8a9d7a8ebba44c7608 [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 *
Michal Vasko90189962023-02-28 12:10:34 +01006 * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
Michal Vasko004d3152020-06-11 19:59:22 +02007 *
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 */
Michal Vasko90189962023-02-28 12:10:34 +010014
15#define _GNU_SOURCE
16
Michal Vasko004d3152020-06-11 19:59:22 +020017#include "path.h"
18
19#include <assert.h>
Michal Vasko004d3152020-06-11 19:59:22 +020020#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"
Michal Vasko40c158c2021-04-28 17:01:03 +020027#include "schema_compile.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020028#include "set.h"
Michal Vasko4c583e82020-07-17 12:16:14 +020029#include "tree.h"
Michal Vasko004d3152020-06-11 19:59:22 +020030#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010031#include "tree_edit.h"
Radek Krejciad97c5f2020-06-30 09:19:28 +020032#include "tree_schema.h"
Michal Vasko004d3152020-06-11 19:59:22 +020033#include "tree_schema_internal.h"
34#include "xpath.h"
35
Radek Krejcic0c66412020-08-21 13:53:50 +020036#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 +020037
Michal Vasko004d3152020-06-11 19:59:22 +020038/**
39 * @brief Check predicate syntax.
40 *
41 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +020042 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +020043 * @param[in] exp Parsed predicate.
44 * @param[in,out] tok_idx Index in @p exp, is adjusted.
45 * @param[in] prefix Prefix option.
46 * @param[in] pred Predicate option.
47 * @return LY_ERR value.
48 */
49static LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +020050ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
Michal Vasko32ca49b2023-02-17 15:11:35 +010051 uint32_t *tok_idx, uint16_t prefix, uint16_t pred)
Michal Vasko004d3152020-06-11 19:59:22 +020052{
Radek Krejciba03a5a2020-08-27 14:40:41 +020053 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +020054 struct ly_set *set = NULL;
55 uint32_t i;
56 const char *name;
57 size_t name_len;
58
Radek Krejciddace2c2021-01-08 11:30:56 +010059 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +010060
Michal Vasko004d3152020-06-11 19:59:22 +020061 if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +020062 /* '[' */
63
Michal Vasko69730152020-10-09 16:30:07 +020064 if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
65 !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +020066 ret = ly_set_new(&set);
67 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +020068
69 do {
70 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +020071 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +020072
73 /* check prefix based on the options */
74 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
75 if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010076 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020077 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020078 goto token_error;
Michal Vasko8b06a5e2020-08-06 12:13:08 +020079 } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010080 LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +020081 exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +020082 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020083 }
84 if (!name) {
85 name = exp->expr + exp->tok_pos[*tok_idx];
86 name_len = exp->tok_len[*tok_idx];
87 } else {
88 ++name;
89 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
90 }
91
92 /* check whether it was not already specified */
93 for (i = 0; i < set->count; ++i) {
94 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +020095 if (!strncmp(set->objs[i], name, name_len) &&
96 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +010097 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +020098 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +020099 }
100 }
101
102 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200103 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200104 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200105
106 /* NameTest */
107 ++(*tok_idx);
108
109 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200110 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200111
Michal Vaskob01983e2023-04-24 10:43:13 +0200112 /* fill repeat */
113 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
114 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
115 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
116
Michal Vasko90189962023-02-28 12:10:34 +0100117 /* Literal, Number, or VariableReference */
118 if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) &&
119 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) &&
120 lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) {
121 /* error */
122 lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL);
123 goto token_error;
124 }
Michal Vasko004d3152020-06-11 19:59:22 +0200125
126 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200127 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200128
Radek Krejci0f969882020-08-21 16:56:47 +0200129 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200130 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
131
Michal Vasko004d3152020-06-11 19:59:22 +0200132 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200133 /* '.' */
134
Michal Vasko004d3152020-06-11 19:59:22 +0200135 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200136 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200137
Michal Vaskob01983e2023-04-24 10:43:13 +0200138 /* fill repeat */
139 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
140 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
141 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
142
Michal Vasko4911eeb2021-06-28 11:23:05 +0200143 /* Literal or Number */
144 LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200145
146 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200147 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200148
Michal Vasko004d3152020-06-11 19:59:22 +0200149 } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200150 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +0200151
Michal Vasko2261dfa2022-09-29 12:29:20 +0200152 /* check for index 0 */
153 if (!atoi(exp->expr + exp->tok_pos[*tok_idx - 1])) {
154 LOGVAL(ctx, LYVE_XPATH, "Invalid positional predicate \"%.*s\".", (int)exp->tok_len[*tok_idx - 1],
155 exp->expr + exp->tok_pos[*tok_idx - 1]);
156 goto token_error;
157 }
158
Michal Vasko004d3152020-06-11 19:59:22 +0200159 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200160 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200161
162 } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
163 assert(prefix == LY_PATH_PREFIX_OPTIONAL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200164 ret = ly_set_new(&set);
165 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200166
167 do {
168 /* NameTest is always expected here */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200169 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200170
171 name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
172 if (!name) {
173 name = exp->expr + exp->tok_pos[*tok_idx];
174 name_len = exp->tok_len[*tok_idx];
175 } else {
176 ++name;
177 name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
178 }
179
180 /* check whether it was not already specified */
181 for (i = 0; i < set->count; ++i) {
182 /* all the keys must be from the same module so this comparison should be fine */
Michal Vasko9ff8d2d2022-09-29 13:41:14 +0200183 if (!strncmp(set->objs[i], name, name_len) &&
184 lysp_check_identifierchar(NULL, ((char *)set->objs[i])[name_len], 0, NULL)) {
Radek Krejci422afb12021-03-04 16:38:16 +0100185 LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200186 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200187 }
188 }
189
190 /* add it into the set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200191 ret = ly_set_add(set, (void *)name, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200192 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200193
194 /* NameTest */
195 ++(*tok_idx);
196
197 /* '=' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200198 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200199
Michal Vaskob01983e2023-04-24 10:43:13 +0200200 /* fill repeat */
201 exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]);
202 LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup);
203 exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY;
204
Michal Vasko004d3152020-06-11 19:59:22 +0200205 /* FuncName */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200206 LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
Radek Krejcif13b87b2020-12-01 22:02:17 +0100207 if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
208 strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100209 LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200210 exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200211 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200212 }
213 ++(*tok_idx);
214
215 /* '(' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200216 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200217
218 /* ')' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200219 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200220
221 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200223
224 /* '..' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200226 do {
227 /* '/' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200228 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200229 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
230
231 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200232 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200233
234 /* '/' */
235 while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
236 /* NameTest */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200237 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200238 }
239
240 /* ']' */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200241 LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
Michal Vasko004d3152020-06-11 19:59:22 +0200242
Radek Krejci0f969882020-08-21 16:56:47 +0200243 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +0200244 } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
245
Michal Vasko3c19b492022-09-05 08:48:10 +0200246 } else if (lyxp_check_token(ctx, exp, *tok_idx, 0)) {
247 /* unexpected EOF */
248 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200249 } else {
Michal Vasko3c19b492022-09-05 08:48:10 +0200250 /* invalid token */
Michal Vasko49fec8e2022-05-24 10:28:33 +0200251 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200252 goto token_error;
Michal Vasko004d3152020-06-11 19:59:22 +0200253 }
254 }
255
Radek Krejciba03a5a2020-08-27 14:40:41 +0200256cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100257 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200258 ly_set_free(set, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200259 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200260
Radek Krejciba03a5a2020-08-27 14:40:41 +0200261token_error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100262 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200263 ly_set_free(set, NULL);
264 return LY_EVALID;
265}
266
267LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200268ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
Michal Vasko32ca49b2023-02-17 15:11:35 +0100269 ly_bool lref, uint16_t begin, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200270{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200271 LY_ERR ret = LY_SUCCESS;
272 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200273 uint32_t tok_idx, cur_len;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200274 const char *cur_node, *prev_prefix = NULL, *ptr;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100275 ly_bool is_abs;
Michal Vasko004d3152020-06-11 19:59:22 +0200276
277 assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
Michal Vasko69730152020-10-09 16:30:07 +0200278 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
Michal Vasko32ca49b2023-02-17 15:11:35 +0100279 (prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
Michal Vasko004d3152020-06-11 19:59:22 +0200280 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
281
Radek Krejciddace2c2021-01-08 11:30:56 +0100282 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100283
Michal Vaskob01983e2023-04-24 10:43:13 +0200284 /* parse as a generic XPath expression, reparse is performed manually */
285 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200286 tok_idx = 0;
287
Michal Vaskob01983e2023-04-24 10:43:13 +0200288 /* alloc empty repeat (only '=', filled manually) */
289 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
290 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
291
Michal Vasko004d3152020-06-11 19:59:22 +0200292 if (begin == LY_PATH_BEGIN_EITHER) {
293 /* is the path relative? */
294 if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200295 /* relative path check specific to leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200296 if (lref) {
Michal Vaskocb8c6d42020-10-16 11:58:30 +0200297 /* mandatory '..' */
298 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
299
300 do {
301 /* '/' */
302 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
303
304 /* optional '..' */
305 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
Michal Vasko004d3152020-06-11 19:59:22 +0200306 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100307
308 is_abs = 0;
309 } else {
310 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200311 }
312 } else {
313 /* '/' */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200314 LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
Michal Vasko32ca49b2023-02-17 15:11:35 +0100315
316 is_abs = 1;
Michal Vasko004d3152020-06-11 19:59:22 +0200317 }
318
319 do {
320 /* NameTest */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200321 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 +0200322
323 /* check prefix based on the options */
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200324 cur_node = exp->expr + exp->tok_pos[tok_idx];
325 cur_len = exp->tok_len[tok_idx];
326 if (prefix == LY_PATH_PREFIX_MANDATORY) {
327 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100328 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200329 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200330 goto error;
331 }
Michal Vasko32ca49b2023-02-17 15:11:35 +0100332 } else if ((prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
333 if (!prev_prefix && is_abs) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200334 /* the first node must have a prefix */
335 if (!strnstr(cur_node, ":", cur_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100336 LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200337 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200338 goto error;
339 }
340
341 /* remember the first prefix */
342 prev_prefix = cur_node;
Michal Vasko32ca49b2023-02-17 15:11:35 +0100343 } else if (prev_prefix && (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) {
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200344 /* the prefix must be different, if any */
345 ptr = strnstr(cur_node, ":", cur_len);
346 if (ptr) {
347 if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100348 LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200349 ret = LY_EVALID;
Michal Vasko8b06a5e2020-08-06 12:13:08 +0200350 goto error;
351 }
352
353 /* remember this next prefix */
354 prev_prefix = cur_node;
355 }
356 }
Michal Vasko004d3152020-06-11 19:59:22 +0200357 }
358
359 ++tok_idx;
360
361 /* Predicate* */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200362 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200363
Radek Krejci0f969882020-08-21 16:56:47 +0200364 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +0200365 } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
366
367 /* trailing token check */
368 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100369 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 +0200370 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200371 goto error;
372 }
373
374 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100375
Radek Krejciddace2c2021-01-08 11:30:56 +0100376 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200377 return LY_SUCCESS;
378
379error:
380 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100381 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200382 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200383}
384
385LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200386ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
Michal Vasko32ca49b2023-02-17 15:11:35 +0100387 size_t path_len, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr)
Michal Vasko004d3152020-06-11 19:59:22 +0200388{
Radek Krejcif03a9e22020-09-18 20:09:31 +0200389 LY_ERR ret = LY_SUCCESS;
390 struct lyxp_expr *exp = NULL;
Michal Vaskodd528af2022-08-08 14:35:07 +0200391 uint32_t tok_idx;
Michal Vasko004d3152020-06-11 19:59:22 +0200392
393 assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
394 assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
395
Radek Krejciddace2c2021-01-08 11:30:56 +0100396 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100397
Michal Vaskob01983e2023-04-24 10:43:13 +0200398 /* parse as a generic XPath expression, reparse is performed manually */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200399 LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200400 tok_idx = 0;
401
Michal Vaskob01983e2023-04-24 10:43:13 +0200402 /* alloc empty repeat (only '=', filled manually) */
403 exp->repeat = calloc(exp->size, sizeof *exp->repeat);
404 LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
405
Radek Krejcif03a9e22020-09-18 20:09:31 +0200406 LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
Michal Vasko004d3152020-06-11 19:59:22 +0200407
408 /* trailing token check */
409 if (exp->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100410 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
Michal Vasko69730152020-10-09 16:30:07 +0200411 exp->expr + exp->tok_pos[tok_idx]);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200412 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200413 goto error;
414 }
415
416 *expr = exp;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100417
Radek Krejciddace2c2021-01-08 11:30:56 +0100418 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200419 return LY_SUCCESS;
420
421error:
422 lyxp_expr_free(ctx, exp);
Radek Krejciddace2c2021-01-08 11:30:56 +0100423 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200424 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200425}
426
427/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200428 * @brief Parse NameTest and get the corresponding schema node.
Michal Vasko004d3152020-06-11 19:59:22 +0200429 *
Michal Vasko00cbf532020-06-15 13:58:47 +0200430 * @param[in] ctx libyang context.
Michal Vasko6b26e742020-07-17 15:02:10 +0200431 * @param[in] cur_node Optional current (original context) node.
Radek Krejci84d7fd72021-07-14 18:32:21 +0200432 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
433 * and ::LY_VALUE_SCHEMA_RESOLVED.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200434 * @param[in] prev_ctx_node Previous context node.
Michal Vasko004d3152020-06-11 19:59:22 +0200435 * @param[in] expr Parsed path.
436 * @param[in] tok_idx Index in @p expr.
Michal Vasko004d3152020-06-11 19:59:22 +0200437 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200438 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko8cc3f662022-03-29 11:25:51 +0200439 * @param[in] top_ext Optional top-level extension to use for searching the schema node.
440 * @param[in] getnext_opts Options to be used for ::lys_getnext() calls.
441 * @param[out] snode Resolved schema node.
442 * @param[out] ext Optional extension instance of @p snode, if any.
Michal Vasko004d3152020-06-11 19:59:22 +0200443 * @return LY_ERR value.
444 */
445static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200446ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskodd528af2022-08-08 14:35:07 +0200447 const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint32_t tok_idx, LY_VALUE_FORMAT format,
Michal Vasko8cc3f662022-03-29 11:25:51 +0200448 void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
449 struct lysc_ext_instance **ext)
Michal Vasko004d3152020-06-11 19:59:22 +0200450{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100451 LY_ERR ret;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200452 const struct lys_module *mod = NULL;
453 struct lysc_ext_instance *e = NULL;
454 const char *pref, *name;
455 size_t len, name_len;
Michal Vasko004d3152020-06-11 19:59:22 +0200456
457 assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
458
Michal Vasko8cc3f662022-03-29 11:25:51 +0200459 *snode = NULL;
460 if (ext) {
461 *ext = NULL;
462 }
463
Michal Vasko004d3152020-06-11 19:59:22 +0200464 /* get prefix */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200465 if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
466 len = pref - (expr->expr + expr->tok_pos[tok_idx]);
467 pref = expr->expr + expr->tok_pos[tok_idx];
468 } else {
469 len = 0;
470 }
Michal Vasko004d3152020-06-11 19:59:22 +0200471
Michal Vasko8cc3f662022-03-29 11:25:51 +0200472 /* set name */
473 if (pref) {
474 name = pref + len + 1;
475 name_len = expr->tok_len[tok_idx] - len - 1;
476 } else {
477 name = expr->expr + expr->tok_pos[tok_idx];
478 name_len = expr->tok_len[tok_idx];
479 }
480
481 /* find node module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200482 if (pref) {
Radek Krejciddace2c2021-01-08 11:30:56 +0100483 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100484
Michal Vasko35b29622022-07-22 14:12:56 +0200485 mod = ly_resolve_prefix(prev_ctx_node ? prev_ctx_node->module->ctx : ctx, pref, len, format, prefix_data);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200486 if ((!mod || !mod->implemented) && prev_ctx_node) {
487 /* check for nested ext data */
488 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
489 if (!ret) {
490 goto success;
491 } else if (ret != LY_ENOT) {
492 goto error;
493 }
494 }
495
496 if (!mod) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100497 LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
Radek Krejci422afb12021-03-04 16:38:16 +0100498 (int)len, pref, ly_format2str(format));
Michal Vasko825a0442021-04-16 16:11:53 +0200499 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100500 goto error;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200501 } else if (!mod->implemented) {
502 LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
Michal Vaskoed725d72021-06-23 12:03:45 +0200503 ret = LY_EVALID;
504 goto error;
Michal Vasko004d3152020-06-11 19:59:22 +0200505 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100506
Radek Krejciddace2c2021-01-08 11:30:56 +0100507 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko004d3152020-06-11 19:59:22 +0200508 } else {
509 switch (format) {
Radek Krejci8df109d2021-04-23 12:19:08 +0200510 case LY_VALUE_SCHEMA:
511 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200512 if (!cur_mod) {
513 LOGINT_RET(ctx);
514 }
515 /* use current module */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200516 mod = cur_mod;
Michal Vasko004d3152020-06-11 19:59:22 +0200517 break;
Radek Krejci8df109d2021-04-23 12:19:08 +0200518 case LY_VALUE_JSON:
Michal Vasko79228af2021-08-26 14:44:28 +0200519 case LY_VALUE_LYB:
Michal Vasko004d3152020-06-11 19:59:22 +0200520 if (!prev_ctx_node) {
Michal Vasko00cbf532020-06-15 13:58:47 +0200521 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200522 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200523 /* inherit module of the previous node */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200524 mod = prev_ctx_node->module;
Michal Vasko004d3152020-06-11 19:59:22 +0200525 break;
Radek Krejci224d4b42021-04-23 13:54:59 +0200526 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +0200527 case LY_VALUE_XML:
Michal Vaskoddd76592022-01-17 13:34:48 +0100528 case LY_VALUE_STR_NS:
Radek Krejcif9943642021-04-26 10:18:21 +0200529 /* not really defined or accepted */
Michal Vasko00cbf532020-06-15 13:58:47 +0200530 LOGINT_RET(ctx);
Michal Vasko004d3152020-06-11 19:59:22 +0200531 }
532 }
533
Michal Vasko8cc3f662022-03-29 11:25:51 +0200534 /* find schema node */
535 if (!prev_ctx_node && top_ext) {
536 *snode = lysc_ext_find_node(top_ext, mod, name, name_len, 0, getnext_opts);
Michal Vasko004d3152020-06-11 19:59:22 +0200537 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200538 *snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
539 if (!(*snode) && prev_ctx_node) {
540 ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
541 LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
542 }
543 }
544 if (!(*snode)) {
545 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
546 return LY_ENOTFOUND;
Michal Vasko004d3152020-06-11 19:59:22 +0200547 }
548
Michal Vasko8cc3f662022-03-29 11:25:51 +0200549success:
550 if (ext) {
551 *ext = e;
552 }
Michal Vasko004d3152020-06-11 19:59:22 +0200553 return LY_SUCCESS;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100554
555error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100556 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Michal Vasko825a0442021-04-16 16:11:53 +0200557 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200558}
559
560LY_ERR
Michal Vasko6b26e742020-07-17 15:02:10 +0200561ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
Michal Vaskodd528af2022-08-08 14:35:07 +0200562 const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
Michal Vasko90189962023-02-28 12:10:34 +0100563 void *prefix_data, struct ly_path_predicate **predicates)
Michal Vasko004d3152020-06-11 19:59:22 +0200564{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100565 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200566 struct ly_path_predicate *p;
567 const struct lysc_node *key;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200568 const char *val;
569 size_t val_len, key_count;
Michal Vasko004d3152020-06-11 19:59:22 +0200570
Michal Vasko00cbf532020-06-15 13:58:47 +0200571 assert(ctx && ctx_node);
572
Radek Krejciddace2c2021-01-08 11:30:56 +0100573 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100574
Michal Vasko90189962023-02-28 12:10:34 +0100575 *predicates = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200576
Michal Vasko004d3152020-06-11 19:59:22 +0200577 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200578 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100579 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200580 }
581
582 if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
583 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100584 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200585 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100586 ret = LY_EVALID;
587 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200588 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100589 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200590 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100591 ret = LY_EVALID;
592 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200593 }
594
595 do {
596 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200597 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
598 NULL, 0, &key, NULL));
599 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100600 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
601 key->name);
602 ret = LY_EVALID;
603 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200604 }
605 ++(*tok_idx);
606
Michal Vasko90189962023-02-28 12:10:34 +0100607 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100608 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200609 p->key = key;
610
611 /* '=' */
612 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
613 ++(*tok_idx);
614
Michal Vasko90189962023-02-28 12:10:34 +0100615 /* Literal, Number, or VariableReference */
616 if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
617 /* store the variable name */
618 p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
619 LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
620
621 p->type = LY_PATH_PREDTYPE_LIST_VAR;
622 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200623 } else {
Michal Vasko90189962023-02-28 12:10:34 +0100624 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
625 /* skip quotes */
626 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
627 val_len = expr->tok_len[*tok_idx] - 2;
628 } else {
629 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
630 val = expr->expr + expr->tok_pos[*tok_idx];
631 val_len = expr->tok_len[*tok_idx];
632 }
633
634 /* store the value */
635 LOG_LOCSET(key, NULL, NULL, NULL);
636 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format,
637 prefix_data, LYD_HINT_DATA, key, NULL);
638 LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
639 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
640
641 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
642 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
643
644 p->type = LY_PATH_PREDTYPE_LIST;
645 ++(*tok_idx);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200646 }
647
Michal Vasko004d3152020-06-11 19:59:22 +0200648 /* ']' */
649 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
650 ++(*tok_idx);
651
652 /* another predicate follows? */
653 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
654
655 /* check that all keys were set */
656 key_count = 0;
Michal Vasko544e58a2021-01-28 14:33:41 +0100657 for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
Michal Vasko004d3152020-06-11 19:59:22 +0200658 ++key_count;
659 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200660 if (LY_ARRAY_COUNT(*predicates) != key_count) {
Michal Vasko004d3152020-06-11 19:59:22 +0200661 /* names (keys) are unique - it was checked when parsing */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100662 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200663 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Michal Vasko90189962023-02-28 12:10:34 +0100664 ly_path_predicates_free(ctx, *predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200665 *predicates = NULL;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100666 ret = LY_EVALID;
667 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200668 }
669
670 } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
671 if (ctx_node->nodetype != LYS_LEAFLIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100672 LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200673 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100674 ret = LY_EVALID;
675 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200676 }
677 ++(*tok_idx);
678
679 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100680 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100681 p->type = LY_PATH_PREDTYPE_LEAFLIST;
Michal Vasko004d3152020-06-11 19:59:22 +0200682
683 /* '=' */
684 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
685 ++(*tok_idx);
686
Michal Vasko4911eeb2021-06-28 11:23:05 +0200687 /* Literal or Number */
688 assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER));
689 if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) {
690 /* skip quotes */
691 val = expr->expr + expr->tok_pos[*tok_idx] + 1;
692 val_len = expr->tok_len[*tok_idx] - 2;
693 } else {
694 val = expr->expr + expr->tok_pos[*tok_idx];
695 val_len = expr->tok_len[*tok_idx];
696 }
697
Michal Vasko004d3152020-06-11 19:59:22 +0200698 /* store the value */
Radek Krejciddace2c2021-01-08 11:30:56 +0100699 LOG_LOCSET(ctx_node, NULL, NULL, NULL);
Michal Vasko4911eeb2021-06-28 11:23:05 +0200700 ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format,
701 prefix_data, LYD_HINT_DATA, ctx_node, NULL);
Radek Krejciddace2c2021-01-08 11:30:56 +0100702 LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
Michal Vasko55b84812021-05-11 09:23:58 +0200703 LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200704 ++(*tok_idx);
705
Michal Vaskoae875662020-10-21 10:33:17 +0200706 /* "allocate" the type to avoid problems when freeing the value after the type was freed */
Michal Vasko04338d92021-09-01 07:58:14 +0200707 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
Michal Vaskoae875662020-10-21 10:33:17 +0200708
Michal Vasko004d3152020-06-11 19:59:22 +0200709 /* ']' */
710 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
711 ++(*tok_idx);
712 } else {
713 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
714 if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100715 ret = LY_EVALID;
716 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200717 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100718 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200719 } else if (ctx_node->flags & LYS_CONFIG_W) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100720 ret = LY_EVALID;
721 LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200722 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100723 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200724 }
Michal Vasko004d3152020-06-11 19:59:22 +0200725
726 /* new predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100727 LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
Michal Vasko90189962023-02-28 12:10:34 +0100728 p->type = LY_PATH_PREDTYPE_POSITION;
Michal Vasko004d3152020-06-11 19:59:22 +0200729
730 /* syntax was already checked */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200731 p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC);
Michal Vasko00cbf532020-06-15 13:58:47 +0200732 ++(*tok_idx);
Michal Vasko004d3152020-06-11 19:59:22 +0200733
734 /* ']' */
735 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
736 ++(*tok_idx);
737 }
738
Radek Krejci2efc45b2020-12-22 16:25:44 +0100739cleanup:
Radek Krejciddace2c2021-01-08 11:30:56 +0100740 LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100741 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200742}
743
744/**
745 * @brief Compile leafref predicate. Actually, it is only checked.
746 *
747 * @param[in] ctx_node Context node, node for which the predicate is defined.
748 * @param[in] cur_node Current (original context) node.
749 * @param[in] expr Parsed path.
750 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
Michal Vasko004d3152020-06-11 19:59:22 +0200751 * @param[in] format Format of the path.
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200752 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +0200753 * @return LY_ERR value.
754 */
755static LY_ERR
756ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
Michal Vaskodd528af2022-08-08 14:35:07 +0200757 const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
Michal Vasko004d3152020-06-11 19:59:22 +0200758{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100759 LY_ERR ret = LY_SUCCESS;
Michal Vasko004d3152020-06-11 19:59:22 +0200760 const struct lysc_node *key, *node, *node2;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100761 struct ly_ctx *ctx = cur_node->module->ctx;
762
Michal Vasko004d3152020-06-11 19:59:22 +0200763 if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
Radek Krejcif6a11002020-08-21 13:29:07 +0200764 /* '[', no predicate */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100765 goto cleanup; /* LY_SUCCESS */
Michal Vasko004d3152020-06-11 19:59:22 +0200766 }
767
768 if (ctx_node->nodetype != LYS_LIST) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100769 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200770 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100771 ret = LY_EVALID;
772 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200773 } else if (ctx_node->flags & LYS_KEYLESS) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100774 LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200775 lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100776 ret = LY_EVALID;
777 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200778 }
779
780 do {
781 /* NameTest, find the key */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200782 ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
783 NULL, 0, &key, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100784 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200785 if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100786 LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200787 lys_nodetype2str(key->nodetype), key->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100788 ret = LY_EVALID;
789 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200790 }
791 ++(*tok_idx);
792
793 /* we are not actually compiling, throw the key away */
794 (void)key;
795
796 /* '=' */
797 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
798 ++(*tok_idx);
799
800 /* FuncName */
801 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
802 ++(*tok_idx);
803
804 /* evaluating from the "current()" node */
805 node = cur_node;
806
807 /* '(' */
808 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
809 ++(*tok_idx);
810
811 /* ')' */
812 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
813 ++(*tok_idx);
814
815 do {
816 /* '/' */
817 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
818 ++(*tok_idx);
819
820 /* go to parent */
821 if (!node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100822 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
823 ret = LY_EVALID;
824 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200825 }
826 node = lysc_data_parent(node);
827
828 /* '..' */
829 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
830 ++(*tok_idx);
831 } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
832
833 do {
834 /* '/' */
835 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
836 ++(*tok_idx);
837
838 /* NameTest */
839 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200840 LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
841 prefix_data, NULL, 0, &node2, NULL));
Michal Vasko004d3152020-06-11 19:59:22 +0200842 node = node2;
843 ++(*tok_idx);
844 } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
845
846 /* check the last target node */
847 if (node->nodetype != LYS_LEAF) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100848 LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200849 lys_nodetype2str(node->nodetype), node->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100850 ret = LY_EVALID;
851 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200852 }
853
854 /* we are not actually compiling, throw the rightside node away */
855 (void)node;
856
857 /* ']' */
858 assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
859 ++(*tok_idx);
860
Radek Krejci0f969882020-08-21 16:56:47 +0200861 /* another predicate follows? */
Michal Vasko004d3152020-06-11 19:59:22 +0200862 } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
863
Radek Krejci2efc45b2020-12-22 16:25:44 +0100864cleanup:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200865 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +0200866}
867
Michal Vaskoed725d72021-06-23 12:03:45 +0200868/**
869 * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled.
870 *
871 * @param[in] ctx libyang context.
872 * @param[in] cur_mod Current module of the path (where it was "instantiated"), ignored of @p lref. Used for nodes
Radek Krejci84d7fd72021-07-14 18:32:21 +0200873 * without a prefix for ::LY_VALUE_SCHEMA and ::LY_VALUE_SCHEMA_RESOLVED format.
Michal Vaskoed725d72021-06-23 12:03:45 +0200874 * @param[in] ctx_node Optional context node, mandatory of @p lref.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200875 * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find the top-level
Michal Vaskoed725d72021-06-23 12:03:45 +0200876 * node inside the extension instance instead of a module. Note that this is the case not only if the @p ctx_node is NULL,
877 * but also if the relative path starting in @p ctx_node reaches the document root via double dots.
878 * @param[in] expr Parsed path.
879 * @param[in] lref Whether leafref is being compiled or not.
880 * @param[in] oper Oper option (@ref path_oper_options).
881 * @param[in] target Target option (@ref path_target_options).
Michal Vasko0884d212021-10-14 09:21:46 +0200882 * @param[in] limit_access_tree Whether to limit accessible tree as described in
883 * [XPath context](https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1).
Michal Vaskoed725d72021-06-23 12:03:45 +0200884 * @param[in] format Format of the path.
885 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
Michal Vaskoed725d72021-06-23 12:03:45 +0200886 * @param[out] path Compiled path.
887 * @return LY_ERECOMPILE, only if @p lref.
888 * @return LY_ERR value.
889 */
890static LY_ERR
891_ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko32ca49b2023-02-17 15:11:35 +0100892 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint16_t oper, uint16_t target,
Michal Vasko0884d212021-10-14 09:21:46 +0200893 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vasko004d3152020-06-11 19:59:22 +0200894{
895 LY_ERR ret = LY_SUCCESS;
Michal Vaskodd528af2022-08-08 14:35:07 +0200896 uint32_t tok_idx = 0, getnext_opts;
Michal Vasko6b26e742020-07-17 15:02:10 +0200897 const struct lysc_node *node2, *cur_node, *op;
Michal Vasko00cbf532020-06-15 13:58:47 +0200898 struct ly_path *p = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200899 struct lysc_ext_instance *ext = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200900
Michal Vasko00cbf532020-06-15 13:58:47 +0200901 assert(ctx);
Michal Vaskoed725d72021-06-23 12:03:45 +0200902 assert(!lref || ctx_node);
Michal Vasko00cbf532020-06-15 13:58:47 +0200903 assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
904 assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
Michal Vasko004d3152020-06-11 19:59:22 +0200905
Michal Vasko0884d212021-10-14 09:21:46 +0200906 if (!limit_access_tree) {
907 op = NULL;
908 } else {
909 /* find operation, if we are in any */
910 for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
911 }
Michal Vasko6b26e742020-07-17 15:02:10 +0200912
Radek Krejci2efc45b2020-12-22 16:25:44 +0100913 *path = NULL;
914
Michal Vasko6b26e742020-07-17 15:02:10 +0200915 /* remember original context node */
916 cur_node = ctx_node;
Michal Vasko62225e22022-08-05 10:06:50 +0200917 LOG_LOCSET(cur_node, NULL, NULL, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +0200918
Michal Vasko00cbf532020-06-15 13:58:47 +0200919 if (oper == LY_PATH_OPER_OUTPUT) {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100920 getnext_opts = LYS_GETNEXT_OUTPUT;
Michal Vasko00cbf532020-06-15 13:58:47 +0200921 } else {
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100922 getnext_opts = 0;
Michal Vasko00cbf532020-06-15 13:58:47 +0200923 }
924
Michal Vasko004d3152020-06-11 19:59:22 +0200925 if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
926 /* absolute path */
927 ctx_node = NULL;
928
929 ++tok_idx;
930 } else {
931 /* relative path */
Michal Vasko80239792021-11-02 11:48:32 +0100932 if (!ctx_node) {
933 LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
934 ret = LY_EVALID;
935 goto cleanup;
936 }
937
938 /* go up the parents for leafref */
Michal Vaskoed725d72021-06-23 12:03:45 +0200939 while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
Michal Vasko004d3152020-06-11 19:59:22 +0200940 if (!ctx_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100941 LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
Michal Vasko14424ba2020-12-09 18:09:51 +0100942 ret = LY_EVALID;
943 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +0200944 }
945
946 /* get parent */
947 ctx_node = lysc_data_parent(ctx_node);
948
949 ++tok_idx;
950
951 assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
952 ++tok_idx;
953 }
Michal Vasko004d3152020-06-11 19:59:22 +0200954 }
955
956 do {
Michal Vasko00cbf532020-06-15 13:58:47 +0200957 /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
Michal Vaskoed725d72021-06-23 12:03:45 +0200958 if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100959 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +0200960 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +0100961 ret = LY_EVALID;
962 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +0200963 }
964
Michal Vasko14424ba2020-12-09 18:09:51 +0100965 /* NameTest */
966 LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
967
Michal Vasko8cc3f662022-03-29 11:25:51 +0200968 /* get schema node */
969 LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
970 top_ext, getnext_opts, &node2, &ext), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200971 ++tok_idx;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200972 if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
973 LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
Radek Krejci8de005f2020-06-25 17:02:07 +0200974 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +0200975 goto cleanup;
976 }
977 ctx_node = node2;
978
979 /* new path segment */
Michal Vasko00cbf532020-06-15 13:58:47 +0200980 LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200981 p->node = ctx_node;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200982 p->ext = ext;
Michal Vasko004d3152020-06-11 19:59:22 +0200983
984 /* compile any predicates */
Michal Vaskoed725d72021-06-23 12:03:45 +0200985 if (lref) {
Michal Vasko24fc4d12021-07-12 14:41:20 +0200986 ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
Michal Vasko004d3152020-06-11 19:59:22 +0200987 } else {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200988 ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
Michal Vasko90189962023-02-28 12:10:34 +0100989 &p->predicates);
Michal Vasko004d3152020-06-11 19:59:22 +0200990 }
991 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +0200992 } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
993
Michal Vasko14424ba2020-12-09 18:09:51 +0100994 /* check leftover tokens */
995 if (tok_idx < expr->used) {
Michal Vasko49fec8e2022-05-24 10:28:33 +0200996 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
Michal Vasko14424ba2020-12-09 18:09:51 +0100997 ret = LY_EVALID;
998 goto cleanup;
999 }
1000
Michal Vasko00cbf532020-06-15 13:58:47 +02001001 /* check last compiled node */
Michal Vaskoed725d72021-06-23 12:03:45 +02001002 if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001003 LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
Michal Vasko69730152020-10-09 16:30:07 +02001004 lys_nodetype2str(p->node->nodetype), p->node->name);
Michal Vasko14424ba2020-12-09 18:09:51 +01001005 ret = LY_EVALID;
1006 goto cleanup;
Michal Vasko00cbf532020-06-15 13:58:47 +02001007 }
1008
Michal Vasko004d3152020-06-11 19:59:22 +02001009cleanup:
1010 if (ret) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001011 ly_path_free(ctx, *path);
Michal Vasko004d3152020-06-11 19:59:22 +02001012 *path = NULL;
1013 }
Radek Krejciddace2c2021-01-08 11:30:56 +01001014 LOG_LOCBACK(1, 0, 0, 0);
Michal Vasko8cc3f662022-03-29 11:25:51 +02001015 return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
Michal Vasko004d3152020-06-11 19:59:22 +02001016}
1017
1018LY_ERR
Michal Vaskoed725d72021-06-23 12:03:45 +02001019ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
Michal Vasko32ca49b2023-02-17 15:11:35 +01001020 const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target,
Michal Vasko0884d212021-10-14 09:21:46 +02001021 ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001022{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001023 return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format,
1024 prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001025}
1026
1027LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +02001028ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *top_ext,
Michal Vasko32ca49b2023-02-17 15:11:35 +01001029 const struct lyxp_expr *expr, uint16_t oper, uint16_t target, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko24fc4d12021-07-12 14:41:20 +02001030 struct ly_path **path)
Michal Vaskoed725d72021-06-23 12:03:45 +02001031{
Michal Vasko8cc3f662022-03-29 11:25:51 +02001032 return _ly_path_compile(ctx, ctx_node->module, ctx_node, top_ext, expr, 1, oper, target, 1, format, prefix_data, path);
Michal Vaskoed725d72021-06-23 12:03:45 +02001033}
1034
1035LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001036ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars,
1037 LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match)
Michal Vasko004d3152020-06-11 19:59:22 +02001038{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001039 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoe43e21f2022-06-07 12:26:36 +02001040 struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target;
Michal Vasko004d3152020-06-11 19:59:22 +02001041 uint64_t pos;
1042
1043 assert(path && start);
1044
1045 if (lysc_data_parent(path[0].node)) {
1046 /* relative path, start from the parent children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001047 start = lyd_child(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001048 } else {
1049 /* absolute path, start from the first top-level sibling */
1050 while (start->parent) {
Michal Vasko9e685082021-01-29 14:49:09 +01001051 start = lyd_parent(start);
Michal Vasko004d3152020-06-11 19:59:22 +02001052 }
1053 while (start->prev->next) {
1054 start = start->prev;
1055 }
1056 }
1057
1058 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001059 if (path[u].predicates) {
1060 switch (path[u].predicates[0].type) {
1061 case LY_PATH_PREDTYPE_POSITION:
1062 /* we cannot use hashes and want an instance on a specific position */
1063 pos = 1;
1064 node = NULL;
1065 LYD_LIST_FOR_INST(start, path[u].node, elem) {
1066 if (pos == path[u].predicates[0].position) {
1067 node = elem;
1068 break;
1069 }
1070 ++pos;
Michal Vasko004d3152020-06-11 19:59:22 +02001071 }
Michal Vasko90189962023-02-28 12:10:34 +01001072 break;
1073 case LY_PATH_PREDTYPE_LEAFLIST:
1074 /* we will use hashes to find one leaf-list instance */
1075 LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
1076 lyd_find_sibling_first(start, target, &node);
1077 lyd_free_tree(target);
1078 break;
1079 case LY_PATH_PREDTYPE_LIST_VAR:
1080 case LY_PATH_PREDTYPE_LIST:
1081 /* we will use hashes to find one list instance */
1082 LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target));
1083 lyd_find_sibling_first(start, target, &node);
1084 lyd_free_tree(target);
1085 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001086 }
Michal Vasko90189962023-02-28 12:10:34 +01001087 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001088 /* we will use hashes to find one any/container/leaf instance */
1089 lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
Michal Vasko004d3152020-06-11 19:59:22 +02001090 }
1091
1092 if (!node) {
1093 /* no matching nodes */
1094 break;
1095 }
1096
Michal Vasko00cbf532020-06-15 13:58:47 +02001097 /* rememeber previous node */
1098 prev_node = node;
1099
Michal Vasko004d3152020-06-11 19:59:22 +02001100 /* next path segment, if any */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001101 start = lyd_child(node);
Michal Vasko004d3152020-06-11 19:59:22 +02001102 }
1103
Michal Vasko004d3152020-06-11 19:59:22 +02001104 if (node) {
Michal Vasko00cbf532020-06-15 13:58:47 +02001105 /* we have found the full path */
1106 if (path_idx) {
1107 *path_idx = u;
1108 }
1109 if (match) {
1110 *match = node;
1111 }
Michal Vasko004d3152020-06-11 19:59:22 +02001112 return LY_SUCCESS;
Michal Vasko00cbf532020-06-15 13:58:47 +02001113
1114 } else if (prev_node) {
1115 /* we have found only some partial match */
1116 if (path_idx) {
1117 *path_idx = u - 1;
1118 }
1119 if (match) {
1120 *match = prev_node;
1121 }
1122 return LY_EINCOMPLETE;
1123 }
1124
1125 /* we have not found any nodes */
1126 if (path_idx) {
1127 *path_idx = 0;
1128 }
1129 if (match) {
1130 *match = NULL;
1131 }
1132 return LY_ENOTFOUND;
1133}
1134
1135LY_ERR
Michal Vasko90189962023-02-28 12:10:34 +01001136ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, struct lyd_node **match)
Michal Vasko00cbf532020-06-15 13:58:47 +02001137{
1138 LY_ERR ret;
1139 struct lyd_node *m;
1140
Michal Vasko90189962023-02-28 12:10:34 +01001141 ret = ly_path_eval_partial(path, start, vars, NULL, &m);
Michal Vasko00cbf532020-06-15 13:58:47 +02001142
1143 if (ret == LY_SUCCESS) {
1144 /* last node was found */
1145 if (match) {
1146 *match = m;
1147 }
1148 return LY_SUCCESS;
1149 }
1150
1151 /* not a full match */
1152 if (match) {
1153 *match = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02001154 }
1155 return LY_ENOTFOUND;
1156}
1157
1158LY_ERR
1159ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1160{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001161 LY_ARRAY_COUNT_TYPE u, v;
Michal Vasko004d3152020-06-11 19:59:22 +02001162
1163 if (!path) {
1164 return LY_SUCCESS;
1165 }
1166
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001167 LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001168 LY_ARRAY_FOR(path, u) {
1169 LY_ARRAY_INCREMENT(*dup);
1170 (*dup)[u].node = path[u].node;
1171 if (path[u].predicates) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001172 LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02001173 LY_ARRAY_FOR(path[u].predicates, v) {
1174 struct ly_path_predicate *pred = &path[u].predicates[v];
1175
1176 LY_ARRAY_INCREMENT((*dup)[u].predicates);
Michal Vasko90189962023-02-28 12:10:34 +01001177 (*dup)[u].predicates[v].type = pred->type;
1178
1179 switch (pred->type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001180 case LY_PATH_PREDTYPE_POSITION:
1181 /* position-predicate */
1182 (*dup)[u].predicates[v].position = pred->position;
1183 break;
1184 case LY_PATH_PREDTYPE_LIST:
1185 case LY_PATH_PREDTYPE_LEAFLIST:
1186 /* key-predicate or leaf-list-predicate */
1187 (*dup)[u].predicates[v].key = pred->key;
Michal Vasko004d3152020-06-11 19:59:22 +02001188 pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
Michal Vasko04338d92021-09-01 07:58:14 +02001189 LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount);
Michal Vasko004d3152020-06-11 19:59:22 +02001190 break;
Michal Vasko90189962023-02-28 12:10:34 +01001191 case LY_PATH_PREDTYPE_LIST_VAR:
1192 /* key-predicate with a variable */
1193 (*dup)[u].predicates[v].key = pred->key;
1194 (*dup)[u].predicates[v].variable = strdup(pred->variable);
Michal Vasko004d3152020-06-11 19:59:22 +02001195 break;
1196 }
1197 }
1198 }
1199 }
1200
1201 return LY_SUCCESS;
1202}
1203
1204void
Michal Vasko90189962023-02-28 12:10:34 +01001205ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates)
Michal Vasko004d3152020-06-11 19:59:22 +02001206{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001207 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoc636ea42022-09-16 10:20:31 +02001208 struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx};
Michal Vasko004d3152020-06-11 19:59:22 +02001209
1210 if (!predicates) {
1211 return;
1212 }
1213
1214 LY_ARRAY_FOR(predicates, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001215 switch (predicates[u].type) {
Michal Vasko004d3152020-06-11 19:59:22 +02001216 case LY_PATH_PREDTYPE_POSITION:
Michal Vasko004d3152020-06-11 19:59:22 +02001217 /* nothing to free */
1218 break;
1219 case LY_PATH_PREDTYPE_LIST:
Michal Vasko004d3152020-06-11 19:59:22 +02001220 case LY_PATH_PREDTYPE_LEAFLIST:
Michal Vaskoae875662020-10-21 10:33:17 +02001221 if (predicates[u].value.realtype) {
1222 predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
Michal Vaskoc636ea42022-09-16 10:20:31 +02001223 lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype);
Michal Vaskoae875662020-10-21 10:33:17 +02001224 }
Michal Vasko004d3152020-06-11 19:59:22 +02001225 break;
Michal Vasko90189962023-02-28 12:10:34 +01001226 case LY_PATH_PREDTYPE_LIST_VAR:
1227 free(predicates[u].variable);
1228 break;
Michal Vasko004d3152020-06-11 19:59:22 +02001229 }
1230 }
1231 LY_ARRAY_FREE(predicates);
1232}
1233
1234void
1235ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1236{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001237 LY_ARRAY_COUNT_TYPE u;
Michal Vasko004d3152020-06-11 19:59:22 +02001238
Michal Vasko55b84812021-05-11 09:23:58 +02001239 if (!path) {
1240 return;
1241 }
1242
Michal Vasko004d3152020-06-11 19:59:22 +02001243 LY_ARRAY_FOR(path, u) {
Michal Vasko90189962023-02-28 12:10:34 +01001244 ly_path_predicates_free(ctx, path[u].predicates);
Michal Vasko004d3152020-06-11 19:59:22 +02001245 }
1246 LY_ARRAY_FREE(path);
1247}