blob: e84aeff08b44f5f93db83e682f508b0acbe48f38 [file] [log] [blame]
Radek Krejcib1646a92018-11-02 16:08:26 +01001/**
2 * @file xpath.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief YANG XPath evaluation functions
5 *
Michal Vasko49fec8e2022-05-24 10:28:33 +02006 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcib1646a92018-11-02 16:08:26 +01007 *
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 */
Christian Hopps32874e12021-05-01 09:43:54 -040014#define _GNU_SOURCE /* asprintf, strdup */
Radek Krejcib1646a92018-11-02 16:08:26 +010015
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#include "xpath.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010017
Radek Krejci535ea9f2020-05-29 16:01:05 +020018#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010019#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include <errno.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020021#include <math.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdint.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010023#include <stdio.h>
24#include <stdlib.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010025#include <string.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010026
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020028#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020029#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "dict.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "hash_table.h"
Radek Krejci47fab892020-11-05 17:02:41 +010032#include "out.h"
Radek Krejci7931b192020-06-25 17:05:03 +020033#include "parser_data.h"
Michal Vasko004d3152020-06-11 19:59:22 +020034#include "path.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020035#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "printer_data.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020037#include "schema_compile_node.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020038#include "tree.h"
Radek Krejci77114102021-03-10 15:21:57 +010039#include "tree_data.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020040#include "tree_data_internal.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010041#include "tree_edit.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020042#include "tree_schema_internal.h"
43#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020044
aPiecekbf968d92021-05-27 14:35:05 +020045static LY_ERR reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth);
Michal Vasko40308e72020-10-20 16:38:40 +020046static LY_ERR eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype,
47 struct lyxp_set *set, uint32_t options);
Michal Vaskofe1af042022-07-29 14:58:59 +020048static LY_ERR moveto_resolve_model(const char **qname, uint32_t *qname_len, const struct lyxp_set *set,
Michal Vasko93923692021-05-07 15:28:02 +020049 const struct lysc_node *ctx_scnode, const struct lys_module **moveto_mod);
Michal Vasko47da6562022-07-14 15:43:15 +020050static LY_ERR moveto_axis_node_next(const struct lyd_node **iter, enum lyxp_node_type *iter_type,
51 const struct lyd_node *node, enum lyxp_node_type node_type, enum lyxp_axis axis, struct lyxp_set *set);
Michal Vasko49fec8e2022-05-24 10:28:33 +020052static LY_ERR moveto_node(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname,
53 enum lyxp_axis axis, uint32_t options);
54static LY_ERR moveto_scnode(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname,
55 enum lyxp_axis axis, uint32_t options);
Michal Vasko8abcecc2022-07-28 09:55:01 +020056static LY_ERR moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op);
Michal Vasko03ff5a72019-09-11 13:49:33 +020057
aPiecek96dc1e32021-10-08 15:45:59 +020058/* Functions are divided into the following basic classes:
59 *
60 * (re)parse functions:
61 * Parse functions parse the expression into
62 * tokens (syntactic analysis).
63 * Reparse functions perform semantic analysis
64 * (do not save the result, just a check) of
65 * the expression and fill repeat indices.
66 *
67 * warn functions:
68 * Warn functions check specific reasonable conditions for schema XPath
69 * and print a warning if they are not satisfied.
70 *
71 * moveto functions:
72 * They and only they actually change the context (set).
73 *
74 * eval functions:
75 * They execute a parsed XPath expression on some data subtree.
76 */
77
Michal Vasko03ff5a72019-09-11 13:49:33 +020078/**
79 * @brief Print the type of an XPath \p set.
80 *
81 * @param[in] set Set to use.
82 * @return Set type string.
83 */
84static const char *
85print_set_type(struct lyxp_set *set)
86{
87 switch (set->type) {
Michal Vasko03ff5a72019-09-11 13:49:33 +020088 case LYXP_SET_NODE_SET:
89 return "node set";
90 case LYXP_SET_SCNODE_SET:
91 return "schema node set";
92 case LYXP_SET_BOOLEAN:
93 return "boolean";
94 case LYXP_SET_NUMBER:
95 return "number";
96 case LYXP_SET_STRING:
97 return "string";
98 }
99
100 return NULL;
101}
102
Michal Vasko24cddf82020-06-01 08:17:01 +0200103const char *
Michal Vasko49fec8e2022-05-24 10:28:33 +0200104lyxp_token2str(enum lyxp_token tok)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200105{
106 switch (tok) {
107 case LYXP_TOKEN_PAR1:
108 return "(";
109 case LYXP_TOKEN_PAR2:
110 return ")";
111 case LYXP_TOKEN_BRACK1:
112 return "[";
113 case LYXP_TOKEN_BRACK2:
114 return "]";
115 case LYXP_TOKEN_DOT:
116 return ".";
117 case LYXP_TOKEN_DDOT:
118 return "..";
119 case LYXP_TOKEN_AT:
120 return "@";
121 case LYXP_TOKEN_COMMA:
122 return ",";
123 case LYXP_TOKEN_NAMETEST:
124 return "NameTest";
125 case LYXP_TOKEN_NODETYPE:
126 return "NodeType";
aPiecekfba75362021-10-07 12:39:48 +0200127 case LYXP_TOKEN_VARREF:
128 return "VariableReference";
Michal Vasko03ff5a72019-09-11 13:49:33 +0200129 case LYXP_TOKEN_FUNCNAME:
130 return "FunctionName";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200131 case LYXP_TOKEN_OPER_LOG:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200132 return "Operator(Logic)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200133 case LYXP_TOKEN_OPER_EQUAL:
134 return "Operator(Equal)";
135 case LYXP_TOKEN_OPER_NEQUAL:
136 return "Operator(Non-equal)";
137 case LYXP_TOKEN_OPER_COMP:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200138 return "Operator(Comparison)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200139 case LYXP_TOKEN_OPER_MATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200140 return "Operator(Math)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200141 case LYXP_TOKEN_OPER_UNI:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200142 return "Operator(Union)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200143 case LYXP_TOKEN_OPER_PATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200144 return "Operator(Path)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200145 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko14676352020-05-29 11:35:55 +0200146 return "Operator(Recursive Path)";
Michal Vasko03ff5a72019-09-11 13:49:33 +0200147 case LYXP_TOKEN_LITERAL:
148 return "Literal";
149 case LYXP_TOKEN_NUMBER:
150 return "Number";
151 default:
152 LOGINT(NULL);
153 return "";
154 }
155}
156
157/**
Michal Vasko49fec8e2022-05-24 10:28:33 +0200158 * @brief Transform string into an axis.
159 *
160 * @param[in] str String to transform.
161 * @param[in] str_len Length of @p str.
162 * @return Transformed axis.
163 */
164static enum lyxp_axis
165str2axis(const char *str, uint16_t str_len)
166{
167 switch (str_len) {
168 case 4:
169 assert(!strncmp("self", str, str_len));
170 return LYXP_AXIS_SELF;
171 case 5:
172 assert(!strncmp("child", str, str_len));
173 return LYXP_AXIS_CHILD;
174 case 6:
175 assert(!strncmp("parent", str, str_len));
176 return LYXP_AXIS_PARENT;
177 case 8:
178 assert(!strncmp("ancestor", str, str_len));
179 return LYXP_AXIS_ANCESTOR;
180 case 9:
181 if (str[0] == 'a') {
182 assert(!strncmp("attribute", str, str_len));
183 return LYXP_AXIS_ATTRIBUTE;
184 } else if (str[0] == 'f') {
185 assert(!strncmp("following", str, str_len));
186 return LYXP_AXIS_FOLLOWING;
187 } else {
188 assert(!strncmp("preceding", str, str_len));
189 return LYXP_AXIS_PRECEDING;
190 }
191 break;
192 case 10:
193 assert(!strncmp("descendant", str, str_len));
194 return LYXP_AXIS_DESCENDANT;
195 case 16:
196 assert(!strncmp("ancestor-or-self", str, str_len));
197 return LYXP_AXIS_ANCESTOR_OR_SELF;
198 case 17:
199 if (str[0] == 'f') {
200 assert(!strncmp("following-sibling", str, str_len));
201 return LYXP_AXIS_FOLLOWING_SIBLING;
202 } else {
203 assert(!strncmp("preceding-sibling", str, str_len));
204 return LYXP_AXIS_PRECEDING_SIBLING;
205 }
206 break;
207 case 18:
208 assert(!strncmp("descendant-or-self", str, str_len));
209 return LYXP_AXIS_DESCENDANT_OR_SELF;
210 }
211
212 LOGINT(NULL);
213 return 0;
214}
215
216/**
Michal Vasko03ff5a72019-09-11 13:49:33 +0200217 * @brief Print the whole expression \p exp to debug output.
218 *
219 * @param[in] exp Expression to use.
220 */
221static void
Michal Vasko40308e72020-10-20 16:38:40 +0200222print_expr_struct_debug(const struct lyxp_expr *exp)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200223{
Radek Krejcif13b87b2020-12-01 22:02:17 +0100224#define MSG_BUFFER_SIZE 128
225 char tmp[MSG_BUFFER_SIZE];
Michal Vasko1fdd8fa2021-01-08 09:21:45 +0100226 uint32_t i, j;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200227
Radek Krejci52b6d512020-10-12 12:33:17 +0200228 if (!exp || (ly_ll < LY_LLDBG)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200229 return;
230 }
231
232 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
233 for (i = 0; i < exp->used; ++i) {
Michal Vasko49fec8e2022-05-24 10:28:33 +0200234 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", lyxp_token2str(exp->tokens[i]), exp->tok_len[i],
Michal Vasko69730152020-10-09 16:30:07 +0200235 &exp->expr[exp->tok_pos[i]]);
Michal Vasko23049552021-03-04 15:57:44 +0100236 if (exp->repeat && exp->repeat[i]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200237 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
238 for (j = 1; exp->repeat[i][j]; ++j) {
239 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
240 }
241 strcat(tmp, ")");
242 }
243 LOGDBG(LY_LDGXPATH, tmp);
244 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100245#undef MSG_BUFFER_SIZE
Michal Vasko03ff5a72019-09-11 13:49:33 +0200246}
247
248#ifndef NDEBUG
249
250/**
251 * @brief Print XPath set content to debug output.
252 *
253 * @param[in] set Set to print.
254 */
255static void
256print_set_debug(struct lyxp_set *set)
257{
258 uint32_t i;
259 char *str;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200260 struct lyxp_set_node *item;
261 struct lyxp_set_scnode *sitem;
262
Radek Krejci52b6d512020-10-12 12:33:17 +0200263 if (ly_ll < LY_LLDBG) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200264 return;
265 }
266
267 switch (set->type) {
268 case LYXP_SET_NODE_SET:
269 LOGDBG(LY_LDGXPATH, "set NODE SET:");
270 for (i = 0; i < set->used; ++i) {
271 item = &set->val.nodes[i];
272
273 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100274 case LYXP_NODE_NONE:
275 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
276 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200277 case LYXP_NODE_ROOT:
278 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
279 break;
280 case LYXP_NODE_ROOT_CONFIG:
281 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
282 break;
283 case LYXP_NODE_ELEM:
Michal Vasko9e685082021-01-29 14:49:09 +0100284 if ((item->node->schema->nodetype == LYS_LIST) && (lyd_child(item->node)->schema->nodetype == LYS_LEAF)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200285 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200286 item->node->schema->name, lyd_get_value(lyd_child(item->node)));
Michal Vasko9e685082021-01-29 14:49:09 +0100287 } else if (item->node->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200288 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200289 item->node->schema->name, lyd_get_value(item->node));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200290 } else {
291 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
292 }
293 break;
294 case LYXP_NODE_TEXT:
295 if (item->node->schema->nodetype & LYS_ANYDATA) {
296 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
Michal Vasko69730152020-10-09 16:30:07 +0200297 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
Michal Vasko03ff5a72019-09-11 13:49:33 +0200298 } else {
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200299 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos, lyd_get_value(item->node));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200300 }
301 break;
Michal Vasko9f96a052020-03-10 09:41:45 +0100302 case LYXP_NODE_META:
303 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): META %s = %s", i + 1, item->pos, set->val.meta[i].meta->name,
Michal Vasko69730152020-10-09 16:30:07 +0200304 set->val.meta[i].meta->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200305 break;
306 }
307 }
308 break;
309
310 case LYXP_SET_SCNODE_SET:
311 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
312 for (i = 0; i < set->used; ++i) {
313 sitem = &set->val.scnodes[i];
314
315 switch (sitem->type) {
316 case LYXP_NODE_ROOT:
317 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
318 break;
319 case LYXP_NODE_ROOT_CONFIG:
320 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
321 break;
322 case LYXP_NODE_ELEM:
323 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
324 break;
325 default:
326 LOGINT(NULL);
327 break;
328 }
329 }
330 break;
331
Michal Vasko03ff5a72019-09-11 13:49:33 +0200332 case LYXP_SET_BOOLEAN:
333 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
Michal Vasko004d3152020-06-11 19:59:22 +0200334 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bln ? "true" : "false"));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200335 break;
336
337 case LYXP_SET_STRING:
338 LOGDBG(LY_LDGXPATH, "set STRING");
339 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
340 break;
341
342 case LYXP_SET_NUMBER:
343 LOGDBG(LY_LDGXPATH, "set NUMBER");
344
345 if (isnan(set->val.num)) {
346 str = strdup("NaN");
347 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
348 str = strdup("0");
349 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
350 str = strdup("Infinity");
351 } else if (isinf(set->val.num) && signbit(set->val.num)) {
352 str = strdup("-Infinity");
353 } else if ((long long)set->val.num == set->val.num) {
354 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
355 str = NULL;
356 }
357 } else {
358 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
359 str = NULL;
360 }
361 }
362 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
363
364 LOGDBG(LY_LDGXPATH, "\t%s", str);
365 free(str);
366 }
367}
368
369#endif
370
371/**
372 * @brief Realloc the string \p str.
373 *
374 * @param[in] ctx libyang context for logging.
375 * @param[in] needed How much free space is required.
376 * @param[in,out] str Pointer to the string to use.
377 * @param[in,out] used Used bytes in \p str.
378 * @param[in,out] size Allocated bytes in \p str.
379 * @return LY_ERR
380 */
381static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100382cast_string_realloc(const struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200383{
384 if (*size - *used < needed) {
385 do {
386 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
387 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
388 return LY_EINVAL;
389 }
390 *size += LYXP_STRING_CAST_SIZE_STEP;
391 } while (*size - *used < needed);
392 *str = ly_realloc(*str, *size * sizeof(char));
393 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
394 }
395
396 return LY_SUCCESS;
397}
398
399/**
400 * @brief Cast nodes recursively to one string @p str.
401 *
Michal Vasko47da6562022-07-14 15:43:15 +0200402 * @param[in] node Node to cast, NULL if root.
403 * @param[in] set XPath set.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200404 * @param[in] indent Current indent.
405 * @param[in,out] str Resulting string.
406 * @param[in,out] used Used bytes in @p str.
407 * @param[in,out] size Allocated bytes in @p str.
Michal Vasko47da6562022-07-14 15:43:15 +0200408 * @return LY_ERR value.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200409 */
410static LY_ERR
Michal Vasko47da6562022-07-14 15:43:15 +0200411cast_string_recursive(const struct lyd_node *node, struct lyxp_set *set, uint16_t indent, char **str, uint16_t *used,
412 uint16_t *size)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200413{
Radek Krejci7f769d72020-07-11 23:13:56 +0200414 char *buf, *line, *ptr = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200415 const char *value_str;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200416 const struct lyd_node *child;
Michal Vasko47da6562022-07-14 15:43:15 +0200417 enum lyxp_node_type child_type;
Michal Vasko60ea6352020-06-29 13:39:39 +0200418 struct lyd_node *tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200419 struct lyd_node_any *any;
420 LY_ERR rc;
421
Michal Vasko47da6562022-07-14 15:43:15 +0200422 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && node && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200423 return LY_SUCCESS;
424 }
425
Michal Vasko47da6562022-07-14 15:43:15 +0200426 if (!node) {
427 /* fake container */
428 LY_CHECK_RET(cast_string_realloc(set->ctx, 1, str, used, size));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200429 strcpy(*str + (*used - 1), "\n");
430 ++(*used);
431
432 ++indent;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200433
Michal Vasko47da6562022-07-14 15:43:15 +0200434 /* print all the top-level nodes */
435 child = NULL;
436 child_type = 0;
437 while (!moveto_axis_node_next(&child, &child_type, NULL, set->root_type, LYXP_AXIS_CHILD, set)) {
438 LY_CHECK_RET(cast_string_recursive(child, set, indent, str, used, size));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200439 }
440
Michal Vasko47da6562022-07-14 15:43:15 +0200441 /* end fake container */
442 LY_CHECK_RET(cast_string_realloc(set->ctx, 1, str, used, size));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200443 strcpy(*str + (*used - 1), "\n");
444 ++(*used);
445
446 --indent;
Michal Vasko47da6562022-07-14 15:43:15 +0200447 } else {
448 switch (node->schema->nodetype) {
449 case LYS_CONTAINER:
450 case LYS_LIST:
451 case LYS_RPC:
452 case LYS_NOTIF:
453 LY_CHECK_RET(cast_string_realloc(set->ctx, 1, str, used, size));
454 strcpy(*str + (*used - 1), "\n");
455 ++(*used);
456
457 for (child = lyd_child(node); child; child = child->next) {
458 LY_CHECK_RET(cast_string_recursive(child, set, indent + 1, str, used, size));
459 }
460
461 break;
462
463 case LYS_LEAF:
464 case LYS_LEAFLIST:
465 value_str = lyd_get_value(node);
466
467 /* print indent */
468 LY_CHECK_RET(cast_string_realloc(set->ctx, indent * 2 + strlen(value_str) + 1, str, used, size));
469 memset(*str + (*used - 1), ' ', indent * 2);
470 *used += indent * 2;
471
472 /* print value */
473 if (*used == 1) {
474 sprintf(*str + (*used - 1), "%s", value_str);
475 *used += strlen(value_str);
476 } else {
477 sprintf(*str + (*used - 1), "%s\n", value_str);
478 *used += strlen(value_str) + 1;
479 }
480
481 break;
482
483 case LYS_ANYXML:
484 case LYS_ANYDATA:
485 any = (struct lyd_node_any *)node;
486 if (!(void *)any->value.tree) {
487 /* no content */
488 buf = strdup("");
489 LY_CHECK_ERR_RET(!buf, LOGMEM(set->ctx), LY_EMEM);
490 } else {
491 struct ly_out *out;
492
493 if (any->value_type == LYD_ANYDATA_LYB) {
494 /* try to parse it into a data tree */
495 if (lyd_parse_data_mem((struct ly_ctx *)set->ctx, any->value.mem, LYD_LYB,
496 LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
497 /* successfully parsed */
498 free(any->value.mem);
499 any->value.tree = tree;
500 any->value_type = LYD_ANYDATA_DATATREE;
501 }
502 /* error is covered by the following switch where LYD_ANYDATA_LYB causes failure */
503 }
504
505 switch (any->value_type) {
506 case LYD_ANYDATA_STRING:
507 case LYD_ANYDATA_XML:
508 case LYD_ANYDATA_JSON:
509 buf = strdup(any->value.json);
510 LY_CHECK_ERR_RET(!buf, LOGMEM(set->ctx), LY_EMEM);
511 break;
512 case LYD_ANYDATA_DATATREE:
513 LY_CHECK_RET(ly_out_new_memory(&buf, 0, &out));
514 rc = lyd_print_all(out, any->value.tree, LYD_XML, 0);
515 ly_out_free(out, NULL, 0);
516 LY_CHECK_RET(rc < 0, -rc);
517 break;
518 case LYD_ANYDATA_LYB:
519 LOGERR(set->ctx, LY_EINVAL, "Cannot convert LYB anydata into string.");
520 return LY_EINVAL;
521 }
522 }
523
524 line = strtok_r(buf, "\n", &ptr);
525 do {
526 rc = cast_string_realloc(set->ctx, indent * 2 + strlen(line) + 1, str, used, size);
527 if (rc != LY_SUCCESS) {
528 free(buf);
529 return rc;
530 }
531 memset(*str + (*used - 1), ' ', indent * 2);
532 *used += indent * 2;
533
534 strcpy(*str + (*used - 1), line);
535 *used += strlen(line);
536
537 strcpy(*str + (*used - 1), "\n");
538 *used += 1;
539 } while ((line = strtok_r(NULL, "\n", &ptr)));
540
541 free(buf);
542 break;
543
544 default:
545 LOGINT_RET(set->ctx);
546 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200547 }
548
549 return LY_SUCCESS;
550}
551
552/**
553 * @brief Cast an element into a string.
554 *
Michal Vasko47da6562022-07-14 15:43:15 +0200555 * @param[in] node Node to cast, NULL if root.
556 * @param[in] set XPath set.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200557 * @param[out] str Element cast to dynamically-allocated string.
558 * @return LY_ERR
559 */
560static LY_ERR
Michal Vasko47da6562022-07-14 15:43:15 +0200561cast_string_elem(const struct lyd_node *node, struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200562{
563 uint16_t used, size;
564 LY_ERR rc;
565
566 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
Michal Vasko47da6562022-07-14 15:43:15 +0200567 LY_CHECK_ERR_RET(!*str, LOGMEM(set->ctx), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200568 (*str)[0] = '\0';
569 used = 1;
570 size = LYXP_STRING_CAST_SIZE_START;
571
Michal Vasko47da6562022-07-14 15:43:15 +0200572 rc = cast_string_recursive(node, set, 0, str, &used, &size);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200573 if (rc != LY_SUCCESS) {
574 free(*str);
575 return rc;
576 }
577
578 if (size > used) {
579 *str = ly_realloc(*str, used * sizeof(char));
Michal Vasko47da6562022-07-14 15:43:15 +0200580 LY_CHECK_ERR_RET(!*str, LOGMEM(set->ctx), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200581 }
582 return LY_SUCCESS;
583}
584
585/**
586 * @brief Cast a LYXP_SET_NODE_SET set into a string.
587 * Context position aware.
588 *
589 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200590 * @param[out] str Cast dynamically-allocated string.
591 * @return LY_ERR
592 */
593static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100594cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200595{
Michal Vaskoaa677062021-03-09 13:52:53 +0100596 if (!set->used) {
597 *str = strdup("");
598 if (!*str) {
599 LOGMEM_RET(set->ctx);
600 }
601 return LY_SUCCESS;
602 }
603
Michal Vasko03ff5a72019-09-11 13:49:33 +0200604 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100605 case LYXP_NODE_NONE:
606 /* invalid */
607 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200608 case LYXP_NODE_ROOT:
609 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200610 case LYXP_NODE_ELEM:
611 case LYXP_NODE_TEXT:
Michal Vasko47da6562022-07-14 15:43:15 +0200612 return cast_string_elem(set->val.nodes[0].node, set, str);
Michal Vasko9f96a052020-03-10 09:41:45 +0100613 case LYXP_NODE_META:
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200614 *str = strdup(lyd_get_meta_value(set->val.meta[0].meta));
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200615 if (!*str) {
616 LOGMEM_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200617 }
618 return LY_SUCCESS;
619 }
620
621 LOGINT_RET(set->ctx);
622}
623
624/**
625 * @brief Cast a string into an XPath number.
626 *
627 * @param[in] str String to use.
628 * @return Cast number.
629 */
630static long double
631cast_string_to_number(const char *str)
632{
633 long double num;
634 char *ptr;
635
636 errno = 0;
637 num = strtold(str, &ptr);
638 if (errno || *ptr) {
639 num = NAN;
640 }
641 return num;
642}
643
644/**
645 * @brief Callback for checking value equality.
646 *
Michal Vasko62524a92021-02-26 10:08:50 +0100647 * Implementation of ::lyht_value_equal_cb.
Radek Krejci857189e2020-09-01 13:26:36 +0200648 *
Michal Vasko03ff5a72019-09-11 13:49:33 +0200649 * @param[in] val1_p First value.
650 * @param[in] val2_p Second value.
651 * @param[in] mod Whether hash table is being modified.
652 * @param[in] cb_data Callback data.
Radek Krejci857189e2020-09-01 13:26:36 +0200653 * @return Boolean value whether values are equal or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200654 */
Radek Krejci857189e2020-09-01 13:26:36 +0200655static ly_bool
656set_values_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
Michal Vasko03ff5a72019-09-11 13:49:33 +0200657{
658 struct lyxp_set_hash_node *val1, *val2;
659
660 val1 = (struct lyxp_set_hash_node *)val1_p;
661 val2 = (struct lyxp_set_hash_node *)val2_p;
662
663 if ((val1->node == val2->node) && (val1->type == val2->type)) {
664 return 1;
665 }
666
667 return 0;
668}
669
670/**
671 * @brief Insert node and its hash into set.
672 *
673 * @param[in] set et to insert to.
674 * @param[in] node Node with hash.
675 * @param[in] type Node type.
676 */
677static void
678set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
679{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200680 LY_ERR r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200681 uint32_t i, hash;
682 struct lyxp_set_hash_node hnode;
683
684 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
685 /* create hash table and add all the nodes */
686 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
687 for (i = 0; i < set->used; ++i) {
688 hnode.node = set->val.nodes[i].node;
689 hnode.type = set->val.nodes[i].type;
690
691 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
692 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
693 hash = dict_hash_multi(hash, NULL, 0);
694
695 r = lyht_insert(set->ht, &hnode, hash, NULL);
696 assert(!r);
697 (void)r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200698
Michal Vasko9d6befd2019-12-11 14:56:56 +0100699 if (hnode.node == node) {
700 /* it was just added, do not add it twice */
701 node = NULL;
702 }
703 }
704 }
705
706 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200707 /* add the new node into hash table */
708 hnode.node = node;
709 hnode.type = type;
710
711 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
712 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
713 hash = dict_hash_multi(hash, NULL, 0);
714
715 r = lyht_insert(set->ht, &hnode, hash, NULL);
716 assert(!r);
717 (void)r;
718 }
719}
720
721/**
722 * @brief Remove node and its hash from set.
723 *
724 * @param[in] set Set to remove from.
725 * @param[in] node Node to remove.
726 * @param[in] type Node type.
727 */
728static void
729set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
730{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200731 LY_ERR r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200732 struct lyxp_set_hash_node hnode;
733 uint32_t hash;
734
735 if (set->ht) {
736 hnode.node = node;
737 hnode.type = type;
738
739 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
740 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
741 hash = dict_hash_multi(hash, NULL, 0);
742
743 r = lyht_remove(set->ht, &hnode, hash);
744 assert(!r);
745 (void)r;
746
747 if (!set->ht->used) {
748 lyht_free(set->ht);
749 set->ht = NULL;
750 }
751 }
752}
753
754/**
755 * @brief Check whether node is in set based on its hash.
756 *
757 * @param[in] set Set to search in.
758 * @param[in] node Node to search for.
759 * @param[in] type Node type.
760 * @param[in] skip_idx Index in @p set to skip.
761 * @return LY_ERR
762 */
763static LY_ERR
764set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
765{
766 struct lyxp_set_hash_node hnode, *match_p;
767 uint32_t hash;
768
769 hnode.node = node;
770 hnode.type = type;
771
772 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
773 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
774 hash = dict_hash_multi(hash, NULL, 0);
775
776 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
777 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
778 /* we found it on the index that should be skipped, find another */
779 hnode = *match_p;
780 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
781 /* none other found */
782 return LY_SUCCESS;
783 }
784 }
785
786 return LY_EEXIST;
787 }
788
789 /* not found */
790 return LY_SUCCESS;
791}
792
Michal Vaskod3678892020-05-21 10:06:58 +0200793void
794lyxp_set_free_content(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200795{
796 if (!set) {
797 return;
798 }
799
800 if (set->type == LYXP_SET_NODE_SET) {
801 free(set->val.nodes);
802 lyht_free(set->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200803 } else if (set->type == LYXP_SET_SCNODE_SET) {
804 free(set->val.scnodes);
Michal Vaskod3678892020-05-21 10:06:58 +0200805 lyht_free(set->ht);
806 } else {
807 if (set->type == LYXP_SET_STRING) {
808 free(set->val.str);
809 }
810 set->type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200811 }
Michal Vaskod3678892020-05-21 10:06:58 +0200812
813 set->val.nodes = NULL;
814 set->used = 0;
815 set->size = 0;
816 set->ht = NULL;
817 set->ctx_pos = 0;
aPiecek748da732021-06-01 09:56:43 +0200818 set->ctx_size = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200819}
820
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100821/**
822 * @brief Free dynamically-allocated set.
823 *
824 * @param[in] set Set to free.
825 */
826static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200827lyxp_set_free(struct lyxp_set *set)
828{
829 if (!set) {
830 return;
831 }
832
Michal Vaskod3678892020-05-21 10:06:58 +0200833 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200834 free(set);
835}
836
837/**
838 * @brief Initialize set context.
839 *
840 * @param[in] new Set to initialize.
841 * @param[in] set Arbitrary initialized set.
842 */
843static void
Michal Vasko4c7763f2020-07-27 17:40:37 +0200844set_init(struct lyxp_set *new, const struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200845{
846 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200847 if (set) {
Michal Vasko306e2832022-07-25 09:15:17 +0200848 new->non_child_axis = set->non_child_axis;
Michal Vasko02a77382019-09-12 11:47:35 +0200849 new->ctx = set->ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200850 new->cur_node = set->cur_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100851 new->root_type = set->root_type;
Michal Vasko6b26e742020-07-17 15:02:10 +0200852 new->context_op = set->context_op;
Michal Vaskof03ed032020-03-04 13:31:44 +0100853 new->tree = set->tree;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200854 new->cur_mod = set->cur_mod;
Michal Vasko02a77382019-09-12 11:47:35 +0200855 new->format = set->format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200856 new->prefix_data = set->prefix_data;
aPiecekfba75362021-10-07 12:39:48 +0200857 new->vars = set->vars;
Michal Vasko02a77382019-09-12 11:47:35 +0200858 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200859}
860
861/**
862 * @brief Create a deep copy of a set.
863 *
864 * @param[in] set Set to copy.
865 * @return Copy of @p set.
866 */
867static struct lyxp_set *
868set_copy(struct lyxp_set *set)
869{
870 struct lyxp_set *ret;
Michal Vasko1fdd8fa2021-01-08 09:21:45 +0100871 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200872
873 if (!set) {
874 return NULL;
875 }
876
877 ret = malloc(sizeof *ret);
878 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
879 set_init(ret, set);
880
881 if (set->type == LYXP_SET_SCNODE_SET) {
882 ret->type = set->type;
883
884 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100885 if ((set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) ||
886 (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_START)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +0200887 uint32_t idx;
888 LY_CHECK_ERR_RET(lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type, &idx),
889 lyxp_set_free(ret), NULL);
Michal Vasko3f27c522020-01-06 08:37:49 +0100890 /* coverity seems to think scnodes can be NULL */
Radek Krejciaa6b53f2020-08-27 15:19:03 +0200891 if (!ret->val.scnodes) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200892 lyxp_set_free(ret);
893 return NULL;
894 }
Michal Vaskoba716542019-12-16 10:01:58 +0100895 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200896 }
897 }
898 } else if (set->type == LYXP_SET_NODE_SET) {
899 ret->type = set->type;
Michal Vasko08e9b112021-06-11 15:41:17 +0200900 if (set->used) {
901 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
902 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
903 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
904 } else {
905 ret->val.nodes = NULL;
906 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200907
908 ret->used = ret->size = set->used;
909 ret->ctx_pos = set->ctx_pos;
910 ret->ctx_size = set->ctx_size;
Michal Vasko4a04e542021-02-01 08:58:30 +0100911 if (set->ht) {
912 ret->ht = lyht_dup(set->ht);
913 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200914 } else {
Radek Krejci0f969882020-08-21 16:56:47 +0200915 memcpy(ret, set, sizeof *ret);
916 if (set->type == LYXP_SET_STRING) {
917 ret->val.str = strdup(set->val.str);
918 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
919 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200920 }
921
922 return ret;
923}
924
925/**
926 * @brief Fill XPath set with a string. Any current data are disposed of.
927 *
928 * @param[in] set Set to fill.
929 * @param[in] string String to fill into \p set.
930 * @param[in] str_len Length of \p string. 0 is a valid value!
931 */
932static void
933set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
934{
Michal Vaskod3678892020-05-21 10:06:58 +0200935 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200936
937 set->type = LYXP_SET_STRING;
938 if ((str_len == 0) && (string[0] != '\0')) {
939 string = "";
940 }
941 set->val.str = strndup(string, str_len);
942}
943
944/**
945 * @brief Fill XPath set with a number. Any current data are disposed of.
946 *
947 * @param[in] set Set to fill.
948 * @param[in] number Number to fill into \p set.
949 */
950static void
951set_fill_number(struct lyxp_set *set, long double number)
952{
Michal Vaskod3678892020-05-21 10:06:58 +0200953 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200954
955 set->type = LYXP_SET_NUMBER;
956 set->val.num = number;
957}
958
959/**
960 * @brief Fill XPath set with a boolean. Any current data are disposed of.
961 *
962 * @param[in] set Set to fill.
963 * @param[in] boolean Boolean to fill into \p set.
964 */
965static void
Radek Krejci857189e2020-09-01 13:26:36 +0200966set_fill_boolean(struct lyxp_set *set, ly_bool boolean)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200967{
Michal Vaskod3678892020-05-21 10:06:58 +0200968 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200969
970 set->type = LYXP_SET_BOOLEAN;
Michal Vasko004d3152020-06-11 19:59:22 +0200971 set->val.bln = boolean;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200972}
973
974/**
975 * @brief Fill XPath set with the value from another set (deep assign).
976 * Any current data are disposed of.
977 *
978 * @param[in] trg Set to fill.
979 * @param[in] src Source set to copy into \p trg.
980 */
981static void
Michal Vasko4c7763f2020-07-27 17:40:37 +0200982set_fill_set(struct lyxp_set *trg, const struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200983{
984 if (!trg || !src) {
985 return;
986 }
987
988 if (trg->type == LYXP_SET_NODE_SET) {
989 free(trg->val.nodes);
990 } else if (trg->type == LYXP_SET_STRING) {
991 free(trg->val.str);
992 }
993 set_init(trg, src);
994
995 if (src->type == LYXP_SET_SCNODE_SET) {
996 trg->type = LYXP_SET_SCNODE_SET;
997 trg->used = src->used;
998 trg->size = src->used;
999
Michal Vasko08e9b112021-06-11 15:41:17 +02001000 if (trg->size) {
1001 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
1002 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
1003 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
1004 } else {
1005 trg->val.scnodes = NULL;
1006 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001007 } else if (src->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +02001008 set_fill_boolean(trg, src->val.bln);
Michal Vasko44f3d2c2020-08-24 09:49:38 +02001009 } else if (src->type == LYXP_SET_NUMBER) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001010 set_fill_number(trg, src->val.num);
1011 } else if (src->type == LYXP_SET_STRING) {
1012 set_fill_string(trg, src->val.str, strlen(src->val.str));
1013 } else {
1014 if (trg->type == LYXP_SET_NODE_SET) {
1015 free(trg->val.nodes);
1016 } else if (trg->type == LYXP_SET_STRING) {
1017 free(trg->val.str);
1018 }
1019
Michal Vaskod3678892020-05-21 10:06:58 +02001020 assert(src->type == LYXP_SET_NODE_SET);
1021
1022 trg->type = LYXP_SET_NODE_SET;
1023 trg->used = src->used;
1024 trg->size = src->used;
1025 trg->ctx_pos = src->ctx_pos;
1026 trg->ctx_size = src->ctx_size;
1027
Michal Vasko08e9b112021-06-11 15:41:17 +02001028 if (trg->size) {
1029 trg->val.nodes = malloc(trg->size * sizeof *trg->val.nodes);
1030 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
1031 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
1032 } else {
1033 trg->val.nodes = NULL;
1034 }
Michal Vaskod3678892020-05-21 10:06:58 +02001035 if (src->ht) {
1036 trg->ht = lyht_dup(src->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001037 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02001038 trg->ht = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001039 }
1040 }
1041}
1042
1043/**
1044 * @brief Clear context of all schema nodes.
1045 *
1046 * @param[in] set Set to clear.
Michal Vasko1a09b212021-05-06 13:00:10 +02001047 * @param[in] new_ctx New context state for all the nodes currently in the context.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001048 */
1049static void
Michal Vasko1a09b212021-05-06 13:00:10 +02001050set_scnode_clear_ctx(struct lyxp_set *set, int32_t new_ctx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001051{
1052 uint32_t i;
1053
1054 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001055 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko1a09b212021-05-06 13:00:10 +02001056 set->val.scnodes[i].in_ctx = new_ctx;
Radek Krejcif13b87b2020-12-01 22:02:17 +01001057 } else if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_START) {
1058 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001059 }
1060 }
1061}
1062
1063/**
1064 * @brief Remove a node from a set. Removing last node changes
1065 * set into LYXP_SET_EMPTY. Context position aware.
1066 *
1067 * @param[in] set Set to use.
1068 * @param[in] idx Index from @p set of the node to be removed.
1069 */
1070static void
1071set_remove_node(struct lyxp_set *set, uint32_t idx)
1072{
1073 assert(set && (set->type == LYXP_SET_NODE_SET));
1074 assert(idx < set->used);
1075
1076 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1077
1078 --set->used;
Michal Vasko08e9b112021-06-11 15:41:17 +02001079 if (idx < set->used) {
1080 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1], (set->used - idx) * sizeof *set->val.nodes);
1081 } else if (!set->used) {
Michal Vaskod3678892020-05-21 10:06:58 +02001082 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001083 }
1084}
1085
1086/**
Michal Vasko2caefc12019-11-14 16:07:56 +01001087 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +02001088 *
1089 * @param[in] set Set to use.
1090 * @param[in] idx Index from @p set of the node to be removed.
1091 */
1092static void
Michal Vasko2caefc12019-11-14 16:07:56 +01001093set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +02001094{
1095 assert(set && (set->type == LYXP_SET_NODE_SET));
1096 assert(idx < set->used);
1097
Michal Vasko2caefc12019-11-14 16:07:56 +01001098 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1099 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1100 }
1101 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +02001102}
1103
1104/**
Michal Vasko2caefc12019-11-14 16:07:56 +01001105 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +02001106 * set into LYXP_SET_EMPTY. Context position aware.
1107 *
1108 * @param[in] set Set to consolidate.
1109 */
1110static void
Michal Vasko2caefc12019-11-14 16:07:56 +01001111set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +02001112{
Michal Vasko1fdd8fa2021-01-08 09:21:45 +01001113 uint32_t i, orig_used, end = 0;
1114 int64_t start;
Michal Vasko57eab132019-09-24 11:46:26 +02001115
Michal Vaskod3678892020-05-21 10:06:58 +02001116 assert(set);
Michal Vasko57eab132019-09-24 11:46:26 +02001117
1118 orig_used = set->used;
1119 set->used = 0;
Michal Vaskod989ba02020-08-24 10:59:24 +02001120 for (i = 0; i < orig_used; ) {
Michal Vasko57eab132019-09-24 11:46:26 +02001121 start = -1;
1122 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001123 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001124 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001125 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001126 end = i;
1127 ++i;
1128 break;
1129 }
1130
1131 ++i;
1132 if (i == orig_used) {
1133 end = i;
1134 }
1135 } while (i < orig_used);
1136
1137 if (start > -1) {
1138 /* move the whole chunk of valid nodes together */
1139 if (set->used != (unsigned)start) {
1140 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1141 }
1142 set->used += end - start;
1143 }
1144 }
Michal Vasko57eab132019-09-24 11:46:26 +02001145}
1146
1147/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001148 * @brief Check for duplicates in a node set.
1149 *
1150 * @param[in] set Set to check.
1151 * @param[in] node Node to look for in @p set.
1152 * @param[in] node_type Type of @p node.
1153 * @param[in] skip_idx Index from @p set to skip.
1154 * @return LY_ERR
1155 */
1156static LY_ERR
1157set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1158{
1159 uint32_t i;
1160
Michal Vasko2caefc12019-11-14 16:07:56 +01001161 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001162 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1163 }
1164
1165 for (i = 0; i < set->used; ++i) {
1166 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1167 continue;
1168 }
1169
1170 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1171 return LY_EEXIST;
1172 }
1173 }
1174
1175 return LY_SUCCESS;
1176}
1177
Radek Krejci857189e2020-09-01 13:26:36 +02001178ly_bool
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001179lyxp_set_scnode_contains(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx,
1180 uint32_t *index_p)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001181{
1182 uint32_t i;
1183
1184 for (i = 0; i < set->used; ++i) {
1185 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1186 continue;
1187 }
1188
1189 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001190 if (index_p) {
1191 *index_p = i;
1192 }
1193 return 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001194 }
1195 }
1196
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001197 return 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001198}
1199
Michal Vaskoecd62de2019-11-13 12:35:11 +01001200void
1201lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001202{
1203 uint32_t orig_used, i, j;
1204
Michal Vaskod3678892020-05-21 10:06:58 +02001205 assert((set1->type == LYXP_SET_SCNODE_SET) && (set2->type == LYXP_SET_SCNODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001206
Michal Vaskod3678892020-05-21 10:06:58 +02001207 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001208 return;
1209 }
1210
Michal Vaskod3678892020-05-21 10:06:58 +02001211 if (!set1->used) {
aPiecekadc1e4f2021-10-07 11:15:12 +02001212 /* release hidden allocated data (lyxp_set.size) */
1213 lyxp_set_free_content(set1);
1214 /* direct copying of the entire structure */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001215 memcpy(set1, set2, sizeof *set1);
1216 return;
1217 }
1218
1219 if (set1->used + set2->used > set1->size) {
1220 set1->size = set1->used + set2->used;
1221 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1222 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1223 }
1224
1225 orig_used = set1->used;
1226
1227 for (i = 0; i < set2->used; ++i) {
1228 for (j = 0; j < orig_used; ++j) {
1229 /* detect duplicities */
1230 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1231 break;
1232 }
1233 }
1234
Michal Vasko0587bce2020-12-10 12:19:21 +01001235 if (j < orig_used) {
1236 /* node is there, but update its status if needed */
1237 if (set1->val.scnodes[j].in_ctx == LYXP_SET_SCNODE_START_USED) {
1238 set1->val.scnodes[j].in_ctx = set2->val.scnodes[i].in_ctx;
Michal Vasko1a09b212021-05-06 13:00:10 +02001239 } else if ((set1->val.scnodes[j].in_ctx == LYXP_SET_SCNODE_ATOM_NODE) &&
1240 (set2->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_VAL)) {
1241 set1->val.scnodes[j].in_ctx = set2->val.scnodes[i].in_ctx;
Michal Vasko0587bce2020-12-10 12:19:21 +01001242 }
1243 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001244 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1245 ++set1->used;
1246 }
1247 }
1248
Michal Vaskod3678892020-05-21 10:06:58 +02001249 lyxp_set_free_content(set2);
1250 set2->type = LYXP_SET_SCNODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001251}
1252
1253/**
1254 * @brief Insert a node into a set. Context position aware.
1255 *
1256 * @param[in] set Set to use.
1257 * @param[in] node Node to insert to @p set.
1258 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1259 * @param[in] node_type Node type of @p node.
1260 * @param[in] idx Index in @p set to insert into.
1261 */
1262static void
1263set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1264{
Michal Vaskod3678892020-05-21 10:06:58 +02001265 assert(set && (set->type == LYXP_SET_NODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001266
Michal Vaskod3678892020-05-21 10:06:58 +02001267 if (!set->size) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001268 /* first item */
1269 if (idx) {
1270 /* no real harm done, but it is a bug */
1271 LOGINT(set->ctx);
1272 idx = 0;
1273 }
1274 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1275 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1276 set->type = LYXP_SET_NODE_SET;
1277 set->used = 0;
1278 set->size = LYXP_SET_SIZE_START;
1279 set->ctx_pos = 1;
1280 set->ctx_size = 1;
1281 set->ht = NULL;
1282 } else {
1283 /* not an empty set */
1284 if (set->used == set->size) {
1285
1286 /* set is full */
Michal Vasko871df522022-04-06 12:14:41 +02001287 set->val.nodes = ly_realloc(set->val.nodes, (set->size * LYXP_SET_SIZE_MUL_STEP) * sizeof *set->val.nodes);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001288 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
Michal Vasko871df522022-04-06 12:14:41 +02001289 set->size *= LYXP_SET_SIZE_MUL_STEP;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001290 }
1291
1292 if (idx > set->used) {
1293 LOGINT(set->ctx);
1294 idx = set->used;
1295 }
1296
1297 /* make space for the new node */
1298 if (idx < set->used) {
1299 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1300 }
1301 }
1302
1303 /* finally assign the value */
1304 set->val.nodes[idx].node = (struct lyd_node *)node;
1305 set->val.nodes[idx].type = node_type;
1306 set->val.nodes[idx].pos = pos;
1307 ++set->used;
1308
Michal Vasko2416fdd2021-10-01 11:07:10 +02001309 /* add into hash table */
1310 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001311}
1312
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001313LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +01001314lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type,
1315 uint32_t *index_p)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001316{
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001317 uint32_t index;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001318
1319 assert(set->type == LYXP_SET_SCNODE_SET);
1320
Michal Vasko871df522022-04-06 12:14:41 +02001321 if (!set->size) {
1322 /* first item */
1323 set->val.scnodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.scnodes);
1324 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), LY_EMEM);
1325 set->type = LYXP_SET_SCNODE_SET;
1326 set->used = 0;
1327 set->size = LYXP_SET_SIZE_START;
1328 set->ctx_pos = 1;
1329 set->ctx_size = 1;
1330 set->ht = NULL;
1331 }
1332
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001333 if (lyxp_set_scnode_contains(set, node, node_type, -1, &index)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001334 set->val.scnodes[index].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001335 } else {
1336 if (set->used == set->size) {
Michal Vasko871df522022-04-06 12:14:41 +02001337 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size * LYXP_SET_SIZE_MUL_STEP) * sizeof *set->val.scnodes);
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001338 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), LY_EMEM);
Michal Vasko871df522022-04-06 12:14:41 +02001339 set->size *= LYXP_SET_SIZE_MUL_STEP;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001340 }
1341
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001342 index = set->used;
1343 set->val.scnodes[index].scnode = (struct lysc_node *)node;
1344 set->val.scnodes[index].type = node_type;
Radek Krejcif13b87b2020-12-01 22:02:17 +01001345 set->val.scnodes[index].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001346 ++set->used;
1347 }
1348
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001349 if (index_p) {
1350 *index_p = index;
1351 }
1352
1353 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001354}
1355
1356/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001357 * @brief Set all nodes with ctx 1 to a new unique context value.
1358 *
1359 * @param[in] set Set to modify.
1360 * @return New context value.
1361 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001362static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001363set_scnode_new_in_ctx(struct lyxp_set *set)
1364{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001365 uint32_t i;
1366 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001367
1368 assert(set->type == LYXP_SET_SCNODE_SET);
1369
Radek Krejcif13b87b2020-12-01 22:02:17 +01001370 ret_ctx = LYXP_SET_SCNODE_ATOM_PRED_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001371retry:
1372 for (i = 0; i < set->used; ++i) {
1373 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1374 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1375 goto retry;
1376 }
1377 }
1378 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001379 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001380 set->val.scnodes[i].in_ctx = ret_ctx;
1381 }
1382 }
1383
1384 return ret_ctx;
1385}
1386
1387/**
1388 * @brief Get unique @p node position in the data.
1389 *
1390 * @param[in] node Node to find.
1391 * @param[in] node_type Node type of @p node.
1392 * @param[in] root Root node.
1393 * @param[in] root_type Type of the XPath @p root node.
1394 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1395 * be used to increase efficiency and start the DFS from this node.
1396 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1397 * @return Node position.
1398 */
1399static uint32_t
1400get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
Radek Krejci0f969882020-08-21 16:56:47 +02001401 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001402{
Michal Vasko56daf732020-08-10 10:57:18 +02001403 const struct lyd_node *elem = NULL, *top_sibling;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001404 uint32_t pos = 1;
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001405 ly_bool found = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001406
1407 assert(prev && prev_pos && !root->prev->next);
1408
1409 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1410 return 0;
1411 }
1412
1413 if (*prev) {
1414 /* start from the previous element instead from the root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001415 pos = *prev_pos;
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001416 for (top_sibling = *prev; top_sibling->parent; top_sibling = lyd_parent(top_sibling)) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001417 goto dfs_search;
1418 }
1419
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001420 LY_LIST_FOR(root, top_sibling) {
Michal Vasko56daf732020-08-10 10:57:18 +02001421 LYD_TREE_DFS_BEGIN(top_sibling, elem) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001422dfs_search:
Michal Vaskoa9309bb2021-07-09 09:31:55 +02001423 LYD_TREE_DFS_continue = 0;
1424
Michal Vasko56daf732020-08-10 10:57:18 +02001425 if (*prev && !elem) {
1426 /* resume previous DFS */
1427 elem = LYD_TREE_DFS_next = (struct lyd_node *)*prev;
1428 LYD_TREE_DFS_continue = 0;
1429 }
1430
Michal Vasko482a6822022-05-06 08:56:12 +02001431 if (!elem->schema || ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R))) {
Michal Vasko56daf732020-08-10 10:57:18 +02001432 /* skip */
1433 LYD_TREE_DFS_continue = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001434 } else {
Michal Vasko56daf732020-08-10 10:57:18 +02001435 if (elem == node) {
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001436 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001437 break;
1438 }
Michal Vasko56daf732020-08-10 10:57:18 +02001439 ++pos;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001440 }
Michal Vasko56daf732020-08-10 10:57:18 +02001441
1442 LYD_TREE_DFS_END(top_sibling, elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001443 }
1444
1445 /* node found */
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001446 if (found) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001447 break;
1448 }
1449 }
1450
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001451 if (!found) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001452 if (!(*prev)) {
1453 /* we went from root and failed to find it, cannot be */
Michal Vaskob7be7a82020-08-20 09:09:04 +02001454 LOGINT(LYD_CTX(node));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001455 return 0;
1456 } else {
Michal Vasko56daf732020-08-10 10:57:18 +02001457 /* start the search again from the beginning */
1458 *prev = root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001459
Michal Vasko56daf732020-08-10 10:57:18 +02001460 top_sibling = root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001461 pos = 1;
1462 goto dfs_search;
1463 }
1464 }
1465
1466 /* remember the last found node for next time */
1467 *prev = node;
1468 *prev_pos = pos;
1469
1470 return pos;
1471}
1472
1473/**
1474 * @brief Assign (fill) missing node positions.
1475 *
1476 * @param[in] set Set to fill positions in.
1477 * @param[in] root Context root node.
1478 * @param[in] root_type Context root type.
1479 * @return LY_ERR
1480 */
1481static LY_ERR
1482set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1483{
1484 const struct lyd_node *prev = NULL, *tmp_node;
1485 uint32_t i, tmp_pos = 0;
1486
1487 for (i = 0; i < set->used; ++i) {
1488 if (!set->val.nodes[i].pos) {
1489 tmp_node = NULL;
1490 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001491 case LYXP_NODE_META:
1492 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001493 if (!tmp_node) {
1494 LOGINT_RET(root->schema->module->ctx);
1495 }
Radek Krejcif13b87b2020-12-01 22:02:17 +01001496 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001497 case LYXP_NODE_ELEM:
1498 case LYXP_NODE_TEXT:
1499 if (!tmp_node) {
1500 tmp_node = set->val.nodes[i].node;
1501 }
1502 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1503 break;
1504 default:
1505 /* all roots have position 0 */
1506 break;
1507 }
1508 }
1509 }
1510
1511 return LY_SUCCESS;
1512}
1513
1514/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001515 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001516 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001517 * @param[in] meta Metadata to use.
1518 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001519 */
1520static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001521get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001522{
1523 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001524 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001525
Michal Vasko9f96a052020-03-10 09:41:45 +01001526 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001527 ++pos;
1528 }
1529
Michal Vasko9f96a052020-03-10 09:41:45 +01001530 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001531 return pos;
1532}
1533
1534/**
1535 * @brief Compare 2 nodes in respect to XPath document order.
1536 *
1537 * @param[in] item1 1st node.
1538 * @param[in] item2 2nd node.
1539 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1540 */
1541static int
1542set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1543{
Michal Vasko9f96a052020-03-10 09:41:45 +01001544 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001545
1546 if (item1->pos < item2->pos) {
1547 return -1;
1548 }
1549
1550 if (item1->pos > item2->pos) {
1551 return 1;
1552 }
1553
1554 /* node positions are equal, the fun case */
1555
1556 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1557 /* special case since text nodes are actually saved as their parents */
1558 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1559 if (item1->type == LYXP_NODE_ELEM) {
1560 assert(item2->type == LYXP_NODE_TEXT);
1561 return -1;
1562 } else {
1563 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1564 return 1;
1565 }
1566 }
1567
Michal Vasko9f96a052020-03-10 09:41:45 +01001568 /* we need meta positions now */
1569 if (item1->type == LYXP_NODE_META) {
1570 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001571 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001572 if (item2->type == LYXP_NODE_META) {
1573 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001574 }
1575
Michal Vasko9f96a052020-03-10 09:41:45 +01001576 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001577 /* check for duplicates */
1578 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001579 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001580 return 0;
1581 }
1582
Michal Vasko9f96a052020-03-10 09:41:45 +01001583 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001584 /* elem is always first, 2nd node is after it */
1585 if (item1->type == LYXP_NODE_ELEM) {
1586 assert(item2->type != LYXP_NODE_ELEM);
1587 return -1;
1588 }
1589
Michal Vasko9f96a052020-03-10 09:41:45 +01001590 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd META, 1st META - any pos - 2nd ELEM, 1st META - >pos> - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001591 /* 2nd is before 1st */
Michal Vasko69730152020-10-09 16:30:07 +02001592 if (((item1->type == LYXP_NODE_TEXT) &&
1593 ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META))) ||
1594 ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM)) ||
1595 (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META)) &&
1596 (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001597 return 1;
1598 }
1599
Michal Vasko9f96a052020-03-10 09:41:45 +01001600 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001601 /* 2nd is after 1st */
1602 return -1;
1603}
1604
1605/**
1606 * @brief Set cast for comparisons.
1607 *
Michal Vasko8abcecc2022-07-28 09:55:01 +02001608 * @param[in,out] trg Target set to cast source into.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001609 * @param[in] src Source set.
1610 * @param[in] type Target set type.
1611 * @param[in] src_idx Source set node index.
Michal Vasko8abcecc2022-07-28 09:55:01 +02001612 * @return LY_SUCCESS on success.
1613 * @return LY_ERR value on error.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001614 */
1615static LY_ERR
Michal Vasko8abcecc2022-07-28 09:55:01 +02001616set_comp_cast(struct lyxp_set *trg, const struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001617{
1618 assert(src->type == LYXP_SET_NODE_SET);
1619
1620 set_init(trg, src);
1621
1622 /* insert node into target set */
1623 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1624
1625 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001626 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001627}
1628
Michal Vasko4c7763f2020-07-27 17:40:37 +02001629/**
1630 * @brief Set content canonization for comparisons.
1631 *
Michal Vasko8abcecc2022-07-28 09:55:01 +02001632 * @param[in,out] set Set to canonize.
Michal Vasko4c7763f2020-07-27 17:40:37 +02001633 * @param[in] xp_node Source XPath node/meta to use for canonization.
Michal Vasko8abcecc2022-07-28 09:55:01 +02001634 * @return LY_SUCCESS on success.
1635 * @return LY_ERR value on error.
Michal Vasko4c7763f2020-07-27 17:40:37 +02001636 */
1637static LY_ERR
Michal Vasko8abcecc2022-07-28 09:55:01 +02001638set_comp_canonize(struct lyxp_set *set, const struct lyxp_set_node *xp_node)
Michal Vasko4c7763f2020-07-27 17:40:37 +02001639{
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001640 const struct lysc_type *type = NULL;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001641 struct lyd_value val;
1642 struct ly_err_item *err = NULL;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001643 LY_ERR rc;
1644
1645 /* is there anything to canonize even? */
Michal Vasko8abcecc2022-07-28 09:55:01 +02001646 if (set->type == LYXP_SET_STRING) {
Michal Vasko4c7763f2020-07-27 17:40:37 +02001647 /* do we have a type to use for canonization? */
1648 if ((xp_node->type == LYXP_NODE_ELEM) && (xp_node->node->schema->nodetype & LYD_NODE_TERM)) {
1649 type = ((struct lyd_node_term *)xp_node->node)->value.realtype;
1650 } else if (xp_node->type == LYXP_NODE_META) {
1651 type = ((struct lyd_meta *)xp_node->node)->value.realtype;
1652 }
1653 }
1654 if (!type) {
Michal Vasko8abcecc2022-07-28 09:55:01 +02001655 /* no canonization needed/possible */
1656 return LY_SUCCESS;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001657 }
1658
Michal Vasko8abcecc2022-07-28 09:55:01 +02001659 /* check for built-in types without required canonization */
1660 if ((type->basetype == LY_TYPE_STRING) && (type->plugin->store == lyplg_type_store_string)) {
1661 /* string */
1662 return LY_SUCCESS;
1663 }
1664 if ((type->basetype == LY_TYPE_BOOL) && (type->plugin->store == lyplg_type_store_boolean)) {
1665 /* boolean */
1666 return LY_SUCCESS;
1667 }
1668 if ((type->basetype == LY_TYPE_ENUM) && (type->plugin->store == lyplg_type_store_enum)) {
1669 /* enumeration */
1670 return LY_SUCCESS;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001671 }
1672
Michal Vasko8abcecc2022-07-28 09:55:01 +02001673 /* print canonized string, ignore errors, the value may not satisfy schema constraints */
1674 rc = type->plugin->store(set->ctx, type, set->val.str, strlen(set->val.str), 0, set->format, set->prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001675 LYD_HINT_DATA, xp_node->node->schema, &val, NULL, &err);
Michal Vasko4c7763f2020-07-27 17:40:37 +02001676 ly_err_free(err);
1677 if (rc) {
Michal Vasko8abcecc2022-07-28 09:55:01 +02001678 /* invalid value, function store automaticaly dealloc value when fail */
1679 return LY_SUCCESS;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001680 }
1681
Michal Vasko8abcecc2022-07-28 09:55:01 +02001682 /* use the canonized string value */
1683 free(set->val.str);
1684 set->val.str = strdup(lyd_value_get_canonical(set->ctx, &val));
1685 type->plugin->free(set->ctx, &val);
1686 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
Michal Vasko4c7763f2020-07-27 17:40:37 +02001687
Michal Vasko4c7763f2020-07-27 17:40:37 +02001688 return LY_SUCCESS;
1689}
1690
Michal Vasko03ff5a72019-09-11 13:49:33 +02001691/**
1692 * @brief Bubble sort @p set into XPath document order.
Michal Vasko49fec8e2022-05-24 10:28:33 +02001693 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001694 *
1695 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001696 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1697 */
1698static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001699set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001700{
1701 uint32_t i, j;
Radek Krejci1deb5be2020-08-26 16:43:36 +02001702 int ret = 0, cmp;
Radek Krejci857189e2020-09-01 13:26:36 +02001703 ly_bool inverted, change;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001704 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001705 struct lyxp_set_node item;
1706 struct lyxp_set_hash_node hnode;
1707 uint64_t hash;
1708
Michal Vasko3cf8fbf2020-05-27 15:21:21 +02001709 if ((set->type != LYXP_SET_NODE_SET) || (set->used < 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001710 return 0;
1711 }
1712
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001713 /* find first top-level node to be used as anchor for positions */
Michal Vasko4a7d4d62021-12-13 17:05:06 +01001714 for (root = set->tree; root->parent; root = lyd_parent(root)) {}
Michal Vaskod989ba02020-08-24 10:59:24 +02001715 for ( ; root->prev->next; root = root->prev) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001716
1717 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001718 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001719 return -1;
1720 }
1721
Michal Vasko88a9e802022-05-24 10:50:28 +02001722#ifndef NDEBUG
Michal Vasko03ff5a72019-09-11 13:49:33 +02001723 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1724 print_set_debug(set);
Michal Vasko88a9e802022-05-24 10:50:28 +02001725#endif
Michal Vasko03ff5a72019-09-11 13:49:33 +02001726
1727 for (i = 0; i < set->used; ++i) {
1728 inverted = 0;
1729 change = 0;
1730
1731 for (j = 1; j < set->used - i; ++j) {
1732 /* compare node positions */
1733 if (inverted) {
1734 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1735 } else {
1736 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1737 }
1738
1739 /* swap if needed */
1740 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1741 change = 1;
1742
1743 item = set->val.nodes[j - 1];
1744 set->val.nodes[j - 1] = set->val.nodes[j];
1745 set->val.nodes[j] = item;
1746 } else {
1747 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1748 inverted = !inverted;
1749 }
1750 }
1751
1752 ++ret;
1753
1754 if (!change) {
1755 break;
1756 }
1757 }
1758
Michal Vasko88a9e802022-05-24 10:50:28 +02001759#ifndef NDEBUG
Michal Vasko03ff5a72019-09-11 13:49:33 +02001760 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1761 print_set_debug(set);
Michal Vasko88a9e802022-05-24 10:50:28 +02001762#endif
Michal Vasko03ff5a72019-09-11 13:49:33 +02001763
1764 /* check node hashes */
1765 if (set->used >= LYD_HT_MIN_ITEMS) {
1766 assert(set->ht);
1767 for (i = 0; i < set->used; ++i) {
1768 hnode.node = set->val.nodes[i].node;
1769 hnode.type = set->val.nodes[i].type;
1770
1771 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1772 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1773 hash = dict_hash_multi(hash, NULL, 0);
1774
1775 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1776 }
1777 }
1778
1779 return ret - 1;
1780}
1781
Michal Vasko03ff5a72019-09-11 13:49:33 +02001782/**
1783 * @brief Merge 2 sorted sets into one.
1784 *
1785 * @param[in,out] trg Set to merge into. Duplicates are removed.
1786 * @param[in] src Set to be merged into @p trg. It is cast to #LYXP_SET_EMPTY on success.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001787 * @return LY_ERR
1788 */
1789static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001790set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001791{
1792 uint32_t i, j, k, count, dup_count;
1793 int cmp;
1794 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001795
Michal Vaskod3678892020-05-21 10:06:58 +02001796 if ((trg->type != LYXP_SET_NODE_SET) || (src->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001797 return LY_EINVAL;
1798 }
1799
Michal Vaskod3678892020-05-21 10:06:58 +02001800 if (!src->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001801 return LY_SUCCESS;
Michal Vaskod3678892020-05-21 10:06:58 +02001802 } else if (!trg->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001803 set_fill_set(trg, src);
Michal Vaskod3678892020-05-21 10:06:58 +02001804 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001805 return LY_SUCCESS;
1806 }
1807
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001808 /* find first top-level node to be used as anchor for positions */
Michal Vasko0143b682021-12-13 17:13:09 +01001809 for (root = trg->tree; root->parent; root = lyd_parent(root)) {}
Michal Vaskod989ba02020-08-24 10:59:24 +02001810 for ( ; root->prev->next; root = root->prev) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001811
1812 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001813 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001814 return LY_EINT;
1815 }
1816
1817#ifndef NDEBUG
1818 LOGDBG(LY_LDGXPATH, "MERGE target");
1819 print_set_debug(trg);
1820 LOGDBG(LY_LDGXPATH, "MERGE source");
1821 print_set_debug(src);
1822#endif
1823
1824 /* make memory for the merge (duplicates are not detected yet, so space
1825 * will likely be wasted on them, too bad) */
1826 if (trg->size - trg->used < src->used) {
1827 trg->size = trg->used + src->used;
1828
1829 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1830 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1831 }
1832
1833 i = 0;
1834 j = 0;
1835 count = 0;
1836 dup_count = 0;
1837 do {
1838 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1839 if (!cmp) {
1840 if (!count) {
1841 /* duplicate, just skip it */
1842 ++i;
1843 ++j;
1844 } else {
1845 /* we are copying something already, so let's copy the duplicate too,
1846 * we are hoping that afterwards there are some more nodes to
1847 * copy and this way we can copy them all together */
1848 ++count;
1849 ++dup_count;
1850 ++i;
1851 ++j;
1852 }
1853 } else if (cmp < 0) {
1854 /* inserting src node into trg, just remember it for now */
1855 ++count;
1856 ++i;
1857
1858 /* insert the hash now */
1859 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1860 } else if (count) {
1861copy_nodes:
1862 /* time to actually copy the nodes, we have found the largest block of nodes */
1863 memmove(&trg->val.nodes[j + (count - dup_count)],
1864 &trg->val.nodes[j],
1865 (trg->used - j) * sizeof *trg->val.nodes);
1866 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1867
1868 trg->used += count - dup_count;
1869 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1870 j += count - dup_count;
1871
1872 count = 0;
1873 dup_count = 0;
1874 } else {
1875 ++j;
1876 }
1877 } while ((i < src->used) && (j < trg->used));
1878
1879 if ((i < src->used) || count) {
1880 /* insert all the hashes first */
1881 for (k = i; k < src->used; ++k) {
1882 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1883 }
1884
1885 /* loop ended, but we need to copy something at trg end */
1886 count += src->used - i;
1887 i = src->used;
1888 goto copy_nodes;
1889 }
1890
1891 /* we are inserting hashes before the actual node insert, which causes
1892 * situations when there were initially not enough items for a hash table,
1893 * but even after some were inserted, hash table was not created (during
1894 * insertion the number of items is not updated yet) */
1895 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1896 set_insert_node_hash(trg, NULL, 0);
1897 }
1898
1899#ifndef NDEBUG
1900 LOGDBG(LY_LDGXPATH, "MERGE result");
1901 print_set_debug(trg);
1902#endif
1903
Michal Vaskod3678892020-05-21 10:06:58 +02001904 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001905 return LY_SUCCESS;
1906}
1907
Michal Vasko14676352020-05-29 11:35:55 +02001908LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02001909lyxp_check_token(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t tok_idx, enum lyxp_token want_tok)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001910{
Michal Vasko004d3152020-06-11 19:59:22 +02001911 if (exp->used == tok_idx) {
Michal Vasko14676352020-05-29 11:35:55 +02001912 if (ctx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001913 LOGVAL(ctx, LY_VCODE_XP_EOF);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001914 }
Michal Vasko14676352020-05-29 11:35:55 +02001915 return LY_EINCOMPLETE;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001916 }
1917
Michal Vasko004d3152020-06-11 19:59:22 +02001918 if (want_tok && (exp->tokens[tok_idx] != want_tok)) {
Michal Vasko14676352020-05-29 11:35:55 +02001919 if (ctx) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02001920 LOGVAL(ctx, LY_VCODE_XP_INTOK2, lyxp_token2str(exp->tokens[tok_idx]),
1921 &exp->expr[exp->tok_pos[tok_idx]], lyxp_token2str(want_tok));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001922 }
Michal Vasko14676352020-05-29 11:35:55 +02001923 return LY_ENOT;
1924 }
1925
1926 return LY_SUCCESS;
1927}
1928
Michal Vasko004d3152020-06-11 19:59:22 +02001929LY_ERR
1930lyxp_next_token(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_token want_tok)
1931{
1932 LY_CHECK_RET(lyxp_check_token(ctx, exp, *tok_idx, want_tok));
1933
1934 /* skip the token */
1935 ++(*tok_idx);
1936
1937 return LY_SUCCESS;
1938}
1939
Michal Vasko14676352020-05-29 11:35:55 +02001940/* just like lyxp_check_token() but tests for 2 tokens */
1941static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02001942exp_check_token2(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t tok_idx, enum lyxp_token want_tok1,
Radek Krejci0f969882020-08-21 16:56:47 +02001943 enum lyxp_token want_tok2)
Michal Vasko14676352020-05-29 11:35:55 +02001944{
Michal Vasko004d3152020-06-11 19:59:22 +02001945 if (exp->used == tok_idx) {
Michal Vasko14676352020-05-29 11:35:55 +02001946 if (ctx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001947 LOGVAL(ctx, LY_VCODE_XP_EOF);
Michal Vasko14676352020-05-29 11:35:55 +02001948 }
1949 return LY_EINCOMPLETE;
1950 }
1951
Michal Vasko004d3152020-06-11 19:59:22 +02001952 if ((exp->tokens[tok_idx] != want_tok1) && (exp->tokens[tok_idx] != want_tok2)) {
Michal Vasko14676352020-05-29 11:35:55 +02001953 if (ctx) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02001954 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[tok_idx]),
Michal Vasko0b468e62020-10-19 09:33:04 +02001955 &exp->expr[exp->tok_pos[tok_idx]]);
Michal Vasko14676352020-05-29 11:35:55 +02001956 }
1957 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001958 }
1959
1960 return LY_SUCCESS;
1961}
1962
Michal Vasko4911eeb2021-06-28 11:23:05 +02001963LY_ERR
1964lyxp_next_token2(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_token want_tok1,
1965 enum lyxp_token want_tok2)
1966{
1967 LY_CHECK_RET(exp_check_token2(ctx, exp, *tok_idx, want_tok1, want_tok2));
1968
1969 /* skip the token */
1970 ++(*tok_idx);
1971
1972 return LY_SUCCESS;
1973}
1974
Michal Vasko03ff5a72019-09-11 13:49:33 +02001975/**
1976 * @brief Stack operation push on the repeat array.
1977 *
1978 * @param[in] exp Expression to use.
Michal Vasko004d3152020-06-11 19:59:22 +02001979 * @param[in] tok_idx Position in the expresion \p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001980 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1981 */
1982static void
Michal Vasko004d3152020-06-11 19:59:22 +02001983exp_repeat_push(struct lyxp_expr *exp, uint16_t tok_idx, uint16_t repeat_op_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001984{
1985 uint16_t i;
1986
Michal Vasko004d3152020-06-11 19:59:22 +02001987 if (exp->repeat[tok_idx]) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001988 for (i = 0; exp->repeat[tok_idx][i]; ++i) {}
Michal Vasko004d3152020-06-11 19:59:22 +02001989 exp->repeat[tok_idx] = realloc(exp->repeat[tok_idx], (i + 2) * sizeof *exp->repeat[tok_idx]);
1990 LY_CHECK_ERR_RET(!exp->repeat[tok_idx], LOGMEM(NULL), );
1991 exp->repeat[tok_idx][i] = repeat_op_idx;
1992 exp->repeat[tok_idx][i + 1] = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001993 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001994 exp->repeat[tok_idx] = calloc(2, sizeof *exp->repeat[tok_idx]);
1995 LY_CHECK_ERR_RET(!exp->repeat[tok_idx], LOGMEM(NULL), );
1996 exp->repeat[tok_idx][0] = repeat_op_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001997 }
1998}
1999
2000/**
2001 * @brief Reparse Predicate. Logs directly on error.
2002 *
2003 * [7] Predicate ::= '[' Expr ']'
2004 *
2005 * @param[in] ctx Context for logging.
2006 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002007 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002008 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002009 * @return LY_ERR
2010 */
2011static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002012reparse_predicate(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002013{
2014 LY_ERR rc;
2015
Michal Vasko004d3152020-06-11 19:59:22 +02002016 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_BRACK1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002017 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002018 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002019
aPiecekbf968d92021-05-27 14:35:05 +02002020 rc = reparse_or_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002021 LY_CHECK_RET(rc);
2022
Michal Vasko004d3152020-06-11 19:59:22 +02002023 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_BRACK2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002024 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002025 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002026
2027 return LY_SUCCESS;
2028}
2029
2030/**
2031 * @brief Reparse RelativeLocationPath. Logs directly on error.
2032 *
2033 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
2034 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
2035 * [6] NodeTest ::= NameTest | NodeType '(' ')'
2036 *
2037 * @param[in] ctx Context for logging.
2038 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002039 * @param[in] tok_idx Position in the expression \p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002040 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002041 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
2042 */
2043static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002044reparse_relative_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002045{
2046 LY_ERR rc;
2047
Michal Vasko004d3152020-06-11 19:59:22 +02002048 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002049 LY_CHECK_RET(rc);
2050
2051 goto step;
2052 do {
2053 /* '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02002054 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002055
Michal Vasko004d3152020-06-11 19:59:22 +02002056 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002057 LY_CHECK_RET(rc);
2058step:
2059 /* Step */
Michal Vasko004d3152020-06-11 19:59:22 +02002060 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002061 case LYXP_TOKEN_DOT:
Michal Vasko004d3152020-06-11 19:59:22 +02002062 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002063 break;
2064
2065 case LYXP_TOKEN_DDOT:
Michal Vasko004d3152020-06-11 19:59:22 +02002066 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002067 break;
2068
Michal Vasko49fec8e2022-05-24 10:28:33 +02002069 case LYXP_TOKEN_AXISNAME:
2070 ++(*tok_idx);
2071
2072 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_DCOLON);
2073 LY_CHECK_RET(rc);
2074
2075 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002076 case LYXP_TOKEN_AT:
Michal Vasko004d3152020-06-11 19:59:22 +02002077 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002078
Michal Vasko004d3152020-06-11 19:59:22 +02002079 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002080 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002081 if ((exp->tokens[*tok_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*tok_idx] != LYXP_TOKEN_NODETYPE)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02002082 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002083 return LY_EVALID;
2084 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02002085 if (exp->tokens[*tok_idx] == LYXP_TOKEN_NODETYPE) {
2086 goto reparse_nodetype;
2087 }
Radek Krejci0f969882020-08-21 16:56:47 +02002088 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002089 case LYXP_TOKEN_NAMETEST:
Michal Vasko004d3152020-06-11 19:59:22 +02002090 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002091 goto reparse_predicate;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002092
2093 case LYXP_TOKEN_NODETYPE:
Michal Vasko49fec8e2022-05-24 10:28:33 +02002094reparse_nodetype:
Michal Vasko004d3152020-06-11 19:59:22 +02002095 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002096
2097 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02002098 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002099 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002100 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002101
2102 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02002103 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002104 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002105 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002106
2107reparse_predicate:
2108 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002109 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
aPiecekbf968d92021-05-27 14:35:05 +02002110 rc = reparse_predicate(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002111 LY_CHECK_RET(rc);
2112 }
2113 break;
2114 default:
Michal Vasko49fec8e2022-05-24 10:28:33 +02002115 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002116 return LY_EVALID;
2117 }
Michal Vasko004d3152020-06-11 19:59:22 +02002118 } while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02002119
2120 return LY_SUCCESS;
2121}
2122
2123/**
2124 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
2125 *
2126 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
2127 *
2128 * @param[in] ctx Context for logging.
2129 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002130 * @param[in] tok_idx Position in the expression \p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002131 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002132 * @return LY_ERR
2133 */
2134static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002135reparse_absolute_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002136{
2137 LY_ERR rc;
2138
Michal Vasko004d3152020-06-11 19:59:22 +02002139 LY_CHECK_RET(exp_check_token2(ctx, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02002140
2141 /* '/' RelativeLocationPath? */
Michal Vasko004d3152020-06-11 19:59:22 +02002142 if (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002143 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +02002144 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002145
Michal Vasko004d3152020-06-11 19:59:22 +02002146 if (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002147 return LY_SUCCESS;
2148 }
Michal Vasko004d3152020-06-11 19:59:22 +02002149 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002150 case LYXP_TOKEN_DOT:
2151 case LYXP_TOKEN_DDOT:
Michal Vasko49fec8e2022-05-24 10:28:33 +02002152 case LYXP_TOKEN_AXISNAME:
Michal Vasko03ff5a72019-09-11 13:49:33 +02002153 case LYXP_TOKEN_AT:
2154 case LYXP_TOKEN_NAMETEST:
2155 case LYXP_TOKEN_NODETYPE:
aPiecekbf968d92021-05-27 14:35:05 +02002156 rc = reparse_relative_location_path(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002157 LY_CHECK_RET(rc);
Radek Krejci0f969882020-08-21 16:56:47 +02002158 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002159 default:
2160 break;
2161 }
2162
Michal Vasko03ff5a72019-09-11 13:49:33 +02002163 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02002164 /* '//' RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002165 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002166
aPiecekbf968d92021-05-27 14:35:05 +02002167 rc = reparse_relative_location_path(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002168 LY_CHECK_RET(rc);
2169 }
2170
2171 return LY_SUCCESS;
2172}
2173
2174/**
2175 * @brief Reparse FunctionCall. Logs directly on error.
2176 *
2177 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2178 *
2179 * @param[in] ctx Context for logging.
2180 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002181 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002182 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002183 * @return LY_ERR
2184 */
2185static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002186reparse_function_call(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002187{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002188 int8_t min_arg_count = -1;
2189 uint32_t arg_count, max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002190 uint16_t func_tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002191 LY_ERR rc;
2192
Michal Vasko004d3152020-06-11 19:59:22 +02002193 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002194 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002195 func_tok_idx = *tok_idx;
2196 switch (exp->tok_len[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002197 case 3:
Michal Vasko004d3152020-06-11 19:59:22 +02002198 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "not", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002199 min_arg_count = 1;
2200 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002201 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "sum", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002202 min_arg_count = 1;
2203 max_arg_count = 1;
2204 }
2205 break;
2206 case 4:
Michal Vasko004d3152020-06-11 19:59:22 +02002207 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "lang", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002208 min_arg_count = 1;
2209 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002210 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "last", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002211 min_arg_count = 0;
2212 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002213 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "name", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002214 min_arg_count = 0;
2215 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002216 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "true", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002217 min_arg_count = 0;
2218 max_arg_count = 0;
2219 }
2220 break;
2221 case 5:
Michal Vasko004d3152020-06-11 19:59:22 +02002222 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "count", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002223 min_arg_count = 1;
2224 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002225 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "false", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002226 min_arg_count = 0;
2227 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002228 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "floor", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002229 min_arg_count = 1;
2230 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002231 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "round", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002232 min_arg_count = 1;
2233 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002234 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002235 min_arg_count = 1;
2236 max_arg_count = 1;
2237 }
2238 break;
2239 case 6:
Michal Vasko004d3152020-06-11 19:59:22 +02002240 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "concat", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002241 min_arg_count = 2;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002242 max_arg_count = UINT32_MAX;
Michal Vasko004d3152020-06-11 19:59:22 +02002243 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "number", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002244 min_arg_count = 0;
2245 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002246 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002247 min_arg_count = 0;
2248 max_arg_count = 1;
2249 }
2250 break;
2251 case 7:
Michal Vasko004d3152020-06-11 19:59:22 +02002252 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "boolean", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002253 min_arg_count = 1;
2254 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002255 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "ceiling", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002256 min_arg_count = 1;
2257 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002258 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "current", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002259 min_arg_count = 0;
2260 max_arg_count = 0;
2261 }
2262 break;
2263 case 8:
Michal Vasko004d3152020-06-11 19:59:22 +02002264 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "contains", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002265 min_arg_count = 2;
2266 max_arg_count = 2;
Michal Vasko004d3152020-06-11 19:59:22 +02002267 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "position", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002268 min_arg_count = 0;
2269 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002270 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "re-match", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002271 min_arg_count = 2;
2272 max_arg_count = 2;
2273 }
2274 break;
2275 case 9:
Michal Vasko004d3152020-06-11 19:59:22 +02002276 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002277 min_arg_count = 2;
2278 max_arg_count = 3;
Michal Vasko004d3152020-06-11 19:59:22 +02002279 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "translate", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002280 min_arg_count = 3;
2281 max_arg_count = 3;
2282 }
2283 break;
2284 case 10:
Michal Vasko004d3152020-06-11 19:59:22 +02002285 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "local-name", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002286 min_arg_count = 0;
2287 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002288 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "enum-value", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002289 min_arg_count = 1;
2290 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002291 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "bit-is-set", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002292 min_arg_count = 2;
2293 max_arg_count = 2;
2294 }
2295 break;
2296 case 11:
Michal Vasko004d3152020-06-11 19:59:22 +02002297 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "starts-with", 11)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002298 min_arg_count = 2;
2299 max_arg_count = 2;
2300 }
2301 break;
2302 case 12:
Michal Vasko004d3152020-06-11 19:59:22 +02002303 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from", 12)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002304 min_arg_count = 2;
2305 max_arg_count = 2;
2306 }
2307 break;
2308 case 13:
Michal Vasko004d3152020-06-11 19:59:22 +02002309 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "namespace-uri", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002310 min_arg_count = 0;
2311 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002312 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string-length", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002313 min_arg_count = 0;
2314 max_arg_count = 1;
2315 }
2316 break;
2317 case 15:
Michal Vasko004d3152020-06-11 19:59:22 +02002318 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "normalize-space", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002319 min_arg_count = 0;
2320 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002321 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-after", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002322 min_arg_count = 2;
2323 max_arg_count = 2;
2324 }
2325 break;
2326 case 16:
Michal Vasko004d3152020-06-11 19:59:22 +02002327 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-before", 16)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002328 min_arg_count = 2;
2329 max_arg_count = 2;
2330 }
2331 break;
2332 case 20:
Michal Vasko004d3152020-06-11 19:59:22 +02002333 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from-or-self", 20)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002334 min_arg_count = 2;
2335 max_arg_count = 2;
2336 }
2337 break;
2338 }
2339 if (min_arg_count == -1) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002340 LOGVAL(ctx, LY_VCODE_XP_INFUNC, exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002341 return LY_EINVAL;
2342 }
Michal Vasko004d3152020-06-11 19:59:22 +02002343 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002344
2345 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02002346 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002347 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002348 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002349
2350 /* ( Expr ( ',' Expr )* )? */
2351 arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002352 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002353 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002354 if (exp->tokens[*tok_idx] != LYXP_TOKEN_PAR2) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002355 ++arg_count;
aPiecekbf968d92021-05-27 14:35:05 +02002356 rc = reparse_or_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002357 LY_CHECK_RET(rc);
2358 }
Michal Vasko004d3152020-06-11 19:59:22 +02002359 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_COMMA)) {
2360 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002361
2362 ++arg_count;
aPiecekbf968d92021-05-27 14:35:05 +02002363 rc = reparse_or_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002364 LY_CHECK_RET(rc);
2365 }
2366
2367 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02002368 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002369 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002370 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002371
Radek Krejci857189e2020-09-01 13:26:36 +02002372 if ((arg_count < (uint32_t)min_arg_count) || (arg_count > max_arg_count)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002373 LOGVAL(ctx, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_tok_idx], &exp->expr[exp->tok_pos[func_tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002374 return LY_EVALID;
2375 }
2376
2377 return LY_SUCCESS;
2378}
2379
2380/**
2381 * @brief Reparse PathExpr. Logs directly on error.
2382 *
2383 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2384 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2385 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2386 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
aPiecekfba75362021-10-07 12:39:48 +02002387 * [8] PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
Michal Vasko03ff5a72019-09-11 13:49:33 +02002388 *
2389 * @param[in] ctx Context for logging.
2390 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002391 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002392 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002393 * @return LY_ERR
2394 */
2395static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002396reparse_path_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002397{
2398 LY_ERR rc;
2399
Michal Vasko004d3152020-06-11 19:59:22 +02002400 if (lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko14676352020-05-29 11:35:55 +02002401 return LY_EVALID;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002402 }
2403
Michal Vasko004d3152020-06-11 19:59:22 +02002404 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002405 case LYXP_TOKEN_PAR1:
2406 /* '(' Expr ')' Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002407 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002408
aPiecekbf968d92021-05-27 14:35:05 +02002409 rc = reparse_or_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002410 LY_CHECK_RET(rc);
2411
Michal Vasko004d3152020-06-11 19:59:22 +02002412 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002413 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002414 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002415 goto predicate;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002416 case LYXP_TOKEN_DOT:
2417 case LYXP_TOKEN_DDOT:
Michal Vasko49fec8e2022-05-24 10:28:33 +02002418 case LYXP_TOKEN_AXISNAME:
Michal Vasko03ff5a72019-09-11 13:49:33 +02002419 case LYXP_TOKEN_AT:
2420 case LYXP_TOKEN_NAMETEST:
2421 case LYXP_TOKEN_NODETYPE:
2422 /* RelativeLocationPath */
aPiecekbf968d92021-05-27 14:35:05 +02002423 rc = reparse_relative_location_path(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002424 LY_CHECK_RET(rc);
2425 break;
aPiecekfba75362021-10-07 12:39:48 +02002426 case LYXP_TOKEN_VARREF:
2427 /* VariableReference */
2428 ++(*tok_idx);
2429 goto predicate;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002430 case LYXP_TOKEN_FUNCNAME:
2431 /* FunctionCall */
aPiecekbf968d92021-05-27 14:35:05 +02002432 rc = reparse_function_call(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002433 LY_CHECK_RET(rc);
2434 goto predicate;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002435 case LYXP_TOKEN_OPER_PATH:
2436 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02002437 /* AbsoluteLocationPath */
aPiecekbf968d92021-05-27 14:35:05 +02002438 rc = reparse_absolute_location_path(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002439 LY_CHECK_RET(rc);
2440 break;
2441 case LYXP_TOKEN_LITERAL:
2442 /* Literal */
Michal Vasko004d3152020-06-11 19:59:22 +02002443 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002444 goto predicate;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002445 case LYXP_TOKEN_NUMBER:
2446 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +02002447 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002448 goto predicate;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002449 default:
Michal Vasko49fec8e2022-05-24 10:28:33 +02002450 LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002451 return LY_EVALID;
2452 }
2453
2454 return LY_SUCCESS;
2455
2456predicate:
2457 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002458 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
aPiecekbf968d92021-05-27 14:35:05 +02002459 rc = reparse_predicate(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002460 LY_CHECK_RET(rc);
2461 }
2462
2463 /* ('/' or '//') RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002464 if (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002465
2466 /* '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02002467 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002468
aPiecekbf968d92021-05-27 14:35:05 +02002469 rc = reparse_relative_location_path(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002470 LY_CHECK_RET(rc);
2471 }
2472
2473 return LY_SUCCESS;
2474}
2475
2476/**
2477 * @brief Reparse UnaryExpr. Logs directly on error.
2478 *
2479 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2480 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2481 *
2482 * @param[in] ctx Context for logging.
2483 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002484 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002485 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002486 * @return LY_ERR
2487 */
2488static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002489reparse_unary_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002490{
2491 uint16_t prev_exp;
2492 LY_ERR rc;
2493
2494 /* ('-')* */
Michal Vasko004d3152020-06-11 19:59:22 +02002495 prev_exp = *tok_idx;
Michal Vasko69730152020-10-09 16:30:07 +02002496 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2497 (exp->expr[exp->tok_pos[*tok_idx]] == '-')) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002498 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
Michal Vasko004d3152020-06-11 19:59:22 +02002499 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002500 }
2501
2502 /* PathExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002503 prev_exp = *tok_idx;
aPiecekbf968d92021-05-27 14:35:05 +02002504 rc = reparse_path_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002505 LY_CHECK_RET(rc);
2506
2507 /* ('|' PathExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002508 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_UNI)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002509 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
Michal Vasko004d3152020-06-11 19:59:22 +02002510 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002511
aPiecekbf968d92021-05-27 14:35:05 +02002512 rc = reparse_path_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002513 LY_CHECK_RET(rc);
2514 }
2515
2516 return LY_SUCCESS;
2517}
2518
2519/**
2520 * @brief Reparse AdditiveExpr. Logs directly on error.
2521 *
2522 * [15] AdditiveExpr ::= MultiplicativeExpr
2523 * | AdditiveExpr '+' MultiplicativeExpr
2524 * | AdditiveExpr '-' MultiplicativeExpr
2525 * [16] MultiplicativeExpr ::= UnaryExpr
2526 * | MultiplicativeExpr '*' UnaryExpr
2527 * | MultiplicativeExpr 'div' UnaryExpr
2528 * | MultiplicativeExpr 'mod' UnaryExpr
2529 *
2530 * @param[in] ctx Context for logging.
2531 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002532 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002533 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002534 * @return LY_ERR
2535 */
2536static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002537reparse_additive_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002538{
2539 uint16_t prev_add_exp, prev_mul_exp;
2540 LY_ERR rc;
2541
Michal Vasko004d3152020-06-11 19:59:22 +02002542 prev_add_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002543 goto reparse_multiplicative_expr;
2544
2545 /* ('+' / '-' MultiplicativeExpr)* */
Michal Vasko69730152020-10-09 16:30:07 +02002546 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2547 ((exp->expr[exp->tok_pos[*tok_idx]] == '+') || (exp->expr[exp->tok_pos[*tok_idx]] == '-'))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002548 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
Michal Vasko004d3152020-06-11 19:59:22 +02002549 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002550
2551reparse_multiplicative_expr:
2552 /* UnaryExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002553 prev_mul_exp = *tok_idx;
aPiecekbf968d92021-05-27 14:35:05 +02002554 rc = reparse_unary_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002555 LY_CHECK_RET(rc);
2556
2557 /* ('*' / 'div' / 'mod' UnaryExpr)* */
Michal Vasko69730152020-10-09 16:30:07 +02002558 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2559 ((exp->expr[exp->tok_pos[*tok_idx]] == '*') || (exp->tok_len[*tok_idx] == 3))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002560 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
Michal Vasko004d3152020-06-11 19:59:22 +02002561 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002562
aPiecekbf968d92021-05-27 14:35:05 +02002563 rc = reparse_unary_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002564 LY_CHECK_RET(rc);
2565 }
2566 }
2567
2568 return LY_SUCCESS;
2569}
2570
2571/**
2572 * @brief Reparse EqualityExpr. Logs directly on error.
2573 *
2574 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2575 * | EqualityExpr '!=' RelationalExpr
2576 * [14] RelationalExpr ::= AdditiveExpr
2577 * | RelationalExpr '<' AdditiveExpr
2578 * | RelationalExpr '>' AdditiveExpr
2579 * | RelationalExpr '<=' AdditiveExpr
2580 * | RelationalExpr '>=' AdditiveExpr
2581 *
2582 * @param[in] ctx Context for logging.
2583 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002584 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002585 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002586 * @return LY_ERR
2587 */
2588static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002589reparse_equality_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002590{
2591 uint16_t prev_eq_exp, prev_rel_exp;
2592 LY_ERR rc;
2593
Michal Vasko004d3152020-06-11 19:59:22 +02002594 prev_eq_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002595 goto reparse_additive_expr;
2596
2597 /* ('=' / '!=' RelationalExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002598 while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_EQUAL, LYXP_TOKEN_OPER_NEQUAL)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002599 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
Michal Vasko004d3152020-06-11 19:59:22 +02002600 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002601
2602reparse_additive_expr:
2603 /* AdditiveExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002604 prev_rel_exp = *tok_idx;
aPiecekbf968d92021-05-27 14:35:05 +02002605 rc = reparse_additive_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002606 LY_CHECK_RET(rc);
2607
2608 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002609 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_COMP)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002610 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
Michal Vasko004d3152020-06-11 19:59:22 +02002611 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002612
aPiecekbf968d92021-05-27 14:35:05 +02002613 rc = reparse_additive_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002614 LY_CHECK_RET(rc);
2615 }
2616 }
2617
2618 return LY_SUCCESS;
2619}
2620
2621/**
2622 * @brief Reparse OrExpr. Logs directly on error.
2623 *
2624 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2625 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2626 *
2627 * @param[in] ctx Context for logging.
2628 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002629 * @param[in] tok_idx Position in the expression @p exp.
aPiecekbf968d92021-05-27 14:35:05 +02002630 * @param[in] depth Current number of nested expressions.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002631 * @return LY_ERR
2632 */
2633static LY_ERR
aPiecekbf968d92021-05-27 14:35:05 +02002634reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t depth)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002635{
2636 uint16_t prev_or_exp, prev_and_exp;
2637 LY_ERR rc;
2638
aPiecekbf968d92021-05-27 14:35:05 +02002639 ++depth;
2640 LY_CHECK_ERR_RET(depth > LYXP_MAX_BLOCK_DEPTH, LOGVAL(ctx, LY_VCODE_XP_DEPTH), LY_EINVAL);
2641
Michal Vasko004d3152020-06-11 19:59:22 +02002642 prev_or_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002643 goto reparse_equality_expr;
2644
2645 /* ('or' AndExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002646 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_LOG) && (exp->tok_len[*tok_idx] == 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002647 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
Michal Vasko004d3152020-06-11 19:59:22 +02002648 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002649
2650reparse_equality_expr:
2651 /* EqualityExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002652 prev_and_exp = *tok_idx;
aPiecekbf968d92021-05-27 14:35:05 +02002653 rc = reparse_equality_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002654 LY_CHECK_RET(rc);
2655
2656 /* ('and' EqualityExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002657 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_LOG) && (exp->tok_len[*tok_idx] == 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002658 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
Michal Vasko004d3152020-06-11 19:59:22 +02002659 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002660
aPiecekbf968d92021-05-27 14:35:05 +02002661 rc = reparse_equality_expr(ctx, exp, tok_idx, depth);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002662 LY_CHECK_RET(rc);
2663 }
2664 }
2665
2666 return LY_SUCCESS;
2667}
Radek Krejcib1646a92018-11-02 16:08:26 +01002668
2669/**
2670 * @brief Parse NCName.
2671 *
2672 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002673 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002674 */
Michal Vasko49fec8e2022-05-24 10:28:33 +02002675static ssize_t
Radek Krejcib1646a92018-11-02 16:08:26 +01002676parse_ncname(const char *ncname)
2677{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002678 uint32_t uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002679 size_t size;
Michal Vasko49fec8e2022-05-24 10:28:33 +02002680 ssize_t len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002681
2682 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2683 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2684 return len;
2685 }
2686
2687 do {
2688 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002689 if (!*ncname) {
2690 break;
2691 }
Radek Krejcid4270262019-01-07 15:07:25 +01002692 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002693 } while (is_xmlqnamechar(uc) && (uc != ':'));
2694
2695 return len;
2696}
2697
2698/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002699 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002700 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002701 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002702 * @param[in] exp Expression to use.
2703 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002704 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002705 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002706 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002707 */
2708static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002709exp_add_token(const struct ly_ctx *ctx, struct lyxp_expr *exp, enum lyxp_token token, uint16_t tok_pos, uint16_t tok_len)
Radek Krejcib1646a92018-11-02 16:08:26 +01002710{
2711 uint32_t prev;
2712
2713 if (exp->used == exp->size) {
2714 prev = exp->size;
2715 exp->size += LYXP_EXPR_SIZE_STEP;
2716 if (prev > exp->size) {
2717 LOGINT(ctx);
2718 return LY_EINT;
2719 }
2720
2721 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2722 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2723 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2724 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2725 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2726 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2727 }
2728
2729 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002730 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002731 exp->tok_len[exp->used] = tok_len;
2732 ++exp->used;
2733 return LY_SUCCESS;
2734}
2735
2736void
Michal Vasko14676352020-05-29 11:35:55 +02002737lyxp_expr_free(const struct ly_ctx *ctx, struct lyxp_expr *expr)
Radek Krejcib1646a92018-11-02 16:08:26 +01002738{
2739 uint16_t i;
2740
2741 if (!expr) {
2742 return;
2743 }
2744
2745 lydict_remove(ctx, expr->expr);
2746 free(expr->tokens);
2747 free(expr->tok_pos);
2748 free(expr->tok_len);
2749 if (expr->repeat) {
2750 for (i = 0; i < expr->used; ++i) {
2751 free(expr->repeat[i]);
2752 }
2753 }
2754 free(expr->repeat);
2755 free(expr);
2756}
2757
Michal Vasko49fec8e2022-05-24 10:28:33 +02002758/**
2759 * @brief Parse Axis name.
2760 *
2761 * @param[in] str String to parse.
2762 * @param[in] str_len Length of @p str.
2763 * @return LY_SUCCESS if an axis.
2764 * @return LY_ENOT otherwise.
2765 */
2766static LY_ERR
2767expr_parse_axis(const char *str, size_t str_len)
2768{
2769 switch (str_len) {
2770 case 4:
2771 if (!strncmp("self", str, str_len)) {
2772 return LY_SUCCESS;
2773 }
2774 break;
2775 case 5:
2776 if (!strncmp("child", str, str_len)) {
2777 return LY_SUCCESS;
2778 }
2779 break;
2780 case 6:
2781 if (!strncmp("parent", str, str_len)) {
2782 return LY_SUCCESS;
2783 }
2784 break;
2785 case 8:
2786 if (!strncmp("ancestor", str, str_len)) {
2787 return LY_SUCCESS;
2788 }
2789 break;
2790 case 9:
2791 if (!strncmp("attribute", str, str_len)) {
2792 return LY_SUCCESS;
2793 } else if (!strncmp("following", str, str_len)) {
2794 return LY_SUCCESS;
2795 } else if (!strncmp("namespace", str, str_len)) {
2796 LOGERR(NULL, LY_EINVAL, "Axis \"namespace\" not supported.");
2797 return LY_ENOT;
2798 } else if (!strncmp("preceding", str, str_len)) {
2799 return LY_SUCCESS;
2800 }
2801 break;
2802 case 10:
2803 if (!strncmp("descendant", str, str_len)) {
2804 return LY_SUCCESS;
2805 }
2806 break;
2807 case 16:
2808 if (!strncmp("ancestor-or-self", str, str_len)) {
2809 return LY_SUCCESS;
2810 }
2811 break;
2812 case 17:
2813 if (!strncmp("following-sibling", str, str_len)) {
2814 return LY_SUCCESS;
2815 } else if (!strncmp("preceding-sibling", str, str_len)) {
2816 return LY_SUCCESS;
2817 }
2818 break;
2819 case 18:
2820 if (!strncmp("descendant-or-self", str, str_len)) {
2821 return LY_SUCCESS;
2822 }
2823 break;
2824 }
2825
2826 return LY_ENOT;
2827}
2828
Radek Krejcif03a9e22020-09-18 20:09:31 +02002829LY_ERR
2830lyxp_expr_parse(const struct ly_ctx *ctx, const char *expr_str, size_t expr_len, ly_bool reparse, struct lyxp_expr **expr_p)
Radek Krejcib1646a92018-11-02 16:08:26 +01002831{
Radek Krejcif03a9e22020-09-18 20:09:31 +02002832 LY_ERR ret = LY_SUCCESS;
2833 struct lyxp_expr *expr;
Radek Krejcid4270262019-01-07 15:07:25 +01002834 size_t parsed = 0, tok_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002835 enum lyxp_token tok_type;
Michal Vasko49fec8e2022-05-24 10:28:33 +02002836 ly_bool prev_func_check = 0, prev_ntype_check = 0, has_axis;
Michal Vasko004d3152020-06-11 19:59:22 +02002837 uint16_t tok_idx = 0;
Michal Vasko49fec8e2022-05-24 10:28:33 +02002838 ssize_t ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002839
Radek Krejcif03a9e22020-09-18 20:09:31 +02002840 assert(expr_p);
2841
2842 if (!expr_str[0]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01002843 LOGVAL(ctx, LY_VCODE_XP_EOF);
Radek Krejcif03a9e22020-09-18 20:09:31 +02002844 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02002845 }
2846
2847 if (!expr_len) {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002848 expr_len = strlen(expr_str);
Michal Vasko004d3152020-06-11 19:59:22 +02002849 }
2850 if (expr_len > UINT16_MAX) {
Michal Vasko623ac7b2021-04-09 12:44:23 +02002851 LOGVAL(ctx, LYVE_XPATH, "XPath expression cannot be longer than %u characters.", UINT16_MAX);
Radek Krejcif03a9e22020-09-18 20:09:31 +02002852 return LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01002853 }
2854
2855 /* init lyxp_expr structure */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002856 expr = calloc(1, sizeof *expr);
2857 LY_CHECK_ERR_GOTO(!expr, LOGMEM(ctx); ret = LY_EMEM, error);
2858 LY_CHECK_GOTO(ret = lydict_insert(ctx, expr_str, expr_len, &expr->expr), error);
2859 expr->used = 0;
2860 expr->size = LYXP_EXPR_SIZE_START;
2861 expr->tokens = malloc(expr->size * sizeof *expr->tokens);
2862 LY_CHECK_ERR_GOTO(!expr->tokens, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002863
Radek Krejcif03a9e22020-09-18 20:09:31 +02002864 expr->tok_pos = malloc(expr->size * sizeof *expr->tok_pos);
2865 LY_CHECK_ERR_GOTO(!expr->tok_pos, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002866
Radek Krejcif03a9e22020-09-18 20:09:31 +02002867 expr->tok_len = malloc(expr->size * sizeof *expr->tok_len);
2868 LY_CHECK_ERR_GOTO(!expr->tok_len, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002869
Michal Vasko004d3152020-06-11 19:59:22 +02002870 /* make expr 0-terminated */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002871 expr_str = expr->expr;
Michal Vasko004d3152020-06-11 19:59:22 +02002872
Radek Krejcif03a9e22020-09-18 20:09:31 +02002873 while (is_xmlws(expr_str[parsed])) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002874 ++parsed;
2875 }
2876
2877 do {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002878 if (expr_str[parsed] == '(') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002879
2880 /* '(' */
2881 tok_len = 1;
2882 tok_type = LYXP_TOKEN_PAR1;
2883
Michal Vasko49fec8e2022-05-24 10:28:33 +02002884 if (prev_ntype_check && expr->used && (expr->tokens[expr->used - 1] == LYXP_TOKEN_NAMETEST) &&
2885 (((expr->tok_len[expr->used - 1] == 4) &&
2886 (!strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "node", 4) ||
2887 !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "text", 4))) ||
2888 ((expr->tok_len[expr->used - 1] == 7) &&
2889 !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "comment", 7)))) {
2890 /* it is NodeType after all */
2891 expr->tokens[expr->used - 1] = LYXP_TOKEN_NODETYPE;
2892
2893 prev_ntype_check = 0;
2894 prev_func_check = 0;
2895 } else if (prev_func_check && expr->used && (expr->tokens[expr->used - 1] == LYXP_TOKEN_NAMETEST)) {
2896 /* it is FunctionName after all */
2897 expr->tokens[expr->used - 1] = LYXP_TOKEN_FUNCNAME;
2898
2899 prev_ntype_check = 0;
2900 prev_func_check = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002901 }
2902
Radek Krejcif03a9e22020-09-18 20:09:31 +02002903 } else if (expr_str[parsed] == ')') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002904
2905 /* ')' */
2906 tok_len = 1;
2907 tok_type = LYXP_TOKEN_PAR2;
2908
Radek Krejcif03a9e22020-09-18 20:09:31 +02002909 } else if (expr_str[parsed] == '[') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002910
2911 /* '[' */
2912 tok_len = 1;
2913 tok_type = LYXP_TOKEN_BRACK1;
2914
Radek Krejcif03a9e22020-09-18 20:09:31 +02002915 } else if (expr_str[parsed] == ']') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002916
2917 /* ']' */
2918 tok_len = 1;
2919 tok_type = LYXP_TOKEN_BRACK2;
2920
Radek Krejcif03a9e22020-09-18 20:09:31 +02002921 } else if (!strncmp(&expr_str[parsed], "..", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002922
2923 /* '..' */
2924 tok_len = 2;
2925 tok_type = LYXP_TOKEN_DDOT;
2926
Radek Krejcif03a9e22020-09-18 20:09:31 +02002927 } else if ((expr_str[parsed] == '.') && (!isdigit(expr_str[parsed + 1]))) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002928
2929 /* '.' */
2930 tok_len = 1;
2931 tok_type = LYXP_TOKEN_DOT;
2932
Radek Krejcif03a9e22020-09-18 20:09:31 +02002933 } else if (expr_str[parsed] == '@') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002934
2935 /* '@' */
2936 tok_len = 1;
2937 tok_type = LYXP_TOKEN_AT;
2938
Radek Krejcif03a9e22020-09-18 20:09:31 +02002939 } else if (expr_str[parsed] == ',') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002940
2941 /* ',' */
2942 tok_len = 1;
2943 tok_type = LYXP_TOKEN_COMMA;
2944
Radek Krejcif03a9e22020-09-18 20:09:31 +02002945 } else if (expr_str[parsed] == '\'') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002946
2947 /* Literal with ' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002948 for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\''); ++tok_len) {}
2949 LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
Radek Krejci2efc45b2020-12-22 16:25:44 +01002950 LOGVAL(ctx, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
Michal Vasko69730152020-10-09 16:30:07 +02002951 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002952 ++tok_len;
2953 tok_type = LYXP_TOKEN_LITERAL;
2954
Radek Krejcif03a9e22020-09-18 20:09:31 +02002955 } else if (expr_str[parsed] == '\"') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002956
2957 /* Literal with " */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002958 for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\"'); ++tok_len) {}
2959 LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
Radek Krejci2efc45b2020-12-22 16:25:44 +01002960 LOGVAL(ctx, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
Michal Vasko69730152020-10-09 16:30:07 +02002961 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002962 ++tok_len;
2963 tok_type = LYXP_TOKEN_LITERAL;
2964
Radek Krejcif03a9e22020-09-18 20:09:31 +02002965 } else if ((expr_str[parsed] == '.') || (isdigit(expr_str[parsed]))) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002966
2967 /* Number */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002968 for (tok_len = 0; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
2969 if (expr_str[parsed + tok_len] == '.') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002970 ++tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02002971 for ( ; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
Radek Krejcib1646a92018-11-02 16:08:26 +01002972 }
2973 tok_type = LYXP_TOKEN_NUMBER;
2974
aPiecekfba75362021-10-07 12:39:48 +02002975 } else if (expr_str[parsed] == '$') {
2976
2977 /* VariableReference */
2978 parsed++;
Michal Vasko49fec8e2022-05-24 10:28:33 +02002979 ncname_len = parse_ncname(&expr_str[parsed]);
aPiecekfba75362021-10-07 12:39:48 +02002980 LY_CHECK_ERR_GOTO(ncname_len < 1, LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed - ncname_len],
2981 parsed - ncname_len + 1, expr_str); ret = LY_EVALID, error);
2982 tok_len = ncname_len;
2983 LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == ':',
2984 LOGVAL(ctx, LYVE_XPATH, "Variable with prefix is not supported."); ret = LY_EVALID,
2985 error);
2986 tok_type = LYXP_TOKEN_VARREF;
2987
Radek Krejcif03a9e22020-09-18 20:09:31 +02002988 } else if (expr_str[parsed] == '/') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002989
2990 /* Operator '/', '//' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002991 if (!strncmp(&expr_str[parsed], "//", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002992 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002993 tok_type = LYXP_TOKEN_OPER_RPATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002994 } else {
2995 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002996 tok_type = LYXP_TOKEN_OPER_PATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002997 }
Radek Krejcib1646a92018-11-02 16:08:26 +01002998
Radek Krejcif03a9e22020-09-18 20:09:31 +02002999 } else if (!strncmp(&expr_str[parsed], "!=", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003000
Michal Vasko3e48bf32020-06-01 08:39:07 +02003001 /* Operator '!=' */
Radek Krejcib1646a92018-11-02 16:08:26 +01003002 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003003 tok_type = LYXP_TOKEN_OPER_NEQUAL;
3004
Radek Krejcif03a9e22020-09-18 20:09:31 +02003005 } else if (!strncmp(&expr_str[parsed], "<=", 2) || !strncmp(&expr_str[parsed], ">=", 2)) {
Michal Vasko3e48bf32020-06-01 08:39:07 +02003006
3007 /* Operator '<=', '>=' */
3008 tok_len = 2;
3009 tok_type = LYXP_TOKEN_OPER_COMP;
Radek Krejcib1646a92018-11-02 16:08:26 +01003010
Radek Krejcif03a9e22020-09-18 20:09:31 +02003011 } else if (expr_str[parsed] == '|') {
Radek Krejcib1646a92018-11-02 16:08:26 +01003012
3013 /* Operator '|' */
3014 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003015 tok_type = LYXP_TOKEN_OPER_UNI;
Radek Krejcib1646a92018-11-02 16:08:26 +01003016
Radek Krejcif03a9e22020-09-18 20:09:31 +02003017 } else if ((expr_str[parsed] == '+') || (expr_str[parsed] == '-')) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003018
3019 /* Operator '+', '-' */
3020 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003021 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01003022
Radek Krejcif03a9e22020-09-18 20:09:31 +02003023 } else if (expr_str[parsed] == '=') {
Radek Krejcib1646a92018-11-02 16:08:26 +01003024
Michal Vasko3e48bf32020-06-01 08:39:07 +02003025 /* Operator '=' */
Radek Krejcib1646a92018-11-02 16:08:26 +01003026 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003027 tok_type = LYXP_TOKEN_OPER_EQUAL;
3028
Radek Krejcif03a9e22020-09-18 20:09:31 +02003029 } else if ((expr_str[parsed] == '<') || (expr_str[parsed] == '>')) {
Michal Vasko3e48bf32020-06-01 08:39:07 +02003030
3031 /* Operator '<', '>' */
3032 tok_len = 1;
3033 tok_type = LYXP_TOKEN_OPER_COMP;
Radek Krejcib1646a92018-11-02 16:08:26 +01003034
Michal Vasko69730152020-10-09 16:30:07 +02003035 } else if (expr->used && (expr->tokens[expr->used - 1] != LYXP_TOKEN_AT) &&
3036 (expr->tokens[expr->used - 1] != LYXP_TOKEN_PAR1) &&
3037 (expr->tokens[expr->used - 1] != LYXP_TOKEN_BRACK1) &&
3038 (expr->tokens[expr->used - 1] != LYXP_TOKEN_COMMA) &&
3039 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_LOG) &&
3040 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_EQUAL) &&
3041 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_NEQUAL) &&
3042 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_COMP) &&
3043 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_MATH) &&
3044 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_UNI) &&
3045 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_PATH) &&
3046 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_RPATH)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003047
3048 /* Operator '*', 'or', 'and', 'mod', or 'div' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02003049 if (expr_str[parsed] == '*') {
Radek Krejcib1646a92018-11-02 16:08:26 +01003050 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003051 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01003052
Radek Krejcif03a9e22020-09-18 20:09:31 +02003053 } else if (!strncmp(&expr_str[parsed], "or", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003054 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003055 tok_type = LYXP_TOKEN_OPER_LOG;
Radek Krejcib1646a92018-11-02 16:08:26 +01003056
Radek Krejcif03a9e22020-09-18 20:09:31 +02003057 } else if (!strncmp(&expr_str[parsed], "and", 3)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003058 tok_len = 3;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003059 tok_type = LYXP_TOKEN_OPER_LOG;
Radek Krejcib1646a92018-11-02 16:08:26 +01003060
Radek Krejcif03a9e22020-09-18 20:09:31 +02003061 } else if (!strncmp(&expr_str[parsed], "mod", 3) || !strncmp(&expr_str[parsed], "div", 3)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003062 tok_len = 3;
Michal Vasko3e48bf32020-06-01 08:39:07 +02003063 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01003064
Michal Vasko49fec8e2022-05-24 10:28:33 +02003065 } else if (prev_ntype_check || prev_func_check) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003066 LOGVAL(ctx, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
Michal Vasko69730152020-10-09 16:30:07 +02003067 expr_str[parsed], expr_str[parsed], expr->tok_len[expr->used - 1], &expr->expr[expr->tok_pos[expr->used - 1]]);
Radek Krejcif03a9e22020-09-18 20:09:31 +02003068 ret = LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01003069 goto error;
3070 } else {
Michal Vasko774ce402021-04-14 15:35:06 +02003071 LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed], parsed + 1, expr_str);
Radek Krejcif03a9e22020-09-18 20:09:31 +02003072 ret = LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01003073 goto error;
3074 }
Radek Krejcib1646a92018-11-02 16:08:26 +01003075 } else {
3076
Michal Vasko49fec8e2022-05-24 10:28:33 +02003077 /* (AxisName '::')? ((NCName ':')? '*' | QName) or NodeType/FunctionName */
3078 if (expr_str[parsed] == '*') {
3079 ncname_len = 1;
3080 } else {
3081 ncname_len = parse_ncname(&expr_str[parsed]);
3082 LY_CHECK_ERR_GOTO(ncname_len < 1, LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed - ncname_len],
3083 parsed - ncname_len + 1, expr_str); ret = LY_EVALID, error);
3084 }
Radek Krejcib1646a92018-11-02 16:08:26 +01003085 tok_len = ncname_len;
3086
Michal Vasko49fec8e2022-05-24 10:28:33 +02003087 has_axis = 0;
3088 if (!strncmp(&expr_str[parsed + tok_len], "::", 2)) {
3089 /* axis */
3090 LY_CHECK_ERR_GOTO(expr_parse_axis(&expr_str[parsed], ncname_len),
3091 LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed], parsed + 1, expr_str); ret = LY_EVALID, error);
3092 tok_type = LYXP_TOKEN_AXISNAME;
3093
3094 LY_CHECK_GOTO(ret = exp_add_token(ctx, expr, tok_type, parsed, tok_len), error);
3095 parsed += tok_len;
3096
3097 /* '::' */
3098 tok_len = 2;
3099 tok_type = LYXP_TOKEN_DCOLON;
3100
3101 LY_CHECK_GOTO(ret = exp_add_token(ctx, expr, tok_type, parsed, tok_len), error);
3102 parsed += tok_len;
3103
3104 if (expr_str[parsed] == '*') {
3105 ncname_len = 1;
3106 } else {
3107 ncname_len = parse_ncname(&expr_str[parsed]);
3108 LY_CHECK_ERR_GOTO(ncname_len < 1, LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed - ncname_len],
3109 parsed - ncname_len + 1, expr_str); ret = LY_EVALID, error);
3110 }
3111 tok_len = ncname_len;
3112
3113 has_axis = 1;
3114 }
3115
Radek Krejcif03a9e22020-09-18 20:09:31 +02003116 if (expr_str[parsed + tok_len] == ':') {
Radek Krejcib1646a92018-11-02 16:08:26 +01003117 ++tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02003118 if (expr_str[parsed + tok_len] == '*') {
Radek Krejcib1646a92018-11-02 16:08:26 +01003119 ++tok_len;
3120 } else {
Radek Krejcif03a9e22020-09-18 20:09:31 +02003121 ncname_len = parse_ncname(&expr_str[parsed + tok_len]);
Michal Vaskoe2be5462021-08-04 10:49:42 +02003122 LY_CHECK_ERR_GOTO(ncname_len < 1, LOGVAL(ctx, LY_VCODE_XP_INEXPR, expr_str[parsed - ncname_len],
Michal Vasko774ce402021-04-14 15:35:06 +02003123 parsed - ncname_len + 1, expr_str); ret = LY_EVALID, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01003124 tok_len += ncname_len;
3125 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02003126 /* remove old flags to prevent ambiguities */
3127 prev_ntype_check = 0;
3128 prev_func_check = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01003129 tok_type = LYXP_TOKEN_NAMETEST;
3130 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02003131 /* if not '*', there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
3132 prev_ntype_check = (expr_str[parsed] == '*') ? 0 : 1;
3133 prev_func_check = (prev_ntype_check && !has_axis) ? 1 : 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01003134 tok_type = LYXP_TOKEN_NAMETEST;
3135 }
3136 }
3137
3138 /* store the token, move on to the next one */
Radek Krejcif03a9e22020-09-18 20:09:31 +02003139 LY_CHECK_GOTO(ret = exp_add_token(ctx, expr, tok_type, parsed, tok_len), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01003140 parsed += tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02003141 while (is_xmlws(expr_str[parsed])) {
Radek Krejcib1646a92018-11-02 16:08:26 +01003142 ++parsed;
3143 }
3144
Radek Krejcif03a9e22020-09-18 20:09:31 +02003145 } while (expr_str[parsed]);
Radek Krejcib1646a92018-11-02 16:08:26 +01003146
Michal Vasko004d3152020-06-11 19:59:22 +02003147 if (reparse) {
3148 /* prealloc repeat */
Radek Krejcif03a9e22020-09-18 20:09:31 +02003149 expr->repeat = calloc(expr->size, sizeof *expr->repeat);
3150 LY_CHECK_ERR_GOTO(!expr->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01003151
Michal Vasko004d3152020-06-11 19:59:22 +02003152 /* fill repeat */
aPiecekbf968d92021-05-27 14:35:05 +02003153 LY_CHECK_ERR_GOTO(reparse_or_expr(ctx, expr, &tok_idx, 0), ret = LY_EVALID, error);
Radek Krejcif03a9e22020-09-18 20:09:31 +02003154 if (expr->used > tok_idx) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003155 LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
Michal Vasko69730152020-10-09 16:30:07 +02003156 &expr->expr[expr->tok_pos[tok_idx]]);
Radek Krejcif03a9e22020-09-18 20:09:31 +02003157 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02003158 goto error;
3159 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003160 }
3161
Radek Krejcif03a9e22020-09-18 20:09:31 +02003162 print_expr_struct_debug(expr);
3163 *expr_p = expr;
3164 return LY_SUCCESS;
Radek Krejcib1646a92018-11-02 16:08:26 +01003165
3166error:
Radek Krejcif03a9e22020-09-18 20:09:31 +02003167 lyxp_expr_free(ctx, expr);
3168 return ret;
Radek Krejcib1646a92018-11-02 16:08:26 +01003169}
3170
Michal Vasko1734be92020-09-22 08:55:10 +02003171LY_ERR
Michal Vaskoe33134a2022-07-29 14:54:40 +02003172lyxp_expr_dup(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t start_idx, uint16_t end_idx,
3173 struct lyxp_expr **dup_p)
Michal Vasko004d3152020-06-11 19:59:22 +02003174{
Michal Vasko1734be92020-09-22 08:55:10 +02003175 LY_ERR ret = LY_SUCCESS;
3176 struct lyxp_expr *dup = NULL;
Michal Vaskoe33134a2022-07-29 14:54:40 +02003177 uint16_t used = 0, i, j, k, expr_len;
3178 const char *expr_start;
3179
3180 assert((!start_idx && !end_idx) || ((start_idx < exp->used) && (end_idx < exp->used) && (start_idx <= end_idx)));
Michal Vasko004d3152020-06-11 19:59:22 +02003181
Michal Vasko7f45cf22020-10-01 12:49:44 +02003182 if (!exp) {
3183 goto cleanup;
3184 }
3185
Michal Vaskoe33134a2022-07-29 14:54:40 +02003186 if (!start_idx && !end_idx) {
3187 end_idx = exp->used - 1;
3188 }
3189
3190 expr_start = exp->expr + exp->tok_pos[start_idx];
3191 expr_len = (exp->tok_pos[end_idx] + exp->tok_len[end_idx]) - exp->tok_pos[start_idx];
3192
Michal Vasko004d3152020-06-11 19:59:22 +02003193 dup = calloc(1, sizeof *dup);
Michal Vasko1734be92020-09-22 08:55:10 +02003194 LY_CHECK_ERR_GOTO(!dup, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02003195
Michal Vasko08e9b112021-06-11 15:41:17 +02003196 if (exp->used) {
Michal Vaskoe33134a2022-07-29 14:54:40 +02003197 used = (end_idx - start_idx) + 1;
3198
3199 dup->tokens = malloc(used * sizeof *dup->tokens);
Michal Vasko08e9b112021-06-11 15:41:17 +02003200 LY_CHECK_ERR_GOTO(!dup->tokens, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vaskoe33134a2022-07-29 14:54:40 +02003201 memcpy(dup->tokens, exp->tokens + start_idx, used * sizeof *dup->tokens);
Michal Vasko004d3152020-06-11 19:59:22 +02003202
Michal Vaskoe33134a2022-07-29 14:54:40 +02003203 dup->tok_pos = malloc(used * sizeof *dup->tok_pos);
Michal Vasko08e9b112021-06-11 15:41:17 +02003204 LY_CHECK_ERR_GOTO(!dup->tok_pos, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vaskoe33134a2022-07-29 14:54:40 +02003205 memcpy(dup->tok_pos, exp->tok_pos + start_idx, used * sizeof *dup->tok_pos);
Michal Vasko004d3152020-06-11 19:59:22 +02003206
Michal Vaskoe33134a2022-07-29 14:54:40 +02003207 if (start_idx) {
3208 /* fix the indices in the expression */
3209 for (i = 0; i < used; ++i) {
3210 dup->tok_pos[i] -= expr_start - exp->expr;
3211 }
3212 }
3213
3214 dup->tok_len = malloc(used * sizeof *dup->tok_len);
Michal Vasko08e9b112021-06-11 15:41:17 +02003215 LY_CHECK_ERR_GOTO(!dup->tok_len, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vaskoe33134a2022-07-29 14:54:40 +02003216 memcpy(dup->tok_len, exp->tok_len + start_idx, used * sizeof *dup->tok_len);
Michal Vasko004d3152020-06-11 19:59:22 +02003217
Michal Vasko79a7a872022-06-17 09:00:48 +02003218 if (exp->repeat) {
Michal Vaskoe33134a2022-07-29 14:54:40 +02003219 dup->repeat = malloc(used * sizeof *dup->repeat);
Michal Vasko79a7a872022-06-17 09:00:48 +02003220 LY_CHECK_ERR_GOTO(!dup->repeat, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vaskoe33134a2022-07-29 14:54:40 +02003221 for (i = start_idx; i <= end_idx; ++i) {
Michal Vasko79a7a872022-06-17 09:00:48 +02003222 if (!exp->repeat[i]) {
Michal Vaskoe33134a2022-07-29 14:54:40 +02003223 dup->repeat[i - start_idx] = NULL;
Michal Vasko79a7a872022-06-17 09:00:48 +02003224 } else {
3225 for (j = 0; exp->repeat[i][j]; ++j) {}
3226 /* the ending 0 as well */
3227 ++j;
Michal Vasko004d3152020-06-11 19:59:22 +02003228
Michal Vaskoe33134a2022-07-29 14:54:40 +02003229 dup->repeat[i - start_idx] = malloc(j * sizeof **dup->repeat);
3230 LY_CHECK_ERR_GOTO(!dup->repeat[i - start_idx], LOGMEM(ctx); ret = LY_EMEM, cleanup);
3231 memcpy(dup->repeat[i - start_idx], exp->repeat[i], j * sizeof **dup->repeat);
3232 dup->repeat[i - start_idx][j - 1] = 0;
3233
3234 if (start_idx) {
3235 /* fix the indices in the tokens */
3236 for (k = 0; k < j; ++k) {
3237 dup->repeat[i - start_idx][k] -= start_idx;
3238 }
3239 }
Michal Vasko79a7a872022-06-17 09:00:48 +02003240 }
Michal Vasko08e9b112021-06-11 15:41:17 +02003241 }
Michal Vasko004d3152020-06-11 19:59:22 +02003242 }
3243 }
3244
Michal Vaskoe33134a2022-07-29 14:54:40 +02003245 dup->used = used;
3246 dup->size = used;
3247
3248 /* copy only subexpression */
3249 LY_CHECK_GOTO(ret = lydict_insert(ctx, expr_start, expr_len, &dup->expr), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02003250
Michal Vasko1734be92020-09-22 08:55:10 +02003251cleanup:
3252 if (ret) {
3253 lyxp_expr_free(ctx, dup);
3254 } else {
3255 *dup_p = dup;
3256 }
3257 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +02003258}
3259
Michal Vasko03ff5a72019-09-11 13:49:33 +02003260/**
3261 * @brief Get the last-added schema node that is currently in the context.
3262 *
3263 * @param[in] set Set to search in.
3264 * @return Last-added schema context node, NULL if no node is in context.
3265 */
3266static struct lysc_node *
3267warn_get_scnode_in_ctx(struct lyxp_set *set)
3268{
3269 uint32_t i;
3270
3271 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
3272 return NULL;
3273 }
3274
3275 i = set->used;
3276 do {
3277 --i;
Radek Krejcif13b87b2020-12-01 22:02:17 +01003278 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003279 /* if there are more, simply return the first found (last added) */
3280 return set->val.scnodes[i].scnode;
3281 }
3282 } while (i);
3283
3284 return NULL;
3285}
3286
3287/**
3288 * @brief Test whether a type is numeric - integer type or decimal64.
3289 *
3290 * @param[in] type Type to test.
Radek Krejci857189e2020-09-01 13:26:36 +02003291 * @return Boolean value whether @p type is numeric type or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003292 */
Radek Krejci857189e2020-09-01 13:26:36 +02003293static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003294warn_is_numeric_type(struct lysc_type *type)
3295{
3296 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003297 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003298 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003299
3300 switch (type->basetype) {
3301 case LY_TYPE_DEC64:
3302 case LY_TYPE_INT8:
3303 case LY_TYPE_UINT8:
3304 case LY_TYPE_INT16:
3305 case LY_TYPE_UINT16:
3306 case LY_TYPE_INT32:
3307 case LY_TYPE_UINT32:
3308 case LY_TYPE_INT64:
3309 case LY_TYPE_UINT64:
3310 return 1;
3311 case LY_TYPE_UNION:
3312 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003313 LY_ARRAY_FOR(uni->types, u) {
3314 ret = warn_is_numeric_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003315 if (ret) {
3316 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003317 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003318 }
3319 }
3320 /* did not find any suitable type */
3321 return 0;
3322 case LY_TYPE_LEAFREF:
3323 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
3324 default:
3325 return 0;
3326 }
3327}
3328
3329/**
3330 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
3331 *
3332 * @param[in] type Type to test.
Radek Krejci857189e2020-09-01 13:26:36 +02003333 * @return Boolean value whether @p type's basetype is string type or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003334 */
Radek Krejci857189e2020-09-01 13:26:36 +02003335static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003336warn_is_string_type(struct lysc_type *type)
3337{
3338 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003339 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003340 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003341
3342 switch (type->basetype) {
3343 case LY_TYPE_BITS:
3344 case LY_TYPE_ENUM:
3345 case LY_TYPE_IDENT:
3346 case LY_TYPE_INST:
3347 case LY_TYPE_STRING:
3348 return 1;
3349 case LY_TYPE_UNION:
3350 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003351 LY_ARRAY_FOR(uni->types, u) {
3352 ret = warn_is_string_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003353 if (ret) {
3354 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003355 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003356 }
3357 }
3358 /* did not find any suitable type */
3359 return 0;
3360 case LY_TYPE_LEAFREF:
3361 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
3362 default:
3363 return 0;
3364 }
3365}
3366
3367/**
3368 * @brief Test whether a type is one specific type.
3369 *
3370 * @param[in] type Type to test.
3371 * @param[in] base Expected type.
Radek Krejci857189e2020-09-01 13:26:36 +02003372 * @return Boolean value whether the given @p type is of the specific basetype @p base.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003373 */
Radek Krejci857189e2020-09-01 13:26:36 +02003374static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003375warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
3376{
3377 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003378 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003379 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003380
3381 if (type->basetype == base) {
3382 return 1;
3383 } else if (type->basetype == LY_TYPE_UNION) {
3384 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003385 LY_ARRAY_FOR(uni->types, u) {
3386 ret = warn_is_specific_type(uni->types[u], base);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003387 if (ret) {
3388 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003389 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003390 }
3391 }
3392 /* did not find any suitable type */
3393 return 0;
3394 } else if (type->basetype == LY_TYPE_LEAFREF) {
3395 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
3396 }
3397
3398 return 0;
3399}
3400
3401/**
3402 * @brief Get next type of a (union) type.
3403 *
3404 * @param[in] type Base type.
3405 * @param[in] prev_type Previously returned type.
3406 * @return Next type or NULL.
3407 */
3408static struct lysc_type *
3409warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3410{
3411 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003412 ly_bool found = 0;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003413 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003414
3415 switch (type->basetype) {
3416 case LY_TYPE_UNION:
3417 uni = (struct lysc_type_union *)type;
3418 if (!prev_type) {
3419 return uni->types[0];
3420 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003421 LY_ARRAY_FOR(uni->types, u) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003422 if (found) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003423 return uni->types[u];
Michal Vasko03ff5a72019-09-11 13:49:33 +02003424 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003425 if (prev_type == uni->types[u]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003426 found = 1;
3427 }
3428 }
3429 return NULL;
3430 default:
3431 if (prev_type) {
3432 assert(type == prev_type);
3433 return NULL;
3434 } else {
3435 return type;
3436 }
3437 }
3438}
3439
3440/**
3441 * @brief Test whether 2 types have a common type.
3442 *
3443 * @param[in] type1 First type.
3444 * @param[in] type2 Second type.
3445 * @return 1 if they do, 0 otherwise.
3446 */
3447static int
3448warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3449{
3450 struct lysc_type *t1, *rt1, *t2, *rt2;
3451
3452 t1 = NULL;
3453 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3454 if (t1->basetype == LY_TYPE_LEAFREF) {
3455 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3456 } else {
3457 rt1 = t1;
3458 }
3459
3460 t2 = NULL;
3461 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3462 if (t2->basetype == LY_TYPE_LEAFREF) {
3463 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3464 } else {
3465 rt2 = t2;
3466 }
3467
3468 if (rt2->basetype == rt1->basetype) {
3469 /* match found */
3470 return 1;
3471 }
3472 }
3473 }
3474
3475 return 0;
3476}
3477
3478/**
Michal Vaskoaa956522021-11-11 10:45:34 +01003479 * @brief Print warning with information about the XPath subexpression that caused previous warning.
3480 *
3481 * @param[in] ctx Context for logging.
3482 * @param[in] tok_pos Index of the subexpression in the whole expression.
3483 * @param[in] subexpr Subexpression start.
3484 * @param[in] subexpr_len Length of @p subexpr to print.
3485 * @param[in] cur_scnode Expression context node.
3486 */
3487static void
3488warn_subexpr_log(const struct ly_ctx *ctx, uint16_t tok_pos, const char *subexpr, int subexpr_len,
3489 const struct lysc_node *cur_scnode)
3490{
3491 char *path;
3492
3493 path = lysc_path(cur_scnode, LYSC_PATH_LOG, NULL, 0);
3494 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%" PRIu16 "] \"%.*s\" with context node \"%s\".",
3495 tok_pos, subexpr_len, subexpr, path);
3496 free(path);
3497}
3498
3499/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02003500 * @brief Check both operands of comparison operators.
3501 *
3502 * @param[in] ctx Context for errors.
3503 * @param[in] set1 First operand set.
3504 * @param[in] set2 Second operand set.
3505 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3506 * @param[in] expr Start of the expression to print with the warning.
3507 * @param[in] tok_pos Token position.
3508 */
3509static void
Michal Vaskoaa956522021-11-11 10:45:34 +01003510warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, ly_bool numbers_only, const char *expr,
3511 uint16_t tok_pos)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003512{
3513 struct lysc_node_leaf *node1, *node2;
Radek Krejci857189e2020-09-01 13:26:36 +02003514 ly_bool leaves = 1, warning = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003515
3516 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3517 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3518
3519 if (!node1 && !node2) {
3520 /* no node-sets involved, nothing to do */
3521 return;
3522 }
3523
3524 if (node1) {
3525 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3526 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3527 warning = 1;
3528 leaves = 0;
3529 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3530 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3531 warning = 1;
3532 }
3533 }
3534
3535 if (node2) {
3536 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3537 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3538 warning = 1;
3539 leaves = 0;
3540 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3541 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3542 warning = 1;
3543 }
3544 }
3545
3546 if (node1 && node2 && leaves && !numbers_only) {
Michal Vasko69730152020-10-09 16:30:07 +02003547 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)) ||
3548 (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type)) ||
3549 (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type) &&
3550 !warn_is_equal_type(node1->type, node2->type))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003551 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3552 warning = 1;
3553 }
3554 }
3555
3556 if (warning) {
Michal Vaskoaa956522021-11-11 10:45:34 +01003557 warn_subexpr_log(ctx, tok_pos, expr + tok_pos, 20, set1->cur_scnode);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003558 }
3559}
3560
3561/**
3562 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3563 *
3564 * @param[in] exp Parsed XPath expression.
3565 * @param[in] set Set with the leaf/leaf-list.
3566 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3567 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3568 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3569 */
3570static void
Michal Vasko40308e72020-10-20 16:38:40 +02003571warn_equality_value(const struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp,
3572 uint16_t last_equal_exp)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003573{
3574 struct lysc_node *scnode;
3575 struct lysc_type *type;
3576 char *value;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003577 struct lyd_value storage;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003578 LY_ERR rc;
3579 struct ly_err_item *err = NULL;
3580
Michal Vasko69730152020-10-09 16:30:07 +02003581 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) &&
3582 ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003583 /* check that the node can have the specified value */
3584 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3585 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3586 } else {
3587 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3588 }
3589 if (!value) {
3590 LOGMEM(set->ctx);
3591 return;
3592 }
3593
3594 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3595 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
Michal Vasko69730152020-10-09 16:30:07 +02003596 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
Michal Vaskoaa956522021-11-11 10:45:34 +01003597 warn_subexpr_log(set->ctx, exp->tok_pos[equal_exp], exp->expr + exp->tok_pos[equal_exp],
Radek Krejci0f969882020-08-21 16:56:47 +02003598 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
Michal Vaskoaa956522021-11-11 10:45:34 +01003599 set->cur_scnode);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003600 }
3601
3602 type = ((struct lysc_node_leaf *)scnode)->type;
3603 if (type->basetype != LY_TYPE_IDENT) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003604 rc = type->plugin->store(set->ctx, type, value, strlen(value), 0, set->format, set->prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +01003605 LYD_HINT_DATA, scnode, &storage, NULL, &err);
Michal Vaskobf42e832020-11-23 16:59:42 +01003606 if (rc == LY_EINCOMPLETE) {
3607 rc = LY_SUCCESS;
3608 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003609
3610 if (err) {
3611 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3612 ly_err_free(err);
3613 } else if (rc != LY_SUCCESS) {
3614 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3615 }
3616 if (rc != LY_SUCCESS) {
Michal Vaskoaa956522021-11-11 10:45:34 +01003617 warn_subexpr_log(set->ctx, exp->tok_pos[equal_exp], exp->expr + exp->tok_pos[equal_exp],
Radek Krejci0f969882020-08-21 16:56:47 +02003618 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
Michal Vaskoaa956522021-11-11 10:45:34 +01003619 set->cur_scnode);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003620 } else {
3621 type->plugin->free(set->ctx, &storage);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003622 }
3623 }
3624 free(value);
3625 }
3626}
3627
3628/*
3629 * XPath functions
3630 */
3631
3632/**
3633 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3634 * depending on whether the first node bit value from the second argument is set.
3635 *
3636 * @param[in] args Array of arguments.
3637 * @param[in] arg_count Count of elements in @p args.
3638 * @param[in,out] set Context and result set at the same time.
3639 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003640 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003641 */
3642static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003643xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003644{
3645 struct lyd_node_term *leaf;
3646 struct lysc_node_leaf *sleaf;
Michal Vasko2588b952021-07-29 07:43:26 +02003647 struct lyd_value_bits *bits;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003648 LY_ERR rc = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003649 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003650
3651 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003652 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003653 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko5676f4e2021-04-06 17:14:45 +02003654 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3655 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3656 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3657 sleaf->name);
3658 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3659 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
3660 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003661 }
3662
3663 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3664 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003665 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3666 sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003667 } else if (!warn_is_string_type(sleaf->type)) {
3668 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003669 }
3670 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003671 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003672 return rc;
3673 }
3674
Michal Vaskod3678892020-05-21 10:06:58 +02003675 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003676 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "bit-is-set(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003677 return LY_EVALID;
3678 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003679 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003680 LY_CHECK_RET(rc);
3681
3682 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003683 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003684 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
Michal Vasko2588b952021-07-29 07:43:26 +02003685 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (leaf->value.realtype->basetype == LY_TYPE_BITS)) {
3686 LYD_VALUE_GET(&leaf->value, bits);
3687 LY_ARRAY_FOR(bits->items, u) {
3688 if (!strcmp(bits->items[u]->name, args[1]->val.str)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003689 set_fill_boolean(set, 1);
3690 break;
3691 }
3692 }
3693 }
3694 }
3695
3696 return LY_SUCCESS;
3697}
3698
3699/**
3700 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3701 * with the argument converted to boolean.
3702 *
3703 * @param[in] args Array of arguments.
3704 * @param[in] arg_count Count of elements in @p args.
3705 * @param[in,out] set Context and result set at the same time.
3706 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003707 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003708 */
3709static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003710xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003711{
3712 LY_ERR rc;
3713
3714 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02003715 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003716 return LY_SUCCESS;
3717 }
3718
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003719 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003720 LY_CHECK_RET(rc);
3721 set_fill_set(set, args[0]);
3722
3723 return LY_SUCCESS;
3724}
3725
3726/**
3727 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3728 * with the first argument rounded up to the nearest integer.
3729 *
3730 * @param[in] args Array of arguments.
3731 * @param[in] arg_count Count of elements in @p args.
3732 * @param[in,out] set Context and result set at the same time.
3733 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003734 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003735 */
3736static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003737xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003738{
3739 struct lysc_node_leaf *sleaf;
3740 LY_ERR rc = LY_SUCCESS;
3741
3742 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003743 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003744 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko5676f4e2021-04-06 17:14:45 +02003745 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3746 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3747 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3748 sleaf->name);
3749 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3750 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
3751 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003752 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003753 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003754 return rc;
3755 }
3756
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003757 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003758 LY_CHECK_RET(rc);
3759 if ((long long)args[0]->val.num != args[0]->val.num) {
3760 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3761 } else {
3762 set_fill_number(set, args[0]->val.num);
3763 }
3764
3765 return LY_SUCCESS;
3766}
3767
3768/**
3769 * @brief Execute the XPath concat(string, string, string*) function.
3770 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3771 *
3772 * @param[in] args Array of arguments.
3773 * @param[in] arg_count Count of elements in @p args.
3774 * @param[in,out] set Context and result set at the same time.
3775 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003776 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003777 */
3778static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003779xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003780{
3781 uint16_t i;
3782 char *str = NULL;
3783 size_t used = 1;
3784 LY_ERR rc = LY_SUCCESS;
3785 struct lysc_node_leaf *sleaf;
3786
3787 if (options & LYXP_SCNODE_ALL) {
3788 for (i = 0; i < arg_count; ++i) {
3789 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3790 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3791 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003792 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003793 } else if (!warn_is_string_type(sleaf->type)) {
Radek Krejci70124c82020-08-14 22:17:03 +02003794 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", i + 1, __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003795 }
3796 }
3797 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003798 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003799 return rc;
3800 }
3801
3802 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003803 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003804 if (rc != LY_SUCCESS) {
3805 free(str);
3806 return rc;
3807 }
3808
3809 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3810 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3811 strcpy(str + used - 1, args[i]->val.str);
3812 used += strlen(args[i]->val.str);
3813 }
3814
3815 /* free, kind of */
Michal Vaskod3678892020-05-21 10:06:58 +02003816 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003817 set->type = LYXP_SET_STRING;
3818 set->val.str = str;
3819
3820 return LY_SUCCESS;
3821}
3822
3823/**
3824 * @brief Execute the XPath contains(string, string) function.
3825 * Returns LYXP_SET_BOOLEAN whether the second argument can
3826 * be found in the first or not.
3827 *
3828 * @param[in] args Array of arguments.
3829 * @param[in] arg_count Count of elements in @p args.
3830 * @param[in,out] set Context and result set at the same time.
3831 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003832 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003833 */
3834static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003835xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003836{
3837 struct lysc_node_leaf *sleaf;
3838 LY_ERR rc = LY_SUCCESS;
3839
3840 if (options & LYXP_SCNODE_ALL) {
3841 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3842 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003843 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3844 sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003845 } else if (!warn_is_string_type(sleaf->type)) {
3846 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003847 }
3848 }
3849
3850 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3851 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003852 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3853 sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003854 } else if (!warn_is_string_type(sleaf->type)) {
3855 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003856 }
3857 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003858 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003859 return rc;
3860 }
3861
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003862 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003863 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003864 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003865 LY_CHECK_RET(rc);
3866
3867 if (strstr(args[0]->val.str, args[1]->val.str)) {
3868 set_fill_boolean(set, 1);
3869 } else {
3870 set_fill_boolean(set, 0);
3871 }
3872
3873 return LY_SUCCESS;
3874}
3875
3876/**
3877 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3878 * with the size of the node-set from the argument.
3879 *
3880 * @param[in] args Array of arguments.
3881 * @param[in] arg_count Count of elements in @p args.
3882 * @param[in,out] set Context and result set at the same time.
3883 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003884 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003885 */
3886static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003887xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003888{
Michal Vasko03ff5a72019-09-11 13:49:33 +02003889 LY_ERR rc = LY_SUCCESS;
3890
3891 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003892 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003893 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003894 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003895 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003896 return rc;
3897 }
3898
Michal Vasko03ff5a72019-09-11 13:49:33 +02003899 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01003900 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003901 return LY_EVALID;
3902 }
3903
3904 set_fill_number(set, args[0]->used);
3905 return LY_SUCCESS;
3906}
3907
3908/**
3909 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3910 * with the context with the intial node.
3911 *
3912 * @param[in] args Array of arguments.
3913 * @param[in] arg_count Count of elements in @p args.
3914 * @param[in,out] set Context and result set at the same time.
3915 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003916 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003917 */
3918static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003919xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003920{
3921 if (arg_count || args) {
Radek Krejcie87c7dc2021-06-02 21:25:42 +02003922 LOGVAL(set->ctx, LY_VCODE_XP_INARGCOUNT, arg_count, LY_PRI_LENSTR("current()"));
Michal Vasko03ff5a72019-09-11 13:49:33 +02003923 return LY_EVALID;
3924 }
3925
3926 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02003927 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003928
Michal Vasko296dfaf2021-12-13 16:57:42 +01003929 if (set->cur_scnode) {
3930 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, set->cur_scnode, LYXP_NODE_ELEM, NULL));
3931 } else {
3932 /* root node */
3933 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, NULL, set->root_type, NULL));
3934 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003935 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02003936 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003937
Michal Vasko296dfaf2021-12-13 16:57:42 +01003938 if (set->cur_node) {
3939 /* position is filled later */
3940 set_insert_node(set, set->cur_node, 0, LYXP_NODE_ELEM, 0);
3941 } else {
3942 /* root node */
3943 set_insert_node(set, NULL, 0, set->root_type, 0);
3944 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003945 }
3946
3947 return LY_SUCCESS;
3948}
3949
3950/**
3951 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3952 * leafref or instance-identifier target node(s).
3953 *
3954 * @param[in] args Array of arguments.
3955 * @param[in] arg_count Count of elements in @p args.
3956 * @param[in,out] set Context and result set at the same time.
3957 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003958 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003959 */
3960static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003961xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003962{
3963 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003964 struct lysc_node_leaf *sleaf = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02003965 struct lysc_type_leafref *lref;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003966 const struct lysc_node *target;
Michal Vasko004d3152020-06-11 19:59:22 +02003967 struct ly_path *p;
3968 struct lyd_node *node;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003969 char *errmsg = NULL;
Michal Vasko00cbf532020-06-15 13:58:47 +02003970 uint8_t oper;
Michal Vasko741bb562021-06-24 11:59:50 +02003971 LY_ERR r;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003972
3973 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003974 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003975 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko5676f4e2021-04-06 17:14:45 +02003976 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
Michal Vasko423ba3f2021-07-19 13:08:50 +02003977 if (!(sleaf->nodetype & LYD_NODE_TERM)) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003978 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
3979 sleaf->name);
Michal Vaskoed725d72021-06-23 12:03:45 +02003980 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) &&
3981 !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02003982 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3983 __func__, sleaf->name);
3984 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003985 }
Michal Vasko1a09b212021-05-06 13:00:10 +02003986 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko423ba3f2021-07-19 13:08:50 +02003987 if (sleaf && (sleaf->nodetype & LYD_NODE_TERM) && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vasko004d3152020-06-11 19:59:22 +02003988 lref = (struct lysc_type_leafref *)sleaf->type;
Michal Vaskod1e53b92021-01-28 13:11:06 +01003989 oper = (sleaf->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko004d3152020-06-11 19:59:22 +02003990
3991 /* it was already evaluated on schema, it must succeed */
Michal Vasko741bb562021-06-24 11:59:50 +02003992 r = ly_path_compile_leafref(set->ctx, &sleaf->node, NULL, lref->path, oper, LY_PATH_TARGET_MANY,
Michal Vasko24fc4d12021-07-12 14:41:20 +02003993 LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, &p);
Michal Vasko741bb562021-06-24 11:59:50 +02003994 if (!r) {
3995 /* get the target node */
3996 target = p[LY_ARRAY_COUNT(p) - 1].node;
3997 ly_path_free(set->ctx, p);
Michal Vasko004d3152020-06-11 19:59:22 +02003998
Michal Vasko741bb562021-06-24 11:59:50 +02003999 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM, NULL));
4000 } /* else the target was found before but is disabled so it was removed */
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02004001 }
4002
Michal Vasko741bb562021-06-24 11:59:50 +02004003 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004004 }
4005
Michal Vaskod3678892020-05-21 10:06:58 +02004006 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004007 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004008 return LY_EVALID;
4009 }
4010
Michal Vaskod3678892020-05-21 10:06:58 +02004011 lyxp_set_free_content(set);
4012 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004013 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
4014 sleaf = (struct lysc_node_leaf *)leaf->schema;
4015 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4016 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
4017 /* find leafref target */
Radek Krejci0b013302021-03-29 15:22:32 +02004018 if (lyplg_type_resolve_leafref((struct lysc_type_leafref *)sleaf->type, &leaf->node, &leaf->value, set->tree,
Michal Vasko9e685082021-01-29 14:49:09 +01004019 &node, &errmsg)) {
Michal Vasko004d3152020-06-11 19:59:22 +02004020 LOGERR(set->ctx, LY_EVALID, errmsg);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004021 free(errmsg);
Michal Vasko004d3152020-06-11 19:59:22 +02004022 return LY_EVALID;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004023 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004024 } else {
4025 assert(sleaf->type->basetype == LY_TYPE_INST);
Michal Vasko004d3152020-06-11 19:59:22 +02004026 if (ly_path_eval(leaf->value.target, set->tree, &node)) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02004027 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.",
Radek Krejci6d5ba0c2021-04-26 07:49:59 +02004028 lyd_get_value(&leaf->node));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004029 return LY_EVALID;
4030 }
4031 }
Michal Vasko004d3152020-06-11 19:59:22 +02004032
4033 /* insert it */
4034 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004035 }
4036 }
4037
4038 return LY_SUCCESS;
4039}
4040
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004041static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02004042xpath_derived_(struct lyxp_set **args, struct lyxp_set *set, uint32_t options, ly_bool self_match, const char *func)
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004043{
Michal Vaskofe1af042022-07-29 14:58:59 +02004044 uint32_t i, id_len;
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004045 LY_ARRAY_COUNT_TYPE u;
4046 struct lyd_node_term *leaf;
4047 struct lysc_node_leaf *sleaf;
4048 struct lyd_meta *meta;
Michal Vasko93923692021-05-07 15:28:02 +02004049 struct lyd_value *val;
4050 const struct lys_module *mod;
4051 const char *id_name;
Michal Vasko93923692021-05-07 15:28:02 +02004052 struct lysc_ident *id;
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004053 LY_ERR rc = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02004054 ly_bool found;
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004055
4056 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02004057 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004058 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", func);
Michal Vasko5676f4e2021-04-06 17:14:45 +02004059 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4060 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4061 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", func, lys_nodetype2str(sleaf->nodetype),
4062 sleaf->name);
4063 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
4064 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", func, sleaf->name);
4065 }
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004066 }
4067
4068 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4069 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4070 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", func, lys_nodetype2str(sleaf->nodetype),
Michal Vasko69730152020-10-09 16:30:07 +02004071 sleaf->name);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004072 } else if (!warn_is_string_type(sleaf->type)) {
4073 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", func, sleaf->name);
4074 }
4075 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004076 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004077 return rc;
4078 }
4079
4080 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004081 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(-or-self)(node-set, string)");
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004082 return LY_EVALID;
4083 }
4084 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
4085 LY_CHECK_RET(rc);
4086
Michal Vasko93923692021-05-07 15:28:02 +02004087 /* parse the identity */
4088 id_name = args[1]->val.str;
4089 id_len = strlen(id_name);
4090 rc = moveto_resolve_model(&id_name, &id_len, set, set->cur_node ? set->cur_node->schema : NULL, &mod);
4091 LY_CHECK_RET(rc);
4092 if (!mod) {
4093 LOGVAL(set->ctx, LYVE_XPATH, "Identity \"%.*s\" without a prefix.", (int)id_len, id_name);
4094 return LY_EVALID;
4095 }
4096
4097 /* find the identity */
4098 found = 0;
4099 LY_ARRAY_FOR(mod->identities, u) {
4100 if (!ly_strncmp(mod->identities[u].name, id_name, id_len)) {
4101 /* we have match */
4102 found = 1;
4103 break;
4104 }
4105 }
4106 if (!found) {
4107 LOGVAL(set->ctx, LYVE_XPATH, "Identity \"%.*s\" not found in module \"%s\".", (int)id_len, id_name, mod->name);
4108 return LY_EVALID;
4109 }
4110 id = &mod->identities[u];
4111
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004112 set_fill_boolean(set, 0);
4113 found = 0;
4114 for (i = 0; i < args[0]->used; ++i) {
4115 if ((args[0]->val.nodes[i].type != LYXP_NODE_ELEM) && (args[0]->val.nodes[i].type != LYXP_NODE_META)) {
4116 continue;
4117 }
4118
4119 if (args[0]->val.nodes[i].type == LYXP_NODE_ELEM) {
4120 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
4121 sleaf = (struct lysc_node_leaf *)leaf->schema;
4122 val = &leaf->value;
4123 if (!(sleaf->nodetype & LYD_NODE_TERM) || (leaf->value.realtype->basetype != LY_TYPE_IDENT)) {
4124 /* uninteresting */
4125 continue;
4126 }
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004127 } else {
4128 meta = args[0]->val.meta[i].meta;
4129 val = &meta->value;
4130 if (val->realtype->basetype != LY_TYPE_IDENT) {
4131 /* uninteresting */
4132 continue;
4133 }
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004134 }
4135
Michal Vasko93923692021-05-07 15:28:02 +02004136 /* check the identity itself */
4137 if (self_match && (id == val->ident)) {
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004138 set_fill_boolean(set, 1);
4139 found = 1;
4140 }
Michal Vasko93923692021-05-07 15:28:02 +02004141 if (!found && !lyplg_type_identity_isderived(id, val->ident)) {
4142 set_fill_boolean(set, 1);
4143 found = 1;
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004144 }
4145
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004146 if (found) {
4147 break;
4148 }
4149 }
4150
4151 return LY_SUCCESS;
4152}
4153
Michal Vasko03ff5a72019-09-11 13:49:33 +02004154/**
4155 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
4156 * on whether the first argument nodes contain a node of an identity derived from the second
4157 * argument identity.
4158 *
4159 * @param[in] args Array of arguments.
4160 * @param[in] arg_count Count of elements in @p args.
4161 * @param[in,out] set Context and result set at the same time.
4162 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004163 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004164 */
4165static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004166xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004167{
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004168 return xpath_derived_(args, set, options, 0, __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004169}
4170
4171/**
4172 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
4173 * on whether the first argument nodes contain a node of an identity that either is or is derived from
4174 * the second argument identity.
4175 *
4176 * @param[in] args Array of arguments.
4177 * @param[in] arg_count Count of elements in @p args.
4178 * @param[in,out] set Context and result set at the same time.
4179 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004180 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004181 */
4182static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004183xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004184{
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02004185 return xpath_derived_(args, set, options, 1, __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004186}
4187
4188/**
4189 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
4190 * with the integer value of the first node's enum value, otherwise NaN.
4191 *
4192 * @param[in] args Array of arguments.
4193 * @param[in] arg_count Count of elements in @p args.
4194 * @param[in,out] set Context and result set at the same time.
4195 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004196 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004197 */
4198static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004199xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004200{
4201 struct lyd_node_term *leaf;
4202 struct lysc_node_leaf *sleaf;
4203 LY_ERR rc = LY_SUCCESS;
4204
4205 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02004206 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004207 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko5676f4e2021-04-06 17:14:45 +02004208 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4209 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4210 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
4211 sleaf->name);
4212 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
4213 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
4214 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004215 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004216 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004217 return rc;
4218 }
4219
Michal Vaskod3678892020-05-21 10:06:58 +02004220 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004221 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004222 return LY_EVALID;
4223 }
4224
4225 set_fill_number(set, NAN);
Michal Vaskod3678892020-05-21 10:06:58 +02004226 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004227 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
4228 sleaf = (struct lysc_node_leaf *)leaf->schema;
4229 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
4230 set_fill_number(set, leaf->value.enum_item->value);
4231 }
4232 }
4233
4234 return LY_SUCCESS;
4235}
4236
4237/**
4238 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
4239 * with false value.
4240 *
4241 * @param[in] args Array of arguments.
4242 * @param[in] arg_count Count of elements in @p args.
4243 * @param[in,out] set Context and result set at the same time.
4244 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004245 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004246 */
4247static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004248xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004249{
4250 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004251 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004252 return LY_SUCCESS;
4253 }
4254
4255 set_fill_boolean(set, 0);
4256 return LY_SUCCESS;
4257}
4258
4259/**
4260 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
4261 * with the first argument floored (truncated).
4262 *
4263 * @param[in] args Array of arguments.
4264 * @param[in] arg_count Count of elements in @p args.
4265 * @param[in,out] set Context and result set at the same time.
4266 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004267 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004268 */
4269static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004270xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02004271{
4272 LY_ERR rc;
4273
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004274 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004275 LY_CHECK_RET(rc);
4276 if (isfinite(args[0]->val.num)) {
4277 set_fill_number(set, (long long)args[0]->val.num);
4278 }
4279
4280 return LY_SUCCESS;
4281}
4282
4283/**
4284 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
4285 * whether the language of the text matches the one from the argument.
4286 *
4287 * @param[in] args Array of arguments.
4288 * @param[in] arg_count Count of elements in @p args.
4289 * @param[in,out] set Context and result set at the same time.
4290 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004291 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004292 */
4293static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004294xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004295{
4296 const struct lyd_node *node;
4297 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01004298 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004299 const char *val;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004300 LY_ERR rc = LY_SUCCESS;
4301
4302 if (options & LYXP_SCNODE_ALL) {
4303 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4304 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004305 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
4306 sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004307 } else if (!warn_is_string_type(sleaf->type)) {
4308 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004309 }
4310 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004311 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004312 return rc;
4313 }
4314
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004315 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004316 LY_CHECK_RET(rc);
4317
Michal Vasko03ff5a72019-09-11 13:49:33 +02004318 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004319 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004320 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004321 } else if (!set->used) {
4322 set_fill_boolean(set, 0);
4323 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004324 }
4325
4326 switch (set->val.nodes[0].type) {
4327 case LYXP_NODE_ELEM:
4328 case LYXP_NODE_TEXT:
4329 node = set->val.nodes[0].node;
4330 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004331 case LYXP_NODE_META:
4332 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004333 break;
4334 default:
4335 /* nothing to do with roots */
4336 set_fill_boolean(set, 0);
4337 return LY_SUCCESS;
4338 }
4339
Michal Vasko9f96a052020-03-10 09:41:45 +01004340 /* find lang metadata */
Michal Vasko9e685082021-01-29 14:49:09 +01004341 for ( ; node; node = lyd_parent(node)) {
Michal Vasko9f96a052020-03-10 09:41:45 +01004342 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004343 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004344 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004345 break;
4346 }
4347 }
4348
Michal Vasko9f96a052020-03-10 09:41:45 +01004349 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004350 break;
4351 }
4352 }
4353
4354 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01004355 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004356 set_fill_boolean(set, 0);
4357 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004358 uint64_t i;
4359
Radek Krejci6d5ba0c2021-04-26 07:49:59 +02004360 val = lyd_get_meta_value(meta);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004361 for (i = 0; args[0]->val.str[i]; ++i) {
4362 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
4363 set_fill_boolean(set, 0);
4364 break;
4365 }
4366 }
4367 if (!args[0]->val.str[i]) {
4368 if (!val[i] || (val[i] == '-')) {
4369 set_fill_boolean(set, 1);
4370 } else {
4371 set_fill_boolean(set, 0);
4372 }
4373 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004374 }
4375
4376 return LY_SUCCESS;
4377}
4378
4379/**
4380 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
4381 * with the context size.
4382 *
4383 * @param[in] args Array of arguments.
4384 * @param[in] arg_count Count of elements in @p args.
4385 * @param[in,out] set Context and result set at the same time.
4386 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004387 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004388 */
4389static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004390xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004391{
4392 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004393 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004394 return LY_SUCCESS;
4395 }
4396
Michal Vasko03ff5a72019-09-11 13:49:33 +02004397 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004398 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004399 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004400 } else if (!set->used) {
4401 set_fill_number(set, 0);
4402 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004403 }
4404
4405 set_fill_number(set, set->ctx_size);
4406 return LY_SUCCESS;
4407}
4408
4409/**
4410 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
4411 * with the node name without namespace from the argument or the context.
4412 *
4413 * @param[in] args Array of arguments.
4414 * @param[in] arg_count Count of elements in @p args.
4415 * @param[in,out] set Context and result set at the same time.
4416 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004417 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004418 */
4419static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004420xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004421{
4422 struct lyxp_set_node *item;
Michal Vasko69730152020-10-09 16:30:07 +02004423
Michal Vasko03ff5a72019-09-11 13:49:33 +02004424 /* suppress unused variable warning */
4425 (void)options;
4426
4427 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004428 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004429 return LY_SUCCESS;
4430 }
4431
4432 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004433 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004434 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004435 "local-name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004436 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004437 } else if (!args[0]->used) {
4438 set_fill_string(set, "", 0);
4439 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004440 }
4441
4442 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004443 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004444
4445 item = &args[0]->val.nodes[0];
4446 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004447 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004448 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004449 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004450 } else if (!set->used) {
4451 set_fill_string(set, "", 0);
4452 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004453 }
4454
4455 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004456 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004457
4458 item = &set->val.nodes[0];
4459 }
4460
4461 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004462 case LYXP_NODE_NONE:
4463 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004464 case LYXP_NODE_ROOT:
4465 case LYXP_NODE_ROOT_CONFIG:
4466 case LYXP_NODE_TEXT:
4467 set_fill_string(set, "", 0);
4468 break;
4469 case LYXP_NODE_ELEM:
4470 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4471 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004472 case LYXP_NODE_META:
4473 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004474 break;
4475 }
4476
4477 return LY_SUCCESS;
4478}
4479
4480/**
4481 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4482 * with the node name fully qualified (with namespace) from the argument or the context.
4483 *
4484 * @param[in] args Array of arguments.
4485 * @param[in] arg_count Count of elements in @p args.
4486 * @param[in,out] set Context and result set at the same time.
4487 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004488 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004489 */
4490static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004491xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004492{
4493 struct lyxp_set_node *item;
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004494 struct lys_module *mod = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004495 char *str;
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004496 const char *name = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004497
4498 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004499 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004500 return LY_SUCCESS;
4501 }
4502
4503 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004504 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004505 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004506 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004507 } else if (!args[0]->used) {
4508 set_fill_string(set, "", 0);
4509 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004510 }
4511
4512 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004513 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004514
4515 item = &args[0]->val.nodes[0];
4516 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004517 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004518 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004519 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004520 } else if (!set->used) {
4521 set_fill_string(set, "", 0);
4522 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004523 }
4524
4525 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004526 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004527
4528 item = &set->val.nodes[0];
4529 }
4530
4531 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004532 case LYXP_NODE_NONE:
4533 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004534 case LYXP_NODE_ROOT:
4535 case LYXP_NODE_ROOT_CONFIG:
4536 case LYXP_NODE_TEXT:
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004537 /* keep NULL */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004538 break;
4539 case LYXP_NODE_ELEM:
4540 mod = item->node->schema->module;
4541 name = item->node->schema->name;
4542 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004543 case LYXP_NODE_META:
4544 mod = ((struct lyd_meta *)item->node)->annotation->module;
4545 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004546 break;
4547 }
4548
4549 if (mod && name) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004550 int rc = asprintf(&str, "%s:%s", ly_get_prefix(mod, set->format, set->prefix_data), name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004551 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4552 set_fill_string(set, str, strlen(str));
4553 free(str);
4554 } else {
4555 set_fill_string(set, "", 0);
4556 }
4557
4558 return LY_SUCCESS;
4559}
4560
4561/**
4562 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4563 * with the namespace of the node from the argument or the context.
4564 *
4565 * @param[in] args Array of arguments.
4566 * @param[in] arg_count Count of elements in @p args.
4567 * @param[in,out] set Context and result set at the same time.
4568 * @param[in] options XPath options.
4569 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4570 */
4571static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004572xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004573{
4574 struct lyxp_set_node *item;
4575 struct lys_module *mod;
Michal Vasko69730152020-10-09 16:30:07 +02004576
Michal Vasko03ff5a72019-09-11 13:49:33 +02004577 /* suppress unused variable warning */
4578 (void)options;
4579
4580 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004581 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004582 return LY_SUCCESS;
4583 }
4584
4585 if (arg_count) {
Michal Vaskod3678892020-05-21 10:06:58 +02004586 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004587 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
Michal Vasko69730152020-10-09 16:30:07 +02004588 "namespace-uri(node-set?)");
Michal Vaskod3678892020-05-21 10:06:58 +02004589 return LY_EVALID;
4590 } else if (!args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004591 set_fill_string(set, "", 0);
4592 return LY_SUCCESS;
4593 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004594
4595 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004596 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004597
4598 item = &args[0]->val.nodes[0];
4599 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004600 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004601 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004602 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004603 } else if (!set->used) {
4604 set_fill_string(set, "", 0);
4605 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004606 }
4607
4608 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004609 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004610
4611 item = &set->val.nodes[0];
4612 }
4613
4614 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004615 case LYXP_NODE_NONE:
4616 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004617 case LYXP_NODE_ROOT:
4618 case LYXP_NODE_ROOT_CONFIG:
4619 case LYXP_NODE_TEXT:
4620 set_fill_string(set, "", 0);
4621 break;
4622 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004623 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004624 if (item->type == LYXP_NODE_ELEM) {
4625 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004626 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004627 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004628 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004629 }
4630
4631 set_fill_string(set, mod->ns, strlen(mod->ns));
4632 break;
4633 }
4634
4635 return LY_SUCCESS;
4636}
4637
4638/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02004639 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4640 * with normalized value (no leading, trailing, double white spaces) of the node
4641 * from the argument or the context.
4642 *
4643 * @param[in] args Array of arguments.
4644 * @param[in] arg_count Count of elements in @p args.
4645 * @param[in,out] set Context and result set at the same time.
4646 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004647 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004648 */
4649static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004650xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004651{
4652 uint16_t i, new_used;
4653 char *new;
Radek Krejci857189e2020-09-01 13:26:36 +02004654 ly_bool have_spaces = 0, space_before = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004655 struct lysc_node_leaf *sleaf;
4656 LY_ERR rc = LY_SUCCESS;
4657
4658 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004659 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) &&
4660 (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004661 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004662 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
4663 sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004664 } else if (!warn_is_string_type(sleaf->type)) {
4665 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004666 }
4667 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004668 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004669 return rc;
4670 }
4671
4672 if (arg_count) {
4673 set_fill_set(set, args[0]);
4674 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004675 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004676 LY_CHECK_RET(rc);
4677
4678 /* is there any normalization necessary? */
4679 for (i = 0; set->val.str[i]; ++i) {
4680 if (is_xmlws(set->val.str[i])) {
4681 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4682 have_spaces = 1;
4683 break;
4684 }
4685 space_before = 1;
4686 } else {
4687 space_before = 0;
4688 }
4689 }
4690
4691 /* yep, there is */
4692 if (have_spaces) {
4693 /* it's enough, at least one character will go, makes space for ending '\0' */
4694 new = malloc(strlen(set->val.str) * sizeof(char));
4695 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4696 new_used = 0;
4697
4698 space_before = 0;
4699 for (i = 0; set->val.str[i]; ++i) {
4700 if (is_xmlws(set->val.str[i])) {
4701 if ((i == 0) || space_before) {
4702 space_before = 1;
4703 continue;
4704 } else {
4705 space_before = 1;
4706 }
4707 } else {
4708 space_before = 0;
4709 }
4710
4711 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4712 ++new_used;
4713 }
4714
4715 /* at worst there is one trailing space now */
4716 if (new_used && is_xmlws(new[new_used - 1])) {
4717 --new_used;
4718 }
4719
4720 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4721 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4722 new[new_used] = '\0';
4723
4724 free(set->val.str);
4725 set->val.str = new;
4726 }
4727
4728 return LY_SUCCESS;
4729}
4730
4731/**
4732 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4733 * with the argument converted to boolean and logically inverted.
4734 *
4735 * @param[in] args Array of arguments.
4736 * @param[in] arg_count Count of elements in @p args.
4737 * @param[in,out] set Context and result set at the same time.
4738 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004739 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004740 */
4741static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004742xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004743{
4744 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004745 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004746 return LY_SUCCESS;
4747 }
4748
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004749 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko004d3152020-06-11 19:59:22 +02004750 if (args[0]->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004751 set_fill_boolean(set, 0);
4752 } else {
4753 set_fill_boolean(set, 1);
4754 }
4755
4756 return LY_SUCCESS;
4757}
4758
4759/**
4760 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4761 * with the number representation of either the argument or the context.
4762 *
4763 * @param[in] args Array of arguments.
4764 * @param[in] arg_count Count of elements in @p args.
4765 * @param[in,out] set Context and result set at the same time.
4766 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004767 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004768 */
4769static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004770xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004771{
4772 LY_ERR rc;
4773
4774 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004775 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004776 return LY_SUCCESS;
4777 }
4778
4779 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004780 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004781 LY_CHECK_RET(rc);
4782 set_fill_set(set, args[0]);
4783 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004784 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004785 LY_CHECK_RET(rc);
4786 }
4787
4788 return LY_SUCCESS;
4789}
4790
4791/**
4792 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4793 * with the context position.
4794 *
4795 * @param[in] args Array of arguments.
4796 * @param[in] arg_count Count of elements in @p args.
4797 * @param[in,out] set Context and result set at the same time.
4798 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004799 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004800 */
4801static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004802xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004803{
4804 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02004805 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004806 return LY_SUCCESS;
4807 }
4808
Michal Vasko03ff5a72019-09-11 13:49:33 +02004809 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01004810 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004811 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004812 } else if (!set->used) {
4813 set_fill_number(set, 0);
4814 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004815 }
4816
4817 set_fill_number(set, set->ctx_pos);
4818
4819 /* UNUSED in 'Release' build type */
4820 (void)options;
4821 return LY_SUCCESS;
4822}
4823
4824/**
4825 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4826 * depending on whether the second argument regex matches the first argument string. For details refer to
4827 * YANG 1.1 RFC section 10.2.1.
4828 *
4829 * @param[in] args Array of arguments.
4830 * @param[in] arg_count Count of elements in @p args.
4831 * @param[in,out] set Context and result set at the same time.
4832 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004833 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004834 */
4835static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004836xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004837{
4838 struct lysc_pattern **patterns = NULL, **pattern;
4839 struct lysc_node_leaf *sleaf;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004840 LY_ERR rc = LY_SUCCESS;
4841 struct ly_err_item *err;
4842
4843 if (options & LYXP_SCNODE_ALL) {
4844 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4845 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4846 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004847 } else if (!warn_is_string_type(sleaf->type)) {
4848 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004849 }
4850 }
4851
4852 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4853 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4854 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004855 } else if (!warn_is_string_type(sleaf->type)) {
4856 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004857 }
4858 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004859 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004860 return rc;
4861 }
4862
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004863 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004864 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004865 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004866 LY_CHECK_RET(rc);
4867
4868 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
Radek Iša45802b52021-02-09 09:21:58 +01004869 *pattern = calloc(1, sizeof **pattern);
Radek Krejciddace2c2021-01-08 11:30:56 +01004870 LOG_LOCSET(NULL, set->cur_node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01004871 rc = lys_compile_type_pattern_check(set->ctx, args[1]->val.str, &(*pattern)->code);
Michal Vasko4a7d4d62021-12-13 17:05:06 +01004872 if (set->cur_node) {
4873 LOG_LOCBACK(0, 1, 0, 0);
4874 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004875 if (rc != LY_SUCCESS) {
4876 LY_ARRAY_FREE(patterns);
4877 return rc;
4878 }
4879
Radek Krejci0b013302021-03-29 15:22:32 +02004880 rc = lyplg_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004881 pcre2_code_free((*pattern)->code);
4882 free(*pattern);
4883 LY_ARRAY_FREE(patterns);
4884 if (rc && (rc != LY_EVALID)) {
Michal Vasko177d0ed2020-11-23 16:43:03 +01004885 ly_err_print(set->ctx, err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004886 ly_err_free(err);
4887 return rc;
4888 }
4889
4890 if (rc == LY_EVALID) {
4891 ly_err_free(err);
4892 set_fill_boolean(set, 0);
4893 } else {
4894 set_fill_boolean(set, 1);
4895 }
4896
4897 return LY_SUCCESS;
4898}
4899
4900/**
4901 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4902 * with the rounded first argument. For details refer to
4903 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4904 *
4905 * @param[in] args Array of arguments.
4906 * @param[in] arg_count Count of elements in @p args.
4907 * @param[in,out] set Context and result set at the same time.
4908 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004909 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004910 */
4911static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004912xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004913{
4914 struct lysc_node_leaf *sleaf;
4915 LY_ERR rc = LY_SUCCESS;
4916
4917 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5676f4e2021-04-06 17:14:45 +02004918 if (args[0]->type != LYXP_SET_SCNODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004919 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko5676f4e2021-04-06 17:14:45 +02004920 } else if ((sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4921 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4922 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype),
4923 sleaf->name);
4924 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4925 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
4926 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004927 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004928 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004929 return rc;
4930 }
4931
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004932 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004933 LY_CHECK_RET(rc);
4934
4935 /* cover only the cases where floor can't be used */
4936 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4937 set_fill_number(set, -0.0f);
4938 } else {
4939 args[0]->val.num += 0.5;
4940 rc = xpath_floor(args, 1, args[0], options);
4941 LY_CHECK_RET(rc);
4942 set_fill_number(set, args[0]->val.num);
4943 }
4944
4945 return LY_SUCCESS;
4946}
4947
4948/**
4949 * @brief Execute the XPath starts-with(string, string) function.
4950 * Returns LYXP_SET_BOOLEAN whether the second argument is
4951 * the prefix of the first or not.
4952 *
4953 * @param[in] args Array of arguments.
4954 * @param[in] arg_count Count of elements in @p args.
4955 * @param[in,out] set Context and result set at the same time.
4956 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004957 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004958 */
4959static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004960xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004961{
4962 struct lysc_node_leaf *sleaf;
4963 LY_ERR rc = LY_SUCCESS;
4964
4965 if (options & LYXP_SCNODE_ALL) {
4966 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4967 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4968 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004969 } else if (!warn_is_string_type(sleaf->type)) {
4970 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004971 }
4972 }
4973
4974 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4975 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4976 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004977 } else if (!warn_is_string_type(sleaf->type)) {
4978 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004979 }
4980 }
Michal Vasko1a09b212021-05-06 13:00:10 +02004981 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004982 return rc;
4983 }
4984
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004985 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004986 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004987 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004988 LY_CHECK_RET(rc);
4989
4990 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4991 set_fill_boolean(set, 0);
4992 } else {
4993 set_fill_boolean(set, 1);
4994 }
4995
4996 return LY_SUCCESS;
4997}
4998
4999/**
5000 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
5001 * with the string representation of either the argument or the context.
5002 *
5003 * @param[in] args Array of arguments.
5004 * @param[in] arg_count Count of elements in @p args.
5005 * @param[in,out] set Context and result set at the same time.
5006 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005007 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005008 */
5009static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005010xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005011{
5012 LY_ERR rc;
5013
5014 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02005015 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005016 return LY_SUCCESS;
5017 }
5018
5019 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005020 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005021 LY_CHECK_RET(rc);
5022 set_fill_set(set, args[0]);
5023 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005024 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005025 LY_CHECK_RET(rc);
5026 }
5027
5028 return LY_SUCCESS;
5029}
5030
5031/**
5032 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
5033 * with the length of the string in either the argument or the context.
5034 *
5035 * @param[in] args Array of arguments.
5036 * @param[in] arg_count Count of elements in @p args.
5037 * @param[in,out] set Context and result set at the same time.
5038 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005039 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005040 */
5041static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005042xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005043{
5044 struct lysc_node_leaf *sleaf;
5045 LY_ERR rc = LY_SUCCESS;
5046
5047 if (options & LYXP_SCNODE_ALL) {
5048 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5049 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5050 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005051 } else if (!warn_is_string_type(sleaf->type)) {
5052 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005053 }
5054 }
5055 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
5056 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5057 LOGWRN(set->ctx, "Argument #0 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005058 } else if (!warn_is_string_type(sleaf->type)) {
5059 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005060 }
5061 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005062 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005063 return rc;
5064 }
5065
5066 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005067 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005068 LY_CHECK_RET(rc);
5069 set_fill_number(set, strlen(args[0]->val.str));
5070 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005071 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005072 LY_CHECK_RET(rc);
5073 set_fill_number(set, strlen(set->val.str));
5074 }
5075
5076 return LY_SUCCESS;
5077}
5078
5079/**
5080 * @brief Execute the XPath substring(string, number, number?) function.
5081 * Returns LYXP_SET_STRING substring of the first argument starting
5082 * on the second argument index ending on the third argument index,
5083 * indexed from 1. For exact definition refer to
5084 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
5085 *
5086 * @param[in] args Array of arguments.
5087 * @param[in] arg_count Count of elements in @p args.
5088 * @param[in,out] set Context and result set at the same time.
5089 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005090 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005091 */
5092static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005093xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005094{
Michal Vasko6db996e2022-07-28 10:28:04 +02005095 int64_t start;
5096 int32_t len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005097 uint16_t str_start, str_len, pos;
5098 struct lysc_node_leaf *sleaf;
5099 LY_ERR rc = LY_SUCCESS;
5100
5101 if (options & LYXP_SCNODE_ALL) {
5102 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5103 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5104 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005105 } else if (!warn_is_string_type(sleaf->type)) {
5106 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005107 }
5108 }
5109
5110 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5111 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5112 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005113 } else if (!warn_is_numeric_type(sleaf->type)) {
5114 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005115 }
5116 }
5117
Michal Vasko69730152020-10-09 16:30:07 +02005118 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET) &&
5119 (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005120 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5121 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005122 } else if (!warn_is_numeric_type(sleaf->type)) {
5123 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005124 }
5125 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005126 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005127 return rc;
5128 }
5129
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005130 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005131 LY_CHECK_RET(rc);
5132
5133 /* start */
5134 if (xpath_round(&args[1], 1, args[1], options)) {
5135 return -1;
5136 }
5137 if (isfinite(args[1]->val.num)) {
5138 start = args[1]->val.num - 1;
5139 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02005140 start = INT32_MIN;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005141 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02005142 start = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005143 }
5144
5145 /* len */
5146 if (arg_count == 3) {
5147 rc = xpath_round(&args[2], 1, args[2], options);
5148 LY_CHECK_RET(rc);
Radek Krejci1deb5be2020-08-26 16:43:36 +02005149 if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005150 len = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +02005151 } else if (isfinite(args[2]->val.num)) {
5152 len = args[2]->val.num;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005153 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02005154 len = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005155 }
5156 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02005157 len = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005158 }
5159
5160 /* find matching character positions */
5161 str_start = 0;
5162 str_len = 0;
5163 for (pos = 0; args[0]->val.str[pos]; ++pos) {
5164 if (pos < start) {
5165 ++str_start;
5166 } else if (pos < start + len) {
5167 ++str_len;
5168 } else {
5169 break;
5170 }
5171 }
5172
5173 set_fill_string(set, args[0]->val.str + str_start, str_len);
5174 return LY_SUCCESS;
5175}
5176
5177/**
5178 * @brief Execute the XPath substring-after(string, string) function.
5179 * Returns LYXP_SET_STRING with the string succeeding the occurance
5180 * of the second argument in the first or an empty string.
5181 *
5182 * @param[in] args Array of arguments.
5183 * @param[in] arg_count Count of elements in @p args.
5184 * @param[in,out] set Context and result set at the same time.
5185 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005186 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005187 */
5188static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005189xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005190{
5191 char *ptr;
5192 struct lysc_node_leaf *sleaf;
5193 LY_ERR rc = LY_SUCCESS;
5194
5195 if (options & LYXP_SCNODE_ALL) {
5196 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5197 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5198 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005199 } else if (!warn_is_string_type(sleaf->type)) {
5200 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005201 }
5202 }
5203
5204 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5205 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5206 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005207 } else if (!warn_is_string_type(sleaf->type)) {
5208 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005209 }
5210 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005211 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005212 return rc;
5213 }
5214
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005215 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005216 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005217 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005218 LY_CHECK_RET(rc);
5219
5220 ptr = strstr(args[0]->val.str, args[1]->val.str);
5221 if (ptr) {
5222 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
5223 } else {
5224 set_fill_string(set, "", 0);
5225 }
5226
5227 return LY_SUCCESS;
5228}
5229
5230/**
5231 * @brief Execute the XPath substring-before(string, string) function.
5232 * Returns LYXP_SET_STRING with the string preceding the occurance
5233 * of the second argument in the first or an empty string.
5234 *
5235 * @param[in] args Array of arguments.
5236 * @param[in] arg_count Count of elements in @p args.
5237 * @param[in,out] set Context and result set at the same time.
5238 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005239 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005240 */
5241static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005242xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005243{
5244 char *ptr;
5245 struct lysc_node_leaf *sleaf;
5246 LY_ERR rc = LY_SUCCESS;
5247
5248 if (options & LYXP_SCNODE_ALL) {
5249 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5250 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5251 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005252 } else if (!warn_is_string_type(sleaf->type)) {
5253 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005254 }
5255 }
5256
5257 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5258 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5259 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005260 } else if (!warn_is_string_type(sleaf->type)) {
5261 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005262 }
5263 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005264 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005265 return rc;
5266 }
5267
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005268 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005269 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005270 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005271 LY_CHECK_RET(rc);
5272
5273 ptr = strstr(args[0]->val.str, args[1]->val.str);
5274 if (ptr) {
5275 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
5276 } else {
5277 set_fill_string(set, "", 0);
5278 }
5279
5280 return LY_SUCCESS;
5281}
5282
5283/**
5284 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
5285 * with the sum of all the nodes in the context.
5286 *
5287 * @param[in] args Array of arguments.
5288 * @param[in] arg_count Count of elements in @p args.
5289 * @param[in,out] set Context and result set at the same time.
5290 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005291 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005292 */
5293static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005294xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005295{
5296 long double num;
5297 char *str;
Michal Vasko1fdd8fa2021-01-08 09:21:45 +01005298 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005299 struct lyxp_set set_item;
5300 struct lysc_node_leaf *sleaf;
5301 LY_ERR rc = LY_SUCCESS;
5302
5303 if (options & LYXP_SCNODE_ALL) {
5304 if (args[0]->type == LYXP_SET_SCNODE_SET) {
5305 for (i = 0; i < args[0]->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005306 if (args[0]->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005307 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
5308 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5309 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
Michal Vasko69730152020-10-09 16:30:07 +02005310 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005311 } else if (!warn_is_numeric_type(sleaf->type)) {
5312 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005313 }
5314 }
5315 }
5316 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005317 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005318 return rc;
5319 }
5320
5321 set_fill_number(set, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005322
5323 if (args[0]->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01005324 LOGVAL(set->ctx, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02005325 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02005326 } else if (!args[0]->used) {
5327 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005328 }
5329
Michal Vasko5c4e5892019-11-14 12:31:38 +01005330 set_init(&set_item, set);
5331
Michal Vasko03ff5a72019-09-11 13:49:33 +02005332 set_item.type = LYXP_SET_NODE_SET;
Michal Vasko41decbf2021-11-02 11:50:21 +01005333 set_item.val.nodes = calloc(1, sizeof *set_item.val.nodes);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005334 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
5335
5336 set_item.used = 1;
5337 set_item.size = 1;
5338
5339 for (i = 0; i < args[0]->used; ++i) {
5340 set_item.val.nodes[0] = args[0]->val.nodes[i];
5341
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005342 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005343 LY_CHECK_RET(rc);
5344 num = cast_string_to_number(str);
5345 free(str);
5346 set->val.num += num;
5347 }
5348
5349 free(set_item.val.nodes);
5350
5351 return LY_SUCCESS;
5352}
5353
5354/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005355 * @brief Execute the XPath translate(string, string, string) function.
5356 * Returns LYXP_SET_STRING with the first argument with the characters
5357 * from the second argument replaced by those on the corresponding
5358 * positions in the third argument.
5359 *
5360 * @param[in] args Array of arguments.
5361 * @param[in] arg_count Count of elements in @p args.
5362 * @param[in,out] set Context and result set at the same time.
5363 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005364 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005365 */
5366static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005367xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005368{
5369 uint16_t i, j, new_used;
5370 char *new;
Radek Krejci857189e2020-09-01 13:26:36 +02005371 ly_bool have_removed;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005372 struct lysc_node_leaf *sleaf;
5373 LY_ERR rc = LY_SUCCESS;
5374
5375 if (options & LYXP_SCNODE_ALL) {
5376 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5377 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5378 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005379 } else if (!warn_is_string_type(sleaf->type)) {
5380 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005381 }
5382 }
5383
5384 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5385 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5386 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005387 } else if (!warn_is_string_type(sleaf->type)) {
5388 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005389 }
5390 }
5391
5392 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5393 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5394 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005395 } else if (!warn_is_string_type(sleaf->type)) {
5396 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005397 }
5398 }
Michal Vasko1a09b212021-05-06 13:00:10 +02005399 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005400 return rc;
5401 }
5402
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005403 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005404 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005405 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005406 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005407 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005408 LY_CHECK_RET(rc);
5409
5410 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5411 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5412 new_used = 0;
5413
5414 have_removed = 0;
5415 for (i = 0; args[0]->val.str[i]; ++i) {
Radek Krejci857189e2020-09-01 13:26:36 +02005416 ly_bool found = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005417
5418 for (j = 0; args[1]->val.str[j]; ++j) {
5419 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5420 /* removing this char */
5421 if (j >= strlen(args[2]->val.str)) {
5422 have_removed = 1;
5423 found = 1;
5424 break;
5425 }
5426 /* replacing this char */
5427 new[new_used] = args[2]->val.str[j];
5428 ++new_used;
5429 found = 1;
5430 break;
5431 }
5432 }
5433
5434 /* copying this char */
5435 if (!found) {
5436 new[new_used] = args[0]->val.str[i];
5437 ++new_used;
5438 }
5439 }
5440
5441 if (have_removed) {
5442 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5443 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5444 }
5445 new[new_used] = '\0';
5446
Michal Vaskod3678892020-05-21 10:06:58 +02005447 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005448 set->type = LYXP_SET_STRING;
5449 set->val.str = new;
5450
5451 return LY_SUCCESS;
5452}
5453
5454/**
5455 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5456 * with true value.
5457 *
5458 * @param[in] args Array of arguments.
5459 * @param[in] arg_count Count of elements in @p args.
5460 * @param[in,out] set Context and result set at the same time.
5461 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005462 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005463 */
5464static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005465xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005466{
5467 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02005468 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005469 return LY_SUCCESS;
5470 }
5471
5472 set_fill_boolean(set, 1);
5473 return LY_SUCCESS;
5474}
5475
Michal Vasko03ff5a72019-09-11 13:49:33 +02005476/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02005477 * @brief Execute the XPath node() processing instruction (node type). Returns LYXP_SET_NODE_SET
5478 * with only nodes from the context.
5479 *
5480 * @param[in,out] set Context and result set at the same time.
5481 * @param[in] axis Axis to search on.
5482 * @param[in] options XPath options.
5483 * @return LY_ERR
5484 */
5485static LY_ERR
5486xpath_pi_node(struct lyxp_set *set, enum lyxp_axis axis, uint32_t options)
5487{
5488 if (options & LYXP_SCNODE_ALL) {
5489 return moveto_scnode(set, NULL, NULL, axis, options);
5490 }
5491
5492 if (set->type != LYXP_SET_NODE_SET) {
5493 lyxp_set_free_content(set);
5494 return LY_SUCCESS;
5495 }
5496
5497 /* just like moving to a node with no restrictions */
5498 return moveto_node(set, NULL, NULL, axis, options);
5499}
5500
5501/**
5502 * @brief Execute the XPath text() processing instruction (node type). Returns LYXP_SET_NODE_SET
5503 * with the text content of the nodes in the context.
5504 *
5505 * @param[in,out] set Context and result set at the same time.
5506 * @param[in] axis Axis to search on.
5507 * @param[in] options XPath options.
5508 * @return LY_ERR
5509 */
5510static LY_ERR
5511xpath_pi_text(struct lyxp_set *set, enum lyxp_axis axis, uint32_t options)
5512{
5513 uint32_t i;
5514
5515 if (options & LYXP_SCNODE_ALL) {
5516 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
5517 return LY_SUCCESS;
5518 }
5519
5520 if (set->type != LYXP_SET_NODE_SET) {
5521 LOGVAL(set->ctx, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
5522 return LY_EVALID;
5523 }
5524
5525 if (axis != LYXP_AXIS_CHILD) {
5526 /* even following and preceding axescan return text nodes, but whatever */
5527 lyxp_set_free_content(set);
5528 return LY_SUCCESS;
5529 }
5530
5531 for (i = 0; i < set->used; ++i) {
5532 switch (set->val.nodes[i].type) {
5533 case LYXP_NODE_NONE:
5534 LOGINT_RET(set->ctx);
5535 case LYXP_NODE_ELEM:
5536 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
5537 set->val.nodes[i].type = LYXP_NODE_TEXT;
5538 break;
5539 }
5540 /* fall through */
5541 case LYXP_NODE_ROOT:
5542 case LYXP_NODE_ROOT_CONFIG:
5543 case LYXP_NODE_TEXT:
5544 case LYXP_NODE_META:
5545 set_remove_node_none(set, i);
5546 break;
5547 }
5548 }
5549 set_remove_nodes_none(set);
5550
5551 return LY_SUCCESS;
5552}
5553
5554/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005555 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005556 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005557 * XPath @p set is expected to be a (sc)node set!
5558 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005559 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5560 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005561 * @param[in] set Set with general XPath context.
5562 * @param[in] ctx_scnode Context node to inherit module for unprefixed node for ::LY_PREF_JSON.
Michal Vasko6346ece2019-09-24 13:12:53 +02005563 * @param[out] moveto_mod Expected module of a matching node.
5564 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005565 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005566static LY_ERR
Michal Vaskofe1af042022-07-29 14:58:59 +02005567moveto_resolve_model(const char **qname, uint32_t *qname_len, const struct lyxp_set *set,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005568 const struct lysc_node *ctx_scnode, const struct lys_module **moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005569{
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02005570 const struct lys_module *mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005571 const char *ptr;
Radek Krejci1deb5be2020-08-26 16:43:36 +02005572 size_t pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005573
Michal Vasko2104e9f2020-03-06 08:23:25 +01005574 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5575
Michal Vasko6346ece2019-09-24 13:12:53 +02005576 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5577 /* specific module */
5578 pref_len = ptr - *qname;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005579 mod = ly_resolve_prefix(set->ctx, *qname, pref_len, set->format, set->prefix_data);
Michal Vasko6346ece2019-09-24 13:12:53 +02005580
Michal Vasko004d3152020-06-11 19:59:22 +02005581 /* check for errors and non-implemented modules, as they are not valid */
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005582 if (!mod || !mod->implemented) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01005583 LOGVAL(set->ctx, LY_VCODE_XP_INMOD, pref_len, *qname);
Michal Vasko6346ece2019-09-24 13:12:53 +02005584 return LY_EVALID;
5585 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005586
Michal Vasko6346ece2019-09-24 13:12:53 +02005587 *qname += pref_len + 1;
5588 *qname_len -= pref_len + 1;
5589 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5590 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005591 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005592 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005593 switch (set->format) {
Radek Krejci8df109d2021-04-23 12:19:08 +02005594 case LY_VALUE_SCHEMA:
5595 case LY_VALUE_SCHEMA_RESOLVED:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005596 /* current module */
5597 mod = set->cur_mod;
5598 break;
Radek Krejci224d4b42021-04-23 13:54:59 +02005599 case LY_VALUE_CANON:
Radek Krejci8df109d2021-04-23 12:19:08 +02005600 case LY_VALUE_JSON:
Radek Krejcif9943642021-04-26 10:18:21 +02005601 case LY_VALUE_LYB:
Michal Vaskoddd76592022-01-17 13:34:48 +01005602 case LY_VALUE_STR_NS:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005603 /* inherit parent (context node) module */
5604 if (ctx_scnode) {
5605 mod = ctx_scnode->module;
5606 } else {
5607 mod = NULL;
5608 }
5609 break;
Radek Krejci8df109d2021-04-23 12:19:08 +02005610 case LY_VALUE_XML:
Michal Vasko52143d12021-04-14 15:36:39 +02005611 /* all nodes need to be prefixed */
5612 LOGVAL(set->ctx, LYVE_DATA, "Non-prefixed node \"%.*s\" in XML xpath found.", *qname_len, *qname);
5613 return LY_EVALID;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005614 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005615 }
5616
Michal Vasko6346ece2019-09-24 13:12:53 +02005617 *moveto_mod = mod;
5618 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005619}
5620
5621/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005622 * @brief Move context @p set to the root. Handles absolute path.
5623 * Result is LYXP_SET_NODE_SET.
5624 *
5625 * @param[in,out] set Set to use.
5626 * @param[in] options Xpath options.
Michal Vaskob0099a92020-08-31 14:55:23 +02005627 * @return LY_ERR value.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005628 */
Michal Vaskob0099a92020-08-31 14:55:23 +02005629static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005630moveto_root(struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005631{
aPiecek8b0cc152021-05-31 16:40:31 +02005632 assert(!(options & LYXP_SKIP_EXPR));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005633
5634 if (options & LYXP_SCNODE_ALL) {
Michal Vasko1a09b212021-05-06 13:00:10 +02005635 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vaskob0099a92020-08-31 14:55:23 +02005636 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, NULL, set->root_type, NULL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005637 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005638 set->type = LYXP_SET_NODE_SET;
5639 set->used = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005640 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko306e2832022-07-25 09:15:17 +02005641 set->non_child_axis = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005642 }
Michal Vaskob0099a92020-08-31 14:55:23 +02005643
5644 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005645}
5646
5647/**
5648 * @brief Check @p node as a part of NameTest processing.
5649 *
5650 * @param[in] node Node to check.
Michal Vasko49fec8e2022-05-24 10:28:33 +02005651 * @param[in] node_type Node type of @p node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005652 * @param[in] set Set to read general context from.
Michal Vaskod3678892020-05-21 10:06:58 +02005653 * @param[in] node_name Node name in the dictionary to move to, NULL for any node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005654 * @param[in] moveto_mod Expected module of the node, NULL for no prefix.
Michal Vaskocdad7122020-11-09 21:04:44 +01005655 * @param[in] options XPath options.
Michal Vasko6346ece2019-09-24 13:12:53 +02005656 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
Michal Vaskocd2c88a2022-06-07 10:54:34 +02005657 * LY_EINVAL if neither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005658 */
5659static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02005660moveto_node_check(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyxp_set *set,
5661 const char *node_name, const struct lys_module *moveto_mod, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005662{
Michal Vasko49fec8e2022-05-24 10:28:33 +02005663 if ((node_type == LYXP_NODE_ROOT_CONFIG) || (node_type == LYXP_NODE_ROOT)) {
5664 assert(node_type == set->root_type);
5665
5666 if (node_name || moveto_mod) {
5667 /* root will not match a specific node */
5668 return LY_ENOT;
5669 }
5670 return LY_SUCCESS;
5671 } else if (node_type != LYXP_NODE_ELEM) {
5672 /* other types will not match */
5673 return LY_ENOT;
5674 }
5675
Michal Vaskodca9f122021-07-16 13:56:22 +02005676 if (!node->schema) {
5677 /* opaque node never matches */
5678 return LY_ENOT;
5679 }
5680
Michal Vasko03ff5a72019-09-11 13:49:33 +02005681 /* module check */
Michal Vasko19089f02022-06-07 11:02:11 +02005682 if (moveto_mod) {
5683 if (!(node->flags & LYD_EXT) && (node->schema->module != moveto_mod)) {
5684 return LY_ENOT;
5685 } else if ((node->flags & LYD_EXT) && strcmp(node->schema->module->name, moveto_mod->name)) {
5686 return LY_ENOT;
5687 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005688 }
5689
Michal Vasko5c4e5892019-11-14 12:31:38 +01005690 /* context check */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005691 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005692 return LY_EINVAL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005693 } else if (set->context_op && (node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) &&
5694 (node->schema != set->context_op)) {
Michal Vasko6b26e742020-07-17 15:02:10 +02005695 return LY_EINVAL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005696 }
5697
5698 /* name check */
Michal Vasko19089f02022-06-07 11:02:11 +02005699 if (node_name) {
5700 if (!(node->flags & LYD_EXT) && (node->schema->name != node_name)) {
5701 return LY_ENOT;
5702 } else if ((node->flags & LYD_EXT) && strcmp(node->schema->name, node_name)) {
5703 return LY_ENOT;
5704 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005705 }
5706
Michal Vaskoa1424542019-11-14 16:08:52 +01005707 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01005708 if (!(options & LYXP_IGNORE_WHEN) && lysc_has_when(node->schema) && !(node->flags & LYD_WHEN_TRUE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005709 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005710 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005711
5712 /* match */
5713 return LY_SUCCESS;
5714}
5715
5716/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02005717 * @brief Get the next node in a forward DFS.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005718 *
Michal Vasko49fec8e2022-05-24 10:28:33 +02005719 * @param[in] iter Last returned node.
5720 * @param[in] stop Node to stop the search on and not return.
5721 * @return Next node, NULL if there are no more.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005722 */
Michal Vasko49fec8e2022-05-24 10:28:33 +02005723static const struct lyd_node *
5724moveto_axis_node_next_dfs_forward(const struct lyd_node *iter, const struct lyd_node *stop)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005725{
Michal Vasko49fec8e2022-05-24 10:28:33 +02005726 const struct lyd_node *next = NULL;
5727
5728 /* 1) child */
5729 next = lyd_child(iter);
5730 if (!next) {
5731 if (iter == stop) {
5732 /* reached stop, no more descendants */
5733 return NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005734 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02005735 /* 2) child next sibling */
5736 next = iter->next;
5737 }
5738 while (!next) {
5739 iter = lyd_parent(iter);
5740 if ((!stop && !iter) || (stop && (lyd_parent(iter) == lyd_parent(stop)))) {
5741 return NULL;
5742 }
5743 next = iter->next;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005744 }
5745
Michal Vasko49fec8e2022-05-24 10:28:33 +02005746 return next;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005747}
5748
5749/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02005750 * @brief Get the next node in a backward DFS.
5751 *
5752 * @param[in] iter Last returned node.
5753 * @param[in] stop Node to stop the search on and not return.
5754 * @return Next node, NULL if there are no more.
5755 */
5756static const struct lyd_node *
5757moveto_axis_node_next_dfs_backward(const struct lyd_node *iter, const struct lyd_node *stop)
5758{
5759 const struct lyd_node *next = NULL;
5760
5761 /* 1) previous sibling innermost last child */
5762 next = iter->prev->next ? iter->prev : NULL;
5763 while (next && lyd_child(next)) {
5764 next = lyd_child(next);
5765 next = next->prev;
5766 }
5767
5768 if (!next) {
5769 /* 2) parent */
5770 iter = lyd_parent(iter);
5771 if ((!stop && !iter) || (stop && (lyd_parent(iter) == lyd_parent(stop)))) {
5772 return NULL;
5773 }
5774 next = iter;
5775 }
5776
5777 return next;
5778}
5779
5780/**
5781 * @brief Get the first node on an axis for a context node.
5782 *
5783 * @param[in,out] iter NULL, updated to the next node.
5784 * @param[in,out] iter_type Node type 0 of @p iter, updated to the node type of the next node.
5785 * @param[in] node Context node.
5786 * @param[in] node_type Type of @p node.
5787 * @param[in] axis Axis to use.
5788 * @param[in] set XPath set with the general context.
5789 * @return LY_SUCCESS on success.
5790 * @return LY_ENOTFOUND if no next node found.
5791 */
5792static LY_ERR
5793moveto_axis_node_next_first(const struct lyd_node **iter, enum lyxp_node_type *iter_type, const struct lyd_node *node,
5794 enum lyxp_node_type node_type, enum lyxp_axis axis, struct lyxp_set *set)
5795{
5796 const struct lyd_node *next = NULL;
5797 enum lyxp_node_type next_type = 0;
5798
5799 assert(!*iter);
5800 assert(!*iter_type);
5801
5802 switch (axis) {
5803 case LYXP_AXIS_ANCESTOR_OR_SELF:
5804 case LYXP_AXIS_DESCENDANT_OR_SELF:
5805 case LYXP_AXIS_SELF:
5806 /* return the context node */
5807 next = node;
5808 next_type = node_type;
5809 break;
5810
5811 case LYXP_AXIS_ANCESTOR:
5812 case LYXP_AXIS_PARENT:
5813 if (node_type == LYXP_NODE_ELEM) {
5814 next = lyd_parent(node);
5815 next_type = next ? LYXP_NODE_ELEM : set->root_type;
5816 } else if (node_type == LYXP_NODE_TEXT) {
5817 next = node;
5818 next_type = LYXP_NODE_ELEM;
5819 } else if (node_type == LYXP_NODE_META) {
5820 next = ((struct lyd_meta *)node)->parent;
5821 next_type = LYXP_NODE_ELEM;
5822 } /* else root does not have a parent */
5823 break;
5824
5825 case LYXP_AXIS_CHILD:
5826 if ((node_type == LYXP_NODE_ROOT_CONFIG) || (node_type == LYXP_NODE_ROOT)) {
5827 assert(!node);
5828
5829 /* search in all the trees */
5830 next = set->tree;
5831 next_type = next ? LYXP_NODE_ELEM : 0;
5832 } else {
5833 /* search in children */
5834 next = lyd_child(node);
5835 next_type = next ? LYXP_NODE_ELEM : 0;
5836 }
5837 break;
5838
5839 case LYXP_AXIS_DESCENDANT:
5840 if ((node_type == LYXP_NODE_ROOT_CONFIG) || (node_type == LYXP_NODE_ROOT)) {
5841 /* top-level nodes */
5842 next = set->tree;
5843 next_type = LYXP_NODE_ELEM;
5844 } else if (node_type == LYXP_NODE_ELEM) {
5845 /* start from the context node */
5846 next = moveto_axis_node_next_dfs_forward(node, node);
5847 next_type = next ? LYXP_NODE_ELEM : 0;
5848 } /* else no children */
5849 break;
5850
5851 case LYXP_AXIS_FOLLOWING:
5852 case LYXP_AXIS_FOLLOWING_SIBLING:
5853 if (node_type == LYXP_NODE_ELEM) {
5854 /* first next sibling */
5855 next = node->next;
5856 next_type = next ? LYXP_NODE_ELEM : 0;
5857 } /* else no sibling */
5858 break;
5859
5860 case LYXP_AXIS_PRECEDING:
5861 if ((node_type == LYXP_NODE_ELEM) && node->prev->next) {
5862 /* skip ancestors */
5863 next = moveto_axis_node_next_dfs_backward(node, NULL);
5864 assert(next);
5865 next_type = LYXP_NODE_ELEM;
5866 } /* else no sibling */
5867 break;
5868
5869 case LYXP_AXIS_PRECEDING_SIBLING:
5870 if (node_type == LYXP_NODE_ELEM) {
5871 /* first previous sibling */
5872 next = node->prev->next ? node->prev : NULL;
5873 next_type = next ? LYXP_NODE_ELEM : 0;
5874 } /* else no sibling */
5875 break;
5876
5877 case LYXP_AXIS_ATTRIBUTE:
5878 /* handled specially */
5879 assert(0);
5880 LOGINT(set->ctx);
5881 break;
5882 }
5883
5884 *iter = next;
5885 *iter_type = next_type;
5886 return next_type ? LY_SUCCESS : LY_ENOTFOUND;
5887}
5888
5889/**
5890 * @brief Iterate over all nodes on an axis for a context node.
5891 *
5892 * @param[in,out] iter Last returned node, start with NULL, updated to the next node.
5893 * @param[in,out] iter_type Node type of @p iter, start with 0, updated to the node type of the next node.
5894 * @param[in] node Context node.
5895 * @param[in] node_type Type of @p node.
5896 * @param[in] axis Axis to use.
5897 * @param[in] set XPath set with the general context.
5898 * @return LY_SUCCESS on success.
5899 * @return LY_ENOTFOUND if no next node found.
5900 */
5901static LY_ERR
5902moveto_axis_node_next(const struct lyd_node **iter, enum lyxp_node_type *iter_type, const struct lyd_node *node,
5903 enum lyxp_node_type node_type, enum lyxp_axis axis, struct lyxp_set *set)
5904{
5905 const struct lyd_node *next = NULL;
5906 enum lyxp_node_type next_type = 0;
5907
5908 if (!*iter_type) {
5909 /* first returned node */
5910 return moveto_axis_node_next_first(iter, iter_type, node, node_type, axis, set);
5911 }
5912
5913 switch (axis) {
5914 case LYXP_AXIS_ANCESTOR_OR_SELF:
5915 if ((*iter == node) && (*iter_type == node_type)) {
5916 /* fake first ancestor, we returned self before */
5917 *iter = NULL;
5918 *iter_type = 0;
5919 return moveto_axis_node_next_first(iter, iter_type, node, node_type, LYXP_AXIS_ANCESTOR, set);
5920 } /* else continue ancestor */
5921
5922 /* fallthrough */
5923 case LYXP_AXIS_ANCESTOR:
5924 if (*iter_type == LYXP_NODE_ELEM) {
5925 /* iter parent */
5926 next = lyd_parent(*iter);
5927 next_type = next ? LYXP_NODE_ELEM : set->root_type;
5928 } /* else root, no ancestors */
5929 break;
5930
5931 case LYXP_AXIS_CHILD:
5932 assert(*iter_type == LYXP_NODE_ELEM);
5933
5934 /* next sibling (child) */
5935 next = (*iter)->next;
5936 next_type = next ? LYXP_NODE_ELEM : 0;
5937 break;
5938
5939 case LYXP_AXIS_DESCENDANT_OR_SELF:
5940 if ((*iter == node) && (*iter_type == node_type)) {
5941 /* fake first descendant, we returned self before */
5942 *iter = NULL;
5943 *iter_type = 0;
5944 return moveto_axis_node_next_first(iter, iter_type, node, node_type, LYXP_AXIS_DESCENDANT, set);
5945 } /* else continue descendant */
5946
5947 /* fallthrough */
5948 case LYXP_AXIS_DESCENDANT:
5949 assert(*iter_type == LYXP_NODE_ELEM);
5950 next = moveto_axis_node_next_dfs_forward(*iter, node);
5951 next_type = next ? LYXP_NODE_ELEM : 0;
5952 break;
5953
5954 case LYXP_AXIS_FOLLOWING:
5955 assert(*iter_type == LYXP_NODE_ELEM);
5956 next = moveto_axis_node_next_dfs_forward(*iter, NULL);
5957 next_type = next ? LYXP_NODE_ELEM : 0;
5958 break;
5959
5960 case LYXP_AXIS_FOLLOWING_SIBLING:
5961 assert(*iter_type == LYXP_NODE_ELEM);
5962
5963 /* next sibling */
5964 next = (*iter)->next;
5965 next_type = next ? LYXP_NODE_ELEM : 0;
5966 break;
5967
5968 case LYXP_AXIS_PARENT:
5969 case LYXP_AXIS_SELF:
5970 /* parent/self was returned before */
5971 break;
5972
5973 case LYXP_AXIS_PRECEDING:
5974 assert(*iter_type == LYXP_NODE_ELEM);
5975 next = moveto_axis_node_next_dfs_backward(*iter, NULL);
5976 next_type = next ? LYXP_NODE_ELEM : 0;
5977 break;
5978
5979 case LYXP_AXIS_PRECEDING_SIBLING:
5980 assert(*iter_type == LYXP_NODE_ELEM);
5981
5982 /* previous sibling */
5983 next = (*iter)->prev->next ? (*iter)->prev : NULL;
5984 next_type = next ? LYXP_NODE_ELEM : 0;
5985 break;
5986
5987 case LYXP_AXIS_ATTRIBUTE:
5988 /* handled specially */
5989 assert(0);
5990 LOGINT(set->ctx);
5991 break;
5992 }
5993
5994 *iter = next;
5995 *iter_type = next_type;
5996 return next_type ? LY_SUCCESS : LY_ENOTFOUND;
5997}
5998
5999/**
6000 * @brief Move context @p set to a node. Result is LYXP_SET_NODE_SET. Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006001 *
6002 * @param[in,out] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006003 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02006004 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko49fec8e2022-05-24 10:28:33 +02006005 * @param[in] axis Axis to search on.
Michal Vaskocdad7122020-11-09 21:04:44 +01006006 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006007 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6008 */
6009static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02006010moveto_node(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, enum lyxp_axis axis,
6011 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006012{
Michal Vasko230cf972021-12-02 12:31:00 +01006013 LY_ERR r, rc = LY_SUCCESS;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006014 const struct lyd_node *iter;
6015 enum lyxp_node_type iter_type;
Michal Vasko230cf972021-12-02 12:31:00 +01006016 struct lyxp_set result;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006017 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006018
aPiecek8b0cc152021-05-31 16:40:31 +02006019 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006020 return LY_SUCCESS;
6021 }
6022
6023 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006024 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006025 return LY_EVALID;
6026 }
6027
Michal Vasko230cf972021-12-02 12:31:00 +01006028 /* init result set */
6029 set_init(&result, set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006030
Michal Vasko49fec8e2022-05-24 10:28:33 +02006031 for (i = 0; i < set->used; ++i) {
6032 /* iterate over all the nodes on the axis of the node */
6033 iter = NULL;
6034 iter_type = 0;
6035 while (!moveto_axis_node_next(&iter, &iter_type, set->val.nodes[i].node, set->val.nodes[i].type, axis, set)) {
6036 r = moveto_node_check(iter, iter_type, set, ncname, moveto_mod, options);
6037 if (r == LY_EINCOMPLETE) {
Michal Vasko230cf972021-12-02 12:31:00 +01006038 rc = r;
6039 goto cleanup;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006040 } else if (r) {
6041 continue;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006042 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02006043
6044 /* check for duplicates if they are possible */
6045 switch (axis) {
6046 case LYXP_AXIS_ANCESTOR:
6047 case LYXP_AXIS_ANCESTOR_OR_SELF:
6048 case LYXP_AXIS_DESCENDANT:
6049 case LYXP_AXIS_DESCENDANT_OR_SELF:
6050 case LYXP_AXIS_FOLLOWING:
6051 case LYXP_AXIS_FOLLOWING_SIBLING:
6052 case LYXP_AXIS_PARENT:
6053 case LYXP_AXIS_PRECEDING:
6054 case LYXP_AXIS_PRECEDING_SIBLING:
Michal Vasko306e2832022-07-25 09:15:17 +02006055 result.non_child_axis = 1;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006056 if (set_dup_node_check(&result, iter, iter_type, -1)) {
6057 continue;
6058 }
6059 break;
6060 case LYXP_AXIS_CHILD:
6061 case LYXP_AXIS_SELF:
6062 break;
6063 case LYXP_AXIS_ATTRIBUTE:
6064 /* handled specially */
6065 assert(0);
6066 LOGINT(set->ctx);
6067 break;
6068 }
6069
6070 /* matching node */
6071 set_insert_node(&result, iter, 0, iter_type, result.used);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006072 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006073 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006074
Michal Vasko230cf972021-12-02 12:31:00 +01006075 /* move result to the set */
6076 lyxp_set_free_content(set);
6077 *set = result;
6078 result.type = LYXP_SET_NUMBER;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006079
Michal Vasko306e2832022-07-25 09:15:17 +02006080 /* sort the final set if the document order could have been broken */
6081 if (set->non_child_axis) {
6082 set_sort(set);
6083 } else {
6084 assert(!set_sort(set));
6085 }
Michal Vasko230cf972021-12-02 12:31:00 +01006086
6087cleanup:
6088 lyxp_set_free_content(&result);
6089 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006090}
6091
6092/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02006093 * @brief Move context @p set to child nodes using hashes. Result is LYXP_SET_NODE_SET. Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006094 *
6095 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02006096 * @param[in] scnode Matching node schema.
Michal Vasko004d3152020-06-11 19:59:22 +02006097 * @param[in] predicates If @p scnode is ::LYS_LIST or ::LYS_LEAFLIST, the predicates specifying a single instance.
Michal Vaskocdad7122020-11-09 21:04:44 +01006098 * @param[in] options XPath options.
Michal Vaskod3678892020-05-21 10:06:58 +02006099 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6100 */
6101static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02006102moveto_node_hash_child(struct lyxp_set *set, const struct lysc_node *scnode, const struct ly_path_predicate *predicates,
Michal Vaskocdad7122020-11-09 21:04:44 +01006103 uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02006104{
Michal Vaskoddd76592022-01-17 13:34:48 +01006105 LY_ERR ret = LY_SUCCESS, r;
Michal Vaskod3678892020-05-21 10:06:58 +02006106 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02006107 const struct lyd_node *siblings;
Michal Vasko230cf972021-12-02 12:31:00 +01006108 struct lyxp_set result;
Michal Vasko004d3152020-06-11 19:59:22 +02006109 struct lyd_node *sub, *inst = NULL;
Michal Vaskod3678892020-05-21 10:06:58 +02006110
Michal Vasko004d3152020-06-11 19:59:22 +02006111 assert(scnode && (!(scnode->nodetype & (LYS_LIST | LYS_LEAFLIST)) || predicates));
Michal Vaskod3678892020-05-21 10:06:58 +02006112
Michal Vasko50aaa072021-12-02 13:11:56 +01006113 /* init result set */
6114 set_init(&result, set);
6115
aPiecek8b0cc152021-05-31 16:40:31 +02006116 if (options & LYXP_SKIP_EXPR) {
Michal Vasko004d3152020-06-11 19:59:22 +02006117 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02006118 }
6119
6120 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006121 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko004d3152020-06-11 19:59:22 +02006122 ret = LY_EVALID;
6123 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02006124 }
6125
6126 /* context check for all the nodes since we have the schema node */
6127 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
6128 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02006129 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02006130 } else if (set->context_op && (scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) &&
6131 (scnode != set->context_op)) {
Michal Vasko6b26e742020-07-17 15:02:10 +02006132 lyxp_set_free_content(set);
6133 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +02006134 }
6135
6136 /* create specific data instance if needed */
6137 if (scnode->nodetype == LYS_LIST) {
6138 LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, &inst), cleanup);
6139 } else if (scnode->nodetype == LYS_LEAFLIST) {
6140 LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02006141 }
6142
Michal Vasko230cf972021-12-02 12:31:00 +01006143 for (i = 0; i < set->used; ++i) {
Michal Vaskod3678892020-05-21 10:06:58 +02006144 siblings = NULL;
6145
6146 if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
6147 assert(!set->val.nodes[i].node);
6148
6149 /* search in all the trees */
6150 siblings = set->tree;
6151 } else if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6152 /* search in children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02006153 siblings = lyd_child(set->val.nodes[i].node);
Michal Vaskod3678892020-05-21 10:06:58 +02006154 }
6155
6156 /* find the node using hashes */
Michal Vasko004d3152020-06-11 19:59:22 +02006157 if (inst) {
Michal Vaskoddd76592022-01-17 13:34:48 +01006158 r = lyd_find_sibling_first(siblings, inst, &sub);
Michal Vaskod3678892020-05-21 10:06:58 +02006159 } else {
Michal Vaskoddd76592022-01-17 13:34:48 +01006160 r = lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
Michal Vaskod3678892020-05-21 10:06:58 +02006161 }
Michal Vaskoddd76592022-01-17 13:34:48 +01006162 LY_CHECK_ERR_GOTO(r && (r != LY_ENOTFOUND), ret = r, cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02006163
6164 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01006165 if (!(options & LYXP_IGNORE_WHEN) && sub && lysc_has_when(sub->schema) && !(sub->flags & LYD_WHEN_TRUE)) {
Michal Vasko004d3152020-06-11 19:59:22 +02006166 ret = LY_EINCOMPLETE;
6167 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02006168 }
6169
6170 if (sub) {
6171 /* pos filled later */
Michal Vasko230cf972021-12-02 12:31:00 +01006172 set_insert_node(&result, sub, 0, LYXP_NODE_ELEM, result.used);
Michal Vaskod3678892020-05-21 10:06:58 +02006173 }
6174 }
6175
Michal Vasko230cf972021-12-02 12:31:00 +01006176 /* move result to the set */
6177 lyxp_set_free_content(set);
6178 *set = result;
6179 result.type = LYXP_SET_NUMBER;
6180 assert(!set_sort(set));
6181
Michal Vasko004d3152020-06-11 19:59:22 +02006182cleanup:
Michal Vasko230cf972021-12-02 12:31:00 +01006183 lyxp_set_free_content(&result);
Michal Vasko004d3152020-06-11 19:59:22 +02006184 lyd_free_tree(inst);
6185 return ret;
Michal Vaskod3678892020-05-21 10:06:58 +02006186}
6187
6188/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02006189 * @brief Check @p node as a part of schema NameTest processing.
6190 *
6191 * @param[in] node Schema node to check.
6192 * @param[in] ctx_scnode Context node.
6193 * @param[in] set Set to read general context from.
6194 * @param[in] node_name Node name in the dictionary to move to, NULL for any nodes.
6195 * @param[in] moveto_mod Expected module of the node, NULL for no prefix.
6196 * @return LY_ERR (LY_ENOT if node does not match, LY_EINVAL if neither node nor any children match)
6197 */
6198static LY_ERR
6199moveto_scnode_check(const struct lysc_node *node, const struct lysc_node *ctx_scnode, const struct lyxp_set *set,
6200 const char *node_name, const struct lys_module *moveto_mod)
6201{
6202 if (!moveto_mod && node_name) {
6203 switch (set->format) {
6204 case LY_VALUE_SCHEMA:
6205 case LY_VALUE_SCHEMA_RESOLVED:
6206 /* use current module */
6207 moveto_mod = set->cur_mod;
6208 break;
6209 case LY_VALUE_JSON:
6210 case LY_VALUE_LYB:
6211 case LY_VALUE_STR_NS:
6212 /* inherit module of the context node, if any */
6213 if (ctx_scnode) {
6214 moveto_mod = ctx_scnode->module;
6215 }
6216 break;
6217 case LY_VALUE_CANON:
6218 case LY_VALUE_XML:
6219 /* not defined */
6220 LOGINT(set->ctx);
6221 return LY_EINVAL;
6222 }
6223 }
6224
6225 if (!node) {
6226 /* root will not match a specific node */
6227 if (node_name || moveto_mod) {
6228 return LY_ENOT;
6229 }
6230 return LY_SUCCESS;
6231 }
6232
6233 /* module check */
6234 if (moveto_mod && (node->module != moveto_mod)) {
6235 return LY_ENOT;
6236 }
6237
6238 /* context check */
6239 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
6240 return LY_EINVAL;
6241 } else if (set->context_op && (node->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node != set->context_op)) {
6242 return LY_EINVAL;
6243 }
6244
6245 /* name check */
6246 if (node_name && (node->name != node_name)) {
6247 return LY_ENOT;
6248 }
6249
6250 /* match */
6251 return LY_SUCCESS;
6252}
6253
6254/**
6255 * @brief Get the next node in a forward schema node DFS.
6256 *
6257 * @param[in] iter Last returned node.
6258 * @param[in] stop Node to stop the search on and not return.
6259 * @param[in] getnext_opts Options for ::lys_getnext().
6260 * @return Next node, NULL if there are no more.
6261 */
6262static const struct lysc_node *
6263moveto_axis_scnode_next_dfs_forward(const struct lysc_node *iter, const struct lysc_node *stop, uint32_t getnext_opts)
6264{
6265 const struct lysc_node *next = NULL;
6266
6267 next = lysc_node_child(iter);
6268 if (!next) {
6269 /* no children, try siblings */
Michal Vasko34a22fe2022-06-15 07:58:55 +02006270 if ((iter == stop) || !lysc_data_parent(iter)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02006271 /* we are done, no next element to process */
6272 return NULL;
6273 }
6274
6275 next = lys_getnext(iter, lysc_data_parent(iter), NULL, getnext_opts);
6276 }
6277 while (!next && iter) {
6278 /* parent is already processed, go to its sibling */
6279 iter = iter->parent;
Michal Vasko34a22fe2022-06-15 07:58:55 +02006280 if ((iter == stop) || !lysc_data_parent(iter)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02006281 /* we are done, no next element to process */
6282 return NULL;
6283 }
6284 next = lys_getnext(iter, lysc_data_parent(iter), NULL, getnext_opts);
6285 }
6286
6287 return next;
6288}
6289
6290/**
6291 * @brief Consider schema node based on its in_ctx enum value.
6292 *
6293 * @param[in,out] in_ctx In_ctx enum of the schema node, may be updated.
6294 * @param[in] axis Axis to use.
6295 * @return LY_SUCCESS on success.
6296 * @return LY_ENOT if the node should not be returned.
6297 */
6298static LY_ERR
6299moveto_axis_scnode_next_in_ctx(int32_t *in_ctx, enum lyxp_axis axis)
6300{
6301 switch (axis) {
6302 case LYXP_AXIS_SELF:
6303 if ((*in_ctx == LYXP_SET_SCNODE_START) || (*in_ctx == LYXP_SET_SCNODE_ATOM_CTX)) {
6304 /* additionally put the start node into context */
6305 *in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
6306 return LY_SUCCESS;
6307 }
6308 break;
6309 case LYXP_AXIS_PARENT:
6310 case LYXP_AXIS_ANCESTOR_OR_SELF:
6311 case LYXP_AXIS_ANCESTOR:
6312 case LYXP_AXIS_DESCENDANT_OR_SELF:
6313 case LYXP_AXIS_DESCENDANT:
6314 case LYXP_AXIS_FOLLOWING:
6315 case LYXP_AXIS_FOLLOWING_SIBLING:
6316 case LYXP_AXIS_PRECEDING:
6317 case LYXP_AXIS_PRECEDING_SIBLING:
6318 case LYXP_AXIS_CHILD:
6319 if (*in_ctx == LYXP_SET_SCNODE_START) {
6320 /* remember that context node was used */
6321 *in_ctx = LYXP_SET_SCNODE_START_USED;
6322 return LY_SUCCESS;
6323 } else if (*in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
6324 /* traversed */
6325 *in_ctx = LYXP_SET_SCNODE_ATOM_NODE;
6326 return LY_SUCCESS;
6327 }
6328 break;
6329 case LYXP_AXIS_ATTRIBUTE:
6330 /* unreachable */
6331 assert(0);
6332 LOGINT(NULL);
6333 break;
6334 }
6335
6336 return LY_ENOT;
6337}
6338
6339/**
6340 * @brief Get previous sibling for a schema node.
6341 *
6342 * @param[in] scnode Schema node.
6343 * @param[in] getnext_opts Options for ::lys_getnext().
6344 * @return Previous sibling, NULL if none.
6345 */
6346static const struct lysc_node *
6347moveto_axis_scnode_preceding_sibling(const struct lysc_node *scnode, uint32_t getnext_opts)
6348{
6349 const struct lysc_node *next = NULL, *prev = NULL;
6350
6351 while ((next = lys_getnext(next, lysc_data_parent(scnode), scnode->module->compiled, getnext_opts))) {
6352 if (next == scnode) {
6353 break;
6354 }
6355
6356 prev = next;
6357 }
6358
6359 return prev;
6360}
6361
6362/**
6363 * @brief Get the first schema node on an axis for a context node.
6364 *
6365 * @param[in,out] iter Last returned node, start with NULL, updated to the next node.
6366 * @param[in,out] iter_type Node type of @p iter, start with 0, updated to the node type of the next node.
6367 * @param[in,out] iter_mod Internal module iterator, do not change.
6368 * @param[in,out] iter_mod_idx Internal module index iterator, do not change.
6369 * @param[in] scnode Context node.
6370 * @param[in] node_type Type of @p scnode.
6371 * @param[in] in_ctx In_ctx enum of @p scnode.
6372 * @param[in] axis Axis to use.
6373 * @param[in] set XPath set with the general context.
6374 * @param[in] getnext_opts Options for ::lys_getnext().
6375 * @return LY_SUCCESS on success.
6376 * @return LY_ENOTFOUND if no next node found.
6377 */
6378static LY_ERR
6379moveto_axis_scnode_next_first(const struct lysc_node **iter, enum lyxp_node_type *iter_type, const struct lys_module **iter_mod,
6380 uint32_t *iter_mod_idx, const struct lysc_node *scnode, enum lyxp_node_type node_type, enum lyxp_axis axis,
6381 struct lyxp_set *set, uint32_t getnext_opts)
6382{
6383 const struct lysc_node *next = NULL;
6384 enum lyxp_node_type next_type = 0;
6385
6386 assert(!*iter);
6387 assert(!*iter_type);
6388
6389 *iter_mod = NULL;
6390 *iter_mod_idx = 0;
6391
6392 switch (axis) {
6393 case LYXP_AXIS_ANCESTOR_OR_SELF:
6394 case LYXP_AXIS_DESCENDANT_OR_SELF:
6395 case LYXP_AXIS_SELF:
6396 if ((node_type == LYXP_NODE_ROOT_CONFIG) || (node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ELEM)) {
6397 /* just return the node */
6398 next = scnode;
6399 next_type = node_type;
6400 }
6401 break;
6402
6403 case LYXP_AXIS_ANCESTOR:
6404 case LYXP_AXIS_PARENT:
6405 if (node_type == LYXP_NODE_ELEM) {
6406 next = lysc_data_parent(scnode);
6407 next_type = next ? LYXP_NODE_ELEM : set->root_type;
6408 } /* else no parent */
6409 break;
6410
6411 case LYXP_AXIS_DESCENDANT:
6412 case LYXP_AXIS_CHILD:
6413 if ((node_type == LYXP_NODE_ROOT_CONFIG) || (node_type == LYXP_NODE_ROOT)) {
6414 /* it can actually be in any module, it's all <running>, and even if it's moveto_mod (if set),
6415 * it can be in a top-level augment */
6416 while ((*iter_mod = ly_ctx_get_module_iter(set->ctx, iter_mod_idx))) {
6417 /* module may not be implemented or not compiled yet */
6418 if (!(*iter_mod)->compiled) {
6419 continue;
6420 }
6421
6422 /* get next node */
6423 if ((next = lys_getnext(NULL, NULL, (*iter_mod)->compiled, getnext_opts))) {
6424 next_type = LYXP_NODE_ELEM;
6425 break;
6426 }
6427 }
6428 } else if (node_type == LYXP_NODE_ELEM) {
6429 /* get next node */
6430 next = lys_getnext(NULL, scnode, NULL, getnext_opts);
6431 next_type = next ? LYXP_NODE_ELEM : 0;
6432 }
6433 break;
6434
6435 case LYXP_AXIS_FOLLOWING:
6436 case LYXP_AXIS_FOLLOWING_SIBLING:
6437 if (node_type == LYXP_NODE_ELEM) {
6438 /* first next sibling */
6439 next = lys_getnext(scnode, lysc_data_parent(scnode), scnode->module->compiled, getnext_opts);
6440 next_type = next ? LYXP_NODE_ELEM : 0;
6441 } /* else no sibling */
6442 break;
6443
6444 case LYXP_AXIS_PRECEDING:
6445 case LYXP_AXIS_PRECEDING_SIBLING:
6446 if (node_type == LYXP_NODE_ELEM) {
6447 /* first parent sibling */
6448 next = lys_getnext(NULL, lysc_data_parent(scnode), scnode->module->compiled, getnext_opts);
6449 if (next == scnode) {
6450 /* no preceding sibling */
6451 next = NULL;
6452 }
6453 next_type = next ? LYXP_NODE_ELEM : 0;
6454 } /* else no sibling */
6455 break;
6456
6457 case LYXP_AXIS_ATTRIBUTE:
6458 /* unreachable */
6459 assert(0);
6460 LOGINT(set->ctx);
6461 break;
6462 }
6463
6464 *iter = next;
6465 *iter_type = next_type;
6466 return next_type ? LY_SUCCESS : LY_ENOTFOUND;
6467}
6468
6469/**
6470 * @brief Iterate over all schema nodes on an axis for a context node.
6471 *
6472 * @param[in,out] iter Last returned node, start with NULL, updated to the next node.
6473 * @param[in,out] iter_type Node type of @p iter, start with 0, updated to the node type of the next node.
6474 * @param[in,out] iter_mod Internal module iterator, do not change.
6475 * @param[in,out] iter_mod_idx Internal module index iterator, do not change.
6476 * @param[in] scnode Context node.
6477 * @param[in] node_type Type of @p scnode.
6478 * @param[in] axis Axis to use.
6479 * @param[in] set XPath set with the general context.
6480 * @param[in] getnext_opts Options for ::lys_getnext().
6481 * @return LY_SUCCESS on success.
6482 * @return LY_ENOTFOUND if no next node found.
6483 */
6484static LY_ERR
6485moveto_axis_scnode_next(const struct lysc_node **iter, enum lyxp_node_type *iter_type, const struct lys_module **iter_mod,
6486 uint32_t *iter_mod_idx, const struct lysc_node *scnode, enum lyxp_node_type node_type, enum lyxp_axis axis,
6487 struct lyxp_set *set, uint32_t getnext_opts)
6488{
6489 const struct lysc_node *next = NULL, *dfs_stop;
6490 enum lyxp_node_type next_type = 0;
6491
6492 if (!*iter_type) {
6493 /* first returned node */
6494 return moveto_axis_scnode_next_first(iter, iter_type, iter_mod, iter_mod_idx, scnode, node_type, axis, set,
6495 getnext_opts);
6496 }
6497
6498 switch (axis) {
6499 case LYXP_AXIS_PARENT:
6500 case LYXP_AXIS_SELF:
6501 /* parent/self was returned before */
6502 break;
6503
6504 case LYXP_AXIS_ANCESTOR_OR_SELF:
6505 if ((*iter == scnode) && (*iter_type == node_type)) {
6506 /* fake first ancestor, we returned self before */
6507 *iter = NULL;
6508 *iter_type = 0;
6509 return moveto_axis_scnode_next_first(iter, iter_type, iter_mod, iter_mod_idx, scnode, node_type,
6510 LYXP_AXIS_ANCESTOR, set, getnext_opts);
6511 } /* else continue ancestor */
6512
6513 /* fallthrough */
6514 case LYXP_AXIS_ANCESTOR:
6515 if (*iter_type == LYXP_NODE_ELEM) {
6516 next = lysc_data_parent(*iter);
6517 next_type = next ? LYXP_NODE_ELEM : set->root_type;
6518 } /* else no ancestor */
6519 break;
6520
6521 case LYXP_AXIS_DESCENDANT_OR_SELF:
6522 if ((*iter == scnode) && (*iter_type == node_type)) {
6523 /* fake first descendant, we returned self before */
6524 *iter = NULL;
6525 *iter_type = 0;
6526 return moveto_axis_scnode_next_first(iter, iter_type, iter_mod, iter_mod_idx, scnode, node_type,
6527 LYXP_AXIS_DESCENDANT, set, getnext_opts);
6528 } /* else DFS until context node */
6529 dfs_stop = scnode;
6530
6531 /* fallthrough */
6532 case LYXP_AXIS_DESCENDANT:
6533 if (axis == LYXP_AXIS_DESCENDANT) {
6534 /* DFS until the context node */
6535 dfs_stop = scnode;
6536 }
6537
6538 /* fallthrough */
6539 case LYXP_AXIS_PRECEDING:
6540 if (axis == LYXP_AXIS_PRECEDING) {
6541 /* DFS until the previous sibling */
6542 dfs_stop = moveto_axis_scnode_preceding_sibling(scnode, getnext_opts);
6543 assert(dfs_stop);
6544
6545 if (*iter == dfs_stop) {
6546 /* we are done */
6547 break;
6548 }
6549 }
6550
6551 /* fallthrough */
6552 case LYXP_AXIS_FOLLOWING:
6553 if (axis == LYXP_AXIS_FOLLOWING) {
6554 /* DFS through the whole module */
6555 dfs_stop = NULL;
6556 }
6557
6558 /* nested nodes */
6559 assert(*iter);
6560 next = moveto_axis_scnode_next_dfs_forward(*iter, dfs_stop, getnext_opts);
6561 if (next) {
6562 next_type = LYXP_NODE_ELEM;
6563 break;
6564 } /* else get next top-level node just like a child */
6565
6566 /* fallthrough */
6567 case LYXP_AXIS_CHILD:
6568 case LYXP_AXIS_FOLLOWING_SIBLING:
6569 if (!*iter_mod) {
6570 /* nodes from a single module */
6571 if ((next = lys_getnext(*iter, lysc_data_parent(*iter), (*iter)->module->compiled, getnext_opts))) {
6572 next_type = LYXP_NODE_ELEM;
6573 break;
6574 }
6575
6576 assert(scnode);
6577 if (!lysc_data_parent(scnode)) {
6578 /* iterating over top-level nodes, find next */
6579 while (lysc_data_parent(*iter)) {
6580 *iter = lysc_data_parent(*iter);
6581 }
6582 if ((next = lys_getnext(*iter, NULL, (*iter)->module->compiled, getnext_opts))) {
6583 next_type = LYXP_NODE_ELEM;
6584 break;
6585 }
6586 }
6587 }
6588
6589 while (*iter_mod) {
6590 /* module top-level nodes */
6591 if ((next = lys_getnext(*iter, NULL, (*iter_mod)->compiled, getnext_opts))) {
6592 next_type = LYXP_NODE_ELEM;
6593 break;
6594 }
6595
6596 /* get next module */
6597 while ((*iter_mod = ly_ctx_get_module_iter(set->ctx, iter_mod_idx))) {
6598 /* module may not be implemented or not compiled yet */
6599 if ((*iter_mod)->compiled) {
6600 break;
6601 }
6602 }
6603
6604 /* new module, start over */
6605 *iter = NULL;
6606 }
6607 break;
6608
6609 case LYXP_AXIS_PRECEDING_SIBLING:
6610 assert(*iter);
6611
6612 /* next parent sibling until scnode */
6613 next = lys_getnext(*iter, lysc_data_parent(*iter), (*iter)->module->compiled, getnext_opts);
6614 if (next == scnode) {
6615 /* no previous sibling */
6616 next = NULL;
6617 }
6618 next_type = next ? LYXP_NODE_ELEM : 0;
6619 break;
6620
6621 case LYXP_AXIS_ATTRIBUTE:
6622 /* unreachable */
6623 assert(0);
6624 LOGINT(set->ctx);
6625 break;
6626 }
6627
6628 *iter = next;
6629 *iter_type = next_type;
6630 return next_type ? LY_SUCCESS : LY_ENOTFOUND;
6631}
6632
6633/**
Michal Vaskod3678892020-05-21 10:06:58 +02006634 * @brief Move context @p set to a schema node. Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
6635 *
6636 * @param[in,out] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006637 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02006638 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko49fec8e2022-05-24 10:28:33 +02006639 * @param[in] axis Axis to search on.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006640 * @param[in] options XPath options.
6641 * @return LY_ERR
6642 */
6643static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02006644moveto_scnode(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, enum lyxp_axis axis,
6645 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006646{
Radek Krejci857189e2020-09-01 13:26:36 +02006647 ly_bool temp_ctx = 0;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006648 uint32_t getnext_opts, orig_used, i, mod_idx, idx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006649 const struct lys_module *mod;
Michal Vasko49fec8e2022-05-24 10:28:33 +02006650 const struct lysc_node *iter;
6651 enum lyxp_node_type iter_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006652
aPiecek8b0cc152021-05-31 16:40:31 +02006653 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006654 return LY_SUCCESS;
6655 }
6656
6657 if (set->type != LYXP_SET_SCNODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006658 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006659 return LY_EVALID;
6660 }
6661
Michal Vaskocafad9d2019-11-07 15:20:03 +01006662 /* getnext opts */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01006663 getnext_opts = 0;
Michal Vaskocafad9d2019-11-07 15:20:03 +01006664 if (options & LYXP_SCNODE_OUTPUT) {
6665 getnext_opts |= LYS_GETNEXT_OUTPUT;
6666 }
6667
Michal Vasko03ff5a72019-09-11 13:49:33 +02006668 orig_used = set->used;
6669 for (i = 0; i < orig_used; ++i) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02006670 /* update in_ctx first */
6671 if (moveto_axis_scnode_next_in_ctx(&set->val.scnodes[i].in_ctx, axis)) {
6672 /* not usable, skip */
6673 continue;
6674 }
Radek Krejciaa6b53f2020-08-27 15:19:03 +02006675
Michal Vasko49fec8e2022-05-24 10:28:33 +02006676 iter = NULL;
6677 iter_type = 0;
6678 while (!moveto_axis_scnode_next(&iter, &iter_type, &mod, &mod_idx, set->val.scnodes[i].scnode,
6679 set->val.scnodes[i].type, axis, set, getnext_opts)) {
6680 if (moveto_scnode_check(iter, NULL, set, ncname, moveto_mod)) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006681 continue;
6682 }
6683
Michal Vasko49fec8e2022-05-24 10:28:33 +02006684 /* insert */
6685 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, iter, iter_type, &idx));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006686
Michal Vasko49fec8e2022-05-24 10:28:33 +02006687 /* we need to prevent these nodes from being considered in this moveto */
6688 if ((idx < orig_used) && (idx > i)) {
6689 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_NEW_CTX;
6690 temp_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006691 }
6692 }
6693 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006694
6695 /* correct temporary in_ctx values */
6696 if (temp_ctx) {
6697 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006698 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NEW_CTX) {
6699 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006700 }
6701 }
6702 }
6703
6704 return LY_SUCCESS;
6705}
6706
6707/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02006708 * @brief Move context @p set to a child node and all its descendants. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006709 * Context position aware.
6710 *
6711 * @param[in] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006712 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02006713 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vaskocdad7122020-11-09 21:04:44 +01006714 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006715 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6716 */
6717static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02006718moveto_node_alldesc_child(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006719{
6720 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006721 const struct lyd_node *next, *elem, *start;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006722 struct lyxp_set ret_set;
6723 LY_ERR rc;
6724
aPiecek8b0cc152021-05-31 16:40:31 +02006725 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006726 return LY_SUCCESS;
6727 }
6728
6729 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006730 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006731 return LY_EVALID;
6732 }
6733
Michal Vasko9f96a052020-03-10 09:41:45 +01006734 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vasko49fec8e2022-05-24 10:28:33 +02006735 rc = xpath_pi_node(set, LYXP_AXIS_CHILD, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006736 LY_CHECK_RET(rc);
6737
Michal Vasko6346ece2019-09-24 13:12:53 +02006738 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006739 set_init(&ret_set, set);
6740 for (i = 0; i < set->used; ++i) {
6741
6742 /* TREE DFS */
6743 start = set->val.nodes[i].node;
6744 for (elem = next = start; elem; elem = next) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02006745 rc = moveto_node_check(elem, LYXP_NODE_ELEM, set, ncname, moveto_mod, options);
Michal Vasko6346ece2019-09-24 13:12:53 +02006746 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006747 /* add matching node into result set */
6748 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
6749 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
6750 /* the node is a duplicate, we'll process it later in the set */
6751 goto skip_children;
6752 }
Michal Vasko6346ece2019-09-24 13:12:53 +02006753 } else if (rc == LY_EINCOMPLETE) {
Michal Vasko6346ece2019-09-24 13:12:53 +02006754 return rc;
6755 } else if (rc == LY_EINVAL) {
6756 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006757 }
6758
6759 /* TREE DFS NEXT ELEM */
6760 /* select element for the next run - children first */
Radek Krejcia1c1e542020-09-29 16:06:52 +02006761 next = lyd_child(elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006762 if (!next) {
6763skip_children:
6764 /* no children, so try siblings, but only if it's not the start,
6765 * that is considered to be the root and it's siblings are not traversed */
6766 if (elem != start) {
6767 next = elem->next;
6768 } else {
6769 break;
6770 }
6771 }
6772 while (!next) {
6773 /* no siblings, go back through the parents */
Michal Vasko9e685082021-01-29 14:49:09 +01006774 if (lyd_parent(elem) == start) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006775 /* we are done, no next element to process */
6776 break;
6777 }
6778 /* parent is already processed, go to its sibling */
Michal Vasko9e685082021-01-29 14:49:09 +01006779 elem = lyd_parent(elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006780 next = elem->next;
6781 }
6782 }
6783 }
6784
6785 /* make the temporary set the current one */
6786 ret_set.ctx_pos = set->ctx_pos;
6787 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02006788 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006789 memcpy(set, &ret_set, sizeof *set);
Michal Vasko306e2832022-07-25 09:15:17 +02006790 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006791
6792 return LY_SUCCESS;
6793}
6794
6795/**
Michal Vasko49fec8e2022-05-24 10:28:33 +02006796 * @brief Move context @p set to a child schema node and all its descendants starting from a node.
6797 * Result is LYXP_SET_NODE_SET.
6798 *
6799 * @param[in] set Set to use.
6800 * @param[in] start Start node whose subtree to add.
6801 * @param[in] start_idx Index of @p start in @p set.
6802 * @param[in] moveto_mod Matching node module, NULL for no prefix.
6803 * @param[in] ncname Matching node name in the dictionary, NULL for any.
6804 * @param[in] options XPath options.
6805 * @return LY_ERR value.
6806 */
6807static LY_ERR
6808moveto_scnode_dfs(struct lyxp_set *set, const struct lysc_node *start, uint32_t start_idx,
6809 const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
6810{
6811 const struct lysc_node *next, *elem;
6812 uint32_t idx;
6813 LY_ERR rc;
6814
6815 /* TREE DFS */
6816 for (elem = next = start; elem; elem = next) {
6817 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
6818 /* schema-only nodes, skip root */
6819 goto next_iter;
6820 }
6821
6822 rc = moveto_scnode_check(elem, start, set, ncname, moveto_mod);
6823 if (!rc) {
6824 if (lyxp_set_scnode_contains(set, elem, LYXP_NODE_ELEM, start_idx, &idx)) {
6825 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
6826 if (idx > start_idx) {
6827 /* we will process it later in the set */
6828 goto skip_children;
6829 }
6830 } else {
6831 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM, NULL));
6832 }
6833 } else if (rc == LY_EINVAL) {
6834 goto skip_children;
6835 }
6836
6837next_iter:
6838 /* TREE DFS NEXT ELEM */
6839 /* select element for the next run - children first */
6840 next = lysc_node_child(elem);
6841 if (next && (next->nodetype == LYS_INPUT) && (options & LYXP_SCNODE_OUTPUT)) {
6842 next = next->next;
6843 } else if (next && (next->nodetype == LYS_OUTPUT) && !(options & LYXP_SCNODE_OUTPUT)) {
6844 next = next->next;
6845 }
6846 if (!next) {
6847skip_children:
6848 /* no children, so try siblings, but only if it's not the start,
6849 * that is considered to be the root and it's siblings are not traversed */
6850 if (elem != start) {
6851 next = elem->next;
6852 } else {
6853 break;
6854 }
6855 }
6856 while (!next) {
6857 /* no siblings, go back through the parents */
6858 if (elem->parent == start) {
6859 /* we are done, no next element to process */
6860 break;
6861 }
6862 /* parent is already processed, go to its sibling */
6863 elem = elem->parent;
6864 next = elem->next;
6865 }
6866 }
6867
6868 return LY_SUCCESS;
6869}
6870
6871/**
6872 * @brief Move context @p set to a child schema node and all its descendants. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006873 *
6874 * @param[in] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006875 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02006876 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006877 * @param[in] options XPath options.
Michal Vasko49fec8e2022-05-24 10:28:33 +02006878 * @return LY_ERR value.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006879 */
6880static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02006881moveto_scnode_alldesc_child(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006882{
Michal Vasko49fec8e2022-05-24 10:28:33 +02006883 uint32_t i, orig_used, mod_idx;
6884 const struct lys_module *mod;
6885 const struct lysc_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006886
aPiecek8b0cc152021-05-31 16:40:31 +02006887 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006888 return LY_SUCCESS;
6889 }
6890
6891 if (set->type != LYXP_SET_SCNODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006892 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006893 return LY_EVALID;
6894 }
6895
Michal Vasko03ff5a72019-09-11 13:49:33 +02006896 orig_used = set->used;
6897 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006898 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
6899 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006900 continue;
6901 }
6902
6903 /* remember context node */
Radek Krejcif13b87b2020-12-01 22:02:17 +01006904 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vaskoec4df482019-12-16 10:02:18 +01006905 } else {
Michal Vasko1a09b212021-05-06 13:00:10 +02006906 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_NODE;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006907 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006908
Michal Vasko49fec8e2022-05-24 10:28:33 +02006909 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
6910 /* traverse all top-level nodes in all the modules */
6911 mod_idx = 0;
6912 while ((mod = ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
6913 /* module may not be implemented or not compiled yet */
6914 if (!mod->compiled) {
6915 continue;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006916 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006917
Michal Vasko49fec8e2022-05-24 10:28:33 +02006918 root = NULL;
6919 /* no getnext opts needed */
6920 while ((root = lys_getnext(root, NULL, mod->compiled, 0))) {
6921 LY_CHECK_RET(moveto_scnode_dfs(set, root, i, moveto_mod, ncname, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006922 }
6923 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02006924
6925 } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6926 /* add all the descendants recursively */
6927 LY_CHECK_RET(moveto_scnode_dfs(set, set->val.scnodes[i].scnode, i, moveto_mod, ncname, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006928 }
6929 }
6930
6931 return LY_SUCCESS;
6932}
6933
6934/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02006935 * @brief Move context @p set to an attribute. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006936 * Indirectly context position aware.
6937 *
6938 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02006939 * @param[in] mod Matching metadata module, NULL for any.
6940 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
aPiecek8b0cc152021-05-31 16:40:31 +02006941 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006942 * @return LY_ERR
6943 */
6944static LY_ERR
aPiecek8b0cc152021-05-31 16:40:31 +02006945moveto_attr(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006946{
Michal Vasko9f96a052020-03-10 09:41:45 +01006947 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006948
aPiecek8b0cc152021-05-31 16:40:31 +02006949 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006950 return LY_SUCCESS;
6951 }
6952
6953 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01006954 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006955 return LY_EVALID;
6956 }
6957
Radek Krejci1deb5be2020-08-26 16:43:36 +02006958 for (uint32_t i = 0; i < set->used; ) {
Radek Krejci857189e2020-09-01 13:26:36 +02006959 ly_bool replaced = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006960
6961 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
6962 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01006963 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01006964 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006965
6966 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02006967 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006968 continue;
6969 }
6970
Michal Vaskod3678892020-05-21 10:06:58 +02006971 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006972 /* match */
6973 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01006974 set->val.meta[i].meta = sub;
6975 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006976 /* pos does not change */
6977 replaced = 1;
6978 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01006979 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006980 }
6981 ++i;
6982 }
6983 }
6984 }
6985
6986 if (!replaced) {
6987 /* no match */
6988 set_remove_node(set, i);
6989 }
6990 }
6991
6992 return LY_SUCCESS;
6993}
6994
6995/**
6996 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
Michal Vasko61ac2f62020-05-25 12:39:51 +02006997 * Result is LYXP_SET_NODE_SET. Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006998 *
6999 * @param[in,out] set1 Set to use for the result.
7000 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007001 * @return LY_ERR
7002 */
7003static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007004moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007005{
7006 LY_ERR rc;
7007
Michal Vaskod3678892020-05-21 10:06:58 +02007008 if ((set1->type != LYXP_SET_NODE_SET) || (set2->type != LYXP_SET_NODE_SET)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01007009 LOGVAL(set1->ctx, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007010 return LY_EVALID;
7011 }
7012
7013 /* set2 is empty or both set1 and set2 */
Michal Vaskod3678892020-05-21 10:06:58 +02007014 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007015 return LY_SUCCESS;
7016 }
7017
Michal Vaskod3678892020-05-21 10:06:58 +02007018 if (!set1->used) {
aPiecekadc1e4f2021-10-07 11:15:12 +02007019 /* release hidden allocated data (lyxp_set.size) */
7020 lyxp_set_free_content(set1);
7021 /* direct copying of the entire structure */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007022 memcpy(set1, set2, sizeof *set1);
7023 /* dynamic memory belongs to set1 now, do not free */
Michal Vaskod3678892020-05-21 10:06:58 +02007024 memset(set2, 0, sizeof *set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007025 return LY_SUCCESS;
7026 }
7027
7028 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007029 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007030
7031 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007032 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007033 LY_CHECK_RET(rc);
7034
7035 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007036 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007037
7038 return LY_SUCCESS;
7039}
7040
7041/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02007042 * @brief Move context @p set to an attribute in any of the descendants. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007043 * Context position aware.
7044 *
7045 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02007046 * @param[in] mod Matching metadata module, NULL for any.
7047 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vaskocdad7122020-11-09 21:04:44 +01007048 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007049 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7050 */
7051static int
Michal Vaskocdad7122020-11-09 21:04:44 +01007052moveto_attr_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007053{
Michal Vasko9f96a052020-03-10 09:41:45 +01007054 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007055 struct lyxp_set *set_all_desc = NULL;
7056 LY_ERR rc;
7057
aPiecek8b0cc152021-05-31 16:40:31 +02007058 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007059 return LY_SUCCESS;
7060 }
7061
7062 if (set->type != LYXP_SET_NODE_SET) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01007063 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007064 return LY_EVALID;
7065 }
7066
Michal Vasko03ff5a72019-09-11 13:49:33 +02007067 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
7068 * but it likely won't be used much, so it's a waste of time */
7069 /* copy the context */
7070 set_all_desc = set_copy(set);
7071 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko49fec8e2022-05-24 10:28:33 +02007072 rc = moveto_node_alldesc_child(set_all_desc, NULL, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007073 if (rc != LY_SUCCESS) {
7074 lyxp_set_free(set_all_desc);
7075 return rc;
7076 }
7077 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007078 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007079 if (rc != LY_SUCCESS) {
7080 lyxp_set_free(set_all_desc);
7081 return rc;
7082 }
7083 lyxp_set_free(set_all_desc);
7084
Radek Krejci1deb5be2020-08-26 16:43:36 +02007085 for (uint32_t i = 0; i < set->used; ) {
Radek Krejci857189e2020-09-01 13:26:36 +02007086 ly_bool replaced = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007087
7088 /* only attributes of an elem can be in the result, skip all the rest,
7089 * we have all attributes qualified in lyd tree */
7090 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01007091 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007092 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02007093 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007094 continue;
7095 }
7096
Michal Vaskod3678892020-05-21 10:06:58 +02007097 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007098 /* match */
7099 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01007100 set->val.meta[i].meta = sub;
7101 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007102 /* pos does not change */
7103 replaced = 1;
7104 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01007105 set_insert_node(set, (struct lyd_node *)sub, set->val.meta[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007106 }
7107 ++i;
7108 }
7109 }
7110 }
7111
7112 if (!replaced) {
7113 /* no match */
7114 set_remove_node(set, i);
7115 }
7116 }
7117
7118 return LY_SUCCESS;
7119}
7120
7121/**
Michal Vasko8abcecc2022-07-28 09:55:01 +02007122 * @brief Move context @p set1 single item to the result of a comparison.
7123 *
7124 * @param[in] set1 First set with the item to compare.
7125 * @param[in] idx1 Index of the item in @p set1.
7126 * @param[in] set2 Second set.
7127 * @param[in] op Comparison operator to process.
7128 * @param[in] switch_operands Whether to switch sets as operands; whether it is `set1 op set2` or `set2 op set1`.
7129 * @param[out] result Result of the comparison.
7130 * @return LY_ERR value.
7131 */
7132static LY_ERR
7133moveto_op_comp_item(const struct lyxp_set *set1, uint32_t idx1, struct lyxp_set *set2, const char *op,
7134 ly_bool switch_operands, ly_bool *result)
7135{
7136 struct lyxp_set tmp1 = {0};
7137 LY_ERR rc = LY_SUCCESS;
7138
7139 assert(set1->type == LYXP_SET_NODE_SET);
7140
7141 /* cast set1 */
7142 switch (set2->type) {
7143 case LYXP_SET_NUMBER:
7144 rc = set_comp_cast(&tmp1, set1, LYXP_SET_NUMBER, idx1);
7145 break;
7146 case LYXP_SET_BOOLEAN:
7147 rc = set_comp_cast(&tmp1, set1, LYXP_SET_BOOLEAN, idx1);
7148 break;
7149 default:
7150 rc = set_comp_cast(&tmp1, set1, LYXP_SET_STRING, idx1);
7151 break;
7152 }
7153 LY_CHECK_GOTO(rc, cleanup);
7154
7155 /* canonize set2 */
7156 LY_CHECK_GOTO(rc = set_comp_canonize(set2, &set1->val.nodes[idx1]), cleanup);
7157
7158 /* compare recursively and store the result */
7159 if (switch_operands) {
7160 LY_CHECK_GOTO(rc = moveto_op_comp(set2, &tmp1, op), cleanup);
7161 *result = set2->val.bln;
7162 } else {
7163 LY_CHECK_GOTO(rc = moveto_op_comp(&tmp1, set2, op), cleanup);
7164 *result = tmp1.val.bln;
7165 }
7166
7167cleanup:
7168 lyxp_set_free_content(&tmp1);
7169 return rc;
7170}
7171
7172/**
7173 * @brief Move context @p set1 to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007174 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
7175 *
7176 * @param[in,out] set1 Set to use for the result.
7177 * @param[in] set2 Set acting as the second operand for @p op.
7178 * @param[in] op Comparison operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007179 * @return LY_ERR
7180 */
7181static LY_ERR
Michal Vasko8abcecc2022-07-28 09:55:01 +02007182moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007183{
7184 /*
7185 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
7186 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
7187 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
7188 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
7189 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
7190 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
7191 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
7192 *
7193 * '=' or '!='
7194 * BOOLEAN + BOOLEAN
7195 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
7196 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
7197 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
7198 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
7199 * NUMBER + NUMBER
7200 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
7201 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
7202 * STRING + STRING
7203 *
7204 * '<=', '<', '>=', '>'
7205 * NUMBER + NUMBER
7206 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
7207 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
7208 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
7209 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
7210 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
7211 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
7212 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
7213 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
7214 */
Michal Vasko8abcecc2022-07-28 09:55:01 +02007215 ly_bool result;
7216 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007217 LY_ERR rc;
7218
Michal Vasko03ff5a72019-09-11 13:49:33 +02007219 /* iterative evaluation with node-sets */
7220 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
7221 if (set1->type == LYXP_SET_NODE_SET) {
7222 for (i = 0; i < set1->used; ++i) {
Michal Vasko8abcecc2022-07-28 09:55:01 +02007223 /* evaluate for the single item */
7224 LY_CHECK_RET(moveto_op_comp_item(set1, i, set2, op, 0, &result));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007225
7226 /* lazy evaluation until true */
Michal Vasko8abcecc2022-07-28 09:55:01 +02007227 if (result) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007228 set_fill_boolean(set1, 1);
7229 return LY_SUCCESS;
7230 }
7231 }
7232 } else {
7233 for (i = 0; i < set2->used; ++i) {
Michal Vasko8abcecc2022-07-28 09:55:01 +02007234 /* evaluate for the single item */
7235 LY_CHECK_RET(moveto_op_comp_item(set2, i, set1, op, 1, &result));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007236
7237 /* lazy evaluation until true */
Michal Vasko8abcecc2022-07-28 09:55:01 +02007238 if (result) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007239 set_fill_boolean(set1, 1);
7240 return LY_SUCCESS;
7241 }
7242 }
7243 }
7244
Michal Vasko8abcecc2022-07-28 09:55:01 +02007245 /* false for all the nodes */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007246 set_fill_boolean(set1, 0);
7247 return LY_SUCCESS;
7248 }
7249
7250 /* first convert properly */
7251 if ((op[0] == '=') || (op[0] == '!')) {
7252 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007253 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
7254 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007255 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007256 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007257 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007258 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007259 LY_CHECK_RET(rc);
7260 } /* else we have 2 strings */
7261 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007262 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007263 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007264 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007265 LY_CHECK_RET(rc);
7266 }
7267
7268 assert(set1->type == set2->type);
7269
7270 /* compute result */
7271 if (op[0] == '=') {
7272 if (set1->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +02007273 result = (set1->val.bln == set2->val.bln);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007274 } else if (set1->type == LYXP_SET_NUMBER) {
7275 result = (set1->val.num == set2->val.num);
7276 } else {
7277 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01007278 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007279 }
7280 } else if (op[0] == '!') {
7281 if (set1->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +02007282 result = (set1->val.bln != set2->val.bln);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007283 } else if (set1->type == LYXP_SET_NUMBER) {
7284 result = (set1->val.num != set2->val.num);
7285 } else {
7286 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoc2058432020-11-06 17:26:21 +01007287 result = strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007288 }
7289 } else {
7290 assert(set1->type == LYXP_SET_NUMBER);
7291 if (op[0] == '<') {
7292 if (op[1] == '=') {
7293 result = (set1->val.num <= set2->val.num);
7294 } else {
7295 result = (set1->val.num < set2->val.num);
7296 }
7297 } else {
7298 if (op[1] == '=') {
7299 result = (set1->val.num >= set2->val.num);
7300 } else {
7301 result = (set1->val.num > set2->val.num);
7302 }
7303 }
7304 }
7305
7306 /* assign result */
7307 if (result) {
7308 set_fill_boolean(set1, 1);
7309 } else {
7310 set_fill_boolean(set1, 0);
7311 }
7312
7313 return LY_SUCCESS;
7314}
7315
7316/**
7317 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
7318 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
7319 *
7320 * @param[in,out] set1 Set to use for the result.
7321 * @param[in] set2 Set acting as the second operand for @p op.
7322 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007323 * @return LY_ERR
7324 */
7325static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007326moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007327{
7328 LY_ERR rc;
7329
7330 /* unary '-' */
7331 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007332 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007333 LY_CHECK_RET(rc);
7334 set1->val.num *= -1;
7335 lyxp_set_free(set2);
7336 return LY_SUCCESS;
7337 }
7338
7339 assert(set1 && set2);
7340
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007341 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007342 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007343 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007344 LY_CHECK_RET(rc);
7345
7346 switch (op[0]) {
7347 /* '+' */
7348 case '+':
7349 set1->val.num += set2->val.num;
7350 break;
7351
7352 /* '-' */
7353 case '-':
7354 set1->val.num -= set2->val.num;
7355 break;
7356
7357 /* '*' */
7358 case '*':
7359 set1->val.num *= set2->val.num;
7360 break;
7361
7362 /* 'div' */
7363 case 'd':
7364 set1->val.num /= set2->val.num;
7365 break;
7366
7367 /* 'mod' */
7368 case 'm':
7369 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
7370 break;
7371
7372 default:
7373 LOGINT_RET(set1->ctx);
7374 }
7375
7376 return LY_SUCCESS;
7377}
7378
Michal Vasko03ff5a72019-09-11 13:49:33 +02007379/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02007380 * @brief Evaluate Predicate. Logs directly on error.
7381 *
Michal Vaskod3678892020-05-21 10:06:58 +02007382 * [9] Predicate ::= '[' Expr ']'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007383 *
7384 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007385 * @param[in] tok_idx Position in the expression @p exp.
aPiecek8b0cc152021-05-31 16:40:31 +02007386 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007387 * @param[in] options XPath options.
Michal Vasko49fec8e2022-05-24 10:28:33 +02007388 * @param[in] axis Axis to search on.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007389 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7390 */
7391static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02007392eval_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options, enum lyxp_axis axis)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007393{
7394 LY_ERR rc;
Michal Vasko1fdd8fa2021-01-08 09:21:45 +01007395 uint16_t orig_exp;
7396 uint32_t i, orig_pos, orig_size;
Michal Vasko5c4e5892019-11-14 12:31:38 +01007397 int32_t pred_in_ctx;
Michal Vasko88a9e802022-05-24 10:50:28 +02007398 ly_bool reverse_axis = 0;
aPiecekfff4dca2021-10-07 10:59:53 +02007399 struct lyxp_set set2 = {0};
Michal Vasko03ff5a72019-09-11 13:49:33 +02007400
7401 /* '[' */
aPiecek8b0cc152021-05-31 16:40:31 +02007402 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02007403 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007404 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007405
aPiecek8b0cc152021-05-31 16:40:31 +02007406 if (options & LYXP_SKIP_EXPR) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007407only_parse:
aPiecek8b0cc152021-05-31 16:40:31 +02007408 rc = eval_expr_select(exp, tok_idx, 0, set, options | LYXP_SKIP_EXPR);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007409 LY_CHECK_RET(rc);
7410 } else if (set->type == LYXP_SET_NODE_SET) {
7411 /* we (possibly) need the set sorted, it can affect the result (if the predicate result is a number) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007412 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007413
7414 /* empty set, nothing to evaluate */
7415 if (!set->used) {
7416 goto only_parse;
7417 }
7418
Michal Vasko49fec8e2022-05-24 10:28:33 +02007419 /* decide forward or reverse axis */
7420 switch (axis) {
7421 case LYXP_AXIS_ANCESTOR:
7422 case LYXP_AXIS_ANCESTOR_OR_SELF:
7423 case LYXP_AXIS_PRECEDING:
7424 case LYXP_AXIS_PRECEDING_SIBLING:
7425 reverse_axis = 1;
7426 break;
7427 case LYXP_AXIS_DESCENDANT:
7428 case LYXP_AXIS_DESCENDANT_OR_SELF:
7429 case LYXP_AXIS_FOLLOWING:
7430 case LYXP_AXIS_FOLLOWING_SIBLING:
7431 case LYXP_AXIS_PARENT:
7432 case LYXP_AXIS_CHILD:
7433 case LYXP_AXIS_SELF:
7434 case LYXP_AXIS_ATTRIBUTE:
7435 reverse_axis = 0;
7436 break;
7437 }
7438
Michal Vasko004d3152020-06-11 19:59:22 +02007439 orig_exp = *tok_idx;
Michal Vasko49fec8e2022-05-24 10:28:33 +02007440 orig_pos = reverse_axis ? set->used + 1 : 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007441 orig_size = set->used;
Michal Vasko39dbf352020-05-21 10:08:59 +02007442 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007443 set_init(&set2, set);
7444 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
Michal Vasko49fec8e2022-05-24 10:28:33 +02007445
7446 /* remember the node context position for position() and context size for last() */
7447 orig_pos += reverse_axis ? -1 : 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007448
7449 set2.ctx_pos = orig_pos;
7450 set2.ctx_size = orig_size;
Michal Vasko004d3152020-06-11 19:59:22 +02007451 *tok_idx = orig_exp;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007452
Michal Vasko004d3152020-06-11 19:59:22 +02007453 rc = eval_expr_select(exp, tok_idx, 0, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007454 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02007455 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007456 return rc;
7457 }
7458
Michal Vasko49fec8e2022-05-24 10:28:33 +02007459 /* number is a proximity position */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007460 if (set2.type == LYXP_SET_NUMBER) {
7461 if ((long long)set2.val.num == orig_pos) {
7462 set2.val.num = 1;
7463 } else {
7464 set2.val.num = 0;
7465 }
7466 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007467 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007468
7469 /* predicate satisfied or not? */
Michal Vasko004d3152020-06-11 19:59:22 +02007470 if (!set2.val.bln) {
Michal Vasko2caefc12019-11-14 16:07:56 +01007471 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007472 }
7473 }
Michal Vasko2caefc12019-11-14 16:07:56 +01007474 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007475
7476 } else if (set->type == LYXP_SET_SCNODE_SET) {
7477 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01007478 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007479 /* there is a currently-valid node */
7480 break;
7481 }
7482 }
7483 /* empty set, nothing to evaluate */
7484 if (i == set->used) {
7485 goto only_parse;
7486 }
7487
Michal Vasko004d3152020-06-11 19:59:22 +02007488 orig_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007489
Michal Vasko03ff5a72019-09-11 13:49:33 +02007490 /* set special in_ctx to all the valid snodes */
7491 pred_in_ctx = set_scnode_new_in_ctx(set);
7492
7493 /* use the valid snodes one-by-one */
7494 for (i = 0; i < set->used; ++i) {
7495 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
7496 continue;
7497 }
Radek Krejcif13b87b2020-12-01 22:02:17 +01007498 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007499
Michal Vasko004d3152020-06-11 19:59:22 +02007500 *tok_idx = orig_exp;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007501
Michal Vasko004d3152020-06-11 19:59:22 +02007502 rc = eval_expr_select(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007503 LY_CHECK_RET(rc);
7504
7505 set->val.scnodes[i].in_ctx = pred_in_ctx;
7506 }
7507
7508 /* restore the state as it was before the predicate */
7509 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01007510 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko1a09b212021-05-06 13:00:10 +02007511 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_NODE;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007512 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01007513 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007514 }
7515 }
7516
7517 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02007518 set2.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007519 set_fill_set(&set2, set);
7520
Michal Vasko004d3152020-06-11 19:59:22 +02007521 rc = eval_expr_select(exp, tok_idx, 0, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007522 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02007523 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007524 return rc;
7525 }
7526
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007527 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko004d3152020-06-11 19:59:22 +02007528 if (!set2.val.bln) {
Michal Vaskod3678892020-05-21 10:06:58 +02007529 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007530 }
Michal Vaskod3678892020-05-21 10:06:58 +02007531 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007532 }
7533
7534 /* ']' */
Michal Vasko004d3152020-06-11 19:59:22 +02007535 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
aPiecek8b0cc152021-05-31 16:40:31 +02007536 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02007537 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007538 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007539
7540 return LY_SUCCESS;
7541}
7542
7543/**
Michal Vaskod3678892020-05-21 10:06:58 +02007544 * @brief Evaluate Literal. Logs directly on error.
7545 *
7546 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007547 * @param[in] tok_idx Position in the expression @p exp.
Michal Vaskod3678892020-05-21 10:06:58 +02007548 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7549 */
7550static void
Michal Vasko40308e72020-10-20 16:38:40 +02007551eval_literal(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
Michal Vaskod3678892020-05-21 10:06:58 +02007552{
7553 if (set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007554 if (exp->tok_len[*tok_idx] == 2) {
Michal Vaskod3678892020-05-21 10:06:58 +02007555 set_fill_string(set, "", 0);
7556 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007557 set_fill_string(set, &exp->expr[exp->tok_pos[*tok_idx] + 1], exp->tok_len[*tok_idx] - 2);
Michal Vaskod3678892020-05-21 10:06:58 +02007558 }
7559 }
7560 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02007561 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007562 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007563}
7564
7565/**
Michal Vasko004d3152020-06-11 19:59:22 +02007566 * @brief Try to compile list or leaf-list predicate in the known format to be used for hash-based instance search.
Michal Vaskod3678892020-05-21 10:06:58 +02007567 *
Michal Vasko004d3152020-06-11 19:59:22 +02007568 * @param[in] exp Full parsed XPath expression.
7569 * @param[in,out] tok_idx Index in @p exp at the beginning of the predicate, is updated on success.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007570 * @param[in] ctx_node Found schema node as the context for the predicate.
7571 * @param[in] cur_mod Current module for the expression.
7572 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +02007573 * @param[in] format Format of any prefixes in key names/values.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007574 * @param[in] prefix_data Format-specific prefix data (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +02007575 * @param[out] predicates Parsed predicates.
7576 * @param[out] pred_type Type of @p predicates.
7577 * @return LY_SUCCESS on success,
7578 * @return LY_ERR on any error.
Michal Vaskod3678892020-05-21 10:06:58 +02007579 */
7580static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007581eval_name_test_try_compile_predicates(const struct lyxp_expr *exp, uint16_t *tok_idx, const struct lysc_node *ctx_node,
Radek Krejci8df109d2021-04-23 12:19:08 +02007582 const struct lys_module *cur_mod, const struct lysc_node *cur_node, LY_VALUE_FORMAT format, void *prefix_data,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007583 struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vaskod3678892020-05-21 10:06:58 +02007584{
Michal Vasko004d3152020-06-11 19:59:22 +02007585 LY_ERR ret = LY_SUCCESS;
7586 uint16_t key_count, e_idx, pred_idx = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02007587 const struct lysc_node *key;
Michal Vasko004d3152020-06-11 19:59:22 +02007588 size_t pred_len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007589 uint32_t prev_lo;
Michal Vasko004d3152020-06-11 19:59:22 +02007590 struct lyxp_expr *exp2 = NULL;
Michal Vaskod3678892020-05-21 10:06:58 +02007591
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007592 assert(ctx_node->nodetype & (LYS_LIST | LYS_LEAFLIST));
Michal Vaskod3678892020-05-21 10:06:58 +02007593
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007594 if (ctx_node->nodetype == LYS_LIST) {
Michal Vasko004d3152020-06-11 19:59:22 +02007595 /* get key count */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007596 if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko004d3152020-06-11 19:59:22 +02007597 return LY_EINVAL;
7598 }
Michal Vasko544e58a2021-01-28 14:33:41 +01007599 for (key_count = 0, key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next, ++key_count) {}
Michal Vasko004d3152020-06-11 19:59:22 +02007600 assert(key_count);
Michal Vaskod3678892020-05-21 10:06:58 +02007601
Michal Vasko004d3152020-06-11 19:59:22 +02007602 /* learn where the predicates end */
7603 e_idx = *tok_idx;
7604 while (key_count) {
7605 /* '[' */
7606 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK1)) {
7607 return LY_EINVAL;
7608 }
7609 ++e_idx;
7610
Michal Vasko3354d272021-04-06 09:40:06 +02007611 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_NAMETEST)) {
7612 /* definitely not a key */
7613 return LY_EINVAL;
7614 }
7615
Michal Vasko004d3152020-06-11 19:59:22 +02007616 /* ']' */
7617 while (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK2)) {
7618 ++e_idx;
7619 }
7620 ++e_idx;
7621
7622 /* another presumably key predicate parsed */
7623 --key_count;
7624 }
Michal Vasko004d3152020-06-11 19:59:22 +02007625 } else {
7626 /* learn just where this single predicate ends */
7627 e_idx = *tok_idx;
7628
Michal Vaskod3678892020-05-21 10:06:58 +02007629 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +02007630 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK1)) {
7631 return LY_EINVAL;
7632 }
7633 ++e_idx;
Michal Vaskod3678892020-05-21 10:06:58 +02007634
Michal Vasko3354d272021-04-06 09:40:06 +02007635 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_DOT)) {
7636 /* definitely not the value */
7637 return LY_EINVAL;
7638 }
7639
Michal Vaskod3678892020-05-21 10:06:58 +02007640 /* ']' */
Michal Vasko004d3152020-06-11 19:59:22 +02007641 while (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK2)) {
7642 ++e_idx;
7643 }
7644 ++e_idx;
Michal Vaskod3678892020-05-21 10:06:58 +02007645 }
7646
Michal Vasko004d3152020-06-11 19:59:22 +02007647 /* get the joined length of all the keys predicates/of the single leaf-list predicate */
7648 pred_len = (exp->tok_pos[e_idx - 1] + exp->tok_len[e_idx - 1]) - exp->tok_pos[*tok_idx];
7649
7650 /* turn logging off */
7651 prev_lo = ly_log_options(0);
7652
7653 /* parse the predicate(s) */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007654 LY_CHECK_GOTO(ret = ly_path_parse_predicate(ctx_node->module->ctx, ctx_node, exp->expr + exp->tok_pos[*tok_idx],
7655 pred_len, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp2), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02007656
7657 /* compile */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007658 ret = ly_path_compile_predicate(ctx_node->module->ctx, cur_node, cur_mod, ctx_node, exp2, &pred_idx, format,
7659 prefix_data, predicates, pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +02007660 LY_CHECK_GOTO(ret, cleanup);
7661
7662 /* success, the predicate must include all the needed information for hash-based search */
7663 *tok_idx = e_idx;
7664
7665cleanup:
7666 ly_log_options(prev_lo);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007667 lyxp_expr_free(ctx_node->module->ctx, exp2);
Michal Vasko004d3152020-06-11 19:59:22 +02007668 return ret;
Michal Vaskod3678892020-05-21 10:06:58 +02007669}
7670
7671/**
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007672 * @brief Search for/check the next schema node that could be the only matching schema node meaning the
7673 * data node(s) could be found using a single hash-based search.
7674 *
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007675 * @param[in] ctx libyang context.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007676 * @param[in] node Next context node to check.
7677 * @param[in] name Expected node name.
7678 * @param[in] name_len Length of @p name.
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007679 * @param[in] moveto_mod Expected node module, can be NULL for JSON format with no prefix.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007680 * @param[in] root_type XPath root type.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007681 * @param[in] format Prefix format.
7682 * @param[in,out] found Previously found node, is updated.
7683 * @return LY_SUCCESS on success,
7684 * @return LY_ENOT if the whole check failed and hashes cannot be used.
7685 */
7686static LY_ERR
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007687eval_name_test_with_predicate_get_scnode(const struct ly_ctx *ctx, const struct lyd_node *node, const char *name,
Radek Krejci8df109d2021-04-23 12:19:08 +02007688 uint16_t name_len, const struct lys_module *moveto_mod, enum lyxp_node_type root_type, LY_VALUE_FORMAT format,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007689 const struct lysc_node **found)
7690{
7691 const struct lysc_node *scnode;
7692 const struct lys_module *mod;
7693 uint32_t idx = 0;
7694
Radek Krejci8df109d2021-04-23 12:19:08 +02007695 assert((format == LY_VALUE_JSON) || moveto_mod);
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007696
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007697continue_search:
Michal Vasko7d1d0912020-10-16 08:38:30 +02007698 scnode = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007699 if (!node) {
Radek Krejci8df109d2021-04-23 12:19:08 +02007700 if ((format == LY_VALUE_JSON) && !moveto_mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007701 /* search all modules for a single match */
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007702 while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
Michal Vasko35a3b1d2021-07-14 09:34:16 +02007703 if (!mod->implemented) {
7704 continue;
7705 }
7706
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007707 scnode = lys_find_child(NULL, mod, name, name_len, 0, 0);
7708 if (scnode) {
7709 /* we have found a match */
7710 break;
7711 }
7712 }
7713
Michal Vasko7d1d0912020-10-16 08:38:30 +02007714 if (!scnode) {
7715 /* all modules searched */
7716 idx = 0;
7717 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007718 } else {
7719 /* search in top-level */
7720 scnode = lys_find_child(NULL, moveto_mod, name, name_len, 0, 0);
7721 }
7722 } else if (!*found || (lysc_data_parent(*found) != node->schema)) {
Radek Krejci8df109d2021-04-23 12:19:08 +02007723 if ((format == LY_VALUE_JSON) && !moveto_mod) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007724 /* we must adjust the module to inherit the one from the context node */
7725 moveto_mod = node->schema->module;
7726 }
7727
7728 /* search in children, do not repeat the same search */
7729 scnode = lys_find_child(node->schema, moveto_mod, name, name_len, 0, 0);
Michal Vasko7d1d0912020-10-16 08:38:30 +02007730 } /* else skip redundant search */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007731
7732 /* additional context check */
7733 if (scnode && (root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
7734 scnode = NULL;
7735 }
7736
7737 if (scnode) {
7738 if (*found) {
7739 /* we found a schema node with the same name but at different level, give up, too complicated
7740 * (more hash-based searches would be required, not supported) */
7741 return LY_ENOT;
7742 } else {
7743 /* remember the found schema node and continue to make sure it can be used */
7744 *found = scnode;
7745 }
7746 }
7747
7748 if (idx) {
7749 /* continue searching all the following models */
7750 goto continue_search;
7751 }
7752
7753 return LY_SUCCESS;
7754}
7755
7756/**
Michal Vasko4ad69e72021-10-26 16:25:55 +02007757 * @brief Generate message when no matching schema nodes were found for a path segment.
7758 *
7759 * @param[in] set XPath set.
7760 * @param[in] scparent Previous schema parent in the context, if only one.
7761 * @param[in] ncname XPath NCName being evaluated.
7762 * @param[in] ncname_len Length of @p ncname.
7763 * @param[in] expr Whole XPath expression.
7764 * @param[in] options XPath options.
7765 */
7766static void
7767eval_name_test_scnode_no_match_msg(struct lyxp_set *set, const struct lyxp_set_scnode *scparent, const char *ncname,
7768 uint16_t ncname_len, const char *expr, uint32_t options)
7769{
7770 const char *format;
7771 char *path = NULL, *ppath = NULL;
7772
7773 path = lysc_path(set->cur_scnode, LYSC_PATH_LOG, NULL, 0);
7774 if (scparent) {
7775 /* generate path for the parent */
7776 if (scparent->type == LYXP_NODE_ELEM) {
7777 ppath = lysc_path(scparent->scnode, LYSC_PATH_LOG, NULL, 0);
7778 } else if (scparent->type == LYXP_NODE_ROOT) {
7779 ppath = strdup("<root>");
7780 } else if (scparent->type == LYXP_NODE_ROOT_CONFIG) {
7781 ppath = strdup("<config-root>");
7782 }
7783 }
7784 if (ppath) {
7785 format = "Schema node \"%.*s\" for parent \"%s\" not found; in expr \"%.*s\" with context node \"%s\".";
7786 if (options & LYXP_SCNODE_ERROR) {
7787 LOGERR(set->ctx, LY_EVALID, format, ncname_len, ncname, ppath, (ncname - expr) + ncname_len, expr, path);
7788 } else {
7789 LOGWRN(set->ctx, format, ncname_len, ncname, ppath, (ncname - expr) + ncname_len, expr, path);
7790 }
7791 } else {
7792 format = "Schema node \"%.*s\" not found; in expr \"%.*s\" with context node \"%s\".";
7793 if (options & LYXP_SCNODE_ERROR) {
7794 LOGERR(set->ctx, LY_EVALID, format, ncname_len, ncname, (ncname - expr) + ncname_len, expr, path);
7795 } else {
7796 LOGWRN(set->ctx, format, ncname_len, ncname, (ncname - expr) + ncname_len, expr, path);
7797 }
7798 }
7799 free(path);
7800 free(ppath);
7801}
7802
7803/**
Michal Vaskod3678892020-05-21 10:06:58 +02007804 * @brief Evaluate NameTest and any following Predicates. Logs directly on error.
7805 *
7806 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
7807 * [6] NodeTest ::= NameTest | NodeType '(' ')'
7808 * [7] NameTest ::= '*' | NCName ':' '*' | QName
7809 *
7810 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007811 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko49fec8e2022-05-24 10:28:33 +02007812 * @param[in] axis What axis to search on.
Michal Vaskod3678892020-05-21 10:06:58 +02007813 * @param[in] all_desc Whether to search all the descendants or children only.
aPiecek8b0cc152021-05-31 16:40:31 +02007814 * @param[in,out] set Context and result set.
Michal Vaskod3678892020-05-21 10:06:58 +02007815 * @param[in] options XPath options.
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007816 * @return LY_ERR (LY_EINCOMPLETE on unresolved when, LY_ENOT for not found schema node)
Michal Vaskod3678892020-05-21 10:06:58 +02007817 */
7818static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02007819eval_name_test_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_axis axis, ly_bool all_desc,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007820 struct lyxp_set *set, uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02007821{
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007822 LY_ERR rc = LY_SUCCESS, r;
Michal Vasko004d3152020-06-11 19:59:22 +02007823 const char *ncname, *ncname_dict = NULL;
Michal Vasko56c008c2022-07-29 14:57:47 +02007824 uint32_t i, ncname_len;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007825 const struct lys_module *moveto_mod = NULL;
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007826 const struct lysc_node *scnode = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02007827 struct ly_path_predicate *predicates = NULL;
7828 enum ly_path_pred_type pred_type = 0;
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007829 int scnode_skip_pred = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02007830
aPiecek8b0cc152021-05-31 16:40:31 +02007831 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02007832 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007833 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007834
aPiecek8b0cc152021-05-31 16:40:31 +02007835 if (options & LYXP_SKIP_EXPR) {
Michal Vaskod3678892020-05-21 10:06:58 +02007836 goto moveto;
7837 }
7838
Michal Vasko004d3152020-06-11 19:59:22 +02007839 ncname = &exp->expr[exp->tok_pos[*tok_idx - 1]];
7840 ncname_len = exp->tok_len[*tok_idx - 1];
Michal Vaskod3678892020-05-21 10:06:58 +02007841
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007842 if ((ncname[0] == '*') && (ncname_len == 1)) {
7843 /* all nodes will match */
7844 goto moveto;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007845 }
7846
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007847 /* parse (and skip) module name */
7848 rc = moveto_resolve_model(&ncname, &ncname_len, set, NULL, &moveto_mod);
Michal Vaskod3678892020-05-21 10:06:58 +02007849 LY_CHECK_GOTO(rc, cleanup);
7850
Michal Vasko49fec8e2022-05-24 10:28:33 +02007851 if ((ncname[0] == '*') && (ncname_len == 1)) {
7852 /* all nodes from the module will match */
7853 goto moveto;
7854 }
7855
7856 if (((set->format == LY_VALUE_JSON) || moveto_mod) && (axis == LYXP_AXIS_CHILD) && !all_desc &&
7857 (set->type == LYXP_SET_NODE_SET)) {
Michal Vaskod3678892020-05-21 10:06:58 +02007858 /* find the matching schema node in some parent in the context */
Michal Vasko56c008c2022-07-29 14:57:47 +02007859 for (i = 0; i < set->used; ++i) {
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007860 if (eval_name_test_with_predicate_get_scnode(set->ctx, set->val.nodes[i].node, ncname, ncname_len,
7861 moveto_mod, set->root_type, set->format, &scnode)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007862 /* check failed */
7863 scnode = NULL;
7864 break;
Michal Vaskod3678892020-05-21 10:06:58 +02007865 }
7866 }
7867
Michal Vasko004d3152020-06-11 19:59:22 +02007868 if (scnode && (scnode->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
7869 /* try to create the predicates */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007870 if (eval_name_test_try_compile_predicates(exp, tok_idx, scnode, set->cur_mod, set->cur_node ?
7871 set->cur_node->schema : NULL, set->format, set->prefix_data, &predicates, &pred_type)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007872 /* hashes cannot be used */
Michal Vaskod3678892020-05-21 10:06:58 +02007873 scnode = NULL;
7874 }
7875 }
7876 }
7877
Michal Vaskoc71c37b2021-01-11 13:40:02 +01007878 if (!scnode) {
7879 /* we are not able to match based on a schema node and not all the modules match ("*"),
Michal Vasko004d3152020-06-11 19:59:22 +02007880 * use dictionary for efficient comparison */
Radek Krejci011e4aa2020-09-04 15:22:31 +02007881 LY_CHECK_GOTO(rc = lydict_insert(set->ctx, ncname, ncname_len, &ncname_dict), cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02007882 }
7883
7884moveto:
7885 /* move to the attribute(s), data node(s), or schema node(s) */
Michal Vasko49fec8e2022-05-24 10:28:33 +02007886 if (axis == LYXP_AXIS_ATTRIBUTE) {
aPiecek8b0cc152021-05-31 16:40:31 +02007887 if (!(options & LYXP_SKIP_EXPR) && (options & LYXP_SCNODE_ALL)) {
Michal Vasko1a09b212021-05-06 13:00:10 +02007888 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vaskod3678892020-05-21 10:06:58 +02007889 } else {
7890 if (all_desc) {
Michal Vaskocdad7122020-11-09 21:04:44 +01007891 rc = moveto_attr_alldesc(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007892 } else {
aPiecek8b0cc152021-05-31 16:40:31 +02007893 rc = moveto_attr(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007894 }
7895 LY_CHECK_GOTO(rc, cleanup);
7896 }
7897 } else {
aPiecek8b0cc152021-05-31 16:40:31 +02007898 if (!(options & LYXP_SKIP_EXPR) && (options & LYXP_SCNODE_ALL)) {
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007899 const struct lyxp_set_scnode *scparent = NULL;
Michal Vasko56c008c2022-07-29 14:57:47 +02007900 ly_bool found = 0;
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007901
7902 /* remember parent if there is only one, to print in the warning */
7903 for (i = 0; i < set->used; ++i) {
7904 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
7905 if (!scparent) {
7906 /* remember the context node */
7907 scparent = &set->val.scnodes[i];
7908 } else {
7909 /* several context nodes, no reasonable error possible */
7910 scparent = NULL;
7911 break;
7912 }
7913 }
7914 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02007915
Michal Vasko49fec8e2022-05-24 10:28:33 +02007916 if (all_desc && (axis == LYXP_AXIS_CHILD)) {
7917 /* efficient evaluation that does not add all the descendants into the set */
7918 rc = moveto_scnode_alldesc_child(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007919 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02007920 if (all_desc) {
7921 /* "//" == "/descendant-or-self::node()/" */
7922 rc = xpath_pi_node(set, LYXP_AXIS_DESCENDANT_OR_SELF, options);
7923 LY_CHECK_GOTO(rc, cleanup);
7924 }
7925 rc = moveto_scnode(set, moveto_mod, ncname_dict, axis, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007926 }
7927 LY_CHECK_GOTO(rc, cleanup);
7928
Michal Vasko56c008c2022-07-29 14:57:47 +02007929 i = set->used;
7930 do {
7931 --i;
Michal Vasko1a09b212021-05-06 13:00:10 +02007932 if (set->val.scnodes[i].in_ctx > LYXP_SET_SCNODE_ATOM_NODE) {
Michal Vasko56c008c2022-07-29 14:57:47 +02007933 found = 1;
Michal Vaskod3678892020-05-21 10:06:58 +02007934 break;
7935 }
Michal Vasko56c008c2022-07-29 14:57:47 +02007936 } while (i);
7937 if (!found) {
Michal Vasko4ad69e72021-10-26 16:25:55 +02007938 /* generate message */
7939 eval_name_test_scnode_no_match_msg(set, scparent, ncname, ncname_len, exp->expr, options);
7940
7941 if (options & LYXP_SCNODE_ERROR) {
7942 /* error */
7943 rc = LY_EVALID;
7944 goto cleanup;
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007945 }
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007946
7947 /* skip the predicates and the rest of this path to not generate invalid warnings */
7948 rc = LY_ENOT;
7949 scnode_skip_pred = 1;
Michal Vaskod3678892020-05-21 10:06:58 +02007950 }
7951 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02007952 if (all_desc && (axis == LYXP_AXIS_CHILD)) {
7953 /* efficient evaluation */
7954 rc = moveto_node_alldesc_child(set, moveto_mod, ncname_dict, options);
7955 } else if (scnode && (axis == LYXP_AXIS_CHILD)) {
7956 /* we can find the child nodes using hashes */
7957 rc = moveto_node_hash_child(set, scnode, predicates, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007958 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02007959 if (all_desc) {
7960 /* "//" == "/descendant-or-self::node()/" */
7961 rc = xpath_pi_node(set, LYXP_AXIS_DESCENDANT_OR_SELF, options);
7962 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02007963 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02007964 rc = moveto_node(set, moveto_mod, ncname_dict, axis, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007965 }
7966 LY_CHECK_GOTO(rc, cleanup);
7967 }
7968 }
7969
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007970 if (scnode_skip_pred) {
7971 /* skip predicates */
7972 options |= LYXP_SKIP_EXPR;
7973 }
7974
Michal Vaskod3678892020-05-21 10:06:58 +02007975 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007976 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02007977 r = eval_predicate(exp, tok_idx, set, options, axis);
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007978 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02007979 }
7980
7981cleanup:
Michal Vaskoa036a6b2021-10-12 16:05:23 +02007982 if (scnode_skip_pred) {
7983 /* restore options */
7984 options &= ~LYXP_SKIP_EXPR;
7985 }
aPiecek8b0cc152021-05-31 16:40:31 +02007986 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007987 lydict_remove(set->ctx, ncname_dict);
Michal Vaskof7e16e22020-10-21 09:24:39 +02007988 ly_path_predicates_free(set->ctx, pred_type, predicates);
Michal Vaskodb51a8d2020-05-27 15:22:29 +02007989 }
Michal Vaskod3678892020-05-21 10:06:58 +02007990 return rc;
7991}
7992
7993/**
7994 * @brief Evaluate NodeType and any following Predicates. Logs directly on error.
7995 *
7996 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
7997 * [6] NodeTest ::= NameTest | NodeType '(' ')'
7998 * [8] NodeType ::= 'text' | 'node'
7999 *
8000 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008001 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko49fec8e2022-05-24 10:28:33 +02008002 * @param[in] axis Axis to search on.
8003 * @param[in] all_desc Whether to search all the descendants or axis only.
aPiecek8b0cc152021-05-31 16:40:31 +02008004 * @param[in,out] set Context and result set.
Michal Vaskod3678892020-05-21 10:06:58 +02008005 * @param[in] options XPath options.
8006 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8007 */
8008static LY_ERR
Michal Vasko49fec8e2022-05-24 10:28:33 +02008009eval_node_type_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_axis axis, ly_bool all_desc,
Radek Krejci1deb5be2020-08-26 16:43:36 +02008010 struct lyxp_set *set, uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02008011{
8012 LY_ERR rc;
8013
Michal Vaskod3678892020-05-21 10:06:58 +02008014 (void)all_desc;
8015
aPiecek8b0cc152021-05-31 16:40:31 +02008016 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko004d3152020-06-11 19:59:22 +02008017 assert(exp->tok_len[*tok_idx] == 4);
Michal Vasko49fec8e2022-05-24 10:28:33 +02008018 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "node", 4)) {
8019 rc = xpath_pi_node(set, axis, options);
Michal Vaskod3678892020-05-21 10:06:58 +02008020 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02008021 assert(!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "text", 4));
8022 rc = xpath_pi_text(set, axis, options);
Michal Vaskod3678892020-05-21 10:06:58 +02008023 }
Michal Vasko49fec8e2022-05-24 10:28:33 +02008024 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02008025 }
aPiecek8b0cc152021-05-31 16:40:31 +02008026 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008027 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008028 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02008029
8030 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02008031 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
aPiecek8b0cc152021-05-31 16:40:31 +02008032 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008033 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008034 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02008035
8036 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02008037 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
aPiecek8b0cc152021-05-31 16:40:31 +02008038 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008039 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008040 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02008041
8042 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02008043 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02008044 rc = eval_predicate(exp, tok_idx, set, options, axis);
Michal Vaskod3678892020-05-21 10:06:58 +02008045 LY_CHECK_RET(rc);
8046 }
8047
8048 return LY_SUCCESS;
8049}
8050
8051/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02008052 * @brief Evaluate RelativeLocationPath. Logs directly on error.
8053 *
8054 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
8055 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
Michal Vaskod3678892020-05-21 10:06:58 +02008056 * [6] NodeTest ::= NameTest | NodeType '(' ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02008057 *
8058 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008059 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008060 * @param[in] all_desc Whether to search all the descendants or children only.
aPiecek8b0cc152021-05-31 16:40:31 +02008061 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008062 * @param[in] options XPath options.
8063 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
8064 */
8065static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008066eval_relative_location_path(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool all_desc, struct lyxp_set *set,
8067 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008068{
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008069 LY_ERR rc = LY_SUCCESS;
Michal Vasko49fec8e2022-05-24 10:28:33 +02008070 enum lyxp_axis axis;
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008071 int scnode_skip_path = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008072
8073 goto step;
8074 do {
8075 /* evaluate '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02008076 if (exp->tok_len[*tok_idx] == 1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008077 all_desc = 0;
8078 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02008079 assert(exp->tok_len[*tok_idx] == 2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008080 all_desc = 1;
8081 }
aPiecek8b0cc152021-05-31 16:40:31 +02008082 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008083 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008084 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008085
8086step:
Michal Vasko49fec8e2022-05-24 10:28:33 +02008087 /* AxisSpecifier */
8088 if (exp->tokens[*tok_idx] == LYXP_TOKEN_AXISNAME) {
8089 axis = str2axis(exp->expr + exp->tok_pos[*tok_idx], exp->tok_len[*tok_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02008090
aPiecek8b0cc152021-05-31 16:40:31 +02008091 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008092 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
8093 ++(*tok_idx);
8094
8095 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_DCOLON);
8096 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
8097 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
8098 ++(*tok_idx);
8099 } else if (exp->tokens[*tok_idx] == LYXP_TOKEN_AT) {
8100 axis = LYXP_AXIS_ATTRIBUTE;
8101
8102 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
8103 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008104 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02008105 } else {
Michal Vasko49fec8e2022-05-24 10:28:33 +02008106 /* default */
8107 axis = LYXP_AXIS_CHILD;
Michal Vaskod3678892020-05-21 10:06:58 +02008108 }
8109
Michal Vasko49fec8e2022-05-24 10:28:33 +02008110 /* NodeTest Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02008111 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008112 case LYXP_TOKEN_DOT:
8113 /* evaluate '.' */
Michal Vasko49fec8e2022-05-24 10:28:33 +02008114 if (!(options & LYXP_SKIP_EXPR)) {
8115 if (((options & LYXP_SCNODE_ALL) && (set->type != LYXP_SET_SCNODE_SET)) ||
8116 (!(options & LYXP_SCNODE_ALL) && (set->type != LYXP_SET_NODE_SET))) {
8117 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
8118 rc = LY_EVALID;
8119 goto cleanup;
8120 }
8121
8122 if (all_desc) {
8123 rc = xpath_pi_node(set, LYXP_AXIS_DESCENDANT_OR_SELF, options);
8124 LY_CHECK_GOTO(rc, cleanup);
8125 }
8126 rc = xpath_pi_node(set, LYXP_AXIS_SELF, options);
8127 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008128 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008129 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008130 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008131 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008132 break;
8133
8134 case LYXP_TOKEN_DDOT:
8135 /* evaluate '..' */
Michal Vasko49fec8e2022-05-24 10:28:33 +02008136 if (!(options & LYXP_SKIP_EXPR)) {
8137 if (((options & LYXP_SCNODE_ALL) && (set->type != LYXP_SET_SCNODE_SET)) ||
8138 (!(options & LYXP_SCNODE_ALL) && (set->type != LYXP_SET_NODE_SET))) {
8139 LOGVAL(set->ctx, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
8140 rc = LY_EVALID;
8141 goto cleanup;
8142 }
8143
8144 if (all_desc) {
8145 rc = xpath_pi_node(set, LYXP_AXIS_DESCENDANT_OR_SELF, options);
8146 LY_CHECK_GOTO(rc, cleanup);
8147 }
8148 rc = xpath_pi_node(set, LYXP_AXIS_PARENT, options);
8149 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008150 }
aPiecek8b0cc152021-05-31 16:40:31 +02008151 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008152 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008153 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008154 break;
8155
Michal Vasko03ff5a72019-09-11 13:49:33 +02008156 case LYXP_TOKEN_NAMETEST:
Michal Vaskod3678892020-05-21 10:06:58 +02008157 /* evaluate NameTest Predicate* */
Michal Vasko49fec8e2022-05-24 10:28:33 +02008158 rc = eval_name_test_with_predicate(exp, tok_idx, axis, all_desc, set, options);
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008159 if (rc == LY_ENOT) {
8160 assert(options & LYXP_SCNODE_ALL);
8161 /* skip the rest of this path */
8162 rc = LY_SUCCESS;
8163 scnode_skip_path = 1;
8164 options |= LYXP_SKIP_EXPR;
8165 }
8166 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02008167 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008168
Michal Vaskod3678892020-05-21 10:06:58 +02008169 case LYXP_TOKEN_NODETYPE:
8170 /* evaluate NodeType Predicate* */
Michal Vasko49fec8e2022-05-24 10:28:33 +02008171 rc = eval_node_type_with_predicate(exp, tok_idx, axis, all_desc, set, options);
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008172 LY_CHECK_GOTO(rc, cleanup);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008173 break;
8174
8175 default:
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008176 LOGINT(set->ctx);
8177 rc = LY_EINT;
8178 goto cleanup;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008179 }
Michal Vasko004d3152020-06-11 19:59:22 +02008180 } while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008181
Michal Vaskoa036a6b2021-10-12 16:05:23 +02008182cleanup:
8183 if (scnode_skip_path) {
8184 options &= ~LYXP_SKIP_EXPR;
8185 }
8186 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008187}
8188
8189/**
8190 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
8191 *
8192 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
8193 *
8194 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008195 * @param[in] tok_idx Position in the expression @p exp.
aPiecek8b0cc152021-05-31 16:40:31 +02008196 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008197 * @param[in] options XPath options.
8198 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8199 */
8200static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008201eval_absolute_location_path(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008202{
Radek Krejci857189e2020-09-01 13:26:36 +02008203 ly_bool all_desc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008204
aPiecek8b0cc152021-05-31 16:40:31 +02008205 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008206 /* no matter what tokens follow, we need to be at the root */
Michal Vaskob0099a92020-08-31 14:55:23 +02008207 LY_CHECK_RET(moveto_root(set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008208 }
8209
8210 /* '/' RelativeLocationPath? */
Michal Vasko004d3152020-06-11 19:59:22 +02008211 if (exp->tok_len[*tok_idx] == 1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008212 /* evaluate '/' - deferred */
8213 all_desc = 0;
aPiecek8b0cc152021-05-31 16:40:31 +02008214 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008215 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008216 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008217
Michal Vasko004d3152020-06-11 19:59:22 +02008218 if (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008219 return LY_SUCCESS;
8220 }
Michal Vasko004d3152020-06-11 19:59:22 +02008221 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008222 case LYXP_TOKEN_DOT:
8223 case LYXP_TOKEN_DDOT:
Michal Vasko49fec8e2022-05-24 10:28:33 +02008224 case LYXP_TOKEN_AXISNAME:
Michal Vasko03ff5a72019-09-11 13:49:33 +02008225 case LYXP_TOKEN_AT:
8226 case LYXP_TOKEN_NAMETEST:
8227 case LYXP_TOKEN_NODETYPE:
Michal Vaskob0099a92020-08-31 14:55:23 +02008228 LY_CHECK_RET(eval_relative_location_path(exp, tok_idx, all_desc, set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008229 break;
8230 default:
8231 break;
8232 }
8233
Michal Vasko03ff5a72019-09-11 13:49:33 +02008234 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02008235 /* '//' RelativeLocationPath */
Michal Vasko03ff5a72019-09-11 13:49:33 +02008236 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
8237 all_desc = 1;
aPiecek8b0cc152021-05-31 16:40:31 +02008238 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008239 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008240 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008241
Michal Vaskob0099a92020-08-31 14:55:23 +02008242 LY_CHECK_RET(eval_relative_location_path(exp, tok_idx, all_desc, set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008243 }
8244
8245 return LY_SUCCESS;
8246}
8247
8248/**
8249 * @brief Evaluate FunctionCall. Logs directly on error.
8250 *
Michal Vaskod3678892020-05-21 10:06:58 +02008251 * [11] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02008252 *
8253 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008254 * @param[in] tok_idx Position in the expression @p exp.
aPiecek8b0cc152021-05-31 16:40:31 +02008255 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008256 * @param[in] options XPath options.
8257 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8258 */
8259static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008260eval_function_call(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008261{
8262 LY_ERR rc;
Michal Vasko69730152020-10-09 16:30:07 +02008263
Radek Krejci1deb5be2020-08-26 16:43:36 +02008264 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, uint32_t) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01008265 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008266 struct lyxp_set **args = NULL, **args_aux;
8267
aPiecek8b0cc152021-05-31 16:40:31 +02008268 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008269 /* FunctionName */
Michal Vasko004d3152020-06-11 19:59:22 +02008270 switch (exp->tok_len[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008271 case 3:
Michal Vasko004d3152020-06-11 19:59:22 +02008272 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "not", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008273 xpath_func = &xpath_not;
Michal Vasko004d3152020-06-11 19:59:22 +02008274 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "sum", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008275 xpath_func = &xpath_sum;
8276 }
8277 break;
8278 case 4:
Michal Vasko004d3152020-06-11 19:59:22 +02008279 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "lang", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008280 xpath_func = &xpath_lang;
Michal Vasko004d3152020-06-11 19:59:22 +02008281 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "last", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008282 xpath_func = &xpath_last;
Michal Vasko004d3152020-06-11 19:59:22 +02008283 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "name", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008284 xpath_func = &xpath_name;
Michal Vasko004d3152020-06-11 19:59:22 +02008285 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "true", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008286 xpath_func = &xpath_true;
8287 }
8288 break;
8289 case 5:
Michal Vasko004d3152020-06-11 19:59:22 +02008290 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "count", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008291 xpath_func = &xpath_count;
Michal Vasko004d3152020-06-11 19:59:22 +02008292 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "false", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008293 xpath_func = &xpath_false;
Michal Vasko004d3152020-06-11 19:59:22 +02008294 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "floor", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008295 xpath_func = &xpath_floor;
Michal Vasko004d3152020-06-11 19:59:22 +02008296 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "round", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008297 xpath_func = &xpath_round;
Michal Vasko004d3152020-06-11 19:59:22 +02008298 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008299 xpath_func = &xpath_deref;
8300 }
8301 break;
8302 case 6:
Michal Vasko004d3152020-06-11 19:59:22 +02008303 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "concat", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008304 xpath_func = &xpath_concat;
Michal Vasko004d3152020-06-11 19:59:22 +02008305 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "number", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008306 xpath_func = &xpath_number;
Michal Vasko004d3152020-06-11 19:59:22 +02008307 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008308 xpath_func = &xpath_string;
8309 }
8310 break;
8311 case 7:
Michal Vasko004d3152020-06-11 19:59:22 +02008312 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "boolean", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008313 xpath_func = &xpath_boolean;
Michal Vasko004d3152020-06-11 19:59:22 +02008314 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "ceiling", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008315 xpath_func = &xpath_ceiling;
Michal Vasko004d3152020-06-11 19:59:22 +02008316 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "current", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008317 xpath_func = &xpath_current;
8318 }
8319 break;
8320 case 8:
Michal Vasko004d3152020-06-11 19:59:22 +02008321 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "contains", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008322 xpath_func = &xpath_contains;
Michal Vasko004d3152020-06-11 19:59:22 +02008323 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "position", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008324 xpath_func = &xpath_position;
Michal Vasko004d3152020-06-11 19:59:22 +02008325 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "re-match", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008326 xpath_func = &xpath_re_match;
8327 }
8328 break;
8329 case 9:
Michal Vasko004d3152020-06-11 19:59:22 +02008330 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008331 xpath_func = &xpath_substring;
Michal Vasko004d3152020-06-11 19:59:22 +02008332 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "translate", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008333 xpath_func = &xpath_translate;
8334 }
8335 break;
8336 case 10:
Michal Vasko004d3152020-06-11 19:59:22 +02008337 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "local-name", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008338 xpath_func = &xpath_local_name;
Michal Vasko004d3152020-06-11 19:59:22 +02008339 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "enum-value", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008340 xpath_func = &xpath_enum_value;
Michal Vasko004d3152020-06-11 19:59:22 +02008341 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "bit-is-set", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008342 xpath_func = &xpath_bit_is_set;
8343 }
8344 break;
8345 case 11:
Michal Vasko004d3152020-06-11 19:59:22 +02008346 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "starts-with", 11)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008347 xpath_func = &xpath_starts_with;
8348 }
8349 break;
8350 case 12:
Michal Vasko004d3152020-06-11 19:59:22 +02008351 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from", 12)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008352 xpath_func = &xpath_derived_from;
8353 }
8354 break;
8355 case 13:
Michal Vasko004d3152020-06-11 19:59:22 +02008356 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "namespace-uri", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008357 xpath_func = &xpath_namespace_uri;
Michal Vasko004d3152020-06-11 19:59:22 +02008358 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string-length", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008359 xpath_func = &xpath_string_length;
8360 }
8361 break;
8362 case 15:
Michal Vasko004d3152020-06-11 19:59:22 +02008363 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "normalize-space", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008364 xpath_func = &xpath_normalize_space;
Michal Vasko004d3152020-06-11 19:59:22 +02008365 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-after", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008366 xpath_func = &xpath_substring_after;
8367 }
8368 break;
8369 case 16:
Michal Vasko004d3152020-06-11 19:59:22 +02008370 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-before", 16)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008371 xpath_func = &xpath_substring_before;
8372 }
8373 break;
8374 case 20:
Michal Vasko004d3152020-06-11 19:59:22 +02008375 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from-or-self", 20)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008376 xpath_func = &xpath_derived_from_or_self;
8377 }
8378 break;
8379 }
8380
8381 if (!xpath_func) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01008382 LOGVAL(set->ctx, LY_VCODE_XP_INFUNC, exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008383 return LY_EVALID;
8384 }
8385 }
8386
aPiecek8b0cc152021-05-31 16:40:31 +02008387 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008388 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008389 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008390
8391 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02008392 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
aPiecek8b0cc152021-05-31 16:40:31 +02008393 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008394 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008395 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008396
8397 /* ( Expr ( ',' Expr )* )? */
Michal Vasko004d3152020-06-11 19:59:22 +02008398 if (exp->tokens[*tok_idx] != LYXP_TOKEN_PAR2) {
aPiecek8b0cc152021-05-31 16:40:31 +02008399 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008400 args = malloc(sizeof *args);
8401 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
8402 arg_count = 1;
8403 args[0] = set_copy(set);
8404 if (!args[0]) {
8405 rc = LY_EMEM;
8406 goto cleanup;
8407 }
8408
Michal Vasko004d3152020-06-11 19:59:22 +02008409 rc = eval_expr_select(exp, tok_idx, 0, args[0], options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008410 LY_CHECK_GOTO(rc, cleanup);
8411 } else {
aPiecek8b0cc152021-05-31 16:40:31 +02008412 rc = eval_expr_select(exp, tok_idx, 0, set, options | LYXP_SKIP_EXPR);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008413 LY_CHECK_GOTO(rc, cleanup);
8414 }
8415 }
Michal Vasko004d3152020-06-11 19:59:22 +02008416 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_COMMA)) {
aPiecek8b0cc152021-05-31 16:40:31 +02008417 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008418 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008419 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008420
aPiecek8b0cc152021-05-31 16:40:31 +02008421 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008422 ++arg_count;
8423 args_aux = realloc(args, arg_count * sizeof *args);
8424 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
8425 args = args_aux;
8426 args[arg_count - 1] = set_copy(set);
8427 if (!args[arg_count - 1]) {
8428 rc = LY_EMEM;
8429 goto cleanup;
8430 }
8431
Michal Vasko004d3152020-06-11 19:59:22 +02008432 rc = eval_expr_select(exp, tok_idx, 0, args[arg_count - 1], options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008433 LY_CHECK_GOTO(rc, cleanup);
8434 } else {
aPiecek8b0cc152021-05-31 16:40:31 +02008435 rc = eval_expr_select(exp, tok_idx, 0, set, options | LYXP_SKIP_EXPR);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008436 LY_CHECK_GOTO(rc, cleanup);
8437 }
8438 }
8439
8440 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02008441 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
aPiecek8b0cc152021-05-31 16:40:31 +02008442 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008443 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008444 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008445
aPiecek8b0cc152021-05-31 16:40:31 +02008446 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008447 /* evaluate function */
8448 rc = xpath_func(args, arg_count, set, options);
8449
8450 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008451 /* merge all nodes from arg evaluations */
8452 for (i = 0; i < arg_count; ++i) {
Michal Vasko1a09b212021-05-06 13:00:10 +02008453 set_scnode_clear_ctx(args[i], LYXP_SET_SCNODE_ATOM_NODE);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008454 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008455 }
8456 }
8457 } else {
8458 rc = LY_SUCCESS;
8459 }
8460
8461cleanup:
8462 for (i = 0; i < arg_count; ++i) {
8463 lyxp_set_free(args[i]);
8464 }
8465 free(args);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008466 return rc;
8467}
8468
8469/**
8470 * @brief Evaluate Number. Logs directly on error.
8471 *
8472 * @param[in] ctx Context for errors.
8473 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008474 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008475 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8476 * @return LY_ERR
8477 */
8478static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008479eval_number(struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008480{
8481 long double num;
8482 char *endptr;
8483
8484 if (set) {
8485 errno = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02008486 num = strtold(&exp->expr[exp->tok_pos[*tok_idx]], &endptr);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008487 if (errno) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01008488 LOGVAL(ctx, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*tok_idx]]);
8489 LOGVAL(ctx, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02008490 exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]], strerror(errno));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008491 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02008492 } else if (endptr - &exp->expr[exp->tok_pos[*tok_idx]] != exp->tok_len[*tok_idx]) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01008493 LOGVAL(ctx, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*tok_idx]]);
8494 LOGVAL(ctx, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
Michal Vasko69730152020-10-09 16:30:07 +02008495 exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008496 return LY_EVALID;
8497 }
8498
8499 set_fill_number(set, num);
8500 }
8501
8502 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008503 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008504 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008505 return LY_SUCCESS;
8506}
8507
aPiecekdf23eee2021-10-07 12:21:50 +02008508LY_ERR
8509lyxp_vars_find(struct lyxp_var *vars, const char *name, size_t name_len, struct lyxp_var **var)
8510{
8511 LY_ERR ret = LY_ENOTFOUND;
8512 LY_ARRAY_COUNT_TYPE u;
8513
8514 assert(vars && name);
8515
8516 name_len = name_len ? name_len : strlen(name);
8517
8518 LY_ARRAY_FOR(vars, u) {
8519 if (!strncmp(vars[u].name, name, name_len)) {
8520 ret = LY_SUCCESS;
8521 break;
8522 }
8523 }
8524
8525 if (var && !ret) {
8526 *var = &vars[u];
8527 }
8528
8529 return ret;
8530}
8531
Michal Vasko03ff5a72019-09-11 13:49:33 +02008532/**
aPiecekfba75362021-10-07 12:39:48 +02008533 * @brief Evaluate VariableReference.
8534 *
8535 * @param[in] exp Parsed XPath expression.
8536 * @param[in] tok_idx Position in the expression @p exp.
8537 * @param[in] vars [Sized array](@ref sizedarrays) of XPath variables.
8538 * @param[in,out] set Context and result set.
8539 * @param[in] options XPath options.
8540 * @return LY_ERR value.
8541 */
8542static LY_ERR
8543eval_variable_reference(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
8544{
8545 LY_ERR ret;
8546 const char *name;
8547 struct lyxp_var *var;
8548 const struct lyxp_var *vars;
8549 struct lyxp_expr *tokens = NULL;
Michal Vaskoe68b5402022-07-29 14:58:15 +02008550 uint16_t token_index, name_len;
aPiecekfba75362021-10-07 12:39:48 +02008551
8552 vars = set->vars;
8553
Michal Vasko49fec8e2022-05-24 10:28:33 +02008554 /* find out the name and value of the variable */
aPiecekfba75362021-10-07 12:39:48 +02008555 name = &exp->expr[exp->tok_pos[*tok_idx]];
Michal Vaskoe68b5402022-07-29 14:58:15 +02008556 name_len = exp->tok_len[*tok_idx];
8557 ret = lyxp_vars_find((struct lyxp_var *)vars, name, name_len, &var);
8558 LY_CHECK_ERR_RET(ret, LOGERR(set->ctx, ret, "XPath variable \"%.*s\" not defined.", (int)name_len, name), ret);
aPiecekfba75362021-10-07 12:39:48 +02008559
Michal Vasko49fec8e2022-05-24 10:28:33 +02008560 /* parse value */
aPiecekfba75362021-10-07 12:39:48 +02008561 ret = lyxp_expr_parse(set->ctx, var->value, 0, 1, &tokens);
8562 LY_CHECK_GOTO(ret, cleanup);
8563
Michal Vasko49fec8e2022-05-24 10:28:33 +02008564 /* evaluate value */
aPiecekfba75362021-10-07 12:39:48 +02008565 token_index = 0;
8566 ret = eval_expr_select(tokens, &token_index, 0, set, options);
8567 LY_CHECK_GOTO(ret, cleanup);
8568
8569cleanup:
8570 lyxp_expr_free(set->ctx, tokens);
8571
8572 return ret;
8573}
8574
8575/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02008576 * @brief Evaluate PathExpr. Logs directly on error.
8577 *
Michal Vaskod3678892020-05-21 10:06:58 +02008578 * [12] PathExpr ::= LocationPath | PrimaryExpr Predicate*
Michal Vasko03ff5a72019-09-11 13:49:33 +02008579 * | PrimaryExpr Predicate* '/' RelativeLocationPath
8580 * | PrimaryExpr Predicate* '//' RelativeLocationPath
8581 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
aPiecekfba75362021-10-07 12:39:48 +02008582 * [10] PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
Michal Vasko03ff5a72019-09-11 13:49:33 +02008583 *
8584 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008585 * @param[in] tok_idx Position in the expression @p exp.
aPiecek8b0cc152021-05-31 16:40:31 +02008586 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008587 * @param[in] options XPath options.
8588 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8589 */
8590static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008591eval_path_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008592{
Michal Vasko49fec8e2022-05-24 10:28:33 +02008593 ly_bool all_desc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008594 LY_ERR rc;
8595
Michal Vasko004d3152020-06-11 19:59:22 +02008596 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008597 case LYXP_TOKEN_PAR1:
8598 /* '(' Expr ')' */
8599
8600 /* '(' */
aPiecek8b0cc152021-05-31 16:40:31 +02008601 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008602 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008603 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008604
8605 /* Expr */
Michal Vasko004d3152020-06-11 19:59:22 +02008606 rc = eval_expr_select(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008607 LY_CHECK_RET(rc);
8608
8609 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02008610 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
aPiecek8b0cc152021-05-31 16:40:31 +02008611 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008612 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008613 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008614
Michal Vasko03ff5a72019-09-11 13:49:33 +02008615 goto predicate;
8616
8617 case LYXP_TOKEN_DOT:
8618 case LYXP_TOKEN_DDOT:
Michal Vasko49fec8e2022-05-24 10:28:33 +02008619 case LYXP_TOKEN_AXISNAME:
Michal Vasko03ff5a72019-09-11 13:49:33 +02008620 case LYXP_TOKEN_AT:
8621 case LYXP_TOKEN_NAMETEST:
8622 case LYXP_TOKEN_NODETYPE:
8623 /* RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02008624 rc = eval_relative_location_path(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008625 LY_CHECK_RET(rc);
8626 break;
8627
aPiecekfba75362021-10-07 12:39:48 +02008628 case LYXP_TOKEN_VARREF:
8629 /* VariableReference */
8630 rc = eval_variable_reference(exp, tok_idx, set, options);
8631 LY_CHECK_RET(rc);
8632 ++(*tok_idx);
8633
aPiecekfba75362021-10-07 12:39:48 +02008634 goto predicate;
8635
Michal Vasko03ff5a72019-09-11 13:49:33 +02008636 case LYXP_TOKEN_FUNCNAME:
8637 /* FunctionCall */
aPiecek8b0cc152021-05-31 16:40:31 +02008638 rc = eval_function_call(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008639 LY_CHECK_RET(rc);
8640
Michal Vasko03ff5a72019-09-11 13:49:33 +02008641 goto predicate;
8642
Michal Vasko3e48bf32020-06-01 08:39:07 +02008643 case LYXP_TOKEN_OPER_PATH:
8644 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02008645 /* AbsoluteLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02008646 rc = eval_absolute_location_path(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008647 LY_CHECK_RET(rc);
8648 break;
8649
8650 case LYXP_TOKEN_LITERAL:
8651 /* Literal */
aPiecek8b0cc152021-05-31 16:40:31 +02008652 if ((options & LYXP_SKIP_EXPR) || (options & LYXP_SCNODE_ALL)) {
8653 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko1a09b212021-05-06 13:00:10 +02008654 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008655 }
Michal Vasko004d3152020-06-11 19:59:22 +02008656 eval_literal(exp, tok_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008657 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02008658 eval_literal(exp, tok_idx, set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008659 }
8660
Michal Vasko03ff5a72019-09-11 13:49:33 +02008661 goto predicate;
8662
8663 case LYXP_TOKEN_NUMBER:
8664 /* Number */
aPiecek8b0cc152021-05-31 16:40:31 +02008665 if ((options & LYXP_SKIP_EXPR) || (options & LYXP_SCNODE_ALL)) {
8666 if (!(options & LYXP_SKIP_EXPR)) {
Michal Vasko1a09b212021-05-06 13:00:10 +02008667 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008668 }
Michal Vasko004d3152020-06-11 19:59:22 +02008669 rc = eval_number(NULL, exp, tok_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008670 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02008671 rc = eval_number(set->ctx, exp, tok_idx, set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008672 }
8673 LY_CHECK_RET(rc);
8674
Michal Vasko03ff5a72019-09-11 13:49:33 +02008675 goto predicate;
8676
8677 default:
Michal Vasko49fec8e2022-05-24 10:28:33 +02008678 LOGVAL(set->ctx, LY_VCODE_XP_INTOK, lyxp_token2str(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008679 return LY_EVALID;
8680 }
8681
8682 return LY_SUCCESS;
8683
8684predicate:
8685 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02008686 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko49fec8e2022-05-24 10:28:33 +02008687 rc = eval_predicate(exp, tok_idx, set, options, LYXP_AXIS_CHILD);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008688 LY_CHECK_RET(rc);
8689 }
8690
8691 /* ('/' or '//') RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02008692 if (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008693
8694 /* evaluate '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02008695 if (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008696 all_desc = 0;
8697 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008698 all_desc = 1;
8699 }
8700
aPiecek8b0cc152021-05-31 16:40:31 +02008701 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008702 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008703 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008704
Michal Vasko004d3152020-06-11 19:59:22 +02008705 rc = eval_relative_location_path(exp, tok_idx, all_desc, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008706 LY_CHECK_RET(rc);
8707 }
8708
8709 return LY_SUCCESS;
8710}
8711
8712/**
8713 * @brief Evaluate UnionExpr. Logs directly on error.
8714 *
Michal Vaskod3678892020-05-21 10:06:58 +02008715 * [20] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008716 *
8717 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008718 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008719 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02008720 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008721 * @param[in] options XPath options.
8722 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8723 */
8724static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008725eval_union_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008726{
8727 LY_ERR rc = LY_SUCCESS;
8728 struct lyxp_set orig_set, set2;
8729 uint16_t i;
8730
8731 assert(repeat);
8732
8733 set_init(&orig_set, set);
8734 set_init(&set2, set);
8735
8736 set_fill_set(&orig_set, set);
8737
Michal Vasko004d3152020-06-11 19:59:22 +02008738 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008739 LY_CHECK_GOTO(rc, cleanup);
8740
8741 /* ('|' PathExpr)* */
8742 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008743 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_UNI);
aPiecek8b0cc152021-05-31 16:40:31 +02008744 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008745 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008746 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008747
aPiecek8b0cc152021-05-31 16:40:31 +02008748 if (options & LYXP_SKIP_EXPR) {
8749 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008750 LY_CHECK_GOTO(rc, cleanup);
8751 continue;
8752 }
8753
8754 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008755 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008756 LY_CHECK_GOTO(rc, cleanup);
8757
8758 /* eval */
8759 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01008760 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008761 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008762 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008763 LY_CHECK_GOTO(rc, cleanup);
8764 }
8765 }
8766
8767cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008768 lyxp_set_free_content(&orig_set);
8769 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008770 return rc;
8771}
8772
8773/**
8774 * @brief Evaluate UnaryExpr. Logs directly on error.
8775 *
Michal Vaskod3678892020-05-21 10:06:58 +02008776 * [19] UnaryExpr ::= UnionExpr | '-' UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008777 *
8778 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008779 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008780 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02008781 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008782 * @param[in] options XPath options.
8783 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8784 */
8785static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008786eval_unary_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008787{
8788 LY_ERR rc;
8789 uint16_t this_op, i;
8790
8791 assert(repeat);
8792
8793 /* ('-')+ */
Michal Vasko004d3152020-06-11 19:59:22 +02008794 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008795 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008796 assert(!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) && (exp->expr[exp->tok_pos[*tok_idx]] == '-'));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008797
aPiecek8b0cc152021-05-31 16:40:31 +02008798 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008799 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008800 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008801 }
8802
Michal Vasko004d3152020-06-11 19:59:22 +02008803 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNARY, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008804 LY_CHECK_RET(rc);
8805
aPiecek8b0cc152021-05-31 16:40:31 +02008806 if (!(options & LYXP_SKIP_EXPR) && (repeat % 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008807 if (options & LYXP_SCNODE_ALL) {
8808 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
8809 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008810 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008811 LY_CHECK_RET(rc);
8812 }
8813 }
8814
8815 return LY_SUCCESS;
8816}
8817
8818/**
8819 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
8820 *
Michal Vaskod3678892020-05-21 10:06:58 +02008821 * [18] MultiplicativeExpr ::= UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008822 * | MultiplicativeExpr '*' UnaryExpr
8823 * | MultiplicativeExpr 'div' UnaryExpr
8824 * | MultiplicativeExpr 'mod' UnaryExpr
8825 *
8826 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008827 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008828 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02008829 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008830 * @param[in] options XPath options.
8831 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8832 */
8833static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008834eval_multiplicative_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set,
8835 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008836{
8837 LY_ERR rc;
8838 uint16_t this_op;
8839 struct lyxp_set orig_set, set2;
8840 uint16_t i;
8841
8842 assert(repeat);
8843
8844 set_init(&orig_set, set);
8845 set_init(&set2, set);
8846
8847 set_fill_set(&orig_set, set);
8848
Michal Vasko004d3152020-06-11 19:59:22 +02008849 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008850 LY_CHECK_GOTO(rc, cleanup);
8851
8852 /* ('*' / 'div' / 'mod' UnaryExpr)* */
8853 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008854 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008855
Michal Vasko004d3152020-06-11 19:59:22 +02008856 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_MATH);
aPiecek8b0cc152021-05-31 16:40:31 +02008857 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008858 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008859 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008860
aPiecek8b0cc152021-05-31 16:40:31 +02008861 if (options & LYXP_SKIP_EXPR) {
8862 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008863 LY_CHECK_GOTO(rc, cleanup);
8864 continue;
8865 }
8866
8867 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008868 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008869 LY_CHECK_GOTO(rc, cleanup);
8870
8871 /* eval */
8872 if (options & LYXP_SCNODE_ALL) {
8873 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008874 lyxp_set_scnode_merge(set, &set2);
Michal Vasko1a09b212021-05-06 13:00:10 +02008875 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008876 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008877 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008878 LY_CHECK_GOTO(rc, cleanup);
8879 }
8880 }
8881
8882cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008883 lyxp_set_free_content(&orig_set);
8884 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008885 return rc;
8886}
8887
8888/**
8889 * @brief Evaluate AdditiveExpr. Logs directly on error.
8890 *
Michal Vaskod3678892020-05-21 10:06:58 +02008891 * [17] AdditiveExpr ::= MultiplicativeExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008892 * | AdditiveExpr '+' MultiplicativeExpr
8893 * | AdditiveExpr '-' MultiplicativeExpr
8894 *
8895 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008896 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008897 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02008898 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008899 * @param[in] options XPath options.
8900 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8901 */
8902static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008903eval_additive_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008904{
8905 LY_ERR rc;
8906 uint16_t this_op;
8907 struct lyxp_set orig_set, set2;
8908 uint16_t i;
8909
8910 assert(repeat);
8911
8912 set_init(&orig_set, set);
8913 set_init(&set2, set);
8914
8915 set_fill_set(&orig_set, set);
8916
Michal Vasko004d3152020-06-11 19:59:22 +02008917 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008918 LY_CHECK_GOTO(rc, cleanup);
8919
8920 /* ('+' / '-' MultiplicativeExpr)* */
8921 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008922 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008923
Michal Vasko004d3152020-06-11 19:59:22 +02008924 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_MATH);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008925 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008926 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008927 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008928
aPiecek8b0cc152021-05-31 16:40:31 +02008929 if (options & LYXP_SKIP_EXPR) {
8930 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008931 LY_CHECK_GOTO(rc, cleanup);
8932 continue;
8933 }
8934
8935 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008936 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008937 LY_CHECK_GOTO(rc, cleanup);
8938
8939 /* eval */
8940 if (options & LYXP_SCNODE_ALL) {
8941 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008942 lyxp_set_scnode_merge(set, &set2);
Michal Vasko1a09b212021-05-06 13:00:10 +02008943 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008944 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008945 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008946 LY_CHECK_GOTO(rc, cleanup);
8947 }
8948 }
8949
8950cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008951 lyxp_set_free_content(&orig_set);
8952 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008953 return rc;
8954}
8955
8956/**
8957 * @brief Evaluate RelationalExpr. Logs directly on error.
8958 *
Michal Vaskod3678892020-05-21 10:06:58 +02008959 * [16] RelationalExpr ::= AdditiveExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008960 * | RelationalExpr '<' AdditiveExpr
8961 * | RelationalExpr '>' AdditiveExpr
8962 * | RelationalExpr '<=' AdditiveExpr
8963 * | RelationalExpr '>=' AdditiveExpr
8964 *
8965 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008966 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008967 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02008968 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008969 * @param[in] options XPath options.
8970 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8971 */
8972static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008973eval_relational_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008974{
8975 LY_ERR rc;
8976 uint16_t this_op;
8977 struct lyxp_set orig_set, set2;
8978 uint16_t i;
8979
8980 assert(repeat);
8981
8982 set_init(&orig_set, set);
8983 set_init(&set2, set);
8984
8985 set_fill_set(&orig_set, set);
8986
Michal Vasko004d3152020-06-11 19:59:22 +02008987 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008988 LY_CHECK_GOTO(rc, cleanup);
8989
8990 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
8991 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008992 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008993
Michal Vasko004d3152020-06-11 19:59:22 +02008994 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_COMP);
aPiecek8b0cc152021-05-31 16:40:31 +02008995 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02008996 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008997 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008998
aPiecek8b0cc152021-05-31 16:40:31 +02008999 if (options & LYXP_SKIP_EXPR) {
9000 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009001 LY_CHECK_GOTO(rc, cleanup);
9002 continue;
9003 }
9004
9005 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02009006 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009007 LY_CHECK_GOTO(rc, cleanup);
9008
9009 /* eval */
9010 if (options & LYXP_SCNODE_ALL) {
9011 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01009012 lyxp_set_scnode_merge(set, &set2);
Michal Vasko1a09b212021-05-06 13:00:10 +02009013 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009014 } else {
Michal Vasko8abcecc2022-07-28 09:55:01 +02009015 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009016 LY_CHECK_GOTO(rc, cleanup);
9017 }
9018 }
9019
9020cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02009021 lyxp_set_free_content(&orig_set);
9022 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009023 return rc;
9024}
9025
9026/**
9027 * @brief Evaluate EqualityExpr. Logs directly on error.
9028 *
Michal Vaskod3678892020-05-21 10:06:58 +02009029 * [15] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02009030 * | EqualityExpr '!=' RelationalExpr
9031 *
9032 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02009033 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009034 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02009035 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009036 * @param[in] options XPath options.
9037 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
9038 */
9039static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02009040eval_equality_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009041{
9042 LY_ERR rc;
9043 uint16_t this_op;
9044 struct lyxp_set orig_set, set2;
9045 uint16_t i;
9046
9047 assert(repeat);
9048
9049 set_init(&orig_set, set);
9050 set_init(&set2, set);
9051
9052 set_fill_set(&orig_set, set);
9053
Michal Vasko004d3152020-06-11 19:59:22 +02009054 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009055 LY_CHECK_GOTO(rc, cleanup);
9056
9057 /* ('=' / '!=' RelationalExpr)* */
9058 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02009059 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009060
Michal Vasko004d3152020-06-11 19:59:22 +02009061 assert((exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL) || (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_NEQUAL));
aPiecek8b0cc152021-05-31 16:40:31 +02009062 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02009063 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02009064 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009065
aPiecek8b0cc152021-05-31 16:40:31 +02009066 if (options & LYXP_SKIP_EXPR) {
9067 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009068 LY_CHECK_GOTO(rc, cleanup);
9069 continue;
9070 }
9071
9072 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02009073 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009074 LY_CHECK_GOTO(rc, cleanup);
9075
9076 /* eval */
9077 if (options & LYXP_SCNODE_ALL) {
9078 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vasko004d3152020-06-11 19:59:22 +02009079 warn_equality_value(exp, set, *tok_idx - 1, this_op - 1, *tok_idx - 1);
9080 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *tok_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01009081 lyxp_set_scnode_merge(set, &set2);
Michal Vasko1a09b212021-05-06 13:00:10 +02009082 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_VAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009083 } else {
Michal Vasko8abcecc2022-07-28 09:55:01 +02009084 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009085 LY_CHECK_GOTO(rc, cleanup);
9086 }
9087 }
9088
9089cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02009090 lyxp_set_free_content(&orig_set);
9091 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009092 return rc;
9093}
9094
9095/**
9096 * @brief Evaluate AndExpr. Logs directly on error.
9097 *
Michal Vaskod3678892020-05-21 10:06:58 +02009098 * [14] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02009099 *
9100 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02009101 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009102 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02009103 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009104 * @param[in] options XPath options.
9105 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
9106 */
9107static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02009108eval_and_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009109{
9110 LY_ERR rc;
9111 struct lyxp_set orig_set, set2;
9112 uint16_t i;
9113
9114 assert(repeat);
9115
9116 set_init(&orig_set, set);
9117 set_init(&set2, set);
9118
9119 set_fill_set(&orig_set, set);
9120
Michal Vasko004d3152020-06-11 19:59:22 +02009121 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009122 LY_CHECK_GOTO(rc, cleanup);
9123
9124 /* cast to boolean, we know that will be the final result */
aPiecek8b0cc152021-05-31 16:40:31 +02009125 if (!(options & LYXP_SKIP_EXPR) && (options & LYXP_SCNODE_ALL)) {
Michal Vasko1a09b212021-05-06 13:00:10 +02009126 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009127 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009128 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009129 }
9130
9131 /* ('and' EqualityExpr)* */
9132 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02009133 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_LOG);
aPiecek8b0cc152021-05-31 16:40:31 +02009134 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, ((options & LYXP_SKIP_EXPR) || !set->val.bln ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02009135 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02009136 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009137
9138 /* lazy evaluation */
aPiecek8b0cc152021-05-31 16:40:31 +02009139 if ((options & LYXP_SKIP_EXPR) || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bln)) {
9140 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, set, options | LYXP_SKIP_EXPR);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009141 LY_CHECK_GOTO(rc, cleanup);
9142 continue;
9143 }
9144
9145 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02009146 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009147 LY_CHECK_GOTO(rc, cleanup);
9148
9149 /* eval - just get boolean value actually */
9150 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vasko1a09b212021-05-06 13:00:10 +02009151 set_scnode_clear_ctx(&set2, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vaskoecd62de2019-11-13 12:35:11 +01009152 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009153 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009154 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009155 set_fill_set(set, &set2);
9156 }
9157 }
9158
9159cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02009160 lyxp_set_free_content(&orig_set);
9161 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009162 return rc;
9163}
9164
9165/**
9166 * @brief Evaluate OrExpr. Logs directly on error.
9167 *
Michal Vaskod3678892020-05-21 10:06:58 +02009168 * [13] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02009169 *
9170 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02009171 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009172 * @param[in] repeat How many times this expression is repeated.
aPiecek8b0cc152021-05-31 16:40:31 +02009173 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009174 * @param[in] options XPath options.
9175 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
9176 */
9177static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02009178eval_or_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009179{
9180 LY_ERR rc;
9181 struct lyxp_set orig_set, set2;
9182 uint16_t i;
9183
9184 assert(repeat);
9185
9186 set_init(&orig_set, set);
9187 set_init(&set2, set);
9188
9189 set_fill_set(&orig_set, set);
9190
Michal Vasko004d3152020-06-11 19:59:22 +02009191 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009192 LY_CHECK_GOTO(rc, cleanup);
9193
9194 /* cast to boolean, we know that will be the final result */
aPiecek8b0cc152021-05-31 16:40:31 +02009195 if (!(options & LYXP_SKIP_EXPR) && (options & LYXP_SCNODE_ALL)) {
Michal Vasko1a09b212021-05-06 13:00:10 +02009196 set_scnode_clear_ctx(set, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009197 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009198 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009199 }
9200
9201 /* ('or' AndExpr)* */
9202 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02009203 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_LOG);
aPiecek8b0cc152021-05-31 16:40:31 +02009204 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, ((options & LYXP_SKIP_EXPR) || set->val.bln ? "skipped" : "parsed"),
Michal Vasko49fec8e2022-05-24 10:28:33 +02009205 lyxp_token2str(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02009206 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009207
9208 /* lazy evaluation */
aPiecek8b0cc152021-05-31 16:40:31 +02009209 if ((options & LYXP_SKIP_EXPR) || ((set->type == LYXP_SET_BOOLEAN) && set->val.bln)) {
9210 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, set, options | LYXP_SKIP_EXPR);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009211 LY_CHECK_GOTO(rc, cleanup);
9212 continue;
9213 }
9214
9215 set_fill_set(&set2, &orig_set);
9216 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
9217 * but it does not matter */
Michal Vasko004d3152020-06-11 19:59:22 +02009218 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009219 LY_CHECK_GOTO(rc, cleanup);
9220
9221 /* eval - just get boolean value actually */
9222 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vasko1a09b212021-05-06 13:00:10 +02009223 set_scnode_clear_ctx(&set2, LYXP_SET_SCNODE_ATOM_NODE);
Michal Vaskoecd62de2019-11-13 12:35:11 +01009224 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009225 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009226 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009227 set_fill_set(set, &set2);
9228 }
9229 }
9230
9231cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02009232 lyxp_set_free_content(&orig_set);
9233 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009234 return rc;
9235}
9236
9237/**
Michal Vasko004d3152020-06-11 19:59:22 +02009238 * @brief Decide what expression is at the pointer @p tok_idx and evaluate it accordingly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009239 *
9240 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02009241 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009242 * @param[in] etype Expression type to evaluate.
aPiecek8b0cc152021-05-31 16:40:31 +02009243 * @param[in,out] set Context and result set.
Michal Vasko03ff5a72019-09-11 13:49:33 +02009244 * @param[in] options XPath options.
9245 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
9246 */
9247static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02009248eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype, struct lyxp_set *set,
9249 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009250{
9251 uint16_t i, count;
9252 enum lyxp_expr_type next_etype;
9253 LY_ERR rc;
9254
9255 /* process operator repeats */
Michal Vasko004d3152020-06-11 19:59:22 +02009256 if (!exp->repeat[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02009257 next_etype = LYXP_EXPR_NONE;
9258 } else {
9259 /* find etype repeat */
Radek Krejci1e008d22020-08-17 11:37:37 +02009260 for (i = 0; exp->repeat[*tok_idx][i] > etype; ++i) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02009261
9262 /* select one-priority lower because etype expression called us */
9263 if (i) {
Michal Vasko004d3152020-06-11 19:59:22 +02009264 next_etype = exp->repeat[*tok_idx][i - 1];
Michal Vasko03ff5a72019-09-11 13:49:33 +02009265 /* count repeats for that expression */
Radek Krejci1e008d22020-08-17 11:37:37 +02009266 for (count = 0; i && exp->repeat[*tok_idx][i - 1] == next_etype; ++count, --i) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02009267 } else {
9268 next_etype = LYXP_EXPR_NONE;
9269 }
9270 }
9271
9272 /* decide what expression are we parsing based on the repeat */
9273 switch (next_etype) {
9274 case LYXP_EXPR_OR:
Michal Vasko004d3152020-06-11 19:59:22 +02009275 rc = eval_or_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009276 break;
9277 case LYXP_EXPR_AND:
Michal Vasko004d3152020-06-11 19:59:22 +02009278 rc = eval_and_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009279 break;
9280 case LYXP_EXPR_EQUALITY:
Michal Vasko004d3152020-06-11 19:59:22 +02009281 rc = eval_equality_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009282 break;
9283 case LYXP_EXPR_RELATIONAL:
Michal Vasko004d3152020-06-11 19:59:22 +02009284 rc = eval_relational_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009285 break;
9286 case LYXP_EXPR_ADDITIVE:
Michal Vasko004d3152020-06-11 19:59:22 +02009287 rc = eval_additive_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009288 break;
9289 case LYXP_EXPR_MULTIPLICATIVE:
Michal Vasko004d3152020-06-11 19:59:22 +02009290 rc = eval_multiplicative_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009291 break;
9292 case LYXP_EXPR_UNARY:
Michal Vasko004d3152020-06-11 19:59:22 +02009293 rc = eval_unary_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009294 break;
9295 case LYXP_EXPR_UNION:
Michal Vasko004d3152020-06-11 19:59:22 +02009296 rc = eval_union_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009297 break;
9298 case LYXP_EXPR_NONE:
Michal Vasko004d3152020-06-11 19:59:22 +02009299 rc = eval_path_expr(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009300 break;
9301 default:
9302 LOGINT_RET(set->ctx);
9303 }
9304
9305 return rc;
9306}
9307
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009308/**
9309 * @brief Get root type.
9310 *
9311 * @param[in] ctx_node Context node.
9312 * @param[in] ctx_scnode Schema context node.
9313 * @param[in] options XPath options.
9314 * @return Root type.
9315 */
9316static enum lyxp_node_type
Radek Krejci1deb5be2020-08-26 16:43:36 +02009317lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, uint32_t options)
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009318{
Michal Vasko6b26e742020-07-17 15:02:10 +02009319 const struct lysc_node *op;
9320
Michal Vaskoa27245c2022-05-02 09:01:35 +02009321 /* explicit */
9322 if (options & LYXP_ACCESS_TREE_ALL) {
9323 return LYXP_NODE_ROOT;
9324 } else if (options & LYXP_ACCESS_TREE_CONFIG) {
9325 return LYXP_NODE_ROOT_CONFIG;
9326 }
9327
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009328 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009329 /* schema */
Radek Krejci1e008d22020-08-17 11:37:37 +02009330 for (op = ctx_scnode; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02009331
9332 if (op || (options & LYXP_SCNODE)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009333 /* general root that can access everything */
9334 return LYXP_NODE_ROOT;
9335 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
9336 /* root context node can access only config data (because we said so, it is unspecified) */
9337 return LYXP_NODE_ROOT_CONFIG;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009338 }
Michal Vasko6b26e742020-07-17 15:02:10 +02009339 return LYXP_NODE_ROOT;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009340 }
9341
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009342 /* data */
Michal Vasko6b26e742020-07-17 15:02:10 +02009343 op = ctx_node ? ctx_node->schema : NULL;
Michal Vaskod989ba02020-08-24 10:59:24 +02009344 for ( ; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02009345
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009346 if (op || !(options & LYXP_SCHEMA)) {
9347 /* general root that can access everything */
9348 return LYXP_NODE_ROOT;
Christian Hoppsb6ecaea2021-02-06 09:45:38 -05009349 } else if (!ctx_node || !ctx_node->schema || (ctx_node->schema->flags & LYS_CONFIG_W)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009350 /* root context node can access only config data (because we said so, it is unspecified) */
9351 return LYXP_NODE_ROOT_CONFIG;
9352 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009353 return LYXP_NODE_ROOT;
9354}
9355
Michal Vasko03ff5a72019-09-11 13:49:33 +02009356LY_ERR
Michal Vasko400e9672021-01-11 13:39:17 +01009357lyxp_eval(const struct ly_ctx *ctx, const struct lyxp_expr *exp, const struct lys_module *cur_mod,
Michal Vaskoa3e92bc2022-07-29 14:56:23 +02009358 LY_VALUE_FORMAT format, void *prefix_data, const struct lyd_node *cur_node, const struct lyd_node *ctx_node,
9359 const struct lyd_node *tree, const struct lyxp_var *vars, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009360{
Michal Vasko004d3152020-06-11 19:59:22 +02009361 uint16_t tok_idx = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01009362 const struct lysc_node *snode;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009363 LY_ERR rc;
9364
Michal Vasko400e9672021-01-11 13:39:17 +01009365 LY_CHECK_ARG_RET(ctx, ctx, exp, set, LY_EINVAL);
Radek Krejci8df109d2021-04-23 12:19:08 +02009366 if (!cur_mod && ((format == LY_VALUE_SCHEMA) || (format == LY_VALUE_SCHEMA_RESOLVED))) {
Michal Vaskoddd76592022-01-17 13:34:48 +01009367 LOGERR(ctx, LY_EINVAL, "Current module must be set if schema format is used.");
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009368 return LY_EINVAL;
Michal Vasko004d3152020-06-11 19:59:22 +02009369 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02009370
Michal Vaskod3bb12f2020-12-04 14:33:09 +01009371 if (tree) {
9372 /* adjust the pointer to be the first top-level sibling */
9373 while (tree->parent) {
9374 tree = lyd_parent(tree);
9375 }
9376 tree = lyd_first_sibling(tree);
Michal Vaskoddd76592022-01-17 13:34:48 +01009377
9378 for (snode = tree->schema->parent; snode && (snode->nodetype & (LYS_CASE | LYS_CHOICE)); snode = snode->parent) {}
9379 if (snode) {
9380 /* unable to evaluate absolute paths */
9381 LOGERR(ctx, LY_EINVAL, "Data node \"%s\" has no parent but is not instance of a top-level schema node.",
9382 LYD_NAME(tree));
9383 return LY_EINVAL;
9384 }
Michal Vaskod3bb12f2020-12-04 14:33:09 +01009385 }
9386
Michal Vasko03ff5a72019-09-11 13:49:33 +02009387 /* prepare set for evaluation */
Michal Vasko03ff5a72019-09-11 13:49:33 +02009388 memset(set, 0, sizeof *set);
Michal Vaskod3678892020-05-21 10:06:58 +02009389 set->type = LYXP_SET_NODE_SET;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009390 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
9391 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node ? LYXP_NODE_ELEM : set->root_type, 0);
9392
Michal Vasko400e9672021-01-11 13:39:17 +01009393 set->ctx = (struct ly_ctx *)ctx;
Michal Vaskoa3e92bc2022-07-29 14:56:23 +02009394 set->cur_node = cur_node;
9395 for (set->context_op = cur_node ? cur_node->schema : NULL;
Radek Krejci0f969882020-08-21 16:56:47 +02009396 set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
9397 set->context_op = set->context_op->parent) {}
Michal Vaskof03ed032020-03-04 13:31:44 +01009398 set->tree = tree;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009399 set->cur_mod = cur_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009400 set->format = format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009401 set->prefix_data = prefix_data;
aPiecekfba75362021-10-07 12:39:48 +02009402 set->vars = vars;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009403
Radek Krejciddace2c2021-01-08 11:30:56 +01009404 LOG_LOCSET(NULL, set->cur_node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01009405
Michal Vasko03ff5a72019-09-11 13:49:33 +02009406 /* evaluate */
Michal Vasko004d3152020-06-11 19:59:22 +02009407 rc = eval_expr_select(exp, &tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009408 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02009409 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009410 }
9411
Michal Vasko4a7d4d62021-12-13 17:05:06 +01009412 if (set->cur_node) {
9413 LOG_LOCBACK(0, 1, 0, 0);
9414 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02009415 return rc;
9416}
9417
9418#if 0
9419
9420/* full xml printing of set elements, not used currently */
9421
9422void
9423lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
9424{
9425 uint32_t i;
9426 char *str_num;
9427 struct lyout out;
9428
9429 memset(&out, 0, sizeof out);
9430
9431 out.type = LYOUT_STREAM;
9432 out.method.f = f;
9433
9434 switch (set->type) {
9435 case LYXP_SET_EMPTY:
Michal Vasko5233e962020-08-14 14:26:20 +02009436 ly_print_(&out, "Empty XPath set\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009437 break;
9438 case LYXP_SET_BOOLEAN:
Michal Vasko5233e962020-08-14 14:26:20 +02009439 ly_print_(&out, "Boolean XPath set:\n");
9440 ly_print_(&out, "%s\n\n", set->value.bool ? "true" : "false");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009441 break;
9442 case LYXP_SET_STRING:
Michal Vasko5233e962020-08-14 14:26:20 +02009443 ly_print_(&out, "String XPath set:\n");
9444 ly_print_(&out, "\"%s\"\n\n", set->value.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009445 break;
9446 case LYXP_SET_NUMBER:
Michal Vasko5233e962020-08-14 14:26:20 +02009447 ly_print_(&out, "Number XPath set:\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009448
9449 if (isnan(set->value.num)) {
9450 str_num = strdup("NaN");
9451 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
9452 str_num = strdup("0");
9453 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
9454 str_num = strdup("Infinity");
9455 } else if (isinf(set->value.num) && signbit(set->value.num)) {
9456 str_num = strdup("-Infinity");
9457 } else if ((long long)set->value.num == set->value.num) {
9458 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
9459 str_num = NULL;
9460 }
9461 } else {
9462 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
9463 str_num = NULL;
9464 }
9465 }
9466 if (!str_num) {
9467 LOGMEM;
9468 return;
9469 }
Michal Vasko5233e962020-08-14 14:26:20 +02009470 ly_print_(&out, "%s\n\n", str_num);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009471 free(str_num);
9472 break;
9473 case LYXP_SET_NODE_SET:
Michal Vasko5233e962020-08-14 14:26:20 +02009474 ly_print_(&out, "Node XPath set:\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009475
9476 for (i = 0; i < set->used; ++i) {
Michal Vasko5233e962020-08-14 14:26:20 +02009477 ly_print_(&out, "%d. ", i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009478 switch (set->node_type[i]) {
9479 case LYXP_NODE_ROOT_ALL:
Michal Vasko5233e962020-08-14 14:26:20 +02009480 ly_print_(&out, "ROOT all\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009481 break;
9482 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5233e962020-08-14 14:26:20 +02009483 ly_print_(&out, "ROOT config\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009484 break;
9485 case LYXP_NODE_ROOT_STATE:
Michal Vasko5233e962020-08-14 14:26:20 +02009486 ly_print_(&out, "ROOT state\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009487 break;
9488 case LYXP_NODE_ROOT_NOTIF:
Michal Vasko5233e962020-08-14 14:26:20 +02009489 ly_print_(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009490 break;
9491 case LYXP_NODE_ROOT_RPC:
Michal Vasko5233e962020-08-14 14:26:20 +02009492 ly_print_(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009493 break;
9494 case LYXP_NODE_ROOT_OUTPUT:
Michal Vasko5233e962020-08-14 14:26:20 +02009495 ly_print_(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009496 break;
9497 case LYXP_NODE_ELEM:
Michal Vasko5233e962020-08-14 14:26:20 +02009498 ly_print_(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009499 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
Michal Vasko5233e962020-08-14 14:26:20 +02009500 ly_print_(&out, "\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02009501 break;
9502 case LYXP_NODE_TEXT:
Michal Vasko5233e962020-08-14 14:26:20 +02009503 ly_print_(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009504 break;
9505 case LYXP_NODE_ATTR:
Michal Vasko5233e962020-08-14 14:26:20 +02009506 ly_print_(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009507 break;
9508 }
9509 }
9510 break;
9511 }
9512}
9513
9514#endif
9515
9516LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009517lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009518{
9519 long double num;
9520 char *str;
9521 LY_ERR rc;
9522
9523 if (!set || (set->type == target)) {
9524 return LY_SUCCESS;
9525 }
9526
9527 /* it's not possible to convert anything into a node set */
Michal Vaskod3678892020-05-21 10:06:58 +02009528 assert(target != LYXP_SET_NODE_SET);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009529
9530 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02009531 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009532 return LY_EINVAL;
9533 }
9534
9535 /* to STRING */
Michal Vaskod3678892020-05-21 10:06:58 +02009536 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER) && (set->type == LYXP_SET_NODE_SET))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02009537 switch (set->type) {
9538 case LYXP_SET_NUMBER:
9539 if (isnan(set->val.num)) {
9540 set->val.str = strdup("NaN");
9541 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
9542 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
9543 set->val.str = strdup("0");
9544 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
9545 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
9546 set->val.str = strdup("Infinity");
9547 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
9548 } else if (isinf(set->val.num) && signbit(set->val.num)) {
9549 set->val.str = strdup("-Infinity");
9550 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
9551 } else if ((long long)set->val.num == set->val.num) {
9552 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
9553 LOGMEM_RET(set->ctx);
9554 }
9555 set->val.str = str;
9556 } else {
9557 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
9558 LOGMEM_RET(set->ctx);
9559 }
9560 set->val.str = str;
9561 }
9562 break;
9563 case LYXP_SET_BOOLEAN:
Michal Vasko004d3152020-06-11 19:59:22 +02009564 if (set->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02009565 set->val.str = strdup("true");
9566 } else {
9567 set->val.str = strdup("false");
9568 }
9569 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
9570 break;
9571 case LYXP_SET_NODE_SET:
Michal Vasko03ff5a72019-09-11 13:49:33 +02009572 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009573 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02009574
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01009575 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009576 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02009577 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009578 set->val.str = str;
9579 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009580 default:
9581 LOGINT_RET(set->ctx);
9582 }
9583 set->type = LYXP_SET_STRING;
9584 }
9585
9586 /* to NUMBER */
9587 if (target == LYXP_SET_NUMBER) {
9588 switch (set->type) {
9589 case LYXP_SET_STRING:
9590 num = cast_string_to_number(set->val.str);
Michal Vaskod3678892020-05-21 10:06:58 +02009591 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02009592 set->val.num = num;
9593 break;
9594 case LYXP_SET_BOOLEAN:
Michal Vasko004d3152020-06-11 19:59:22 +02009595 if (set->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02009596 set->val.num = 1;
9597 } else {
9598 set->val.num = 0;
9599 }
9600 break;
9601 default:
9602 LOGINT_RET(set->ctx);
9603 }
9604 set->type = LYXP_SET_NUMBER;
9605 }
9606
9607 /* to BOOLEAN */
9608 if (target == LYXP_SET_BOOLEAN) {
9609 switch (set->type) {
9610 case LYXP_SET_NUMBER:
9611 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
Michal Vasko004d3152020-06-11 19:59:22 +02009612 set->val.bln = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009613 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02009614 set->val.bln = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009615 }
9616 break;
9617 case LYXP_SET_STRING:
9618 if (set->val.str[0]) {
Michal Vaskod3678892020-05-21 10:06:58 +02009619 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02009620 set->val.bln = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009621 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02009622 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02009623 set->val.bln = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009624 }
9625 break;
9626 case LYXP_SET_NODE_SET:
Michal Vaskod3678892020-05-21 10:06:58 +02009627 if (set->used) {
9628 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02009629 set->val.bln = 1;
Michal Vaskod3678892020-05-21 10:06:58 +02009630 } else {
9631 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02009632 set->val.bln = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02009633 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02009634 break;
9635 default:
9636 LOGINT_RET(set->ctx);
9637 }
9638 set->type = LYXP_SET_BOOLEAN;
9639 }
9640
Michal Vasko03ff5a72019-09-11 13:49:33 +02009641 return LY_SUCCESS;
9642}
9643
9644LY_ERR
Michal Vasko400e9672021-01-11 13:39:17 +01009645lyxp_atomize(const struct ly_ctx *ctx, const struct lyxp_expr *exp, const struct lys_module *cur_mod,
Michal Vaskoa3e92bc2022-07-29 14:56:23 +02009646 LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *cur_scnode,
9647 const struct lysc_node *ctx_scnode, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02009648{
Radek Krejci2efc45b2020-12-22 16:25:44 +01009649 LY_ERR ret;
Michal Vasko004d3152020-06-11 19:59:22 +02009650 uint16_t tok_idx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009651
Michal Vasko400e9672021-01-11 13:39:17 +01009652 LY_CHECK_ARG_RET(ctx, ctx, exp, set, LY_EINVAL);
Radek Krejci8df109d2021-04-23 12:19:08 +02009653 if (!cur_mod && ((format == LY_VALUE_SCHEMA) || (format == LY_VALUE_SCHEMA_RESOLVED))) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009654 LOGARG(NULL, "Current module must be set if schema format is used.");
9655 return LY_EINVAL;
Michal Vasko004d3152020-06-11 19:59:22 +02009656 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02009657
9658 /* prepare set for evaluation */
Michal Vasko03ff5a72019-09-11 13:49:33 +02009659 memset(set, 0, sizeof *set);
9660 set->type = LYXP_SET_SCNODE_SET;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009661 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
9662 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode ? LYXP_NODE_ELEM : set->root_type, NULL));
Radek Krejcif13b87b2020-12-01 22:02:17 +01009663 set->val.scnodes[0].in_ctx = LYXP_SET_SCNODE_START;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009664
Michal Vasko400e9672021-01-11 13:39:17 +01009665 set->ctx = (struct ly_ctx *)ctx;
Michal Vaskoa3e92bc2022-07-29 14:56:23 +02009666 set->cur_scnode = cur_scnode;
9667 for (set->context_op = cur_scnode;
Radek Krejci0f969882020-08-21 16:56:47 +02009668 set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
9669 set->context_op = set->context_op->parent) {}
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009670 set->cur_mod = cur_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009671 set->format = format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02009672 set->prefix_data = prefix_data;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009673
Radek Krejciddace2c2021-01-08 11:30:56 +01009674 LOG_LOCSET(set->cur_scnode, NULL, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +01009675
Michal Vasko03ff5a72019-09-11 13:49:33 +02009676 /* evaluate */
Radek Krejci2efc45b2020-12-22 16:25:44 +01009677 ret = eval_expr_select(exp, &tok_idx, 0, set, options);
9678
Radek Krejciddace2c2021-01-08 11:30:56 +01009679 LOG_LOCBACK(1, 0, 0, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +01009680 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02009681}
Michal Vaskod43d71a2020-08-07 14:54:58 +02009682
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01009683LIBYANG_API_DEF const char *
Michal Vaskod43d71a2020-08-07 14:54:58 +02009684lyxp_get_expr(const struct lyxp_expr *path)
9685{
9686 if (!path) {
9687 return NULL;
9688 }
9689
9690 return path->expr;
9691}