blob: 7c3eb591de309c4abc4199a6f0e498590887f91d [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 Vasko61ac2f62020-05-25 12:39:51 +02006 * Copyright (c) 2015 - 2020 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 */
Michal Vasko03ff5a72019-09-11 13:49:33 +020014#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010015#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
Michal Vasko03ff5a72019-09-11 13:49:33 +020016
17/* needed by libmath functions isfinite(), isinf(), isnan(), signbit(), ... */
18#define _ISOC99_SOURCE
Radek Krejcib1646a92018-11-02 16:08:26 +010019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "xpath.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010021
Radek Krejci535ea9f2020-05-29 16:01:05 +020022#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010023#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include <errno.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include <math.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include <stdint.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010027#include <stdio.h>
28#include <stdlib.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010029#include <string.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010030
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020032#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020033#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020034#include "dict.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "hash_table.h"
Radek Krejci47fab892020-11-05 17:02:41 +010036#include "out.h"
Radek Krejci7931b192020-06-25 17:05:03 +020037#include "parser_data.h"
Michal Vasko004d3152020-06-11 19:59:22 +020038#include "path.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020039#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020040#include "printer_data.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020041#include "schema_compile_node.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020042#include "tree.h"
43#include "tree_data_internal.h"
44#include "tree_schema_internal.h"
45#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020046
Michal Vasko004d3152020-06-11 19:59:22 +020047static LY_ERR reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx);
Michal Vasko40308e72020-10-20 16:38:40 +020048static LY_ERR eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype,
49 struct lyxp_set *set, uint32_t options);
Michal Vasko03ff5a72019-09-11 13:49:33 +020050
51/**
52 * @brief Print the type of an XPath \p set.
53 *
54 * @param[in] set Set to use.
55 * @return Set type string.
56 */
57static const char *
58print_set_type(struct lyxp_set *set)
59{
60 switch (set->type) {
Michal Vasko03ff5a72019-09-11 13:49:33 +020061 case LYXP_SET_NODE_SET:
62 return "node set";
63 case LYXP_SET_SCNODE_SET:
64 return "schema node set";
65 case LYXP_SET_BOOLEAN:
66 return "boolean";
67 case LYXP_SET_NUMBER:
68 return "number";
69 case LYXP_SET_STRING:
70 return "string";
71 }
72
73 return NULL;
74}
75
Michal Vasko24cddf82020-06-01 08:17:01 +020076const char *
77lyxp_print_token(enum lyxp_token tok)
Michal Vasko03ff5a72019-09-11 13:49:33 +020078{
79 switch (tok) {
80 case LYXP_TOKEN_PAR1:
81 return "(";
82 case LYXP_TOKEN_PAR2:
83 return ")";
84 case LYXP_TOKEN_BRACK1:
85 return "[";
86 case LYXP_TOKEN_BRACK2:
87 return "]";
88 case LYXP_TOKEN_DOT:
89 return ".";
90 case LYXP_TOKEN_DDOT:
91 return "..";
92 case LYXP_TOKEN_AT:
93 return "@";
94 case LYXP_TOKEN_COMMA:
95 return ",";
96 case LYXP_TOKEN_NAMETEST:
97 return "NameTest";
98 case LYXP_TOKEN_NODETYPE:
99 return "NodeType";
100 case LYXP_TOKEN_FUNCNAME:
101 return "FunctionName";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200102 case LYXP_TOKEN_OPER_LOG:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200103 return "Operator(Logic)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200104 case LYXP_TOKEN_OPER_EQUAL:
105 return "Operator(Equal)";
106 case LYXP_TOKEN_OPER_NEQUAL:
107 return "Operator(Non-equal)";
108 case LYXP_TOKEN_OPER_COMP:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200109 return "Operator(Comparison)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200110 case LYXP_TOKEN_OPER_MATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200111 return "Operator(Math)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200112 case LYXP_TOKEN_OPER_UNI:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200113 return "Operator(Union)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200114 case LYXP_TOKEN_OPER_PATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +0200115 return "Operator(Path)";
Michal Vasko3e48bf32020-06-01 08:39:07 +0200116 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko14676352020-05-29 11:35:55 +0200117 return "Operator(Recursive Path)";
Michal Vasko03ff5a72019-09-11 13:49:33 +0200118 case LYXP_TOKEN_LITERAL:
119 return "Literal";
120 case LYXP_TOKEN_NUMBER:
121 return "Number";
122 default:
123 LOGINT(NULL);
124 return "";
125 }
126}
127
128/**
129 * @brief Print the whole expression \p exp to debug output.
130 *
131 * @param[in] exp Expression to use.
132 */
133static void
Michal Vasko40308e72020-10-20 16:38:40 +0200134print_expr_struct_debug(const struct lyxp_expr *exp)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200135{
Radek Krejcif13b87b2020-12-01 22:02:17 +0100136#define MSG_BUFFER_SIZE 128
137 char tmp[MSG_BUFFER_SIZE];
Michal Vasko03ff5a72019-09-11 13:49:33 +0200138 uint16_t i, j;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200139
Radek Krejci52b6d512020-10-12 12:33:17 +0200140 if (!exp || (ly_ll < LY_LLDBG)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200141 return;
142 }
143
144 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
145 for (i = 0; i < exp->used; ++i) {
Michal Vasko24cddf82020-06-01 08:17:01 +0200146 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", lyxp_print_token(exp->tokens[i]), exp->tok_len[i],
Michal Vasko69730152020-10-09 16:30:07 +0200147 &exp->expr[exp->tok_pos[i]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200148 if (exp->repeat[i]) {
149 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
150 for (j = 1; exp->repeat[i][j]; ++j) {
151 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
152 }
153 strcat(tmp, ")");
154 }
155 LOGDBG(LY_LDGXPATH, tmp);
156 }
Radek Krejcif13b87b2020-12-01 22:02:17 +0100157#undef MSG_BUFFER_SIZE
Michal Vasko03ff5a72019-09-11 13:49:33 +0200158}
159
160#ifndef NDEBUG
161
162/**
163 * @brief Print XPath set content to debug output.
164 *
165 * @param[in] set Set to print.
166 */
167static void
168print_set_debug(struct lyxp_set *set)
169{
170 uint32_t i;
171 char *str;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200172 struct lyxp_set_node *item;
173 struct lyxp_set_scnode *sitem;
174
Radek Krejci52b6d512020-10-12 12:33:17 +0200175 if (ly_ll < LY_LLDBG) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200176 return;
177 }
178
179 switch (set->type) {
180 case LYXP_SET_NODE_SET:
181 LOGDBG(LY_LDGXPATH, "set NODE SET:");
182 for (i = 0; i < set->used; ++i) {
183 item = &set->val.nodes[i];
184
185 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100186 case LYXP_NODE_NONE:
187 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
188 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200189 case LYXP_NODE_ROOT:
190 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
191 break;
192 case LYXP_NODE_ROOT_CONFIG:
193 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
194 break;
195 case LYXP_NODE_ELEM:
Michal Vasko69730152020-10-09 16:30:07 +0200196 if ((item->node->schema->nodetype == LYS_LIST) &&
197 (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200198 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
Michal Vasko69730152020-10-09 16:30:07 +0200199 item->node->schema->name, LYD_CANON_VALUE(lyd_child(item->node)));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200200 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
201 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
Michal Vasko69730152020-10-09 16:30:07 +0200202 item->node->schema->name, LYD_CANON_VALUE(item->node));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200203 } else {
204 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
205 }
206 break;
207 case LYXP_NODE_TEXT:
208 if (item->node->schema->nodetype & LYS_ANYDATA) {
209 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
Michal Vasko69730152020-10-09 16:30:07 +0200210 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
Michal Vasko03ff5a72019-09-11 13:49:33 +0200211 } else {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200212 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos, LYD_CANON_VALUE(item->node));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200213 }
214 break;
Michal Vasko9f96a052020-03-10 09:41:45 +0100215 case LYXP_NODE_META:
216 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 +0200217 set->val.meta[i].meta->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200218 break;
219 }
220 }
221 break;
222
223 case LYXP_SET_SCNODE_SET:
224 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
225 for (i = 0; i < set->used; ++i) {
226 sitem = &set->val.scnodes[i];
227
228 switch (sitem->type) {
229 case LYXP_NODE_ROOT:
230 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
231 break;
232 case LYXP_NODE_ROOT_CONFIG:
233 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
234 break;
235 case LYXP_NODE_ELEM:
236 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
237 break;
238 default:
239 LOGINT(NULL);
240 break;
241 }
242 }
243 break;
244
Michal Vasko03ff5a72019-09-11 13:49:33 +0200245 case LYXP_SET_BOOLEAN:
246 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
Michal Vasko004d3152020-06-11 19:59:22 +0200247 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bln ? "true" : "false"));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200248 break;
249
250 case LYXP_SET_STRING:
251 LOGDBG(LY_LDGXPATH, "set STRING");
252 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
253 break;
254
255 case LYXP_SET_NUMBER:
256 LOGDBG(LY_LDGXPATH, "set NUMBER");
257
258 if (isnan(set->val.num)) {
259 str = strdup("NaN");
260 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
261 str = strdup("0");
262 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
263 str = strdup("Infinity");
264 } else if (isinf(set->val.num) && signbit(set->val.num)) {
265 str = strdup("-Infinity");
266 } else if ((long long)set->val.num == set->val.num) {
267 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
268 str = NULL;
269 }
270 } else {
271 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
272 str = NULL;
273 }
274 }
275 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
276
277 LOGDBG(LY_LDGXPATH, "\t%s", str);
278 free(str);
279 }
280}
281
282#endif
283
284/**
285 * @brief Realloc the string \p str.
286 *
287 * @param[in] ctx libyang context for logging.
288 * @param[in] needed How much free space is required.
289 * @param[in,out] str Pointer to the string to use.
290 * @param[in,out] used Used bytes in \p str.
291 * @param[in,out] size Allocated bytes in \p str.
292 * @return LY_ERR
293 */
294static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100295cast_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 +0200296{
297 if (*size - *used < needed) {
298 do {
299 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
300 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
301 return LY_EINVAL;
302 }
303 *size += LYXP_STRING_CAST_SIZE_STEP;
304 } while (*size - *used < needed);
305 *str = ly_realloc(*str, *size * sizeof(char));
306 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
307 }
308
309 return LY_SUCCESS;
310}
311
312/**
313 * @brief Cast nodes recursively to one string @p str.
314 *
315 * @param[in] node Node to cast.
316 * @param[in] fake_cont Whether to put the data into a "fake" container.
317 * @param[in] root_type Type of the XPath root.
318 * @param[in] indent Current indent.
319 * @param[in,out] str Resulting string.
320 * @param[in,out] used Used bytes in @p str.
321 * @param[in,out] size Allocated bytes in @p str.
322 * @return LY_ERR
323 */
324static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200325cast_string_recursive(const struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
Radek Krejci0f969882020-08-21 16:56:47 +0200326 uint16_t *used, uint16_t *size)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200327{
Radek Krejci7f769d72020-07-11 23:13:56 +0200328 char *buf, *line, *ptr = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200329 const char *value_str;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200330 const struct lyd_node *child;
Michal Vasko60ea6352020-06-29 13:39:39 +0200331 struct lyd_node *tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200332 struct lyd_node_any *any;
333 LY_ERR rc;
334
335 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
336 return LY_SUCCESS;
337 }
338
339 if (fake_cont) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200340 rc = cast_string_realloc(LYD_CTX(node), 1, str, used, size);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200341 LY_CHECK_RET(rc);
342 strcpy(*str + (*used - 1), "\n");
343 ++(*used);
344
345 ++indent;
346 }
347
348 switch (node->schema->nodetype) {
349 case LYS_CONTAINER:
350 case LYS_LIST:
351 case LYS_RPC:
352 case LYS_NOTIF:
Michal Vaskob7be7a82020-08-20 09:09:04 +0200353 rc = cast_string_realloc(LYD_CTX(node), 1, str, used, size);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200354 LY_CHECK_RET(rc);
355 strcpy(*str + (*used - 1), "\n");
356 ++(*used);
357
Radek Krejcia1c1e542020-09-29 16:06:52 +0200358 for (child = lyd_child(node); child; child = child->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200359 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
360 LY_CHECK_RET(rc);
361 }
362
363 break;
364
365 case LYS_LEAF:
366 case LYS_LEAFLIST:
Michal Vaskob7be7a82020-08-20 09:09:04 +0200367 value_str = LYD_CANON_VALUE(node);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200368
369 /* print indent */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200370 LY_CHECK_RET(cast_string_realloc(LYD_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200371 memset(*str + (*used - 1), ' ', indent * 2);
372 *used += indent * 2;
373
374 /* print value */
375 if (*used == 1) {
376 sprintf(*str + (*used - 1), "%s", value_str);
377 *used += strlen(value_str);
378 } else {
379 sprintf(*str + (*used - 1), "%s\n", value_str);
380 *used += strlen(value_str) + 1;
381 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200382
383 break;
384
385 case LYS_ANYXML:
386 case LYS_ANYDATA:
387 any = (struct lyd_node_any *)node;
388 if (!(void *)any->value.tree) {
389 /* no content */
390 buf = strdup("");
Michal Vaskob7be7a82020-08-20 09:09:04 +0200391 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_CTX(node)), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200392 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200393 struct ly_out *out;
Radek Krejcia5bba312020-01-09 15:41:20 +0100394
Michal Vasko60ea6352020-06-29 13:39:39 +0200395 if (any->value_type == LYD_ANYDATA_LYB) {
396 /* try to parse it into a data tree */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200397 if (lyd_parse_data_mem((struct ly_ctx *)LYD_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &tree) == LY_SUCCESS) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200398 /* successfully parsed */
399 free(any->value.mem);
400 any->value.tree = tree;
401 any->value_type = LYD_ANYDATA_DATATREE;
402 }
Radek Krejci7931b192020-06-25 17:05:03 +0200403 /* error is covered by the following switch where LYD_ANYDATA_LYB causes failure */
Michal Vasko60ea6352020-06-29 13:39:39 +0200404 }
405
Michal Vasko03ff5a72019-09-11 13:49:33 +0200406 switch (any->value_type) {
407 case LYD_ANYDATA_STRING:
408 case LYD_ANYDATA_XML:
409 case LYD_ANYDATA_JSON:
410 buf = strdup(any->value.json);
Michal Vaskob7be7a82020-08-20 09:09:04 +0200411 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_CTX(node)), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200412 break;
413 case LYD_ANYDATA_DATATREE:
Radek Krejci84ce7b12020-06-11 17:28:25 +0200414 LY_CHECK_RET(ly_out_new_memory(&buf, 0, &out));
Michal Vasko3a41dff2020-07-15 14:30:28 +0200415 rc = lyd_print_all(out, any->value.tree, LYD_XML, 0);
Radek Krejci241f6b52020-05-21 18:13:49 +0200416 ly_out_free(out, NULL, 0);
Radek Krejcia5bba312020-01-09 15:41:20 +0100417 LY_CHECK_RET(rc < 0, -rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200418 break;
Michal Vasko60ea6352020-06-29 13:39:39 +0200419 case LYD_ANYDATA_LYB:
Michal Vaskob7be7a82020-08-20 09:09:04 +0200420 LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
Michal Vasko60ea6352020-06-29 13:39:39 +0200421 return LY_EINVAL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200422 }
423 }
424
425 line = strtok_r(buf, "\n", &ptr);
426 do {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200427 rc = cast_string_realloc(LYD_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200428 if (rc != LY_SUCCESS) {
429 free(buf);
430 return rc;
431 }
432 memset(*str + (*used - 1), ' ', indent * 2);
433 *used += indent * 2;
434
435 strcpy(*str + (*used - 1), line);
436 *used += strlen(line);
437
438 strcpy(*str + (*used - 1), "\n");
439 *used += 1;
440 } while ((line = strtok_r(NULL, "\n", &ptr)));
441
442 free(buf);
443 break;
444
445 default:
Michal Vaskob7be7a82020-08-20 09:09:04 +0200446 LOGINT_RET(LYD_CTX(node));
Michal Vasko03ff5a72019-09-11 13:49:33 +0200447 }
448
449 if (fake_cont) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200450 rc = cast_string_realloc(LYD_CTX(node), 1, str, used, size);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200451 LY_CHECK_RET(rc);
452 strcpy(*str + (*used - 1), "\n");
453 ++(*used);
454
455 --indent;
456 }
457
458 return LY_SUCCESS;
459}
460
461/**
462 * @brief Cast an element into a string.
463 *
464 * @param[in] node Node to cast.
465 * @param[in] fake_cont Whether to put the data into a "fake" container.
466 * @param[in] root_type Type of the XPath root.
467 * @param[out] str Element cast to dynamically-allocated string.
468 * @return LY_ERR
469 */
470static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200471cast_string_elem(struct lyd_node *node, ly_bool fake_cont, enum lyxp_node_type root_type, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200472{
473 uint16_t used, size;
474 LY_ERR rc;
475
476 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
Michal Vaskob7be7a82020-08-20 09:09:04 +0200477 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_CTX(node)), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200478 (*str)[0] = '\0';
479 used = 1;
480 size = LYXP_STRING_CAST_SIZE_START;
481
482 rc = cast_string_recursive(node, fake_cont, root_type, 0, str, &used, &size);
483 if (rc != LY_SUCCESS) {
484 free(*str);
485 return rc;
486 }
487
488 if (size > used) {
489 *str = ly_realloc(*str, used * sizeof(char));
Michal Vaskob7be7a82020-08-20 09:09:04 +0200490 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_CTX(node)), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200491 }
492 return LY_SUCCESS;
493}
494
495/**
496 * @brief Cast a LYXP_SET_NODE_SET set into a string.
497 * Context position aware.
498 *
499 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200500 * @param[out] str Cast dynamically-allocated string.
501 * @return LY_ERR
502 */
503static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100504cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200505{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200506 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100507 case LYXP_NODE_NONE:
508 /* invalid */
509 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200510 case LYXP_NODE_ROOT:
511 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100512 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200513 case LYXP_NODE_ELEM:
514 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100515 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko9f96a052020-03-10 09:41:45 +0100516 case LYXP_NODE_META:
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200517 *str = strdup(set->val.meta[0].meta->value.canonical);
518 if (!*str) {
519 LOGMEM_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200520 }
521 return LY_SUCCESS;
522 }
523
524 LOGINT_RET(set->ctx);
525}
526
527/**
528 * @brief Cast a string into an XPath number.
529 *
530 * @param[in] str String to use.
531 * @return Cast number.
532 */
533static long double
534cast_string_to_number(const char *str)
535{
536 long double num;
537 char *ptr;
538
539 errno = 0;
540 num = strtold(str, &ptr);
541 if (errno || *ptr) {
542 num = NAN;
543 }
544 return num;
545}
546
547/**
548 * @brief Callback for checking value equality.
549 *
Radek Krejci857189e2020-09-01 13:26:36 +0200550 * Implementation of ::values_equal_cb.
551 *
Michal Vasko03ff5a72019-09-11 13:49:33 +0200552 * @param[in] val1_p First value.
553 * @param[in] val2_p Second value.
554 * @param[in] mod Whether hash table is being modified.
555 * @param[in] cb_data Callback data.
Radek Krejci857189e2020-09-01 13:26:36 +0200556 * @return Boolean value whether values are equal or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200557 */
Radek Krejci857189e2020-09-01 13:26:36 +0200558static ly_bool
559set_values_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
Michal Vasko03ff5a72019-09-11 13:49:33 +0200560{
561 struct lyxp_set_hash_node *val1, *val2;
562
563 val1 = (struct lyxp_set_hash_node *)val1_p;
564 val2 = (struct lyxp_set_hash_node *)val2_p;
565
566 if ((val1->node == val2->node) && (val1->type == val2->type)) {
567 return 1;
568 }
569
570 return 0;
571}
572
573/**
574 * @brief Insert node and its hash into set.
575 *
576 * @param[in] set et to insert to.
577 * @param[in] node Node with hash.
578 * @param[in] type Node type.
579 */
580static void
581set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
582{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200583 LY_ERR r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200584 uint32_t i, hash;
585 struct lyxp_set_hash_node hnode;
586
587 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
588 /* create hash table and add all the nodes */
589 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
590 for (i = 0; i < set->used; ++i) {
591 hnode.node = set->val.nodes[i].node;
592 hnode.type = set->val.nodes[i].type;
593
594 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
595 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
596 hash = dict_hash_multi(hash, NULL, 0);
597
598 r = lyht_insert(set->ht, &hnode, hash, NULL);
599 assert(!r);
600 (void)r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200601
Michal Vasko9d6befd2019-12-11 14:56:56 +0100602 if (hnode.node == node) {
603 /* it was just added, do not add it twice */
604 node = NULL;
605 }
606 }
607 }
608
609 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200610 /* add the new node into hash table */
611 hnode.node = node;
612 hnode.type = type;
613
614 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
615 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
616 hash = dict_hash_multi(hash, NULL, 0);
617
618 r = lyht_insert(set->ht, &hnode, hash, NULL);
619 assert(!r);
620 (void)r;
621 }
622}
623
624/**
625 * @brief Remove node and its hash from set.
626 *
627 * @param[in] set Set to remove from.
628 * @param[in] node Node to remove.
629 * @param[in] type Node type.
630 */
631static void
632set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
633{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200634 LY_ERR r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200635 struct lyxp_set_hash_node hnode;
636 uint32_t hash;
637
638 if (set->ht) {
639 hnode.node = node;
640 hnode.type = type;
641
642 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
643 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
644 hash = dict_hash_multi(hash, NULL, 0);
645
646 r = lyht_remove(set->ht, &hnode, hash);
647 assert(!r);
648 (void)r;
649
650 if (!set->ht->used) {
651 lyht_free(set->ht);
652 set->ht = NULL;
653 }
654 }
655}
656
657/**
658 * @brief Check whether node is in set based on its hash.
659 *
660 * @param[in] set Set to search in.
661 * @param[in] node Node to search for.
662 * @param[in] type Node type.
663 * @param[in] skip_idx Index in @p set to skip.
664 * @return LY_ERR
665 */
666static LY_ERR
667set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
668{
669 struct lyxp_set_hash_node hnode, *match_p;
670 uint32_t hash;
671
672 hnode.node = node;
673 hnode.type = type;
674
675 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
676 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
677 hash = dict_hash_multi(hash, NULL, 0);
678
679 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
680 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
681 /* we found it on the index that should be skipped, find another */
682 hnode = *match_p;
683 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
684 /* none other found */
685 return LY_SUCCESS;
686 }
687 }
688
689 return LY_EEXIST;
690 }
691
692 /* not found */
693 return LY_SUCCESS;
694}
695
Michal Vaskod3678892020-05-21 10:06:58 +0200696void
697lyxp_set_free_content(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200698{
699 if (!set) {
700 return;
701 }
702
703 if (set->type == LYXP_SET_NODE_SET) {
704 free(set->val.nodes);
705 lyht_free(set->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200706 } else if (set->type == LYXP_SET_SCNODE_SET) {
707 free(set->val.scnodes);
Michal Vaskod3678892020-05-21 10:06:58 +0200708 lyht_free(set->ht);
709 } else {
710 if (set->type == LYXP_SET_STRING) {
711 free(set->val.str);
712 }
713 set->type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200714 }
Michal Vaskod3678892020-05-21 10:06:58 +0200715
716 set->val.nodes = NULL;
717 set->used = 0;
718 set->size = 0;
719 set->ht = NULL;
720 set->ctx_pos = 0;
721 set->ctx_pos = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200722}
723
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100724/**
725 * @brief Free dynamically-allocated set.
726 *
727 * @param[in] set Set to free.
728 */
729static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200730lyxp_set_free(struct lyxp_set *set)
731{
732 if (!set) {
733 return;
734 }
735
Michal Vaskod3678892020-05-21 10:06:58 +0200736 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200737 free(set);
738}
739
740/**
741 * @brief Initialize set context.
742 *
743 * @param[in] new Set to initialize.
744 * @param[in] set Arbitrary initialized set.
745 */
746static void
Michal Vasko4c7763f2020-07-27 17:40:37 +0200747set_init(struct lyxp_set *new, const struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200748{
749 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200750 if (set) {
751 new->ctx = set->ctx;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200752 new->cur_node = set->cur_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100753 new->root_type = set->root_type;
Michal Vasko6b26e742020-07-17 15:02:10 +0200754 new->context_op = set->context_op;
Michal Vaskof03ed032020-03-04 13:31:44 +0100755 new->tree = set->tree;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200756 new->cur_mod = set->cur_mod;
Michal Vasko02a77382019-09-12 11:47:35 +0200757 new->format = set->format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200758 new->prefix_data = set->prefix_data;
Michal Vasko02a77382019-09-12 11:47:35 +0200759 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200760}
761
762/**
763 * @brief Create a deep copy of a set.
764 *
765 * @param[in] set Set to copy.
766 * @return Copy of @p set.
767 */
768static struct lyxp_set *
769set_copy(struct lyxp_set *set)
770{
771 struct lyxp_set *ret;
772 uint16_t i;
773
774 if (!set) {
775 return NULL;
776 }
777
778 ret = malloc(sizeof *ret);
779 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
780 set_init(ret, set);
781
782 if (set->type == LYXP_SET_SCNODE_SET) {
783 ret->type = set->type;
784
785 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100786 if ((set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) ||
787 (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_START)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +0200788 uint32_t idx;
789 LY_CHECK_ERR_RET(lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type, &idx),
790 lyxp_set_free(ret), NULL);
Michal Vasko3f27c522020-01-06 08:37:49 +0100791 /* coverity seems to think scnodes can be NULL */
Radek Krejciaa6b53f2020-08-27 15:19:03 +0200792 if (!ret->val.scnodes) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200793 lyxp_set_free(ret);
794 return NULL;
795 }
Michal Vaskoba716542019-12-16 10:01:58 +0100796 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200797 }
798 }
799 } else if (set->type == LYXP_SET_NODE_SET) {
800 ret->type = set->type;
801 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
802 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
803 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
804
805 ret->used = ret->size = set->used;
806 ret->ctx_pos = set->ctx_pos;
807 ret->ctx_size = set->ctx_size;
808 ret->ht = lyht_dup(set->ht);
809 } else {
Radek Krejci0f969882020-08-21 16:56:47 +0200810 memcpy(ret, set, sizeof *ret);
811 if (set->type == LYXP_SET_STRING) {
812 ret->val.str = strdup(set->val.str);
813 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
814 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200815 }
816
817 return ret;
818}
819
820/**
821 * @brief Fill XPath set with a string. Any current data are disposed of.
822 *
823 * @param[in] set Set to fill.
824 * @param[in] string String to fill into \p set.
825 * @param[in] str_len Length of \p string. 0 is a valid value!
826 */
827static void
828set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
829{
Michal Vaskod3678892020-05-21 10:06:58 +0200830 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200831
832 set->type = LYXP_SET_STRING;
833 if ((str_len == 0) && (string[0] != '\0')) {
834 string = "";
835 }
836 set->val.str = strndup(string, str_len);
837}
838
839/**
840 * @brief Fill XPath set with a number. Any current data are disposed of.
841 *
842 * @param[in] set Set to fill.
843 * @param[in] number Number to fill into \p set.
844 */
845static void
846set_fill_number(struct lyxp_set *set, long double number)
847{
Michal Vaskod3678892020-05-21 10:06:58 +0200848 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200849
850 set->type = LYXP_SET_NUMBER;
851 set->val.num = number;
852}
853
854/**
855 * @brief Fill XPath set with a boolean. Any current data are disposed of.
856 *
857 * @param[in] set Set to fill.
858 * @param[in] boolean Boolean to fill into \p set.
859 */
860static void
Radek Krejci857189e2020-09-01 13:26:36 +0200861set_fill_boolean(struct lyxp_set *set, ly_bool boolean)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200862{
Michal Vaskod3678892020-05-21 10:06:58 +0200863 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200864
865 set->type = LYXP_SET_BOOLEAN;
Michal Vasko004d3152020-06-11 19:59:22 +0200866 set->val.bln = boolean;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200867}
868
869/**
870 * @brief Fill XPath set with the value from another set (deep assign).
871 * Any current data are disposed of.
872 *
873 * @param[in] trg Set to fill.
874 * @param[in] src Source set to copy into \p trg.
875 */
876static void
Michal Vasko4c7763f2020-07-27 17:40:37 +0200877set_fill_set(struct lyxp_set *trg, const struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200878{
879 if (!trg || !src) {
880 return;
881 }
882
883 if (trg->type == LYXP_SET_NODE_SET) {
884 free(trg->val.nodes);
885 } else if (trg->type == LYXP_SET_STRING) {
886 free(trg->val.str);
887 }
888 set_init(trg, src);
889
890 if (src->type == LYXP_SET_SCNODE_SET) {
891 trg->type = LYXP_SET_SCNODE_SET;
892 trg->used = src->used;
893 trg->size = src->used;
894
895 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
896 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
897 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
898 } else if (src->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +0200899 set_fill_boolean(trg, src->val.bln);
Michal Vasko44f3d2c2020-08-24 09:49:38 +0200900 } else if (src->type == LYXP_SET_NUMBER) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200901 set_fill_number(trg, src->val.num);
902 } else if (src->type == LYXP_SET_STRING) {
903 set_fill_string(trg, src->val.str, strlen(src->val.str));
904 } else {
905 if (trg->type == LYXP_SET_NODE_SET) {
906 free(trg->val.nodes);
907 } else if (trg->type == LYXP_SET_STRING) {
908 free(trg->val.str);
909 }
910
Michal Vaskod3678892020-05-21 10:06:58 +0200911 assert(src->type == LYXP_SET_NODE_SET);
912
913 trg->type = LYXP_SET_NODE_SET;
914 trg->used = src->used;
915 trg->size = src->used;
916 trg->ctx_pos = src->ctx_pos;
917 trg->ctx_size = src->ctx_size;
918
919 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
920 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
921 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
922 if (src->ht) {
923 trg->ht = lyht_dup(src->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200924 } else {
Michal Vaskod3678892020-05-21 10:06:58 +0200925 trg->ht = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200926 }
927 }
928}
929
930/**
931 * @brief Clear context of all schema nodes.
932 *
933 * @param[in] set Set to clear.
934 */
935static void
936set_scnode_clear_ctx(struct lyxp_set *set)
937{
938 uint32_t i;
939
940 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +0100941 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
942 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
943 } else if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_START) {
944 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200945 }
946 }
947}
948
949/**
950 * @brief Remove a node from a set. Removing last node changes
951 * set into LYXP_SET_EMPTY. Context position aware.
952 *
953 * @param[in] set Set to use.
954 * @param[in] idx Index from @p set of the node to be removed.
955 */
956static void
957set_remove_node(struct lyxp_set *set, uint32_t idx)
958{
959 assert(set && (set->type == LYXP_SET_NODE_SET));
960 assert(idx < set->used);
961
962 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
963
964 --set->used;
965 if (set->used) {
966 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
967 (set->used - idx) * sizeof *set->val.nodes);
968 } else {
Michal Vaskod3678892020-05-21 10:06:58 +0200969 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200970 }
971}
972
973/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100974 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200975 *
976 * @param[in] set Set to use.
977 * @param[in] idx Index from @p set of the node to be removed.
978 */
979static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100980set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200981{
982 assert(set && (set->type == LYXP_SET_NODE_SET));
983 assert(idx < set->used);
984
Michal Vasko2caefc12019-11-14 16:07:56 +0100985 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
986 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
987 }
988 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200989}
990
991/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100992 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200993 * set into LYXP_SET_EMPTY. Context position aware.
994 *
995 * @param[in] set Set to consolidate.
996 */
997static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100998set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200999{
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02001000 uint16_t i, orig_used, end = 0;
Michal Vasko57eab132019-09-24 11:46:26 +02001001 int32_t start;
1002
Michal Vaskod3678892020-05-21 10:06:58 +02001003 assert(set);
Michal Vasko57eab132019-09-24 11:46:26 +02001004
1005 orig_used = set->used;
1006 set->used = 0;
Michal Vaskod989ba02020-08-24 10:59:24 +02001007 for (i = 0; i < orig_used; ) {
Michal Vasko57eab132019-09-24 11:46:26 +02001008 start = -1;
1009 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001010 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001011 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001012 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001013 end = i;
1014 ++i;
1015 break;
1016 }
1017
1018 ++i;
1019 if (i == orig_used) {
1020 end = i;
1021 }
1022 } while (i < orig_used);
1023
1024 if (start > -1) {
1025 /* move the whole chunk of valid nodes together */
1026 if (set->used != (unsigned)start) {
1027 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1028 }
1029 set->used += end - start;
1030 }
1031 }
Michal Vasko57eab132019-09-24 11:46:26 +02001032}
1033
1034/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001035 * @brief Check for duplicates in a node set.
1036 *
1037 * @param[in] set Set to check.
1038 * @param[in] node Node to look for in @p set.
1039 * @param[in] node_type Type of @p node.
1040 * @param[in] skip_idx Index from @p set to skip.
1041 * @return LY_ERR
1042 */
1043static LY_ERR
1044set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1045{
1046 uint32_t i;
1047
Michal Vasko2caefc12019-11-14 16:07:56 +01001048 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001049 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1050 }
1051
1052 for (i = 0; i < set->used; ++i) {
1053 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1054 continue;
1055 }
1056
1057 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1058 return LY_EEXIST;
1059 }
1060 }
1061
1062 return LY_SUCCESS;
1063}
1064
Radek Krejci857189e2020-09-01 13:26:36 +02001065ly_bool
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001066lyxp_set_scnode_contains(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx,
1067 uint32_t *index_p)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001068{
1069 uint32_t i;
1070
1071 for (i = 0; i < set->used; ++i) {
1072 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1073 continue;
1074 }
1075
1076 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001077 if (index_p) {
1078 *index_p = i;
1079 }
1080 return 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001081 }
1082 }
1083
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001084 return 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001085}
1086
Michal Vaskoecd62de2019-11-13 12:35:11 +01001087void
1088lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001089{
1090 uint32_t orig_used, i, j;
1091
Michal Vaskod3678892020-05-21 10:06:58 +02001092 assert((set1->type == LYXP_SET_SCNODE_SET) && (set2->type == LYXP_SET_SCNODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001093
Michal Vaskod3678892020-05-21 10:06:58 +02001094 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001095 return;
1096 }
1097
Michal Vaskod3678892020-05-21 10:06:58 +02001098 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001099 memcpy(set1, set2, sizeof *set1);
1100 return;
1101 }
1102
1103 if (set1->used + set2->used > set1->size) {
1104 set1->size = set1->used + set2->used;
1105 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1106 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1107 }
1108
1109 orig_used = set1->used;
1110
1111 for (i = 0; i < set2->used; ++i) {
1112 for (j = 0; j < orig_used; ++j) {
1113 /* detect duplicities */
1114 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1115 break;
1116 }
1117 }
1118
1119 if (j == orig_used) {
1120 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1121 ++set1->used;
1122 }
1123 }
1124
Michal Vaskod3678892020-05-21 10:06:58 +02001125 lyxp_set_free_content(set2);
1126 set2->type = LYXP_SET_SCNODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001127}
1128
1129/**
1130 * @brief Insert a node into a set. Context position aware.
1131 *
1132 * @param[in] set Set to use.
1133 * @param[in] node Node to insert to @p set.
1134 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1135 * @param[in] node_type Node type of @p node.
1136 * @param[in] idx Index in @p set to insert into.
1137 */
1138static void
1139set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1140{
Michal Vaskod3678892020-05-21 10:06:58 +02001141 assert(set && (set->type == LYXP_SET_NODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001142
Michal Vaskod3678892020-05-21 10:06:58 +02001143 if (!set->size) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001144 /* first item */
1145 if (idx) {
1146 /* no real harm done, but it is a bug */
1147 LOGINT(set->ctx);
1148 idx = 0;
1149 }
1150 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1151 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1152 set->type = LYXP_SET_NODE_SET;
1153 set->used = 0;
1154 set->size = LYXP_SET_SIZE_START;
1155 set->ctx_pos = 1;
1156 set->ctx_size = 1;
1157 set->ht = NULL;
1158 } else {
1159 /* not an empty set */
1160 if (set->used == set->size) {
1161
1162 /* set is full */
1163 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1164 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1165 set->size += LYXP_SET_SIZE_STEP;
1166 }
1167
1168 if (idx > set->used) {
1169 LOGINT(set->ctx);
1170 idx = set->used;
1171 }
1172
1173 /* make space for the new node */
1174 if (idx < set->used) {
1175 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1176 }
1177 }
1178
1179 /* finally assign the value */
1180 set->val.nodes[idx].node = (struct lyd_node *)node;
1181 set->val.nodes[idx].type = node_type;
1182 set->val.nodes[idx].pos = pos;
1183 ++set->used;
1184
Michal Vasko2caefc12019-11-14 16:07:56 +01001185 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1186 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1187 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001188}
1189
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001190LY_ERR
1191lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, uint32_t *index_p)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001192{
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001193 uint32_t index;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001194
1195 assert(set->type == LYXP_SET_SCNODE_SET);
1196
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001197 if (lyxp_set_scnode_contains(set, node, node_type, -1, &index)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001198 set->val.scnodes[index].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001199 } else {
1200 if (set->used == set->size) {
1201 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001202 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), LY_EMEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001203 set->size += LYXP_SET_SIZE_STEP;
1204 }
1205
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001206 index = set->used;
1207 set->val.scnodes[index].scnode = (struct lysc_node *)node;
1208 set->val.scnodes[index].type = node_type;
Radek Krejcif13b87b2020-12-01 22:02:17 +01001209 set->val.scnodes[index].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001210 ++set->used;
1211 }
1212
Radek Krejciaa6b53f2020-08-27 15:19:03 +02001213 if (index_p) {
1214 *index_p = index;
1215 }
1216
1217 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001218}
1219
1220/**
1221 * @brief Replace a node in a set with another. Context position aware.
1222 *
1223 * @param[in] set Set to use.
1224 * @param[in] node Node to insert to @p set.
1225 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1226 * @param[in] node_type Node type of @p node.
1227 * @param[in] idx Index in @p set of the node to replace.
1228 */
1229static void
1230set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1231{
1232 assert(set && (idx < set->used));
1233
Michal Vasko2caefc12019-11-14 16:07:56 +01001234 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1235 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1236 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001237 set->val.nodes[idx].node = (struct lyd_node *)node;
1238 set->val.nodes[idx].type = node_type;
1239 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001240 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1241 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1242 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001243}
1244
1245/**
1246 * @brief Set all nodes with ctx 1 to a new unique context value.
1247 *
1248 * @param[in] set Set to modify.
1249 * @return New context value.
1250 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001251static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001252set_scnode_new_in_ctx(struct lyxp_set *set)
1253{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001254 uint32_t i;
1255 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001256
1257 assert(set->type == LYXP_SET_SCNODE_SET);
1258
Radek Krejcif13b87b2020-12-01 22:02:17 +01001259 ret_ctx = LYXP_SET_SCNODE_ATOM_PRED_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001260retry:
1261 for (i = 0; i < set->used; ++i) {
1262 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1263 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1264 goto retry;
1265 }
1266 }
1267 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01001268 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001269 set->val.scnodes[i].in_ctx = ret_ctx;
1270 }
1271 }
1272
1273 return ret_ctx;
1274}
1275
1276/**
1277 * @brief Get unique @p node position in the data.
1278 *
1279 * @param[in] node Node to find.
1280 * @param[in] node_type Node type of @p node.
1281 * @param[in] root Root node.
1282 * @param[in] root_type Type of the XPath @p root node.
1283 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1284 * be used to increase efficiency and start the DFS from this node.
1285 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1286 * @return Node position.
1287 */
1288static uint32_t
1289get_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 +02001290 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001291{
Michal Vasko56daf732020-08-10 10:57:18 +02001292 const struct lyd_node *elem = NULL, *top_sibling;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001293 uint32_t pos = 1;
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001294 ly_bool found = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001295
1296 assert(prev && prev_pos && !root->prev->next);
1297
1298 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1299 return 0;
1300 }
1301
1302 if (*prev) {
1303 /* start from the previous element instead from the root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001304 pos = *prev_pos;
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001305 for (top_sibling = *prev; top_sibling->parent; top_sibling = lyd_parent(top_sibling)) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001306 goto dfs_search;
1307 }
1308
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001309 LY_LIST_FOR(root, top_sibling) {
Michal Vasko56daf732020-08-10 10:57:18 +02001310 LYD_TREE_DFS_BEGIN(top_sibling, elem) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001311dfs_search:
Michal Vasko56daf732020-08-10 10:57:18 +02001312 if (*prev && !elem) {
1313 /* resume previous DFS */
1314 elem = LYD_TREE_DFS_next = (struct lyd_node *)*prev;
1315 LYD_TREE_DFS_continue = 0;
1316 }
1317
Michal Vasko03ff5a72019-09-11 13:49:33 +02001318 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
Michal Vasko56daf732020-08-10 10:57:18 +02001319 /* skip */
1320 LYD_TREE_DFS_continue = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001321 } else {
Michal Vasko56daf732020-08-10 10:57:18 +02001322 if (elem == node) {
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001323 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001324 break;
1325 }
Michal Vasko56daf732020-08-10 10:57:18 +02001326 ++pos;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001327 }
Michal Vasko56daf732020-08-10 10:57:18 +02001328
1329 LYD_TREE_DFS_END(top_sibling, elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001330 }
1331
1332 /* node found */
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001333 if (found) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001334 break;
1335 }
1336 }
1337
Michal Vaskofb6c9dd2020-11-18 18:18:47 +01001338 if (!found) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001339 if (!(*prev)) {
1340 /* we went from root and failed to find it, cannot be */
Michal Vaskob7be7a82020-08-20 09:09:04 +02001341 LOGINT(LYD_CTX(node));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001342 return 0;
1343 } else {
Michal Vasko56daf732020-08-10 10:57:18 +02001344 /* start the search again from the beginning */
1345 *prev = root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001346
Michal Vasko56daf732020-08-10 10:57:18 +02001347 top_sibling = root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001348 pos = 1;
1349 goto dfs_search;
1350 }
1351 }
1352
1353 /* remember the last found node for next time */
1354 *prev = node;
1355 *prev_pos = pos;
1356
1357 return pos;
1358}
1359
1360/**
1361 * @brief Assign (fill) missing node positions.
1362 *
1363 * @param[in] set Set to fill positions in.
1364 * @param[in] root Context root node.
1365 * @param[in] root_type Context root type.
1366 * @return LY_ERR
1367 */
1368static LY_ERR
1369set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1370{
1371 const struct lyd_node *prev = NULL, *tmp_node;
1372 uint32_t i, tmp_pos = 0;
1373
1374 for (i = 0; i < set->used; ++i) {
1375 if (!set->val.nodes[i].pos) {
1376 tmp_node = NULL;
1377 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001378 case LYXP_NODE_META:
1379 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001380 if (!tmp_node) {
1381 LOGINT_RET(root->schema->module->ctx);
1382 }
Radek Krejcif13b87b2020-12-01 22:02:17 +01001383 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001384 case LYXP_NODE_ELEM:
1385 case LYXP_NODE_TEXT:
1386 if (!tmp_node) {
1387 tmp_node = set->val.nodes[i].node;
1388 }
1389 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1390 break;
1391 default:
1392 /* all roots have position 0 */
1393 break;
1394 }
1395 }
1396 }
1397
1398 return LY_SUCCESS;
1399}
1400
1401/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001402 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001403 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001404 * @param[in] meta Metadata to use.
1405 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001406 */
1407static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001408get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001409{
1410 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001411 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001412
Michal Vasko9f96a052020-03-10 09:41:45 +01001413 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001414 ++pos;
1415 }
1416
Michal Vasko9f96a052020-03-10 09:41:45 +01001417 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001418 return pos;
1419}
1420
1421/**
1422 * @brief Compare 2 nodes in respect to XPath document order.
1423 *
1424 * @param[in] item1 1st node.
1425 * @param[in] item2 2nd node.
1426 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1427 */
1428static int
1429set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1430{
Michal Vasko9f96a052020-03-10 09:41:45 +01001431 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001432
1433 if (item1->pos < item2->pos) {
1434 return -1;
1435 }
1436
1437 if (item1->pos > item2->pos) {
1438 return 1;
1439 }
1440
1441 /* node positions are equal, the fun case */
1442
1443 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1444 /* special case since text nodes are actually saved as their parents */
1445 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1446 if (item1->type == LYXP_NODE_ELEM) {
1447 assert(item2->type == LYXP_NODE_TEXT);
1448 return -1;
1449 } else {
1450 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1451 return 1;
1452 }
1453 }
1454
Michal Vasko9f96a052020-03-10 09:41:45 +01001455 /* we need meta positions now */
1456 if (item1->type == LYXP_NODE_META) {
1457 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001458 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001459 if (item2->type == LYXP_NODE_META) {
1460 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001461 }
1462
Michal Vasko9f96a052020-03-10 09:41:45 +01001463 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001464 /* check for duplicates */
1465 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001466 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001467 return 0;
1468 }
1469
Michal Vasko9f96a052020-03-10 09:41:45 +01001470 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001471 /* elem is always first, 2nd node is after it */
1472 if (item1->type == LYXP_NODE_ELEM) {
1473 assert(item2->type != LYXP_NODE_ELEM);
1474 return -1;
1475 }
1476
Michal Vasko9f96a052020-03-10 09:41:45 +01001477 /* 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 +02001478 /* 2nd is before 1st */
Michal Vasko69730152020-10-09 16:30:07 +02001479 if (((item1->type == LYXP_NODE_TEXT) &&
1480 ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META))) ||
1481 ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM)) ||
1482 (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META)) &&
1483 (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001484 return 1;
1485 }
1486
Michal Vasko9f96a052020-03-10 09:41:45 +01001487 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001488 /* 2nd is after 1st */
1489 return -1;
1490}
1491
1492/**
1493 * @brief Set cast for comparisons.
1494 *
1495 * @param[in] trg Target set to cast source into.
1496 * @param[in] src Source set.
1497 * @param[in] type Target set type.
1498 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001499 * @return LY_ERR
1500 */
1501static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001502set_comp_cast(struct lyxp_set *trg, struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001503{
1504 assert(src->type == LYXP_SET_NODE_SET);
1505
1506 set_init(trg, src);
1507
1508 /* insert node into target set */
1509 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1510
1511 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001512 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001513}
1514
Michal Vasko4c7763f2020-07-27 17:40:37 +02001515/**
1516 * @brief Set content canonization for comparisons.
1517 *
1518 * @param[in] trg Target set to put the canononized source into.
1519 * @param[in] src Source set.
1520 * @param[in] xp_node Source XPath node/meta to use for canonization.
1521 * @return LY_ERR
1522 */
1523static LY_ERR
1524set_comp_canonize(struct lyxp_set *trg, const struct lyxp_set *src, const struct lyxp_set_node *xp_node)
1525{
Michal Vaskofeca4fb2020-10-05 08:58:40 +02001526 const struct lysc_type *type = NULL;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001527 struct lyd_value val;
1528 struct ly_err_item *err = NULL;
1529 char *str, *ptr;
Michal Vasko4c7763f2020-07-27 17:40:37 +02001530 LY_ERR rc;
1531
1532 /* is there anything to canonize even? */
1533 if ((src->type == LYXP_SET_NUMBER) || (src->type == LYXP_SET_STRING)) {
1534 /* do we have a type to use for canonization? */
1535 if ((xp_node->type == LYXP_NODE_ELEM) && (xp_node->node->schema->nodetype & LYD_NODE_TERM)) {
1536 type = ((struct lyd_node_term *)xp_node->node)->value.realtype;
1537 } else if (xp_node->type == LYXP_NODE_META) {
1538 type = ((struct lyd_meta *)xp_node->node)->value.realtype;
1539 }
1540 }
1541 if (!type) {
1542 goto fill;
1543 }
1544
1545 if (src->type == LYXP_SET_NUMBER) {
1546 /* canonize number */
1547 if (asprintf(&str, "%Lf", src->val.num) == -1) {
1548 LOGMEM(src->ctx);
1549 return LY_EMEM;
1550 }
1551 } else {
1552 /* canonize string */
1553 str = strdup(src->val.str);
1554 }
1555
1556 /* ignore errors, the value may not satisfy schema constraints */
Michal Vasko0fdb0d92020-11-06 17:25:50 +01001557 rc = type->plugin->store(src->ctx, type, str, strlen(str), LY_TYPE_STORE_DYNAMIC, src->format, src->prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +01001558 LYD_HINT_DATA, xp_node->node->schema, &val, NULL, &err);
Michal Vasko4c7763f2020-07-27 17:40:37 +02001559 ly_err_free(err);
1560 if (rc) {
1561 /* invalid value */
1562 free(str);
1563 goto fill;
1564 }
1565
Michal Vasko4c7763f2020-07-27 17:40:37 +02001566 /* use the canonized value */
1567 set_init(trg, src);
1568 trg->type = src->type;
1569 if (src->type == LYXP_SET_NUMBER) {
Michal Vasko0fdb0d92020-11-06 17:25:50 +01001570 trg->val.num = strtold(val.canonical, &ptr);
Michal Vasko4c7763f2020-07-27 17:40:37 +02001571 LY_CHECK_ERR_RET(ptr[0], LOGINT(src->ctx), LY_EINT);
1572 } else {
Michal Vasko0fdb0d92020-11-06 17:25:50 +01001573 trg->val.str = strdup(val.canonical);
Michal Vasko4c7763f2020-07-27 17:40:37 +02001574 }
1575 type->plugin->free(src->ctx, &val);
1576 return LY_SUCCESS;
1577
1578fill:
1579 /* no canonization needed/possible */
1580 set_fill_set(trg, src);
1581 return LY_SUCCESS;
1582}
1583
Michal Vasko03ff5a72019-09-11 13:49:33 +02001584#ifndef NDEBUG
1585
1586/**
1587 * @brief Bubble sort @p set into XPath document order.
1588 * Context position aware. Unused in the 'Release' build target.
1589 *
1590 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001591 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1592 */
1593static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001594set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001595{
1596 uint32_t i, j;
Radek Krejci1deb5be2020-08-26 16:43:36 +02001597 int ret = 0, cmp;
Radek Krejci857189e2020-09-01 13:26:36 +02001598 ly_bool inverted, change;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001599 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001600 struct lyxp_set_node item;
1601 struct lyxp_set_hash_node hnode;
1602 uint64_t hash;
1603
Michal Vasko3cf8fbf2020-05-27 15:21:21 +02001604 if ((set->type != LYXP_SET_NODE_SET) || (set->used < 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001605 return 0;
1606 }
1607
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001608 /* find first top-level node to be used as anchor for positions */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001609 for (root = set->cur_node; root->parent; root = (const struct lyd_node *)root->parent) {}
Michal Vaskod989ba02020-08-24 10:59:24 +02001610 for ( ; root->prev->next; root = root->prev) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001611
1612 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001613 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001614 return -1;
1615 }
1616
1617 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1618 print_set_debug(set);
1619
1620 for (i = 0; i < set->used; ++i) {
1621 inverted = 0;
1622 change = 0;
1623
1624 for (j = 1; j < set->used - i; ++j) {
1625 /* compare node positions */
1626 if (inverted) {
1627 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1628 } else {
1629 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1630 }
1631
1632 /* swap if needed */
1633 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1634 change = 1;
1635
1636 item = set->val.nodes[j - 1];
1637 set->val.nodes[j - 1] = set->val.nodes[j];
1638 set->val.nodes[j] = item;
1639 } else {
1640 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1641 inverted = !inverted;
1642 }
1643 }
1644
1645 ++ret;
1646
1647 if (!change) {
1648 break;
1649 }
1650 }
1651
1652 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1653 print_set_debug(set);
1654
1655 /* check node hashes */
1656 if (set->used >= LYD_HT_MIN_ITEMS) {
1657 assert(set->ht);
1658 for (i = 0; i < set->used; ++i) {
1659 hnode.node = set->val.nodes[i].node;
1660 hnode.type = set->val.nodes[i].type;
1661
1662 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1663 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1664 hash = dict_hash_multi(hash, NULL, 0);
1665
1666 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1667 }
1668 }
1669
1670 return ret - 1;
1671}
1672
1673/**
1674 * @brief Remove duplicate entries in a sorted node set.
1675 *
1676 * @param[in] set Sorted set to check.
1677 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1678 */
1679static LY_ERR
1680set_sorted_dup_node_clean(struct lyxp_set *set)
1681{
1682 uint32_t i = 0;
1683 LY_ERR ret = LY_SUCCESS;
1684
1685 if (set->used > 1) {
1686 while (i < set->used - 1) {
Michal Vasko69730152020-10-09 16:30:07 +02001687 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node) &&
1688 (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001689 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001690 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001691 }
Michal Vasko57eab132019-09-24 11:46:26 +02001692 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001693 }
1694 }
1695
Michal Vasko2caefc12019-11-14 16:07:56 +01001696 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001697 return ret;
1698}
1699
1700#endif
1701
1702/**
1703 * @brief Merge 2 sorted sets into one.
1704 *
1705 * @param[in,out] trg Set to merge into. Duplicates are removed.
1706 * @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 +02001707 * @return LY_ERR
1708 */
1709static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001710set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001711{
1712 uint32_t i, j, k, count, dup_count;
1713 int cmp;
1714 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001715
Michal Vaskod3678892020-05-21 10:06:58 +02001716 if ((trg->type != LYXP_SET_NODE_SET) || (src->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001717 return LY_EINVAL;
1718 }
1719
Michal Vaskod3678892020-05-21 10:06:58 +02001720 if (!src->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001721 return LY_SUCCESS;
Michal Vaskod3678892020-05-21 10:06:58 +02001722 } else if (!trg->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001723 set_fill_set(trg, src);
Michal Vaskod3678892020-05-21 10:06:58 +02001724 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001725 return LY_SUCCESS;
1726 }
1727
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001728 /* find first top-level node to be used as anchor for positions */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001729 for (root = trg->cur_node; root->parent; root = (const struct lyd_node *)root->parent) {}
Michal Vaskod989ba02020-08-24 10:59:24 +02001730 for ( ; root->prev->next; root = root->prev) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02001731
1732 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001733 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001734 return LY_EINT;
1735 }
1736
1737#ifndef NDEBUG
1738 LOGDBG(LY_LDGXPATH, "MERGE target");
1739 print_set_debug(trg);
1740 LOGDBG(LY_LDGXPATH, "MERGE source");
1741 print_set_debug(src);
1742#endif
1743
1744 /* make memory for the merge (duplicates are not detected yet, so space
1745 * will likely be wasted on them, too bad) */
1746 if (trg->size - trg->used < src->used) {
1747 trg->size = trg->used + src->used;
1748
1749 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1750 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1751 }
1752
1753 i = 0;
1754 j = 0;
1755 count = 0;
1756 dup_count = 0;
1757 do {
1758 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1759 if (!cmp) {
1760 if (!count) {
1761 /* duplicate, just skip it */
1762 ++i;
1763 ++j;
1764 } else {
1765 /* we are copying something already, so let's copy the duplicate too,
1766 * we are hoping that afterwards there are some more nodes to
1767 * copy and this way we can copy them all together */
1768 ++count;
1769 ++dup_count;
1770 ++i;
1771 ++j;
1772 }
1773 } else if (cmp < 0) {
1774 /* inserting src node into trg, just remember it for now */
1775 ++count;
1776 ++i;
1777
1778 /* insert the hash now */
1779 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1780 } else if (count) {
1781copy_nodes:
1782 /* time to actually copy the nodes, we have found the largest block of nodes */
1783 memmove(&trg->val.nodes[j + (count - dup_count)],
1784 &trg->val.nodes[j],
1785 (trg->used - j) * sizeof *trg->val.nodes);
1786 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1787
1788 trg->used += count - dup_count;
1789 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1790 j += count - dup_count;
1791
1792 count = 0;
1793 dup_count = 0;
1794 } else {
1795 ++j;
1796 }
1797 } while ((i < src->used) && (j < trg->used));
1798
1799 if ((i < src->used) || count) {
1800 /* insert all the hashes first */
1801 for (k = i; k < src->used; ++k) {
1802 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1803 }
1804
1805 /* loop ended, but we need to copy something at trg end */
1806 count += src->used - i;
1807 i = src->used;
1808 goto copy_nodes;
1809 }
1810
1811 /* we are inserting hashes before the actual node insert, which causes
1812 * situations when there were initially not enough items for a hash table,
1813 * but even after some were inserted, hash table was not created (during
1814 * insertion the number of items is not updated yet) */
1815 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1816 set_insert_node_hash(trg, NULL, 0);
1817 }
1818
1819#ifndef NDEBUG
1820 LOGDBG(LY_LDGXPATH, "MERGE result");
1821 print_set_debug(trg);
1822#endif
1823
Michal Vaskod3678892020-05-21 10:06:58 +02001824 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001825 return LY_SUCCESS;
1826}
1827
1828/*
1829 * (re)parse functions
1830 *
1831 * Parse functions parse the expression into
1832 * tokens (syntactic analysis).
1833 *
1834 * Reparse functions perform semantic analysis
1835 * (do not save the result, just a check) of
1836 * the expression and fill repeat indices.
1837 */
1838
Michal Vasko14676352020-05-29 11:35:55 +02001839LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02001840lyxp_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 +02001841{
Michal Vasko004d3152020-06-11 19:59:22 +02001842 if (exp->used == tok_idx) {
Michal Vasko14676352020-05-29 11:35:55 +02001843 if (ctx) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001844 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1845 }
Michal Vasko14676352020-05-29 11:35:55 +02001846 return LY_EINCOMPLETE;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001847 }
1848
Michal Vasko004d3152020-06-11 19:59:22 +02001849 if (want_tok && (exp->tokens[tok_idx] != want_tok)) {
Michal Vasko14676352020-05-29 11:35:55 +02001850 if (ctx) {
Michal Vasko0b468e62020-10-19 09:33:04 +02001851 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK2, lyxp_print_token(exp->tokens[tok_idx]),
1852 &exp->expr[exp->tok_pos[tok_idx]], lyxp_print_token(want_tok));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001853 }
Michal Vasko14676352020-05-29 11:35:55 +02001854 return LY_ENOT;
1855 }
1856
1857 return LY_SUCCESS;
1858}
1859
Michal Vasko004d3152020-06-11 19:59:22 +02001860LY_ERR
1861lyxp_next_token(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_token want_tok)
1862{
1863 LY_CHECK_RET(lyxp_check_token(ctx, exp, *tok_idx, want_tok));
1864
1865 /* skip the token */
1866 ++(*tok_idx);
1867
1868 return LY_SUCCESS;
1869}
1870
Michal Vasko14676352020-05-29 11:35:55 +02001871/* just like lyxp_check_token() but tests for 2 tokens */
1872static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02001873exp_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 +02001874 enum lyxp_token want_tok2)
Michal Vasko14676352020-05-29 11:35:55 +02001875{
Michal Vasko004d3152020-06-11 19:59:22 +02001876 if (exp->used == tok_idx) {
Michal Vasko14676352020-05-29 11:35:55 +02001877 if (ctx) {
1878 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1879 }
1880 return LY_EINCOMPLETE;
1881 }
1882
Michal Vasko004d3152020-06-11 19:59:22 +02001883 if ((exp->tokens[tok_idx] != want_tok1) && (exp->tokens[tok_idx] != want_tok2)) {
Michal Vasko14676352020-05-29 11:35:55 +02001884 if (ctx) {
Michal Vasko0b468e62020-10-19 09:33:04 +02001885 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[tok_idx]),
1886 &exp->expr[exp->tok_pos[tok_idx]]);
Michal Vasko14676352020-05-29 11:35:55 +02001887 }
1888 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001889 }
1890
1891 return LY_SUCCESS;
1892}
1893
1894/**
1895 * @brief Stack operation push on the repeat array.
1896 *
1897 * @param[in] exp Expression to use.
Michal Vasko004d3152020-06-11 19:59:22 +02001898 * @param[in] tok_idx Position in the expresion \p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001899 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1900 */
1901static void
Michal Vasko004d3152020-06-11 19:59:22 +02001902exp_repeat_push(struct lyxp_expr *exp, uint16_t tok_idx, uint16_t repeat_op_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001903{
1904 uint16_t i;
1905
Michal Vasko004d3152020-06-11 19:59:22 +02001906 if (exp->repeat[tok_idx]) {
Radek Krejci1e008d22020-08-17 11:37:37 +02001907 for (i = 0; exp->repeat[tok_idx][i]; ++i) {}
Michal Vasko004d3152020-06-11 19:59:22 +02001908 exp->repeat[tok_idx] = realloc(exp->repeat[tok_idx], (i + 2) * sizeof *exp->repeat[tok_idx]);
1909 LY_CHECK_ERR_RET(!exp->repeat[tok_idx], LOGMEM(NULL), );
1910 exp->repeat[tok_idx][i] = repeat_op_idx;
1911 exp->repeat[tok_idx][i + 1] = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001912 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02001913 exp->repeat[tok_idx] = calloc(2, sizeof *exp->repeat[tok_idx]);
1914 LY_CHECK_ERR_RET(!exp->repeat[tok_idx], LOGMEM(NULL), );
1915 exp->repeat[tok_idx][0] = repeat_op_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001916 }
1917}
1918
1919/**
1920 * @brief Reparse Predicate. Logs directly on error.
1921 *
1922 * [7] Predicate ::= '[' Expr ']'
1923 *
1924 * @param[in] ctx Context for logging.
1925 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02001926 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001927 * @return LY_ERR
1928 */
1929static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02001930reparse_predicate(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001931{
1932 LY_ERR rc;
1933
Michal Vasko004d3152020-06-11 19:59:22 +02001934 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_BRACK1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001935 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02001936 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001937
Michal Vasko004d3152020-06-11 19:59:22 +02001938 rc = reparse_or_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001939 LY_CHECK_RET(rc);
1940
Michal Vasko004d3152020-06-11 19:59:22 +02001941 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_BRACK2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001942 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02001943 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001944
1945 return LY_SUCCESS;
1946}
1947
1948/**
1949 * @brief Reparse RelativeLocationPath. Logs directly on error.
1950 *
1951 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1952 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1953 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1954 *
1955 * @param[in] ctx Context for logging.
1956 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02001957 * @param[in] tok_idx Position in the expression \p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001958 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1959 */
1960static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02001961reparse_relative_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001962{
1963 LY_ERR rc;
1964
Michal Vasko004d3152020-06-11 19:59:22 +02001965 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001966 LY_CHECK_RET(rc);
1967
1968 goto step;
1969 do {
1970 /* '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02001971 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001972
Michal Vasko004d3152020-06-11 19:59:22 +02001973 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001974 LY_CHECK_RET(rc);
1975step:
1976 /* Step */
Michal Vasko004d3152020-06-11 19:59:22 +02001977 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001978 case LYXP_TOKEN_DOT:
Michal Vasko004d3152020-06-11 19:59:22 +02001979 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001980 break;
1981
1982 case LYXP_TOKEN_DDOT:
Michal Vasko004d3152020-06-11 19:59:22 +02001983 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001984 break;
1985
1986 case LYXP_TOKEN_AT:
Michal Vasko004d3152020-06-11 19:59:22 +02001987 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001988
Michal Vasko004d3152020-06-11 19:59:22 +02001989 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001990 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02001991 if ((exp->tokens[*tok_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*tok_idx] != LYXP_TOKEN_NODETYPE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001992 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko69730152020-10-09 16:30:07 +02001993 lyxp_print_token(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001994 return LY_EVALID;
1995 }
Radek Krejci0f969882020-08-21 16:56:47 +02001996 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001997 case LYXP_TOKEN_NAMETEST:
Michal Vasko004d3152020-06-11 19:59:22 +02001998 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001999 goto reparse_predicate;
2000 break;
2001
2002 case LYXP_TOKEN_NODETYPE:
Michal Vasko004d3152020-06-11 19:59:22 +02002003 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002004
2005 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02002006 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002007 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002008 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002009
2010 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02002011 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002012 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002013 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002014
2015reparse_predicate:
2016 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002017 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
2018 rc = reparse_predicate(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002019 LY_CHECK_RET(rc);
2020 }
2021 break;
2022 default:
2023 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko69730152020-10-09 16:30:07 +02002024 lyxp_print_token(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002025 return LY_EVALID;
2026 }
Michal Vasko004d3152020-06-11 19:59:22 +02002027 } while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02002028
2029 return LY_SUCCESS;
2030}
2031
2032/**
2033 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
2034 *
2035 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
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.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002040 * @return LY_ERR
2041 */
2042static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002043reparse_absolute_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002044{
2045 LY_ERR rc;
2046
Michal Vasko004d3152020-06-11 19:59:22 +02002047 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 +02002048
2049 /* '/' RelativeLocationPath? */
Michal Vasko004d3152020-06-11 19:59:22 +02002050 if (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002051 /* '/' */
Michal Vasko004d3152020-06-11 19:59:22 +02002052 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002053
Michal Vasko004d3152020-06-11 19:59:22 +02002054 if (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002055 return LY_SUCCESS;
2056 }
Michal Vasko004d3152020-06-11 19:59:22 +02002057 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002058 case LYXP_TOKEN_DOT:
2059 case LYXP_TOKEN_DDOT:
2060 case LYXP_TOKEN_AT:
2061 case LYXP_TOKEN_NAMETEST:
2062 case LYXP_TOKEN_NODETYPE:
Michal Vasko004d3152020-06-11 19:59:22 +02002063 rc = reparse_relative_location_path(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002064 LY_CHECK_RET(rc);
Radek Krejci0f969882020-08-21 16:56:47 +02002065 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002066 default:
2067 break;
2068 }
2069
Michal Vasko03ff5a72019-09-11 13:49:33 +02002070 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02002071 /* '//' RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002072 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002073
Michal Vasko004d3152020-06-11 19:59:22 +02002074 rc = reparse_relative_location_path(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002075 LY_CHECK_RET(rc);
2076 }
2077
2078 return LY_SUCCESS;
2079}
2080
2081/**
2082 * @brief Reparse FunctionCall. Logs directly on error.
2083 *
2084 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2085 *
2086 * @param[in] ctx Context for logging.
2087 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002088 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002089 * @return LY_ERR
2090 */
2091static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002092reparse_function_call(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002093{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002094 int8_t min_arg_count = -1;
2095 uint32_t arg_count, max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002096 uint16_t func_tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002097 LY_ERR rc;
2098
Michal Vasko004d3152020-06-11 19:59:22 +02002099 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002100 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002101 func_tok_idx = *tok_idx;
2102 switch (exp->tok_len[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002103 case 3:
Michal Vasko004d3152020-06-11 19:59:22 +02002104 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "not", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002105 min_arg_count = 1;
2106 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002107 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "sum", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002108 min_arg_count = 1;
2109 max_arg_count = 1;
2110 }
2111 break;
2112 case 4:
Michal Vasko004d3152020-06-11 19:59:22 +02002113 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "lang", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002114 min_arg_count = 1;
2115 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002116 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "last", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002117 min_arg_count = 0;
2118 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002119 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "name", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002120 min_arg_count = 0;
2121 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002122 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "true", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002123 min_arg_count = 0;
2124 max_arg_count = 0;
2125 }
2126 break;
2127 case 5:
Michal Vasko004d3152020-06-11 19:59:22 +02002128 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "count", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002129 min_arg_count = 1;
2130 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002131 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "false", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002132 min_arg_count = 0;
2133 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002134 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "floor", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002135 min_arg_count = 1;
2136 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002137 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "round", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002138 min_arg_count = 1;
2139 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002140 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002141 min_arg_count = 1;
2142 max_arg_count = 1;
2143 }
2144 break;
2145 case 6:
Michal Vasko004d3152020-06-11 19:59:22 +02002146 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "concat", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002147 min_arg_count = 2;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002148 max_arg_count = UINT32_MAX;
Michal Vasko004d3152020-06-11 19:59:22 +02002149 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "number", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002150 min_arg_count = 0;
2151 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002152 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002153 min_arg_count = 0;
2154 max_arg_count = 1;
2155 }
2156 break;
2157 case 7:
Michal Vasko004d3152020-06-11 19:59:22 +02002158 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "boolean", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002159 min_arg_count = 1;
2160 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002161 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "ceiling", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002162 min_arg_count = 1;
2163 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002164 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "current", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002165 min_arg_count = 0;
2166 max_arg_count = 0;
2167 }
2168 break;
2169 case 8:
Michal Vasko004d3152020-06-11 19:59:22 +02002170 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "contains", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002171 min_arg_count = 2;
2172 max_arg_count = 2;
Michal Vasko004d3152020-06-11 19:59:22 +02002173 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "position", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002174 min_arg_count = 0;
2175 max_arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002176 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "re-match", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002177 min_arg_count = 2;
2178 max_arg_count = 2;
2179 }
2180 break;
2181 case 9:
Michal Vasko004d3152020-06-11 19:59:22 +02002182 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002183 min_arg_count = 2;
2184 max_arg_count = 3;
Michal Vasko004d3152020-06-11 19:59:22 +02002185 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "translate", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002186 min_arg_count = 3;
2187 max_arg_count = 3;
2188 }
2189 break;
2190 case 10:
Michal Vasko004d3152020-06-11 19:59:22 +02002191 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "local-name", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002192 min_arg_count = 0;
2193 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002194 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "enum-value", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002195 min_arg_count = 1;
2196 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002197 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "bit-is-set", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002198 min_arg_count = 2;
2199 max_arg_count = 2;
2200 }
2201 break;
2202 case 11:
Michal Vasko004d3152020-06-11 19:59:22 +02002203 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "starts-with", 11)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002204 min_arg_count = 2;
2205 max_arg_count = 2;
2206 }
2207 break;
2208 case 12:
Michal Vasko004d3152020-06-11 19:59:22 +02002209 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from", 12)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002210 min_arg_count = 2;
2211 max_arg_count = 2;
2212 }
2213 break;
2214 case 13:
Michal Vasko004d3152020-06-11 19:59:22 +02002215 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "namespace-uri", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002216 min_arg_count = 0;
2217 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002218 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string-length", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002219 min_arg_count = 0;
2220 max_arg_count = 1;
2221 }
2222 break;
2223 case 15:
Michal Vasko004d3152020-06-11 19:59:22 +02002224 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "normalize-space", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002225 min_arg_count = 0;
2226 max_arg_count = 1;
Michal Vasko004d3152020-06-11 19:59:22 +02002227 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-after", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002228 min_arg_count = 2;
2229 max_arg_count = 2;
2230 }
2231 break;
2232 case 16:
Michal Vasko004d3152020-06-11 19:59:22 +02002233 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-before", 16)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002234 min_arg_count = 2;
2235 max_arg_count = 2;
2236 }
2237 break;
2238 case 20:
Michal Vasko004d3152020-06-11 19:59:22 +02002239 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from-or-self", 20)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002240 min_arg_count = 2;
2241 max_arg_count = 2;
2242 }
2243 break;
2244 }
2245 if (min_arg_count == -1) {
Michal Vasko004d3152020-06-11 19:59:22 +02002246 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002247 return LY_EINVAL;
2248 }
Michal Vasko004d3152020-06-11 19:59:22 +02002249 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002250
2251 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02002252 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002253 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002254 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002255
2256 /* ( Expr ( ',' Expr )* )? */
2257 arg_count = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002258 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002259 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002260 if (exp->tokens[*tok_idx] != LYXP_TOKEN_PAR2) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002261 ++arg_count;
Michal Vasko004d3152020-06-11 19:59:22 +02002262 rc = reparse_or_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002263 LY_CHECK_RET(rc);
2264 }
Michal Vasko004d3152020-06-11 19:59:22 +02002265 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_COMMA)) {
2266 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002267
2268 ++arg_count;
Michal Vasko004d3152020-06-11 19:59:22 +02002269 rc = reparse_or_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002270 LY_CHECK_RET(rc);
2271 }
2272
2273 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02002274 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002275 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002276 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002277
Radek Krejci857189e2020-09-01 13:26:36 +02002278 if ((arg_count < (uint32_t)min_arg_count) || (arg_count > max_arg_count)) {
Michal Vasko004d3152020-06-11 19:59:22 +02002279 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_tok_idx],
Michal Vasko69730152020-10-09 16:30:07 +02002280 &exp->expr[exp->tok_pos[func_tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002281 return LY_EVALID;
2282 }
2283
2284 return LY_SUCCESS;
2285}
2286
2287/**
2288 * @brief Reparse PathExpr. Logs directly on error.
2289 *
2290 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2291 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2292 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2293 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2294 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2295 *
2296 * @param[in] ctx Context for logging.
2297 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002298 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002299 * @return LY_ERR
2300 */
2301static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002302reparse_path_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002303{
2304 LY_ERR rc;
2305
Michal Vasko004d3152020-06-11 19:59:22 +02002306 if (lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko14676352020-05-29 11:35:55 +02002307 return LY_EVALID;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002308 }
2309
Michal Vasko004d3152020-06-11 19:59:22 +02002310 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002311 case LYXP_TOKEN_PAR1:
2312 /* '(' Expr ')' Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002313 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002314
Michal Vasko004d3152020-06-11 19:59:22 +02002315 rc = reparse_or_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002316 LY_CHECK_RET(rc);
2317
Michal Vasko004d3152020-06-11 19:59:22 +02002318 rc = lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002319 LY_CHECK_RET(rc);
Michal Vasko004d3152020-06-11 19:59:22 +02002320 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002321 goto predicate;
2322 break;
2323 case LYXP_TOKEN_DOT:
2324 case LYXP_TOKEN_DDOT:
2325 case LYXP_TOKEN_AT:
2326 case LYXP_TOKEN_NAMETEST:
2327 case LYXP_TOKEN_NODETYPE:
2328 /* RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002329 rc = reparse_relative_location_path(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002330 LY_CHECK_RET(rc);
2331 break;
2332 case LYXP_TOKEN_FUNCNAME:
2333 /* FunctionCall */
Michal Vasko004d3152020-06-11 19:59:22 +02002334 rc = reparse_function_call(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002335 LY_CHECK_RET(rc);
2336 goto predicate;
2337 break;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002338 case LYXP_TOKEN_OPER_PATH:
2339 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02002340 /* AbsoluteLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002341 rc = reparse_absolute_location_path(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002342 LY_CHECK_RET(rc);
2343 break;
2344 case LYXP_TOKEN_LITERAL:
2345 /* Literal */
Michal Vasko004d3152020-06-11 19:59:22 +02002346 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002347 goto predicate;
2348 break;
2349 case LYXP_TOKEN_NUMBER:
2350 /* Number */
Michal Vasko004d3152020-06-11 19:59:22 +02002351 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002352 goto predicate;
2353 break;
2354 default:
2355 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko69730152020-10-09 16:30:07 +02002356 lyxp_print_token(exp->tokens[*tok_idx]), &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002357 return LY_EVALID;
2358 }
2359
2360 return LY_SUCCESS;
2361
2362predicate:
2363 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02002364 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
2365 rc = reparse_predicate(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002366 LY_CHECK_RET(rc);
2367 }
2368
2369 /* ('/' or '//') RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02002370 if (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002371
2372 /* '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02002373 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002374
Michal Vasko004d3152020-06-11 19:59:22 +02002375 rc = reparse_relative_location_path(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002376 LY_CHECK_RET(rc);
2377 }
2378
2379 return LY_SUCCESS;
2380}
2381
2382/**
2383 * @brief Reparse UnaryExpr. Logs directly on error.
2384 *
2385 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2386 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2387 *
2388 * @param[in] ctx Context for logging.
2389 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002390 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002391 * @return LY_ERR
2392 */
2393static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002394reparse_unary_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002395{
2396 uint16_t prev_exp;
2397 LY_ERR rc;
2398
2399 /* ('-')* */
Michal Vasko004d3152020-06-11 19:59:22 +02002400 prev_exp = *tok_idx;
Michal Vasko69730152020-10-09 16:30:07 +02002401 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2402 (exp->expr[exp->tok_pos[*tok_idx]] == '-')) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002403 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
Michal Vasko004d3152020-06-11 19:59:22 +02002404 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002405 }
2406
2407 /* PathExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002408 prev_exp = *tok_idx;
2409 rc = reparse_path_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002410 LY_CHECK_RET(rc);
2411
2412 /* ('|' PathExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002413 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_UNI)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002414 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
Michal Vasko004d3152020-06-11 19:59:22 +02002415 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002416
Michal Vasko004d3152020-06-11 19:59:22 +02002417 rc = reparse_path_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002418 LY_CHECK_RET(rc);
2419 }
2420
2421 return LY_SUCCESS;
2422}
2423
2424/**
2425 * @brief Reparse AdditiveExpr. Logs directly on error.
2426 *
2427 * [15] AdditiveExpr ::= MultiplicativeExpr
2428 * | AdditiveExpr '+' MultiplicativeExpr
2429 * | AdditiveExpr '-' MultiplicativeExpr
2430 * [16] MultiplicativeExpr ::= UnaryExpr
2431 * | MultiplicativeExpr '*' UnaryExpr
2432 * | MultiplicativeExpr 'div' UnaryExpr
2433 * | MultiplicativeExpr 'mod' UnaryExpr
2434 *
2435 * @param[in] ctx Context for logging.
2436 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002437 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002438 * @return LY_ERR
2439 */
2440static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002441reparse_additive_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002442{
2443 uint16_t prev_add_exp, prev_mul_exp;
2444 LY_ERR rc;
2445
Michal Vasko004d3152020-06-11 19:59:22 +02002446 prev_add_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002447 goto reparse_multiplicative_expr;
2448
2449 /* ('+' / '-' MultiplicativeExpr)* */
Michal Vasko69730152020-10-09 16:30:07 +02002450 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2451 ((exp->expr[exp->tok_pos[*tok_idx]] == '+') || (exp->expr[exp->tok_pos[*tok_idx]] == '-'))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002452 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
Michal Vasko004d3152020-06-11 19:59:22 +02002453 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002454
2455reparse_multiplicative_expr:
2456 /* UnaryExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002457 prev_mul_exp = *tok_idx;
2458 rc = reparse_unary_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002459 LY_CHECK_RET(rc);
2460
2461 /* ('*' / 'div' / 'mod' UnaryExpr)* */
Michal Vasko69730152020-10-09 16:30:07 +02002462 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_MATH) &&
2463 ((exp->expr[exp->tok_pos[*tok_idx]] == '*') || (exp->tok_len[*tok_idx] == 3))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002464 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
Michal Vasko004d3152020-06-11 19:59:22 +02002465 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002466
Michal Vasko004d3152020-06-11 19:59:22 +02002467 rc = reparse_unary_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002468 LY_CHECK_RET(rc);
2469 }
2470 }
2471
2472 return LY_SUCCESS;
2473}
2474
2475/**
2476 * @brief Reparse EqualityExpr. Logs directly on error.
2477 *
2478 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2479 * | EqualityExpr '!=' RelationalExpr
2480 * [14] RelationalExpr ::= AdditiveExpr
2481 * | RelationalExpr '<' AdditiveExpr
2482 * | RelationalExpr '>' AdditiveExpr
2483 * | RelationalExpr '<=' AdditiveExpr
2484 * | RelationalExpr '>=' AdditiveExpr
2485 *
2486 * @param[in] ctx Context for logging.
2487 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02002488 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002489 * @return LY_ERR
2490 */
2491static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002492reparse_equality_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002493{
2494 uint16_t prev_eq_exp, prev_rel_exp;
2495 LY_ERR rc;
2496
Michal Vasko004d3152020-06-11 19:59:22 +02002497 prev_eq_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002498 goto reparse_additive_expr;
2499
2500 /* ('=' / '!=' RelationalExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002501 while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_EQUAL, LYXP_TOKEN_OPER_NEQUAL)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002502 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
Michal Vasko004d3152020-06-11 19:59:22 +02002503 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002504
2505reparse_additive_expr:
2506 /* AdditiveExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002507 prev_rel_exp = *tok_idx;
2508 rc = reparse_additive_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002509 LY_CHECK_RET(rc);
2510
2511 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002512 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_COMP)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002513 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
Michal Vasko004d3152020-06-11 19:59:22 +02002514 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002515
Michal Vasko004d3152020-06-11 19:59:22 +02002516 rc = reparse_additive_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002517 LY_CHECK_RET(rc);
2518 }
2519 }
2520
2521 return LY_SUCCESS;
2522}
2523
2524/**
2525 * @brief Reparse OrExpr. Logs directly on error.
2526 *
2527 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2528 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
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.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002533 * @return LY_ERR
2534 */
2535static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02002536reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *tok_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002537{
2538 uint16_t prev_or_exp, prev_and_exp;
2539 LY_ERR rc;
2540
Michal Vasko004d3152020-06-11 19:59:22 +02002541 prev_or_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002542 goto reparse_equality_expr;
2543
2544 /* ('or' AndExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002545 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 +02002546 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
Michal Vasko004d3152020-06-11 19:59:22 +02002547 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002548
2549reparse_equality_expr:
2550 /* EqualityExpr */
Michal Vasko004d3152020-06-11 19:59:22 +02002551 prev_and_exp = *tok_idx;
2552 rc = reparse_equality_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002553 LY_CHECK_RET(rc);
2554
2555 /* ('and' EqualityExpr)* */
Michal Vasko004d3152020-06-11 19:59:22 +02002556 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 +02002557 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
Michal Vasko004d3152020-06-11 19:59:22 +02002558 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002559
Michal Vasko004d3152020-06-11 19:59:22 +02002560 rc = reparse_equality_expr(ctx, exp, tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002561 LY_CHECK_RET(rc);
2562 }
2563 }
2564
2565 return LY_SUCCESS;
2566}
Radek Krejcib1646a92018-11-02 16:08:26 +01002567
2568/**
2569 * @brief Parse NCName.
2570 *
2571 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002572 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002573 */
Radek Krejcid4270262019-01-07 15:07:25 +01002574static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002575parse_ncname(const char *ncname)
2576{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002577 uint32_t uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002578 size_t size;
2579 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002580
2581 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2582 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2583 return len;
2584 }
2585
2586 do {
2587 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002588 if (!*ncname) {
2589 break;
2590 }
Radek Krejcid4270262019-01-07 15:07:25 +01002591 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002592 } while (is_xmlqnamechar(uc) && (uc != ':'));
2593
2594 return len;
2595}
2596
2597/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002598 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002599 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002600 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002601 * @param[in] exp Expression to use.
2602 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002603 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002604 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002605 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002606 */
2607static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002608exp_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 +01002609{
2610 uint32_t prev;
2611
2612 if (exp->used == exp->size) {
2613 prev = exp->size;
2614 exp->size += LYXP_EXPR_SIZE_STEP;
2615 if (prev > exp->size) {
2616 LOGINT(ctx);
2617 return LY_EINT;
2618 }
2619
2620 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2621 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2622 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2623 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2624 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2625 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2626 }
2627
2628 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002629 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002630 exp->tok_len[exp->used] = tok_len;
2631 ++exp->used;
2632 return LY_SUCCESS;
2633}
2634
2635void
Michal Vasko14676352020-05-29 11:35:55 +02002636lyxp_expr_free(const struct ly_ctx *ctx, struct lyxp_expr *expr)
Radek Krejcib1646a92018-11-02 16:08:26 +01002637{
2638 uint16_t i;
2639
2640 if (!expr) {
2641 return;
2642 }
2643
2644 lydict_remove(ctx, expr->expr);
2645 free(expr->tokens);
2646 free(expr->tok_pos);
2647 free(expr->tok_len);
2648 if (expr->repeat) {
2649 for (i = 0; i < expr->used; ++i) {
2650 free(expr->repeat[i]);
2651 }
2652 }
2653 free(expr->repeat);
2654 free(expr);
2655}
2656
Radek Krejcif03a9e22020-09-18 20:09:31 +02002657LY_ERR
2658lyxp_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 +01002659{
Radek Krejcif03a9e22020-09-18 20:09:31 +02002660 LY_ERR ret = LY_SUCCESS;
2661 struct lyxp_expr *expr;
Radek Krejcid4270262019-01-07 15:07:25 +01002662 size_t parsed = 0, tok_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002663 enum lyxp_token tok_type;
Radek Krejci857189e2020-09-01 13:26:36 +02002664 ly_bool prev_function_check = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02002665 uint16_t tok_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002666
Radek Krejcif03a9e22020-09-18 20:09:31 +02002667 assert(expr_p);
2668
2669 if (!expr_str[0]) {
Michal Vasko004d3152020-06-11 19:59:22 +02002670 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
Radek Krejcif03a9e22020-09-18 20:09:31 +02002671 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02002672 }
2673
2674 if (!expr_len) {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002675 expr_len = strlen(expr_str);
Michal Vasko004d3152020-06-11 19:59:22 +02002676 }
2677 if (expr_len > UINT16_MAX) {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002678 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2679 return LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01002680 }
2681
2682 /* init lyxp_expr structure */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002683 expr = calloc(1, sizeof *expr);
2684 LY_CHECK_ERR_GOTO(!expr, LOGMEM(ctx); ret = LY_EMEM, error);
2685 LY_CHECK_GOTO(ret = lydict_insert(ctx, expr_str, expr_len, &expr->expr), error);
2686 expr->used = 0;
2687 expr->size = LYXP_EXPR_SIZE_START;
2688 expr->tokens = malloc(expr->size * sizeof *expr->tokens);
2689 LY_CHECK_ERR_GOTO(!expr->tokens, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002690
Radek Krejcif03a9e22020-09-18 20:09:31 +02002691 expr->tok_pos = malloc(expr->size * sizeof *expr->tok_pos);
2692 LY_CHECK_ERR_GOTO(!expr->tok_pos, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002693
Radek Krejcif03a9e22020-09-18 20:09:31 +02002694 expr->tok_len = malloc(expr->size * sizeof *expr->tok_len);
2695 LY_CHECK_ERR_GOTO(!expr->tok_len, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002696
Michal Vasko004d3152020-06-11 19:59:22 +02002697 /* make expr 0-terminated */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002698 expr_str = expr->expr;
Michal Vasko004d3152020-06-11 19:59:22 +02002699
Radek Krejcif03a9e22020-09-18 20:09:31 +02002700 while (is_xmlws(expr_str[parsed])) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002701 ++parsed;
2702 }
2703
2704 do {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002705 if (expr_str[parsed] == '(') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002706
2707 /* '(' */
2708 tok_len = 1;
2709 tok_type = LYXP_TOKEN_PAR1;
2710
Radek Krejcif03a9e22020-09-18 20:09:31 +02002711 if (prev_function_check && expr->used && (expr->tokens[expr->used - 1] == LYXP_TOKEN_NAMETEST)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002712 /* it is a NodeType/FunctionName after all */
Michal Vasko69730152020-10-09 16:30:07 +02002713 if (((expr->tok_len[expr->used - 1] == 4) &&
2714 (!strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "node", 4) ||
2715 !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "text", 4))) ||
2716 ((expr->tok_len[expr->used - 1] == 7) &&
2717 !strncmp(&expr_str[expr->tok_pos[expr->used - 1]], "comment", 7))) {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002718 expr->tokens[expr->used - 1] = LYXP_TOKEN_NODETYPE;
Radek Krejcib1646a92018-11-02 16:08:26 +01002719 } else {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002720 expr->tokens[expr->used - 1] = LYXP_TOKEN_FUNCNAME;
Radek Krejcib1646a92018-11-02 16:08:26 +01002721 }
2722 prev_function_check = 0;
2723 }
2724
Radek Krejcif03a9e22020-09-18 20:09:31 +02002725 } else if (expr_str[parsed] == ')') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002726
2727 /* ')' */
2728 tok_len = 1;
2729 tok_type = LYXP_TOKEN_PAR2;
2730
Radek Krejcif03a9e22020-09-18 20:09:31 +02002731 } else if (expr_str[parsed] == '[') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002732
2733 /* '[' */
2734 tok_len = 1;
2735 tok_type = LYXP_TOKEN_BRACK1;
2736
Radek Krejcif03a9e22020-09-18 20:09:31 +02002737 } else if (expr_str[parsed] == ']') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002738
2739 /* ']' */
2740 tok_len = 1;
2741 tok_type = LYXP_TOKEN_BRACK2;
2742
Radek Krejcif03a9e22020-09-18 20:09:31 +02002743 } else if (!strncmp(&expr_str[parsed], "..", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002744
2745 /* '..' */
2746 tok_len = 2;
2747 tok_type = LYXP_TOKEN_DDOT;
2748
Radek Krejcif03a9e22020-09-18 20:09:31 +02002749 } else if ((expr_str[parsed] == '.') && (!isdigit(expr_str[parsed + 1]))) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002750
2751 /* '.' */
2752 tok_len = 1;
2753 tok_type = LYXP_TOKEN_DOT;
2754
Radek Krejcif03a9e22020-09-18 20:09:31 +02002755 } else if (expr_str[parsed] == '@') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002756
2757 /* '@' */
2758 tok_len = 1;
2759 tok_type = LYXP_TOKEN_AT;
2760
Radek Krejcif03a9e22020-09-18 20:09:31 +02002761 } else if (expr_str[parsed] == ',') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002762
2763 /* ',' */
2764 tok_len = 1;
2765 tok_type = LYXP_TOKEN_COMMA;
2766
Radek Krejcif03a9e22020-09-18 20:09:31 +02002767 } else if (expr_str[parsed] == '\'') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002768
2769 /* Literal with ' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002770 for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\''); ++tok_len) {}
2771 LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
Michal Vasko69730152020-10-09 16:30:07 +02002772 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
2773 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002774 ++tok_len;
2775 tok_type = LYXP_TOKEN_LITERAL;
2776
Radek Krejcif03a9e22020-09-18 20:09:31 +02002777 } else if (expr_str[parsed] == '\"') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002778
2779 /* Literal with " */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002780 for (tok_len = 1; (expr_str[parsed + tok_len] != '\0') && (expr_str[parsed + tok_len] != '\"'); ++tok_len) {}
2781 LY_CHECK_ERR_GOTO(expr_str[parsed + tok_len] == '\0',
Michal Vasko69730152020-10-09 16:30:07 +02002782 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr_str[parsed], &expr_str[parsed]); ret = LY_EVALID,
2783 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002784 ++tok_len;
2785 tok_type = LYXP_TOKEN_LITERAL;
2786
Radek Krejcif03a9e22020-09-18 20:09:31 +02002787 } else if ((expr_str[parsed] == '.') || (isdigit(expr_str[parsed]))) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002788
2789 /* Number */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002790 for (tok_len = 0; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
2791 if (expr_str[parsed + tok_len] == '.') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002792 ++tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02002793 for ( ; isdigit(expr_str[parsed + tok_len]); ++tok_len) {}
Radek Krejcib1646a92018-11-02 16:08:26 +01002794 }
2795 tok_type = LYXP_TOKEN_NUMBER;
2796
Radek Krejcif03a9e22020-09-18 20:09:31 +02002797 } else if (expr_str[parsed] == '/') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002798
2799 /* Operator '/', '//' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002800 if (!strncmp(&expr_str[parsed], "//", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002801 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002802 tok_type = LYXP_TOKEN_OPER_RPATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002803 } else {
2804 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002805 tok_type = LYXP_TOKEN_OPER_PATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002806 }
Radek Krejcib1646a92018-11-02 16:08:26 +01002807
Radek Krejcif03a9e22020-09-18 20:09:31 +02002808 } else if (!strncmp(&expr_str[parsed], "!=", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002809
Michal Vasko3e48bf32020-06-01 08:39:07 +02002810 /* Operator '!=' */
Radek Krejcib1646a92018-11-02 16:08:26 +01002811 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002812 tok_type = LYXP_TOKEN_OPER_NEQUAL;
2813
Radek Krejcif03a9e22020-09-18 20:09:31 +02002814 } else if (!strncmp(&expr_str[parsed], "<=", 2) || !strncmp(&expr_str[parsed], ">=", 2)) {
Michal Vasko3e48bf32020-06-01 08:39:07 +02002815
2816 /* Operator '<=', '>=' */
2817 tok_len = 2;
2818 tok_type = LYXP_TOKEN_OPER_COMP;
Radek Krejcib1646a92018-11-02 16:08:26 +01002819
Radek Krejcif03a9e22020-09-18 20:09:31 +02002820 } else if (expr_str[parsed] == '|') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002821
2822 /* Operator '|' */
2823 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002824 tok_type = LYXP_TOKEN_OPER_UNI;
Radek Krejcib1646a92018-11-02 16:08:26 +01002825
Radek Krejcif03a9e22020-09-18 20:09:31 +02002826 } else if ((expr_str[parsed] == '+') || (expr_str[parsed] == '-')) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002827
2828 /* Operator '+', '-' */
2829 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002830 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002831
Radek Krejcif03a9e22020-09-18 20:09:31 +02002832 } else if (expr_str[parsed] == '=') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002833
Michal Vasko3e48bf32020-06-01 08:39:07 +02002834 /* Operator '=' */
Radek Krejcib1646a92018-11-02 16:08:26 +01002835 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002836 tok_type = LYXP_TOKEN_OPER_EQUAL;
2837
Radek Krejcif03a9e22020-09-18 20:09:31 +02002838 } else if ((expr_str[parsed] == '<') || (expr_str[parsed] == '>')) {
Michal Vasko3e48bf32020-06-01 08:39:07 +02002839
2840 /* Operator '<', '>' */
2841 tok_len = 1;
2842 tok_type = LYXP_TOKEN_OPER_COMP;
Radek Krejcib1646a92018-11-02 16:08:26 +01002843
Michal Vasko69730152020-10-09 16:30:07 +02002844 } else if (expr->used && (expr->tokens[expr->used - 1] != LYXP_TOKEN_AT) &&
2845 (expr->tokens[expr->used - 1] != LYXP_TOKEN_PAR1) &&
2846 (expr->tokens[expr->used - 1] != LYXP_TOKEN_BRACK1) &&
2847 (expr->tokens[expr->used - 1] != LYXP_TOKEN_COMMA) &&
2848 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_LOG) &&
2849 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_EQUAL) &&
2850 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_NEQUAL) &&
2851 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_COMP) &&
2852 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_MATH) &&
2853 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_UNI) &&
2854 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_PATH) &&
2855 (expr->tokens[expr->used - 1] != LYXP_TOKEN_OPER_RPATH)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002856
2857 /* Operator '*', 'or', 'and', 'mod', or 'div' */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002858 if (expr_str[parsed] == '*') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002859 tok_len = 1;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002860 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002861
Radek Krejcif03a9e22020-09-18 20:09:31 +02002862 } else if (!strncmp(&expr_str[parsed], "or", 2)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002863 tok_len = 2;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002864 tok_type = LYXP_TOKEN_OPER_LOG;
Radek Krejcib1646a92018-11-02 16:08:26 +01002865
Radek Krejcif03a9e22020-09-18 20:09:31 +02002866 } else if (!strncmp(&expr_str[parsed], "and", 3)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002867 tok_len = 3;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002868 tok_type = LYXP_TOKEN_OPER_LOG;
Radek Krejcib1646a92018-11-02 16:08:26 +01002869
Radek Krejcif03a9e22020-09-18 20:09:31 +02002870 } else if (!strncmp(&expr_str[parsed], "mod", 3) || !strncmp(&expr_str[parsed], "div", 3)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002871 tok_len = 3;
Michal Vasko3e48bf32020-06-01 08:39:07 +02002872 tok_type = LYXP_TOKEN_OPER_MATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002873
2874 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002875 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
Michal Vasko69730152020-10-09 16:30:07 +02002876 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 +02002877 ret = LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01002878 goto error;
2879 } else {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002880 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr_str);
2881 ret = LY_EVALID;
Radek Krejcib1646a92018-11-02 16:08:26 +01002882 goto error;
2883 }
Radek Krejcif03a9e22020-09-18 20:09:31 +02002884 } else if (expr_str[parsed] == '*') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002885
2886 /* NameTest '*' */
2887 tok_len = 1;
2888 tok_type = LYXP_TOKEN_NAMETEST;
2889
2890 } else {
2891
2892 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002893 long int ncname_len = parse_ncname(&expr_str[parsed]);
2894 LY_CHECK_ERR_GOTO(ncname_len < 0,
Michal Vasko69730152020-10-09 16:30:07 +02002895 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr_str); ret = LY_EVALID,
2896 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002897 tok_len = ncname_len;
2898
Radek Krejcif03a9e22020-09-18 20:09:31 +02002899 if (expr_str[parsed + tok_len] == ':') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002900 ++tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02002901 if (expr_str[parsed + tok_len] == '*') {
Radek Krejcib1646a92018-11-02 16:08:26 +01002902 ++tok_len;
2903 } else {
Radek Krejcif03a9e22020-09-18 20:09:31 +02002904 ncname_len = parse_ncname(&expr_str[parsed + tok_len]);
2905 LY_CHECK_ERR_GOTO(ncname_len < 0,
Michal Vasko69730152020-10-09 16:30:07 +02002906 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr_str); ret = LY_EVALID,
2907 error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002908 tok_len += ncname_len;
2909 }
2910 /* remove old flag to prevent ambiguities */
2911 prev_function_check = 0;
2912 tok_type = LYXP_TOKEN_NAMETEST;
2913 } else {
2914 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2915 prev_function_check = 1;
2916 tok_type = LYXP_TOKEN_NAMETEST;
2917 }
2918 }
2919
2920 /* store the token, move on to the next one */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002921 LY_CHECK_GOTO(ret = exp_add_token(ctx, expr, tok_type, parsed, tok_len), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002922 parsed += tok_len;
Radek Krejcif03a9e22020-09-18 20:09:31 +02002923 while (is_xmlws(expr_str[parsed])) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002924 ++parsed;
2925 }
2926
Radek Krejcif03a9e22020-09-18 20:09:31 +02002927 } while (expr_str[parsed]);
Radek Krejcib1646a92018-11-02 16:08:26 +01002928
Michal Vasko004d3152020-06-11 19:59:22 +02002929 if (reparse) {
2930 /* prealloc repeat */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002931 expr->repeat = calloc(expr->size, sizeof *expr->repeat);
2932 LY_CHECK_ERR_GOTO(!expr->repeat, LOGMEM(ctx); ret = LY_EMEM, error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002933
Michal Vasko004d3152020-06-11 19:59:22 +02002934 /* fill repeat */
Radek Krejcif03a9e22020-09-18 20:09:31 +02002935 LY_CHECK_ERR_GOTO(reparse_or_expr(ctx, expr, &tok_idx), ret = LY_EVALID, error);
2936 if (expr->used > tok_idx) {
Michal Vasko004d3152020-06-11 19:59:22 +02002937 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
Michal Vasko69730152020-10-09 16:30:07 +02002938 &expr->expr[expr->tok_pos[tok_idx]]);
Radek Krejcif03a9e22020-09-18 20:09:31 +02002939 ret = LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02002940 goto error;
2941 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02002942 }
2943
Radek Krejcif03a9e22020-09-18 20:09:31 +02002944 print_expr_struct_debug(expr);
2945 *expr_p = expr;
2946 return LY_SUCCESS;
Radek Krejcib1646a92018-11-02 16:08:26 +01002947
2948error:
Radek Krejcif03a9e22020-09-18 20:09:31 +02002949 lyxp_expr_free(ctx, expr);
2950 return ret;
Radek Krejcib1646a92018-11-02 16:08:26 +01002951}
2952
Michal Vasko1734be92020-09-22 08:55:10 +02002953LY_ERR
2954lyxp_expr_dup(const struct ly_ctx *ctx, const struct lyxp_expr *exp, struct lyxp_expr **dup_p)
Michal Vasko004d3152020-06-11 19:59:22 +02002955{
Michal Vasko1734be92020-09-22 08:55:10 +02002956 LY_ERR ret = LY_SUCCESS;
2957 struct lyxp_expr *dup = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02002958 uint32_t i, j;
2959
Michal Vasko7f45cf22020-10-01 12:49:44 +02002960 if (!exp) {
2961 goto cleanup;
2962 }
2963
Michal Vasko004d3152020-06-11 19:59:22 +02002964 dup = calloc(1, sizeof *dup);
Michal Vasko1734be92020-09-22 08:55:10 +02002965 LY_CHECK_ERR_GOTO(!dup, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002966
2967 dup->tokens = malloc(exp->used * sizeof *dup->tokens);
Michal Vasko1734be92020-09-22 08:55:10 +02002968 LY_CHECK_ERR_GOTO(!dup->tokens, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002969 memcpy(dup->tokens, exp->tokens, exp->used * sizeof *dup->tokens);
2970
2971 dup->tok_pos = malloc(exp->used * sizeof *dup->tok_pos);
Michal Vasko1734be92020-09-22 08:55:10 +02002972 LY_CHECK_ERR_GOTO(!dup->tok_pos, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002973 memcpy(dup->tok_pos, exp->tok_pos, exp->used * sizeof *dup->tok_pos);
2974
2975 dup->tok_len = malloc(exp->used * sizeof *dup->tok_len);
Michal Vasko1734be92020-09-22 08:55:10 +02002976 LY_CHECK_ERR_GOTO(!dup->tok_len, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002977 memcpy(dup->tok_len, exp->tok_len, exp->used * sizeof *dup->tok_len);
2978
2979 dup->repeat = malloc(exp->used * sizeof *dup->repeat);
Michal Vasko1734be92020-09-22 08:55:10 +02002980 LY_CHECK_ERR_GOTO(!dup->repeat, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002981 for (i = 0; i < exp->used; ++i) {
2982 if (!exp->repeat[i]) {
2983 dup->repeat[i] = NULL;
2984 } else {
Radek Krejci1e008d22020-08-17 11:37:37 +02002985 for (j = 0; exp->repeat[i][j]; ++j) {}
Michal Vasko004d3152020-06-11 19:59:22 +02002986 /* the ending 0 as well */
2987 ++j;
2988
Michal Vasko99c71642020-07-03 13:33:36 +02002989 dup->repeat[i] = malloc(j * sizeof **dup->repeat);
Michal Vasko1734be92020-09-22 08:55:10 +02002990 LY_CHECK_ERR_GOTO(!dup->repeat[i], LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002991 memcpy(dup->repeat[i], exp->repeat[i], j * sizeof **dup->repeat);
2992 dup->repeat[i][j - 1] = 0;
2993 }
2994 }
2995
2996 dup->used = exp->used;
2997 dup->size = exp->used;
Michal Vasko1734be92020-09-22 08:55:10 +02002998 LY_CHECK_GOTO(ret = lydict_insert(ctx, exp->expr, 0, &dup->expr), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02002999
Michal Vasko1734be92020-09-22 08:55:10 +02003000cleanup:
3001 if (ret) {
3002 lyxp_expr_free(ctx, dup);
3003 } else {
3004 *dup_p = dup;
3005 }
3006 return ret;
Michal Vasko004d3152020-06-11 19:59:22 +02003007}
3008
Michal Vasko03ff5a72019-09-11 13:49:33 +02003009/*
3010 * warn functions
3011 *
3012 * Warn functions check specific reasonable conditions for schema XPath
3013 * and print a warning if they are not satisfied.
3014 */
3015
3016/**
3017 * @brief Get the last-added schema node that is currently in the context.
3018 *
3019 * @param[in] set Set to search in.
3020 * @return Last-added schema context node, NULL if no node is in context.
3021 */
3022static struct lysc_node *
3023warn_get_scnode_in_ctx(struct lyxp_set *set)
3024{
3025 uint32_t i;
3026
3027 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
3028 return NULL;
3029 }
3030
3031 i = set->used;
3032 do {
3033 --i;
Radek Krejcif13b87b2020-12-01 22:02:17 +01003034 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003035 /* if there are more, simply return the first found (last added) */
3036 return set->val.scnodes[i].scnode;
3037 }
3038 } while (i);
3039
3040 return NULL;
3041}
3042
3043/**
3044 * @brief Test whether a type is numeric - integer type or decimal64.
3045 *
3046 * @param[in] type Type to test.
Radek Krejci857189e2020-09-01 13:26:36 +02003047 * @return Boolean value whether @p type is numeric type or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003048 */
Radek Krejci857189e2020-09-01 13:26:36 +02003049static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003050warn_is_numeric_type(struct lysc_type *type)
3051{
3052 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003053 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003054 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003055
3056 switch (type->basetype) {
3057 case LY_TYPE_DEC64:
3058 case LY_TYPE_INT8:
3059 case LY_TYPE_UINT8:
3060 case LY_TYPE_INT16:
3061 case LY_TYPE_UINT16:
3062 case LY_TYPE_INT32:
3063 case LY_TYPE_UINT32:
3064 case LY_TYPE_INT64:
3065 case LY_TYPE_UINT64:
3066 return 1;
3067 case LY_TYPE_UNION:
3068 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003069 LY_ARRAY_FOR(uni->types, u) {
3070 ret = warn_is_numeric_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003071 if (ret) {
3072 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003073 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003074 }
3075 }
3076 /* did not find any suitable type */
3077 return 0;
3078 case LY_TYPE_LEAFREF:
3079 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
3080 default:
3081 return 0;
3082 }
3083}
3084
3085/**
3086 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
3087 *
3088 * @param[in] type Type to test.
Radek Krejci857189e2020-09-01 13:26:36 +02003089 * @return Boolean value whether @p type's basetype is string type or not.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003090 */
Radek Krejci857189e2020-09-01 13:26:36 +02003091static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003092warn_is_string_type(struct lysc_type *type)
3093{
3094 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003095 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003096 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003097
3098 switch (type->basetype) {
3099 case LY_TYPE_BITS:
3100 case LY_TYPE_ENUM:
3101 case LY_TYPE_IDENT:
3102 case LY_TYPE_INST:
3103 case LY_TYPE_STRING:
3104 return 1;
3105 case LY_TYPE_UNION:
3106 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003107 LY_ARRAY_FOR(uni->types, u) {
3108 ret = warn_is_string_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003109 if (ret) {
3110 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003111 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003112 }
3113 }
3114 /* did not find any suitable type */
3115 return 0;
3116 case LY_TYPE_LEAFREF:
3117 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
3118 default:
3119 return 0;
3120 }
3121}
3122
3123/**
3124 * @brief Test whether a type is one specific type.
3125 *
3126 * @param[in] type Type to test.
3127 * @param[in] base Expected type.
Radek Krejci857189e2020-09-01 13:26:36 +02003128 * @return Boolean value whether the given @p type is of the specific basetype @p base.
Michal Vasko03ff5a72019-09-11 13:49:33 +02003129 */
Radek Krejci857189e2020-09-01 13:26:36 +02003130static ly_bool
Michal Vasko03ff5a72019-09-11 13:49:33 +02003131warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
3132{
3133 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003134 ly_bool ret;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003135 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003136
3137 if (type->basetype == base) {
3138 return 1;
3139 } else if (type->basetype == LY_TYPE_UNION) {
3140 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003141 LY_ARRAY_FOR(uni->types, u) {
3142 ret = warn_is_specific_type(uni->types[u], base);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003143 if (ret) {
3144 /* found a suitable type */
Radek Krejci857189e2020-09-01 13:26:36 +02003145 return ret;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003146 }
3147 }
3148 /* did not find any suitable type */
3149 return 0;
3150 } else if (type->basetype == LY_TYPE_LEAFREF) {
3151 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
3152 }
3153
3154 return 0;
3155}
3156
3157/**
3158 * @brief Get next type of a (union) type.
3159 *
3160 * @param[in] type Base type.
3161 * @param[in] prev_type Previously returned type.
3162 * @return Next type or NULL.
3163 */
3164static struct lysc_type *
3165warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3166{
3167 struct lysc_type_union *uni;
Radek Krejci857189e2020-09-01 13:26:36 +02003168 ly_bool found = 0;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003169 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003170
3171 switch (type->basetype) {
3172 case LY_TYPE_UNION:
3173 uni = (struct lysc_type_union *)type;
3174 if (!prev_type) {
3175 return uni->types[0];
3176 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003177 LY_ARRAY_FOR(uni->types, u) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003178 if (found) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003179 return uni->types[u];
Michal Vasko03ff5a72019-09-11 13:49:33 +02003180 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003181 if (prev_type == uni->types[u]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003182 found = 1;
3183 }
3184 }
3185 return NULL;
3186 default:
3187 if (prev_type) {
3188 assert(type == prev_type);
3189 return NULL;
3190 } else {
3191 return type;
3192 }
3193 }
3194}
3195
3196/**
3197 * @brief Test whether 2 types have a common type.
3198 *
3199 * @param[in] type1 First type.
3200 * @param[in] type2 Second type.
3201 * @return 1 if they do, 0 otherwise.
3202 */
3203static int
3204warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3205{
3206 struct lysc_type *t1, *rt1, *t2, *rt2;
3207
3208 t1 = NULL;
3209 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3210 if (t1->basetype == LY_TYPE_LEAFREF) {
3211 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3212 } else {
3213 rt1 = t1;
3214 }
3215
3216 t2 = NULL;
3217 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3218 if (t2->basetype == LY_TYPE_LEAFREF) {
3219 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3220 } else {
3221 rt2 = t2;
3222 }
3223
3224 if (rt2->basetype == rt1->basetype) {
3225 /* match found */
3226 return 1;
3227 }
3228 }
3229 }
3230
3231 return 0;
3232}
3233
3234/**
3235 * @brief Check both operands of comparison operators.
3236 *
3237 * @param[in] ctx Context for errors.
3238 * @param[in] set1 First operand set.
3239 * @param[in] set2 Second operand set.
3240 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3241 * @param[in] expr Start of the expression to print with the warning.
3242 * @param[in] tok_pos Token position.
3243 */
3244static void
Radek Krejci857189e2020-09-01 13:26:36 +02003245warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, ly_bool numbers_only, const char *expr, uint16_t tok_pos)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003246{
3247 struct lysc_node_leaf *node1, *node2;
Radek Krejci857189e2020-09-01 13:26:36 +02003248 ly_bool leaves = 1, warning = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003249
3250 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3251 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3252
3253 if (!node1 && !node2) {
3254 /* no node-sets involved, nothing to do */
3255 return;
3256 }
3257
3258 if (node1) {
3259 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3260 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3261 warning = 1;
3262 leaves = 0;
3263 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3264 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3265 warning = 1;
3266 }
3267 }
3268
3269 if (node2) {
3270 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3271 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3272 warning = 1;
3273 leaves = 0;
3274 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3275 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3276 warning = 1;
3277 }
3278 }
3279
3280 if (node1 && node2 && leaves && !numbers_only) {
Michal Vasko69730152020-10-09 16:30:07 +02003281 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)) ||
3282 (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type)) ||
3283 (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type) &&
3284 !warn_is_equal_type(node1->type, node2->type))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003285 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3286 warning = 1;
3287 }
3288 }
3289
3290 if (warning) {
3291 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3292 }
3293}
3294
3295/**
3296 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3297 *
3298 * @param[in] exp Parsed XPath expression.
3299 * @param[in] set Set with the leaf/leaf-list.
3300 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3301 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3302 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3303 */
3304static void
Michal Vasko40308e72020-10-20 16:38:40 +02003305warn_equality_value(const struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp,
3306 uint16_t last_equal_exp)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003307{
3308 struct lysc_node *scnode;
3309 struct lysc_type *type;
3310 char *value;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003311 struct lyd_value storage;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003312 LY_ERR rc;
3313 struct ly_err_item *err = NULL;
3314
Michal Vasko69730152020-10-09 16:30:07 +02003315 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) &&
3316 ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003317 /* check that the node can have the specified value */
3318 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3319 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3320 } else {
3321 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3322 }
3323 if (!value) {
3324 LOGMEM(set->ctx);
3325 return;
3326 }
3327
3328 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3329 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
Michal Vasko69730152020-10-09 16:30:07 +02003330 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003331 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
Radek Krejci0f969882020-08-21 16:56:47 +02003332 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
Michal Vasko69730152020-10-09 16:30:07 +02003333 exp->expr + exp->tok_pos[equal_exp]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003334 }
3335
3336 type = ((struct lysc_node_leaf *)scnode)->type;
3337 if (type->basetype != LY_TYPE_IDENT) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003338 rc = type->plugin->store(set->ctx, type, value, strlen(value), 0, set->format, set->prefix_data,
Michal Vasko405cc9e2020-12-01 12:01:27 +01003339 LYD_HINT_DATA, scnode, &storage, NULL, &err);
Michal Vaskobf42e832020-11-23 16:59:42 +01003340 if (rc == LY_EINCOMPLETE) {
3341 rc = LY_SUCCESS;
3342 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003343
3344 if (err) {
3345 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3346 ly_err_free(err);
3347 } else if (rc != LY_SUCCESS) {
3348 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3349 }
3350 if (rc != LY_SUCCESS) {
3351 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
Radek Krejci0f969882020-08-21 16:56:47 +02003352 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
Michal Vasko69730152020-10-09 16:30:07 +02003353 exp->expr + exp->tok_pos[equal_exp]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003354 } else {
3355 type->plugin->free(set->ctx, &storage);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003356 }
3357 }
3358 free(value);
3359 }
3360}
3361
3362/*
3363 * XPath functions
3364 */
3365
3366/**
3367 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3368 * depending on whether the first node bit value from the second argument is set.
3369 *
3370 * @param[in] args Array of arguments.
3371 * @param[in] arg_count Count of elements in @p args.
3372 * @param[in,out] set Context and result set at the same time.
3373 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003374 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003375 */
3376static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003377xpath_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 +02003378{
3379 struct lyd_node_term *leaf;
3380 struct lysc_node_leaf *sleaf;
3381 struct lysc_type_bits *bits;
3382 LY_ERR rc = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003383 LY_ARRAY_COUNT_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003384
3385 if (options & LYXP_SCNODE_ALL) {
3386 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3387 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003388 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3389 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 +02003390 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3391 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003392 }
3393
3394 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3395 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3396 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 +02003397 } else if (!warn_is_string_type(sleaf->type)) {
3398 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003399 }
3400 }
3401 set_scnode_clear_ctx(set);
3402 return rc;
3403 }
3404
Michal Vaskod3678892020-05-21 10:06:58 +02003405 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003406 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
3407 "bit-is-set(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003408 return LY_EVALID;
3409 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003410 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003411 LY_CHECK_RET(rc);
3412
3413 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003414 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003415 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
Michal Vasko69730152020-10-09 16:30:07 +02003416 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) &&
3417 (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003418 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003419 LY_ARRAY_FOR(bits->bits, u) {
3420 if (!strcmp(bits->bits[u].name, args[1]->val.str)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003421 set_fill_boolean(set, 1);
3422 break;
3423 }
3424 }
3425 }
3426 }
3427
3428 return LY_SUCCESS;
3429}
3430
3431/**
3432 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3433 * with the argument converted to boolean.
3434 *
3435 * @param[in] args Array of arguments.
3436 * @param[in] arg_count Count of elements in @p args.
3437 * @param[in,out] set Context and result set at the same time.
3438 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003439 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003440 */
3441static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003442xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003443{
3444 LY_ERR rc;
3445
3446 if (options & LYXP_SCNODE_ALL) {
3447 set_scnode_clear_ctx(set);
3448 return LY_SUCCESS;
3449 }
3450
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003451 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003452 LY_CHECK_RET(rc);
3453 set_fill_set(set, args[0]);
3454
3455 return LY_SUCCESS;
3456}
3457
3458/**
3459 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3460 * with the first argument rounded up to the nearest integer.
3461 *
3462 * @param[in] args Array of arguments.
3463 * @param[in] arg_count Count of elements in @p args.
3464 * @param[in,out] set Context and result set at the same time.
3465 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003466 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003467 */
3468static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003469xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003470{
3471 struct lysc_node_leaf *sleaf;
3472 LY_ERR rc = LY_SUCCESS;
3473
3474 if (options & LYXP_SCNODE_ALL) {
3475 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3476 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003477 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3478 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 +02003479 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3480 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003481 }
3482 set_scnode_clear_ctx(set);
3483 return rc;
3484 }
3485
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003486 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003487 LY_CHECK_RET(rc);
3488 if ((long long)args[0]->val.num != args[0]->val.num) {
3489 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3490 } else {
3491 set_fill_number(set, args[0]->val.num);
3492 }
3493
3494 return LY_SUCCESS;
3495}
3496
3497/**
3498 * @brief Execute the XPath concat(string, string, string*) function.
3499 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3500 *
3501 * @param[in] args Array of arguments.
3502 * @param[in] arg_count Count of elements in @p args.
3503 * @param[in,out] set Context and result set at the same time.
3504 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003505 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003506 */
3507static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003508xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003509{
3510 uint16_t i;
3511 char *str = NULL;
3512 size_t used = 1;
3513 LY_ERR rc = LY_SUCCESS;
3514 struct lysc_node_leaf *sleaf;
3515
3516 if (options & LYXP_SCNODE_ALL) {
3517 for (i = 0; i < arg_count; ++i) {
3518 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3519 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3520 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003521 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003522 } else if (!warn_is_string_type(sleaf->type)) {
Radek Krejci70124c82020-08-14 22:17:03 +02003523 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 +02003524 }
3525 }
3526 }
3527 set_scnode_clear_ctx(set);
3528 return rc;
3529 }
3530
3531 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003532 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003533 if (rc != LY_SUCCESS) {
3534 free(str);
3535 return rc;
3536 }
3537
3538 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3539 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3540 strcpy(str + used - 1, args[i]->val.str);
3541 used += strlen(args[i]->val.str);
3542 }
3543
3544 /* free, kind of */
Michal Vaskod3678892020-05-21 10:06:58 +02003545 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003546 set->type = LYXP_SET_STRING;
3547 set->val.str = str;
3548
3549 return LY_SUCCESS;
3550}
3551
3552/**
3553 * @brief Execute the XPath contains(string, string) function.
3554 * Returns LYXP_SET_BOOLEAN whether the second argument can
3555 * be found in the first or not.
3556 *
3557 * @param[in] args Array of arguments.
3558 * @param[in] arg_count Count of elements in @p args.
3559 * @param[in,out] set Context and result set at the same time.
3560 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003561 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003562 */
3563static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003564xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003565{
3566 struct lysc_node_leaf *sleaf;
3567 LY_ERR rc = LY_SUCCESS;
3568
3569 if (options & LYXP_SCNODE_ALL) {
3570 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3571 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3572 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 +02003573 } else if (!warn_is_string_type(sleaf->type)) {
3574 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003575 }
3576 }
3577
3578 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3579 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3580 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 +02003581 } else if (!warn_is_string_type(sleaf->type)) {
3582 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003583 }
3584 }
3585 set_scnode_clear_ctx(set);
3586 return rc;
3587 }
3588
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003589 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003590 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003591 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003592 LY_CHECK_RET(rc);
3593
3594 if (strstr(args[0]->val.str, args[1]->val.str)) {
3595 set_fill_boolean(set, 1);
3596 } else {
3597 set_fill_boolean(set, 0);
3598 }
3599
3600 return LY_SUCCESS;
3601}
3602
3603/**
3604 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3605 * with the size of the node-set from the argument.
3606 *
3607 * @param[in] args Array of arguments.
3608 * @param[in] arg_count Count of elements in @p args.
3609 * @param[in,out] set Context and result set at the same time.
3610 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003611 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003612 */
3613static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003614xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003615{
3616 struct lysc_node *scnode = NULL;
3617 LY_ERR rc = LY_SUCCESS;
3618
3619 if (options & LYXP_SCNODE_ALL) {
3620 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3621 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003622 }
3623 set_scnode_clear_ctx(set);
3624 return rc;
3625 }
3626
Michal Vasko03ff5a72019-09-11 13:49:33 +02003627 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003628 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003629 return LY_EVALID;
3630 }
3631
3632 set_fill_number(set, args[0]->used);
3633 return LY_SUCCESS;
3634}
3635
3636/**
3637 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3638 * with the context with the intial node.
3639 *
3640 * @param[in] args Array of arguments.
3641 * @param[in] arg_count Count of elements in @p args.
3642 * @param[in,out] set Context and result set at the same time.
3643 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003644 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003645 */
3646static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003647xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003648{
3649 if (arg_count || args) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003650 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003651 return LY_EVALID;
3652 }
3653
3654 if (options & LYXP_SCNODE_ALL) {
3655 set_scnode_clear_ctx(set);
3656
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003657 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, set->cur_scnode, LYXP_NODE_ELEM, NULL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02003658 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02003659 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003660
3661 /* position is filled later */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003662 set_insert_node(set, set->cur_node, 0, LYXP_NODE_ELEM, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003663 }
3664
3665 return LY_SUCCESS;
3666}
3667
3668/**
3669 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3670 * leafref or instance-identifier target node(s).
3671 *
3672 * @param[in] args Array of arguments.
3673 * @param[in] arg_count Count of elements in @p args.
3674 * @param[in,out] set Context and result set at the same time.
3675 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003676 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003677 */
3678static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003679xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003680{
3681 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003682 struct lysc_node_leaf *sleaf = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +02003683 struct lysc_type_leafref *lref;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003684 const struct lysc_node *target;
Michal Vasko004d3152020-06-11 19:59:22 +02003685 struct ly_path *p;
3686 struct lyd_node *node;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003687 char *errmsg = NULL;
Michal Vasko00cbf532020-06-15 13:58:47 +02003688 uint8_t oper;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003689 LY_ERR rc = LY_SUCCESS;
3690
3691 if (options & LYXP_SCNODE_ALL) {
3692 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3693 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003694 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3695 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 +02003696 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3697 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
Michal Vasko69730152020-10-09 16:30:07 +02003698 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003699 }
3700 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003701 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vasko004d3152020-06-11 19:59:22 +02003702 lref = (struct lysc_type_leafref *)sleaf->type;
Michal Vasko00cbf532020-06-15 13:58:47 +02003703 oper = lysc_is_output((struct lysc_node *)sleaf) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
Michal Vasko004d3152020-06-11 19:59:22 +02003704
3705 /* it was already evaluated on schema, it must succeed */
Michal Vaskoc0792ca2020-12-01 12:03:21 +01003706 rc = ly_path_compile(set->ctx, lref->cur_mod, (struct lysc_node *)sleaf, lref->path,
Michal Vasko405cc9e2020-12-01 12:01:27 +01003707 LY_PATH_LREF_TRUE, oper, LY_PATH_TARGET_MANY, LY_PREF_SCHEMA_RESOLVED, lref->prefixes, NULL, &p);
Michal Vasko004d3152020-06-11 19:59:22 +02003708 assert(!rc);
3709
3710 /* get the target node */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003711 target = p[LY_ARRAY_COUNT(p) - 1].node;
Michal Vasko004d3152020-06-11 19:59:22 +02003712 ly_path_free(set->ctx, p);
3713
Radek Krejciaa6b53f2020-08-27 15:19:03 +02003714 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM, NULL));
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003715 }
3716
Michal Vasko03ff5a72019-09-11 13:49:33 +02003717 return rc;
3718 }
3719
Michal Vaskod3678892020-05-21 10:06:58 +02003720 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003721 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003722 return LY_EVALID;
3723 }
3724
Michal Vaskod3678892020-05-21 10:06:58 +02003725 lyxp_set_free_content(set);
3726 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003727 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3728 sleaf = (struct lysc_node_leaf *)leaf->schema;
3729 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3730 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3731 /* find leafref target */
Michal Vasko004d3152020-06-11 19:59:22 +02003732 if (ly_type_find_leafref((struct lysc_type_leafref *)sleaf->type, (struct lyd_node *)leaf,
Michal Vasko69730152020-10-09 16:30:07 +02003733 &leaf->value, set->tree, &node, &errmsg)) {
Michal Vasko004d3152020-06-11 19:59:22 +02003734 LOGERR(set->ctx, LY_EVALID, errmsg);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003735 free(errmsg);
Michal Vasko004d3152020-06-11 19:59:22 +02003736 return LY_EVALID;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003737 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003738 } else {
3739 assert(sleaf->type->basetype == LY_TYPE_INST);
Michal Vasko004d3152020-06-11 19:59:22 +02003740 if (ly_path_eval(leaf->value.target, set->tree, &node)) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003741 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.",
Michal Vasko69730152020-10-09 16:30:07 +02003742 LYD_CANON_VALUE(leaf));
Michal Vasko03ff5a72019-09-11 13:49:33 +02003743 return LY_EVALID;
3744 }
3745 }
Michal Vasko004d3152020-06-11 19:59:22 +02003746
3747 /* insert it */
3748 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003749 }
3750 }
3751
3752 return LY_SUCCESS;
3753}
3754
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003755static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02003756xpath_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 +02003757{
3758 uint16_t i;
3759 LY_ARRAY_COUNT_TYPE u;
3760 struct lyd_node_term *leaf;
3761 struct lysc_node_leaf *sleaf;
3762 struct lyd_meta *meta;
3763 struct lyd_value data = {0}, *val;
3764 struct ly_err_item *err = NULL;
3765 LY_ERR rc = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02003766 ly_bool found;
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003767
3768 if (options & LYXP_SCNODE_ALL) {
3769 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3770 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", func);
3771 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3772 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", func, lys_nodetype2str(sleaf->nodetype),
Michal Vasko69730152020-10-09 16:30:07 +02003773 sleaf->name);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003774 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3775 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", func, sleaf->name);
3776 }
3777
3778 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3779 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3780 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", func, lys_nodetype2str(sleaf->nodetype),
Michal Vasko69730152020-10-09 16:30:07 +02003781 sleaf->name);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003782 } else if (!warn_is_string_type(sleaf->type)) {
3783 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", func, sleaf->name);
3784 }
3785 }
3786 set_scnode_clear_ctx(set);
3787 return rc;
3788 }
3789
3790 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003791 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
Michal Vasko69730152020-10-09 16:30:07 +02003792 "derived-from(-or-self)(node-set, string)");
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003793 return LY_EVALID;
3794 }
3795 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
3796 LY_CHECK_RET(rc);
3797
3798 set_fill_boolean(set, 0);
3799 found = 0;
3800 for (i = 0; i < args[0]->used; ++i) {
3801 if ((args[0]->val.nodes[i].type != LYXP_NODE_ELEM) && (args[0]->val.nodes[i].type != LYXP_NODE_META)) {
3802 continue;
3803 }
3804
3805 if (args[0]->val.nodes[i].type == LYXP_NODE_ELEM) {
3806 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3807 sleaf = (struct lysc_node_leaf *)leaf->schema;
3808 val = &leaf->value;
3809 if (!(sleaf->nodetype & LYD_NODE_TERM) || (leaf->value.realtype->basetype != LY_TYPE_IDENT)) {
3810 /* uninteresting */
3811 continue;
3812 }
3813
3814 /* store args[1] as ident */
3815 rc = val->realtype->plugin->store(set->ctx, val->realtype, args[1]->val.str, strlen(args[1]->val.str),
Michal Vasko405cc9e2020-12-01 12:01:27 +01003816 0, set->format, set->prefix_data, LYD_HINT_DATA, leaf->schema, &data, NULL, &err);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003817 } else {
3818 meta = args[0]->val.meta[i].meta;
3819 val = &meta->value;
3820 if (val->realtype->basetype != LY_TYPE_IDENT) {
3821 /* uninteresting */
3822 continue;
3823 }
3824
3825 /* store args[1] as ident */
Michal Vaskofeca4fb2020-10-05 08:58:40 +02003826 rc = val->realtype->plugin->store(set->ctx, val->realtype, args[1]->val.str, strlen(args[1]->val.str), 0,
Michal Vasko405cc9e2020-12-01 12:01:27 +01003827 set->format, set->prefix_data, LYD_HINT_DATA, meta->parent->schema, &data, NULL, &err);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003828 }
3829
3830 if (err) {
Michal Vasko177d0ed2020-11-23 16:43:03 +01003831 ly_err_print(set->ctx, err);
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003832 ly_err_free(err);
3833 }
3834 LY_CHECK_RET(rc);
3835
3836 /* finally check the identity itself */
3837 if (self_match && (data.ident == val->ident)) {
3838 set_fill_boolean(set, 1);
3839 found = 1;
3840 }
3841 if (!found) {
3842 LY_ARRAY_FOR(data.ident->derived, u) {
3843 if (data.ident->derived[u] == val->ident) {
3844 set_fill_boolean(set, 1);
3845 found = 1;
3846 break;
3847 }
3848 }
3849 }
3850
3851 /* free temporary value */
3852 val->realtype->plugin->free(set->ctx, &data);
3853 if (found) {
3854 break;
3855 }
3856 }
3857
3858 return LY_SUCCESS;
3859}
3860
Michal Vasko03ff5a72019-09-11 13:49:33 +02003861/**
3862 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3863 * on whether the first argument nodes contain a node of an identity derived from the second
3864 * argument identity.
3865 *
3866 * @param[in] args Array of arguments.
3867 * @param[in] arg_count Count of elements in @p args.
3868 * @param[in,out] set Context and result set at the same time.
3869 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003870 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003871 */
3872static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003873xpath_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 +02003874{
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003875 return xpath_derived_(args, set, options, 0, __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003876}
3877
3878/**
3879 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3880 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3881 * the second argument identity.
3882 *
3883 * @param[in] args Array of arguments.
3884 * @param[in] arg_count Count of elements in @p args.
3885 * @param[in,out] set Context and result set at the same time.
3886 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003887 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003888 */
3889static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003890xpath_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 +02003891{
Michal Vaskoe0dd59d2020-07-17 16:10:23 +02003892 return xpath_derived_(args, set, options, 1, __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003893}
3894
3895/**
3896 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3897 * with the integer value of the first node's enum value, otherwise NaN.
3898 *
3899 * @param[in] args Array of arguments.
3900 * @param[in] arg_count Count of elements in @p args.
3901 * @param[in,out] set Context and result set at the same time.
3902 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003903 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003904 */
3905static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003906xpath_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 +02003907{
3908 struct lyd_node_term *leaf;
3909 struct lysc_node_leaf *sleaf;
3910 LY_ERR rc = LY_SUCCESS;
3911
3912 if (options & LYXP_SCNODE_ALL) {
3913 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3914 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003915 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3916 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 +02003917 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3918 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003919 }
3920 set_scnode_clear_ctx(set);
3921 return rc;
3922 }
3923
Michal Vaskod3678892020-05-21 10:06:58 +02003924 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02003925 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003926 return LY_EVALID;
3927 }
3928
3929 set_fill_number(set, NAN);
Michal Vaskod3678892020-05-21 10:06:58 +02003930 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003931 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3932 sleaf = (struct lysc_node_leaf *)leaf->schema;
3933 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3934 set_fill_number(set, leaf->value.enum_item->value);
3935 }
3936 }
3937
3938 return LY_SUCCESS;
3939}
3940
3941/**
3942 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3943 * with false value.
3944 *
3945 * @param[in] args Array of arguments.
3946 * @param[in] arg_count Count of elements in @p args.
3947 * @param[in,out] set Context and result set at the same time.
3948 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003949 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003950 */
3951static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003952xpath_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 +02003953{
3954 if (options & LYXP_SCNODE_ALL) {
3955 set_scnode_clear_ctx(set);
3956 return LY_SUCCESS;
3957 }
3958
3959 set_fill_boolean(set, 0);
3960 return LY_SUCCESS;
3961}
3962
3963/**
3964 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3965 * with the first argument floored (truncated).
3966 *
3967 * @param[in] args Array of arguments.
3968 * @param[in] arg_count Count of elements in @p args.
3969 * @param[in,out] set Context and result set at the same time.
3970 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003971 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003972 */
3973static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003974xpath_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 +02003975{
3976 LY_ERR rc;
3977
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003978 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003979 LY_CHECK_RET(rc);
3980 if (isfinite(args[0]->val.num)) {
3981 set_fill_number(set, (long long)args[0]->val.num);
3982 }
3983
3984 return LY_SUCCESS;
3985}
3986
3987/**
3988 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3989 * whether the language of the text matches the one from the argument.
3990 *
3991 * @param[in] args Array of arguments.
3992 * @param[in] arg_count Count of elements in @p args.
3993 * @param[in,out] set Context and result set at the same time.
3994 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003995 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003996 */
3997static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02003998xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02003999{
4000 const struct lyd_node *node;
4001 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01004002 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004003 const char *val;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004004 LY_ERR rc = LY_SUCCESS;
4005
4006 if (options & LYXP_SCNODE_ALL) {
4007 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4008 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4009 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 +02004010 } else if (!warn_is_string_type(sleaf->type)) {
4011 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004012 }
4013 }
4014 set_scnode_clear_ctx(set);
4015 return rc;
4016 }
4017
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004018 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004019 LY_CHECK_RET(rc);
4020
Michal Vasko03ff5a72019-09-11 13:49:33 +02004021 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004022 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004023 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004024 } else if (!set->used) {
4025 set_fill_boolean(set, 0);
4026 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004027 }
4028
4029 switch (set->val.nodes[0].type) {
4030 case LYXP_NODE_ELEM:
4031 case LYXP_NODE_TEXT:
4032 node = set->val.nodes[0].node;
4033 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004034 case LYXP_NODE_META:
4035 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004036 break;
4037 default:
4038 /* nothing to do with roots */
4039 set_fill_boolean(set, 0);
4040 return LY_SUCCESS;
4041 }
4042
Michal Vasko9f96a052020-03-10 09:41:45 +01004043 /* find lang metadata */
Michal Vaskod989ba02020-08-24 10:59:24 +02004044 for ( ; node; node = (struct lyd_node *)node->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01004045 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004046 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004047 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004048 break;
4049 }
4050 }
4051
Michal Vasko9f96a052020-03-10 09:41:45 +01004052 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004053 break;
4054 }
4055 }
4056
4057 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01004058 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004059 set_fill_boolean(set, 0);
4060 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004061 uint64_t i;
4062
Michal Vaskoba99a3e2020-08-18 15:50:05 +02004063 val = meta->value.canonical;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004064 for (i = 0; args[0]->val.str[i]; ++i) {
4065 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
4066 set_fill_boolean(set, 0);
4067 break;
4068 }
4069 }
4070 if (!args[0]->val.str[i]) {
4071 if (!val[i] || (val[i] == '-')) {
4072 set_fill_boolean(set, 1);
4073 } else {
4074 set_fill_boolean(set, 0);
4075 }
4076 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004077 }
4078
4079 return LY_SUCCESS;
4080}
4081
4082/**
4083 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
4084 * with the context size.
4085 *
4086 * @param[in] args Array of arguments.
4087 * @param[in] arg_count Count of elements in @p args.
4088 * @param[in,out] set Context and result set at the same time.
4089 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004090 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004091 */
4092static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004093xpath_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 +02004094{
4095 if (options & LYXP_SCNODE_ALL) {
4096 set_scnode_clear_ctx(set);
4097 return LY_SUCCESS;
4098 }
4099
Michal Vasko03ff5a72019-09-11 13:49:33 +02004100 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004101 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004102 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004103 } else if (!set->used) {
4104 set_fill_number(set, 0);
4105 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004106 }
4107
4108 set_fill_number(set, set->ctx_size);
4109 return LY_SUCCESS;
4110}
4111
4112/**
4113 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
4114 * with the node name without namespace from the argument or the context.
4115 *
4116 * @param[in] args Array of arguments.
4117 * @param[in] arg_count Count of elements in @p args.
4118 * @param[in,out] set Context and result set at the same time.
4119 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004120 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004121 */
4122static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004123xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004124{
4125 struct lyxp_set_node *item;
Michal Vasko69730152020-10-09 16:30:07 +02004126
Michal Vasko03ff5a72019-09-11 13:49:33 +02004127 /* suppress unused variable warning */
4128 (void)options;
4129
4130 if (options & LYXP_SCNODE_ALL) {
4131 set_scnode_clear_ctx(set);
4132 return LY_SUCCESS;
4133 }
4134
4135 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004136 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004137 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
4138 "local-name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004139 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004140 } else if (!args[0]->used) {
4141 set_fill_string(set, "", 0);
4142 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004143 }
4144
4145 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004146 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004147
4148 item = &args[0]->val.nodes[0];
4149 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004150 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004151 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004152 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004153 } else if (!set->used) {
4154 set_fill_string(set, "", 0);
4155 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004156 }
4157
4158 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004159 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004160
4161 item = &set->val.nodes[0];
4162 }
4163
4164 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004165 case LYXP_NODE_NONE:
4166 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004167 case LYXP_NODE_ROOT:
4168 case LYXP_NODE_ROOT_CONFIG:
4169 case LYXP_NODE_TEXT:
4170 set_fill_string(set, "", 0);
4171 break;
4172 case LYXP_NODE_ELEM:
4173 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4174 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004175 case LYXP_NODE_META:
4176 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004177 break;
4178 }
4179
4180 return LY_SUCCESS;
4181}
4182
4183/**
4184 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4185 * with the node name fully qualified (with namespace) from the argument or the context.
4186 *
4187 * @param[in] args Array of arguments.
4188 * @param[in] arg_count Count of elements in @p args.
4189 * @param[in,out] set Context and result set at the same time.
4190 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004191 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004192 */
4193static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004194xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004195{
4196 struct lyxp_set_node *item;
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004197 struct lys_module *mod = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004198 char *str;
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004199 const char *name = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004200
4201 if (options & LYXP_SCNODE_ALL) {
4202 set_scnode_clear_ctx(set);
4203 return LY_SUCCESS;
4204 }
4205
4206 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004207 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004208 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004209 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004210 } else if (!args[0]->used) {
4211 set_fill_string(set, "", 0);
4212 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004213 }
4214
4215 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004216 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004217
4218 item = &args[0]->val.nodes[0];
4219 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004220 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004221 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004222 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004223 } else if (!set->used) {
4224 set_fill_string(set, "", 0);
4225 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004226 }
4227
4228 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004229 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004230
4231 item = &set->val.nodes[0];
4232 }
4233
4234 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004235 case LYXP_NODE_NONE:
4236 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004237 case LYXP_NODE_ROOT:
4238 case LYXP_NODE_ROOT_CONFIG:
4239 case LYXP_NODE_TEXT:
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02004240 /* keep NULL */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004241 break;
4242 case LYXP_NODE_ELEM:
4243 mod = item->node->schema->module;
4244 name = item->node->schema->name;
4245 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004246 case LYXP_NODE_META:
4247 mod = ((struct lyd_meta *)item->node)->annotation->module;
4248 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004249 break;
4250 }
4251
4252 if (mod && name) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004253 int rc = asprintf(&str, "%s:%s", ly_get_prefix(mod, set->format, set->prefix_data), name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004254 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4255 set_fill_string(set, str, strlen(str));
4256 free(str);
4257 } else {
4258 set_fill_string(set, "", 0);
4259 }
4260
4261 return LY_SUCCESS;
4262}
4263
4264/**
4265 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4266 * with the namespace of the node from the argument or the context.
4267 *
4268 * @param[in] args Array of arguments.
4269 * @param[in] arg_count Count of elements in @p args.
4270 * @param[in,out] set Context and result set at the same time.
4271 * @param[in] options XPath options.
4272 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4273 */
4274static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004275xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004276{
4277 struct lyxp_set_node *item;
4278 struct lys_module *mod;
Michal Vasko69730152020-10-09 16:30:07 +02004279
Michal Vasko03ff5a72019-09-11 13:49:33 +02004280 /* suppress unused variable warning */
4281 (void)options;
4282
4283 if (options & LYXP_SCNODE_ALL) {
4284 set_scnode_clear_ctx(set);
4285 return LY_SUCCESS;
4286 }
4287
4288 if (arg_count) {
Michal Vaskod3678892020-05-21 10:06:58 +02004289 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004290 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
Michal Vasko69730152020-10-09 16:30:07 +02004291 "namespace-uri(node-set?)");
Michal Vaskod3678892020-05-21 10:06:58 +02004292 return LY_EVALID;
4293 } else if (!args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004294 set_fill_string(set, "", 0);
4295 return LY_SUCCESS;
4296 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004297
4298 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004299 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004300
4301 item = &args[0]->val.nodes[0];
4302 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004303 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004304 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004305 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004306 } else if (!set->used) {
4307 set_fill_string(set, "", 0);
4308 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004309 }
4310
4311 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004312 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004313
4314 item = &set->val.nodes[0];
4315 }
4316
4317 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004318 case LYXP_NODE_NONE:
4319 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004320 case LYXP_NODE_ROOT:
4321 case LYXP_NODE_ROOT_CONFIG:
4322 case LYXP_NODE_TEXT:
4323 set_fill_string(set, "", 0);
4324 break;
4325 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004326 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004327 if (item->type == LYXP_NODE_ELEM) {
4328 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004329 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004330 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004331 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004332 }
4333
4334 set_fill_string(set, mod->ns, strlen(mod->ns));
4335 break;
4336 }
4337
4338 return LY_SUCCESS;
4339}
4340
4341/**
4342 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4343 * with only nodes from the context. In practice it either leaves the context
4344 * as it is or returns an empty node set.
4345 *
4346 * @param[in] args Array of arguments.
4347 * @param[in] arg_count Count of elements in @p args.
4348 * @param[in,out] set Context and result set at the same time.
4349 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004350 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004351 */
4352static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004353xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004354{
4355 if (options & LYXP_SCNODE_ALL) {
4356 set_scnode_clear_ctx(set);
4357 return LY_SUCCESS;
4358 }
4359
4360 if (set->type != LYXP_SET_NODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02004361 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004362 }
4363 return LY_SUCCESS;
4364}
4365
4366/**
4367 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4368 * with normalized value (no leading, trailing, double white spaces) of the node
4369 * from the argument or the context.
4370 *
4371 * @param[in] args Array of arguments.
4372 * @param[in] arg_count Count of elements in @p args.
4373 * @param[in,out] set Context and result set at the same time.
4374 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004375 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004376 */
4377static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004378xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004379{
4380 uint16_t i, new_used;
4381 char *new;
Radek Krejci857189e2020-09-01 13:26:36 +02004382 ly_bool have_spaces = 0, space_before = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004383 struct lysc_node_leaf *sleaf;
4384 LY_ERR rc = LY_SUCCESS;
4385
4386 if (options & LYXP_SCNODE_ALL) {
4387 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4388 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4389 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 +02004390 } else if (!warn_is_string_type(sleaf->type)) {
4391 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004392 }
4393 }
4394 set_scnode_clear_ctx(set);
4395 return rc;
4396 }
4397
4398 if (arg_count) {
4399 set_fill_set(set, args[0]);
4400 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004401 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004402 LY_CHECK_RET(rc);
4403
4404 /* is there any normalization necessary? */
4405 for (i = 0; set->val.str[i]; ++i) {
4406 if (is_xmlws(set->val.str[i])) {
4407 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4408 have_spaces = 1;
4409 break;
4410 }
4411 space_before = 1;
4412 } else {
4413 space_before = 0;
4414 }
4415 }
4416
4417 /* yep, there is */
4418 if (have_spaces) {
4419 /* it's enough, at least one character will go, makes space for ending '\0' */
4420 new = malloc(strlen(set->val.str) * sizeof(char));
4421 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4422 new_used = 0;
4423
4424 space_before = 0;
4425 for (i = 0; set->val.str[i]; ++i) {
4426 if (is_xmlws(set->val.str[i])) {
4427 if ((i == 0) || space_before) {
4428 space_before = 1;
4429 continue;
4430 } else {
4431 space_before = 1;
4432 }
4433 } else {
4434 space_before = 0;
4435 }
4436
4437 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4438 ++new_used;
4439 }
4440
4441 /* at worst there is one trailing space now */
4442 if (new_used && is_xmlws(new[new_used - 1])) {
4443 --new_used;
4444 }
4445
4446 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4447 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4448 new[new_used] = '\0';
4449
4450 free(set->val.str);
4451 set->val.str = new;
4452 }
4453
4454 return LY_SUCCESS;
4455}
4456
4457/**
4458 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4459 * with the argument converted to boolean and logically inverted.
4460 *
4461 * @param[in] args Array of arguments.
4462 * @param[in] arg_count Count of elements in @p args.
4463 * @param[in,out] set Context and result set at the same time.
4464 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004465 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004466 */
4467static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004468xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004469{
4470 if (options & LYXP_SCNODE_ALL) {
4471 set_scnode_clear_ctx(set);
4472 return LY_SUCCESS;
4473 }
4474
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004475 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko004d3152020-06-11 19:59:22 +02004476 if (args[0]->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004477 set_fill_boolean(set, 0);
4478 } else {
4479 set_fill_boolean(set, 1);
4480 }
4481
4482 return LY_SUCCESS;
4483}
4484
4485/**
4486 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4487 * with the number representation of either the argument or the context.
4488 *
4489 * @param[in] args Array of arguments.
4490 * @param[in] arg_count Count of elements in @p args.
4491 * @param[in,out] set Context and result set at the same time.
4492 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004493 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004494 */
4495static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004496xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004497{
4498 LY_ERR rc;
4499
4500 if (options & LYXP_SCNODE_ALL) {
4501 set_scnode_clear_ctx(set);
4502 return LY_SUCCESS;
4503 }
4504
4505 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004506 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004507 LY_CHECK_RET(rc);
4508 set_fill_set(set, args[0]);
4509 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004510 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004511 LY_CHECK_RET(rc);
4512 }
4513
4514 return LY_SUCCESS;
4515}
4516
4517/**
4518 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4519 * with the context position.
4520 *
4521 * @param[in] args Array of arguments.
4522 * @param[in] arg_count Count of elements in @p args.
4523 * @param[in,out] set Context and result set at the same time.
4524 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004525 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004526 */
4527static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004528xpath_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 +02004529{
4530 if (options & LYXP_SCNODE_ALL) {
4531 set_scnode_clear_ctx(set);
4532 return LY_SUCCESS;
4533 }
4534
Michal Vasko03ff5a72019-09-11 13:49:33 +02004535 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004536 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02004537 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004538 } else if (!set->used) {
4539 set_fill_number(set, 0);
4540 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004541 }
4542
4543 set_fill_number(set, set->ctx_pos);
4544
4545 /* UNUSED in 'Release' build type */
4546 (void)options;
4547 return LY_SUCCESS;
4548}
4549
4550/**
4551 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4552 * depending on whether the second argument regex matches the first argument string. For details refer to
4553 * YANG 1.1 RFC section 10.2.1.
4554 *
4555 * @param[in] args Array of arguments.
4556 * @param[in] arg_count Count of elements in @p args.
4557 * @param[in,out] set Context and result set at the same time.
4558 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004559 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004560 */
4561static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004562xpath_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 +02004563{
4564 struct lysc_pattern **patterns = NULL, **pattern;
4565 struct lysc_node_leaf *sleaf;
4566 char *path;
4567 LY_ERR rc = LY_SUCCESS;
4568 struct ly_err_item *err;
4569
4570 if (options & LYXP_SCNODE_ALL) {
4571 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4572 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4573 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 +02004574 } else if (!warn_is_string_type(sleaf->type)) {
4575 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004576 }
4577 }
4578
4579 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4580 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4581 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 +02004582 } else if (!warn_is_string_type(sleaf->type)) {
4583 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004584 }
4585 }
4586 set_scnode_clear_ctx(set);
4587 return rc;
4588 }
4589
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004590 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004591 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004592 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004593 LY_CHECK_RET(rc);
4594
4595 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4596 *pattern = malloc(sizeof **pattern);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02004597 path = lyd_path(set->cur_node, LYD_PATH_LOG, NULL, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004598 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4599 free(path);
4600 if (rc != LY_SUCCESS) {
4601 LY_ARRAY_FREE(patterns);
4602 return rc;
4603 }
4604
4605 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4606 pcre2_code_free((*pattern)->code);
4607 free(*pattern);
4608 LY_ARRAY_FREE(patterns);
4609 if (rc && (rc != LY_EVALID)) {
Michal Vasko177d0ed2020-11-23 16:43:03 +01004610 ly_err_print(set->ctx, err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004611 ly_err_free(err);
4612 return rc;
4613 }
4614
4615 if (rc == LY_EVALID) {
4616 ly_err_free(err);
4617 set_fill_boolean(set, 0);
4618 } else {
4619 set_fill_boolean(set, 1);
4620 }
4621
4622 return LY_SUCCESS;
4623}
4624
4625/**
4626 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4627 * with the rounded first argument. For details refer to
4628 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4629 *
4630 * @param[in] args Array of arguments.
4631 * @param[in] arg_count Count of elements in @p args.
4632 * @param[in,out] set Context and result set at the same time.
4633 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004634 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004635 */
4636static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004637xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004638{
4639 struct lysc_node_leaf *sleaf;
4640 LY_ERR rc = LY_SUCCESS;
4641
4642 if (options & LYXP_SCNODE_ALL) {
4643 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4644 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004645 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4646 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 +02004647 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4648 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004649 }
4650 set_scnode_clear_ctx(set);
4651 return rc;
4652 }
4653
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004654 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004655 LY_CHECK_RET(rc);
4656
4657 /* cover only the cases where floor can't be used */
4658 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4659 set_fill_number(set, -0.0f);
4660 } else {
4661 args[0]->val.num += 0.5;
4662 rc = xpath_floor(args, 1, args[0], options);
4663 LY_CHECK_RET(rc);
4664 set_fill_number(set, args[0]->val.num);
4665 }
4666
4667 return LY_SUCCESS;
4668}
4669
4670/**
4671 * @brief Execute the XPath starts-with(string, string) function.
4672 * Returns LYXP_SET_BOOLEAN whether the second argument is
4673 * the prefix of the first or not.
4674 *
4675 * @param[in] args Array of arguments.
4676 * @param[in] arg_count Count of elements in @p args.
4677 * @param[in,out] set Context and result set at the same time.
4678 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004679 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004680 */
4681static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004682xpath_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 +02004683{
4684 struct lysc_node_leaf *sleaf;
4685 LY_ERR rc = LY_SUCCESS;
4686
4687 if (options & LYXP_SCNODE_ALL) {
4688 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4689 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4690 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 +02004691 } else if (!warn_is_string_type(sleaf->type)) {
4692 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004693 }
4694 }
4695
4696 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4697 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4698 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 +02004699 } else if (!warn_is_string_type(sleaf->type)) {
4700 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004701 }
4702 }
4703 set_scnode_clear_ctx(set);
4704 return rc;
4705 }
4706
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004707 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004708 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004709 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004710 LY_CHECK_RET(rc);
4711
4712 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4713 set_fill_boolean(set, 0);
4714 } else {
4715 set_fill_boolean(set, 1);
4716 }
4717
4718 return LY_SUCCESS;
4719}
4720
4721/**
4722 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4723 * with the string representation of either the argument or the context.
4724 *
4725 * @param[in] args Array of arguments.
4726 * @param[in] arg_count Count of elements in @p args.
4727 * @param[in,out] set Context and result set at the same time.
4728 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004729 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004730 */
4731static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004732xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004733{
4734 LY_ERR rc;
4735
4736 if (options & LYXP_SCNODE_ALL) {
4737 set_scnode_clear_ctx(set);
4738 return LY_SUCCESS;
4739 }
4740
4741 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004742 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004743 LY_CHECK_RET(rc);
4744 set_fill_set(set, args[0]);
4745 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004746 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004747 LY_CHECK_RET(rc);
4748 }
4749
4750 return LY_SUCCESS;
4751}
4752
4753/**
4754 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4755 * with the length of the string in either the argument or the context.
4756 *
4757 * @param[in] args Array of arguments.
4758 * @param[in] arg_count Count of elements in @p args.
4759 * @param[in,out] set Context and result set at the same time.
4760 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004761 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004762 */
4763static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004764xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004765{
4766 struct lysc_node_leaf *sleaf;
4767 LY_ERR rc = LY_SUCCESS;
4768
4769 if (options & LYXP_SCNODE_ALL) {
4770 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4771 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4772 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 +02004773 } else if (!warn_is_string_type(sleaf->type)) {
4774 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004775 }
4776 }
4777 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4778 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4779 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 +02004780 } else if (!warn_is_string_type(sleaf->type)) {
4781 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004782 }
4783 }
4784 set_scnode_clear_ctx(set);
4785 return rc;
4786 }
4787
4788 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004789 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004790 LY_CHECK_RET(rc);
4791 set_fill_number(set, strlen(args[0]->val.str));
4792 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004793 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004794 LY_CHECK_RET(rc);
4795 set_fill_number(set, strlen(set->val.str));
4796 }
4797
4798 return LY_SUCCESS;
4799}
4800
4801/**
4802 * @brief Execute the XPath substring(string, number, number?) function.
4803 * Returns LYXP_SET_STRING substring of the first argument starting
4804 * on the second argument index ending on the third argument index,
4805 * indexed from 1. For exact definition refer to
4806 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4807 *
4808 * @param[in] args Array of arguments.
4809 * @param[in] arg_count Count of elements in @p args.
4810 * @param[in,out] set Context and result set at the same time.
4811 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004812 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004813 */
4814static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004815xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02004816{
Radek Krejci1deb5be2020-08-26 16:43:36 +02004817 int32_t start, len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004818 uint16_t str_start, str_len, pos;
4819 struct lysc_node_leaf *sleaf;
4820 LY_ERR rc = LY_SUCCESS;
4821
4822 if (options & LYXP_SCNODE_ALL) {
4823 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4824 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4825 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 +02004826 } else if (!warn_is_string_type(sleaf->type)) {
4827 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004828 }
4829 }
4830
4831 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4832 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4833 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 +02004834 } else if (!warn_is_numeric_type(sleaf->type)) {
4835 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004836 }
4837 }
4838
Michal Vasko69730152020-10-09 16:30:07 +02004839 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET) &&
4840 (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004841 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4842 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 +02004843 } else if (!warn_is_numeric_type(sleaf->type)) {
4844 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004845 }
4846 }
4847 set_scnode_clear_ctx(set);
4848 return rc;
4849 }
4850
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004851 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004852 LY_CHECK_RET(rc);
4853
4854 /* start */
4855 if (xpath_round(&args[1], 1, args[1], options)) {
4856 return -1;
4857 }
4858 if (isfinite(args[1]->val.num)) {
4859 start = args[1]->val.num - 1;
4860 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004861 start = INT32_MIN;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004862 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004863 start = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004864 }
4865
4866 /* len */
4867 if (arg_count == 3) {
4868 rc = xpath_round(&args[2], 1, args[2], options);
4869 LY_CHECK_RET(rc);
Radek Krejci1deb5be2020-08-26 16:43:36 +02004870 if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004871 len = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004872 } else if (isfinite(args[2]->val.num)) {
4873 len = args[2]->val.num;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004874 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004875 len = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004876 }
4877 } else {
Radek Krejci1deb5be2020-08-26 16:43:36 +02004878 len = INT32_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004879 }
4880
4881 /* find matching character positions */
4882 str_start = 0;
4883 str_len = 0;
4884 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4885 if (pos < start) {
4886 ++str_start;
4887 } else if (pos < start + len) {
4888 ++str_len;
4889 } else {
4890 break;
4891 }
4892 }
4893
4894 set_fill_string(set, args[0]->val.str + str_start, str_len);
4895 return LY_SUCCESS;
4896}
4897
4898/**
4899 * @brief Execute the XPath substring-after(string, string) function.
4900 * Returns LYXP_SET_STRING with the string succeeding the occurance
4901 * of the second argument in the first or an empty string.
4902 *
4903 * @param[in] args Array of arguments.
4904 * @param[in] arg_count Count of elements in @p args.
4905 * @param[in,out] set Context and result set at the same time.
4906 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004907 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004908 */
4909static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004910xpath_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 +02004911{
4912 char *ptr;
4913 struct lysc_node_leaf *sleaf;
4914 LY_ERR rc = LY_SUCCESS;
4915
4916 if (options & LYXP_SCNODE_ALL) {
4917 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4918 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4919 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 +02004920 } else if (!warn_is_string_type(sleaf->type)) {
4921 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004922 }
4923 }
4924
4925 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4926 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4927 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 +02004928 } else if (!warn_is_string_type(sleaf->type)) {
4929 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004930 }
4931 }
4932 set_scnode_clear_ctx(set);
4933 return rc;
4934 }
4935
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004936 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004937 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004938 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004939 LY_CHECK_RET(rc);
4940
4941 ptr = strstr(args[0]->val.str, args[1]->val.str);
4942 if (ptr) {
4943 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4944 } else {
4945 set_fill_string(set, "", 0);
4946 }
4947
4948 return LY_SUCCESS;
4949}
4950
4951/**
4952 * @brief Execute the XPath substring-before(string, string) function.
4953 * Returns LYXP_SET_STRING with the string preceding the occurance
4954 * of the second argument in the first or an empty string.
4955 *
4956 * @param[in] args Array of arguments.
4957 * @param[in] arg_count Count of elements in @p args.
4958 * @param[in,out] set Context and result set at the same time.
4959 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004960 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004961 */
4962static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02004963xpath_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 +02004964{
4965 char *ptr;
4966 struct lysc_node_leaf *sleaf;
4967 LY_ERR rc = LY_SUCCESS;
4968
4969 if (options & LYXP_SCNODE_ALL) {
4970 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4971 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4972 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 +02004973 } else if (!warn_is_string_type(sleaf->type)) {
4974 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004975 }
4976 }
4977
4978 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4979 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4980 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 +02004981 } else if (!warn_is_string_type(sleaf->type)) {
4982 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004983 }
4984 }
4985 set_scnode_clear_ctx(set);
4986 return rc;
4987 }
4988
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004989 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004990 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004991 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004992 LY_CHECK_RET(rc);
4993
4994 ptr = strstr(args[0]->val.str, args[1]->val.str);
4995 if (ptr) {
4996 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4997 } else {
4998 set_fill_string(set, "", 0);
4999 }
5000
5001 return LY_SUCCESS;
5002}
5003
5004/**
5005 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
5006 * with the sum of all the nodes in the context.
5007 *
5008 * @param[in] args Array of arguments.
5009 * @param[in] arg_count Count of elements in @p args.
5010 * @param[in,out] set Context and result set at the same time.
5011 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005012 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005013 */
5014static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005015xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005016{
5017 long double num;
5018 char *str;
5019 uint16_t i;
5020 struct lyxp_set set_item;
5021 struct lysc_node_leaf *sleaf;
5022 LY_ERR rc = LY_SUCCESS;
5023
5024 if (options & LYXP_SCNODE_ALL) {
5025 if (args[0]->type == LYXP_SET_SCNODE_SET) {
5026 for (i = 0; i < args[0]->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005027 if (args[0]->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005028 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
5029 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5030 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
Michal Vasko69730152020-10-09 16:30:07 +02005031 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005032 } else if (!warn_is_numeric_type(sleaf->type)) {
5033 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005034 }
5035 }
5036 }
5037 }
5038 set_scnode_clear_ctx(set);
5039 return rc;
5040 }
5041
5042 set_fill_number(set, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005043
5044 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005045 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02005046 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02005047 } else if (!args[0]->used) {
5048 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005049 }
5050
Michal Vasko5c4e5892019-11-14 12:31:38 +01005051 set_init(&set_item, set);
5052
Michal Vasko03ff5a72019-09-11 13:49:33 +02005053 set_item.type = LYXP_SET_NODE_SET;
5054 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
5055 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
5056
5057 set_item.used = 1;
5058 set_item.size = 1;
5059
5060 for (i = 0; i < args[0]->used; ++i) {
5061 set_item.val.nodes[0] = args[0]->val.nodes[i];
5062
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005063 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005064 LY_CHECK_RET(rc);
5065 num = cast_string_to_number(str);
5066 free(str);
5067 set->val.num += num;
5068 }
5069
5070 free(set_item.val.nodes);
5071
5072 return LY_SUCCESS;
5073}
5074
5075/**
5076 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
5077 * with the text content of the nodes in the context.
5078 *
5079 * @param[in] args Array of arguments.
5080 * @param[in] arg_count Count of elements in @p args.
5081 * @param[in,out] set Context and result set at the same time.
5082 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005083 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005084 */
5085static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005086xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005087{
5088 uint32_t i;
5089
5090 if (options & LYXP_SCNODE_ALL) {
5091 set_scnode_clear_ctx(set);
5092 return LY_SUCCESS;
5093 }
5094
Michal Vasko03ff5a72019-09-11 13:49:33 +02005095 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005096 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
Michal Vasko03ff5a72019-09-11 13:49:33 +02005097 return LY_EVALID;
5098 }
5099
Michal Vaskod989ba02020-08-24 10:59:24 +02005100 for (i = 0; i < set->used; ) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005101 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01005102 case LYXP_NODE_NONE:
5103 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005104 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02005105 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
5106 set->val.nodes[i].type = LYXP_NODE_TEXT;
5107 ++i;
5108 break;
5109 }
Radek Krejci0f969882020-08-21 16:56:47 +02005110 /* fall through */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005111 case LYXP_NODE_ROOT:
5112 case LYXP_NODE_ROOT_CONFIG:
5113 case LYXP_NODE_TEXT:
Michal Vasko9f96a052020-03-10 09:41:45 +01005114 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02005115 set_remove_node(set, i);
5116 break;
5117 }
5118 }
5119
5120 return LY_SUCCESS;
5121}
5122
5123/**
5124 * @brief Execute the XPath translate(string, string, string) function.
5125 * Returns LYXP_SET_STRING with the first argument with the characters
5126 * from the second argument replaced by those on the corresponding
5127 * positions in the third argument.
5128 *
5129 * @param[in] args Array of arguments.
5130 * @param[in] arg_count Count of elements in @p args.
5131 * @param[in,out] set Context and result set at the same time.
5132 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005133 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005134 */
5135static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005136xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005137{
5138 uint16_t i, j, new_used;
5139 char *new;
Radek Krejci857189e2020-09-01 13:26:36 +02005140 ly_bool have_removed;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005141 struct lysc_node_leaf *sleaf;
5142 LY_ERR rc = LY_SUCCESS;
5143
5144 if (options & LYXP_SCNODE_ALL) {
5145 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5146 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5147 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 +02005148 } else if (!warn_is_string_type(sleaf->type)) {
5149 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005150 }
5151 }
5152
5153 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5154 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5155 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 +02005156 } else if (!warn_is_string_type(sleaf->type)) {
5157 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005158 }
5159 }
5160
5161 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5162 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5163 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 +02005164 } else if (!warn_is_string_type(sleaf->type)) {
5165 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005166 }
5167 }
5168 set_scnode_clear_ctx(set);
5169 return rc;
5170 }
5171
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005172 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005173 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005174 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005175 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005176 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005177 LY_CHECK_RET(rc);
5178
5179 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5180 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5181 new_used = 0;
5182
5183 have_removed = 0;
5184 for (i = 0; args[0]->val.str[i]; ++i) {
Radek Krejci857189e2020-09-01 13:26:36 +02005185 ly_bool found = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005186
5187 for (j = 0; args[1]->val.str[j]; ++j) {
5188 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5189 /* removing this char */
5190 if (j >= strlen(args[2]->val.str)) {
5191 have_removed = 1;
5192 found = 1;
5193 break;
5194 }
5195 /* replacing this char */
5196 new[new_used] = args[2]->val.str[j];
5197 ++new_used;
5198 found = 1;
5199 break;
5200 }
5201 }
5202
5203 /* copying this char */
5204 if (!found) {
5205 new[new_used] = args[0]->val.str[i];
5206 ++new_used;
5207 }
5208 }
5209
5210 if (have_removed) {
5211 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5212 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5213 }
5214 new[new_used] = '\0';
5215
Michal Vaskod3678892020-05-21 10:06:58 +02005216 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005217 set->type = LYXP_SET_STRING;
5218 set->val.str = new;
5219
5220 return LY_SUCCESS;
5221}
5222
5223/**
5224 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5225 * with true value.
5226 *
5227 * @param[in] args Array of arguments.
5228 * @param[in] arg_count Count of elements in @p args.
5229 * @param[in,out] set Context and result set at the same time.
5230 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005231 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005232 */
5233static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005234xpath_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 +02005235{
5236 if (options & LYXP_SCNODE_ALL) {
5237 set_scnode_clear_ctx(set);
5238 return LY_SUCCESS;
5239 }
5240
5241 set_fill_boolean(set, 1);
5242 return LY_SUCCESS;
5243}
5244
5245/*
5246 * moveto functions
5247 *
5248 * They and only they actually change the context (set).
5249 */
5250
5251/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005252 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005253 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005254 * XPath @p set is expected to be a (sc)node set!
5255 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005256 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5257 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005258 * @param[in] set Set with general XPath context.
5259 * @param[in] ctx_scnode Context node to inherit module for unprefixed node for ::LY_PREF_JSON.
Michal Vasko6346ece2019-09-24 13:12:53 +02005260 * @param[out] moveto_mod Expected module of a matching node.
5261 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005262 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005263static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005264moveto_resolve_model(const char **qname, uint16_t *qname_len, const struct lyxp_set *set,
5265 const struct lysc_node *ctx_scnode, const struct lys_module **moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005266{
Michal Vaskoed4fcfe2020-07-08 10:38:56 +02005267 const struct lys_module *mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005268 const char *ptr;
Radek Krejci1deb5be2020-08-26 16:43:36 +02005269 size_t pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005270
Michal Vasko2104e9f2020-03-06 08:23:25 +01005271 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5272
Michal Vasko6346ece2019-09-24 13:12:53 +02005273 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5274 /* specific module */
5275 pref_len = ptr - *qname;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005276 mod = ly_resolve_prefix(set->ctx, *qname, pref_len, set->format, set->prefix_data);
Michal Vasko6346ece2019-09-24 13:12:53 +02005277
Michal Vasko004d3152020-06-11 19:59:22 +02005278 /* check for errors and non-implemented modules, as they are not valid */
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005279 if (!mod || !mod->implemented) {
Michal Vasko2104e9f2020-03-06 08:23:25 +01005280 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005281 LOGVAL(set->ctx, LY_VLOG_LYSC, set->cur_scnode, LY_VCODE_XP_INMOD, pref_len, *qname);
Michal Vasko2104e9f2020-03-06 08:23:25 +01005282 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005283 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INMOD, pref_len, *qname);
Michal Vasko2104e9f2020-03-06 08:23:25 +01005284 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005285 return LY_EVALID;
5286 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005287
Michal Vasko6346ece2019-09-24 13:12:53 +02005288 *qname += pref_len + 1;
5289 *qname_len -= pref_len + 1;
5290 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5291 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005292 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005293 } else {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005294 switch (set->format) {
5295 case LY_PREF_SCHEMA:
5296 case LY_PREF_SCHEMA_RESOLVED:
5297 /* current module */
5298 mod = set->cur_mod;
5299 break;
5300 case LY_PREF_JSON:
5301 /* inherit parent (context node) module */
5302 if (ctx_scnode) {
5303 mod = ctx_scnode->module;
5304 } else {
5305 mod = NULL;
5306 }
5307 break;
5308 case LY_PREF_XML:
5309 /* not defined */
5310 LOGINT_RET(set->ctx);
5311 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005312 }
5313
Michal Vasko6346ece2019-09-24 13:12:53 +02005314 *moveto_mod = mod;
5315 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005316}
5317
5318/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005319 * @brief Move context @p set to the root. Handles absolute path.
5320 * Result is LYXP_SET_NODE_SET.
5321 *
5322 * @param[in,out] set Set to use.
5323 * @param[in] options Xpath options.
Michal Vaskob0099a92020-08-31 14:55:23 +02005324 * @return LY_ERR value.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005325 */
Michal Vaskob0099a92020-08-31 14:55:23 +02005326static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02005327moveto_root(struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005328{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005329 if (!set) {
Michal Vaskob0099a92020-08-31 14:55:23 +02005330 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005331 }
5332
5333 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005334 set_scnode_clear_ctx(set);
Michal Vaskob0099a92020-08-31 14:55:23 +02005335 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, NULL, set->root_type, NULL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005336 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005337 set->type = LYXP_SET_NODE_SET;
5338 set->used = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005339 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005340 }
Michal Vaskob0099a92020-08-31 14:55:23 +02005341
5342 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005343}
5344
5345/**
5346 * @brief Check @p node as a part of NameTest processing.
5347 *
5348 * @param[in] node Node to check.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005349 * @param[in] ctx_node Context node.
5350 * @param[in] set Set to read general context from.
Michal Vaskod3678892020-05-21 10:06:58 +02005351 * @param[in] node_name Node name in the dictionary to move to, NULL for any node.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005352 * @param[in] moveto_mod Expected module of the node, NULL for no prefix.
Michal Vaskocdad7122020-11-09 21:04:44 +01005353 * @param[in] options XPath options.
Michal Vasko6346ece2019-09-24 13:12:53 +02005354 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5355 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005356 */
5357static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005358moveto_node_check(const struct lyd_node *node, const struct lyd_node *ctx_node, const struct lyxp_set *set,
Michal Vaskocdad7122020-11-09 21:04:44 +01005359 const char *node_name, const struct lys_module *moveto_mod, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005360{
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005361 if (!moveto_mod && (!node_name || strcmp(node_name, "*"))) {
5362 switch (set->format) {
5363 case LY_PREF_SCHEMA:
5364 case LY_PREF_SCHEMA_RESOLVED:
5365 /* use current module */
5366 moveto_mod = set->cur_mod;
5367 break;
5368 case LY_PREF_JSON:
5369 /* inherit module of the context node, if any */
5370 if (ctx_node) {
5371 moveto_mod = ctx_node->schema->module;
5372 }
5373 break;
5374 case LY_PREF_XML:
5375 /* not defined */
5376 LOGINT(set->ctx);
5377 return LY_EINVAL;
5378 }
5379 }
5380
Michal Vasko03ff5a72019-09-11 13:49:33 +02005381 /* module check */
5382 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005383 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005384 }
5385
Michal Vasko5c4e5892019-11-14 12:31:38 +01005386 /* context check */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005387 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005388 return LY_EINVAL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005389 } else if (set->context_op && (node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) &&
5390 (node->schema != set->context_op)) {
Michal Vasko6b26e742020-07-17 15:02:10 +02005391 return LY_EINVAL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005392 }
5393
5394 /* name check */
Michal Vasko61ac2f62020-05-25 12:39:51 +02005395 if (node_name && strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005396 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005397 }
5398
Michal Vaskoa1424542019-11-14 16:08:52 +01005399 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01005400 if (!(options & LYXP_IGNORE_WHEN) && lysc_has_when(node->schema) && !(node->flags & LYD_WHEN_TRUE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005401 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005402 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005403
5404 /* match */
5405 return LY_SUCCESS;
5406}
5407
5408/**
5409 * @brief Check @p node as a part of schema NameTest processing.
5410 *
5411 * @param[in] node Schema node to check.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005412 * @param[in] ctx_scnode Context node.
5413 * @param[in] set Set to read general context from.
Michal Vaskod3678892020-05-21 10:06:58 +02005414 * @param[in] node_name Node name in the dictionary to move to, NULL for any nodes.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005415 * @param[in] moveto_mod Expected module of the node, NULL for no prefix.
Michal Vasko6346ece2019-09-24 13:12:53 +02005416 * @return LY_ERR (LY_ENOT if node does not match, LY_EINVAL if neither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005417 */
5418static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005419moveto_scnode_check(const struct lysc_node *node, const struct lysc_node *ctx_scnode, const struct lyxp_set *set,
Radek Krejci0f969882020-08-21 16:56:47 +02005420 const char *node_name, const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005421{
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005422 if (!moveto_mod && (!node_name || strcmp(node_name, "*"))) {
5423 switch (set->format) {
5424 case LY_PREF_SCHEMA:
5425 case LY_PREF_SCHEMA_RESOLVED:
5426 /* use current module */
5427 moveto_mod = set->cur_mod;
5428 break;
5429 case LY_PREF_JSON:
5430 /* inherit module of the context node, if any */
5431 if (ctx_scnode) {
5432 moveto_mod = ctx_scnode->module;
5433 }
5434 break;
5435 case LY_PREF_XML:
5436 /* not defined */
5437 LOGINT(set->ctx);
5438 return LY_EINVAL;
5439 }
5440 }
5441
Michal Vasko03ff5a72019-09-11 13:49:33 +02005442 /* module check */
Michal Vaskod3678892020-05-21 10:06:58 +02005443 if (moveto_mod && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005444 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005445 }
5446
5447 /* context check */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005448 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005449 return LY_EINVAL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005450 } else if (set->context_op && (node->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node != set->context_op)) {
Michal Vasko6b26e742020-07-17 15:02:10 +02005451 return LY_EINVAL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005452 }
5453
5454 /* name check */
Michal Vasko61ac2f62020-05-25 12:39:51 +02005455 if (node_name && strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005456 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005457 }
5458
5459 /* match */
5460 return LY_SUCCESS;
5461}
5462
5463/**
Michal Vaskod3678892020-05-21 10:06:58 +02005464 * @brief Move context @p set to a node. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005465 *
5466 * @param[in,out] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005467 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02005468 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vaskocdad7122020-11-09 21:04:44 +01005469 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005470 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5471 */
5472static LY_ERR
Michal Vaskocdad7122020-11-09 21:04:44 +01005473moveto_node(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005474{
Michal Vaskof03ed032020-03-04 13:31:44 +01005475 uint32_t i;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005476 const struct lyd_node *siblings, *sub, *ctx_node;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005477 LY_ERR rc;
5478
Michal Vaskod3678892020-05-21 10:06:58 +02005479 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005480 return LY_SUCCESS;
5481 }
5482
5483 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005484 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005485 return LY_EVALID;
5486 }
5487
Michal Vasko03ff5a72019-09-11 13:49:33 +02005488 for (i = 0; i < set->used; ) {
Radek Krejci857189e2020-09-01 13:26:36 +02005489 ly_bool replaced = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005490
5491 if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005492 assert(!set->val.nodes[i].node);
Michal Vaskod3678892020-05-21 10:06:58 +02005493
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005494 /* search in all the trees */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005495 ctx_node = NULL;
Michal Vaskod3678892020-05-21 10:06:58 +02005496 siblings = set->tree;
Michal Vasko5bfd4be2020-06-23 13:26:19 +02005497 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005498 /* search in children */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005499 ctx_node = set->val.nodes[i].node;
5500 siblings = lyd_child(ctx_node);
Michal Vaskod3678892020-05-21 10:06:58 +02005501 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005502
Michal Vaskod3678892020-05-21 10:06:58 +02005503 for (sub = siblings; sub; sub = sub->next) {
Michal Vaskocdad7122020-11-09 21:04:44 +01005504 rc = moveto_node_check(sub, ctx_node, set, ncname, moveto_mod, options);
Michal Vaskod3678892020-05-21 10:06:58 +02005505 if (rc == LY_SUCCESS) {
5506 if (!replaced) {
5507 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5508 replaced = 1;
5509 } else {
5510 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005511 }
Michal Vaskod3678892020-05-21 10:06:58 +02005512 ++i;
5513 } else if (rc == LY_EINCOMPLETE) {
5514 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005515 }
5516 }
5517
5518 if (!replaced) {
5519 /* no match */
5520 set_remove_node(set, i);
5521 }
5522 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005523
5524 return LY_SUCCESS;
5525}
5526
5527/**
Michal Vaskod3678892020-05-21 10:06:58 +02005528 * @brief Move context @p set to a node using hashes. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5529 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005530 *
5531 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005532 * @param[in] scnode Matching node schema.
Michal Vasko004d3152020-06-11 19:59:22 +02005533 * @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 +01005534 * @param[in] options XPath options.
Michal Vaskod3678892020-05-21 10:06:58 +02005535 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5536 */
5537static LY_ERR
Michal Vaskocdad7122020-11-09 21:04:44 +01005538moveto_node_hash(struct lyxp_set *set, const struct lysc_node *scnode, const struct ly_path_predicate *predicates,
5539 uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02005540{
Michal Vasko004d3152020-06-11 19:59:22 +02005541 LY_ERR ret = LY_SUCCESS;
Michal Vaskod3678892020-05-21 10:06:58 +02005542 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02005543 const struct lyd_node *siblings;
Michal Vasko004d3152020-06-11 19:59:22 +02005544 struct lyd_node *sub, *inst = NULL;
Michal Vaskod3678892020-05-21 10:06:58 +02005545
Michal Vasko004d3152020-06-11 19:59:22 +02005546 assert(scnode && (!(scnode->nodetype & (LYS_LIST | LYS_LEAFLIST)) || predicates));
Michal Vaskod3678892020-05-21 10:06:58 +02005547
5548 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02005549 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02005550 }
5551
5552 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005553 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko004d3152020-06-11 19:59:22 +02005554 ret = LY_EVALID;
5555 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02005556 }
5557
5558 /* context check for all the nodes since we have the schema node */
5559 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
5560 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02005561 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02005562 } else if (set->context_op && (scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) &&
5563 (scnode != set->context_op)) {
Michal Vasko6b26e742020-07-17 15:02:10 +02005564 lyxp_set_free_content(set);
5565 goto cleanup;
Michal Vasko004d3152020-06-11 19:59:22 +02005566 }
5567
5568 /* create specific data instance if needed */
5569 if (scnode->nodetype == LYS_LIST) {
5570 LY_CHECK_GOTO(ret = lyd_create_list(scnode, predicates, &inst), cleanup);
5571 } else if (scnode->nodetype == LYS_LEAFLIST) {
5572 LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02005573 }
5574
5575 for (i = 0; i < set->used; ) {
Michal Vaskod3678892020-05-21 10:06:58 +02005576 siblings = NULL;
5577
5578 if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
5579 assert(!set->val.nodes[i].node);
5580
5581 /* search in all the trees */
5582 siblings = set->tree;
5583 } else if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5584 /* search in children */
Radek Krejcia1c1e542020-09-29 16:06:52 +02005585 siblings = lyd_child(set->val.nodes[i].node);
Michal Vaskod3678892020-05-21 10:06:58 +02005586 }
5587
5588 /* find the node using hashes */
Michal Vasko004d3152020-06-11 19:59:22 +02005589 if (inst) {
5590 lyd_find_sibling_first(siblings, inst, &sub);
Michal Vaskod3678892020-05-21 10:06:58 +02005591 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02005592 lyd_find_sibling_val(siblings, scnode, NULL, 0, &sub);
Michal Vaskod3678892020-05-21 10:06:58 +02005593 }
5594
5595 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01005596 if (!(options & LYXP_IGNORE_WHEN) && sub && lysc_has_when(sub->schema) && !(sub->flags & LYD_WHEN_TRUE)) {
Michal Vasko004d3152020-06-11 19:59:22 +02005597 ret = LY_EINCOMPLETE;
5598 goto cleanup;
Michal Vaskod3678892020-05-21 10:06:58 +02005599 }
5600
5601 if (sub) {
5602 /* pos filled later */
Michal Vaskocb1b7c02020-07-03 13:38:12 +02005603 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vaskod3678892020-05-21 10:06:58 +02005604 ++i;
Michal Vaskocb1b7c02020-07-03 13:38:12 +02005605 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005606 /* no match */
5607 set_remove_node(set, i);
5608 }
5609 }
5610
Michal Vasko004d3152020-06-11 19:59:22 +02005611cleanup:
5612 lyd_free_tree(inst);
5613 return ret;
Michal Vaskod3678892020-05-21 10:06:58 +02005614}
5615
5616/**
5617 * @brief Move context @p set to a schema node. Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5618 *
5619 * @param[in,out] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005620 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02005621 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005622 * @param[in] options XPath options.
5623 * @return LY_ERR
5624 */
5625static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005626moveto_scnode(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005627{
Radek Krejci857189e2020-09-01 13:26:36 +02005628 ly_bool temp_ctx = 0;
Radek Krejci1deb5be2020-08-26 16:43:36 +02005629 uint32_t getnext_opts;
5630 uint32_t orig_used, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005631 uint32_t mod_idx;
Michal Vasko519fd602020-05-26 12:17:39 +02005632 const struct lysc_node *iter, *start_parent;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005633 const struct lys_module *mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005634
Michal Vaskod3678892020-05-21 10:06:58 +02005635 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005636 return LY_SUCCESS;
5637 }
5638
5639 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005640 LOGVAL(set->ctx, LY_VLOG_LYSC, set->cur_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005641 return LY_EVALID;
5642 }
5643
Michal Vaskocafad9d2019-11-07 15:20:03 +01005644 /* getnext opts */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01005645 getnext_opts = 0;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005646 if (options & LYXP_SCNODE_OUTPUT) {
5647 getnext_opts |= LYS_GETNEXT_OUTPUT;
5648 }
5649
Michal Vasko03ff5a72019-09-11 13:49:33 +02005650 orig_used = set->used;
5651 for (i = 0; i < orig_used; ++i) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005652 uint32_t idx;
5653
Radek Krejcif13b87b2020-12-01 22:02:17 +01005654 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
5655 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005656 continue;
5657 }
5658
5659 /* remember context node */
Radek Krejcif13b87b2020-12-01 22:02:17 +01005660 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vaskoec4df482019-12-16 10:02:18 +01005661 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005662 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005663 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005664
5665 start_parent = set->val.scnodes[i].scnode;
5666
5667 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005668 /* it can actually be in any module, it's all <running>, and even if it's moveto_mod (if set),
Michal Vasko9e9f26d2020-10-12 16:31:33 +02005669 * it can be in a top-level augment (the root node itself is useless in this case) */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005670 mod_idx = 0;
Michal Vasko9e9f26d2020-10-12 16:31:33 +02005671 while ((mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
Michal Vasko519fd602020-05-26 12:17:39 +02005672 iter = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005673 /* module may not be implemented */
Michal Vasko519fd602020-05-26 12:17:39 +02005674 while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005675 if (!moveto_scnode_check(iter, NULL, set, ncname, moveto_mod)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005676 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM, &idx));
5677
Michal Vasko03ff5a72019-09-11 13:49:33 +02005678 /* we need to prevent these nodes from being considered in this moveto */
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005679 if ((idx < orig_used) && (idx > i)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005680 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_NEW_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005681 temp_ctx = 1;
5682 }
5683 }
5684 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005685 }
5686
Michal Vasko519fd602020-05-26 12:17:39 +02005687 } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
5688 iter = NULL;
5689 while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005690 if (!moveto_scnode_check(iter, start_parent, set, ncname, moveto_mod)) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005691 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM, &idx));
5692
5693 if ((idx < orig_used) && (idx > i)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005694 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_NEW_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005695 temp_ctx = 1;
5696 }
5697 }
5698 }
5699 }
5700 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005701
5702 /* correct temporary in_ctx values */
5703 if (temp_ctx) {
5704 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005705 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NEW_CTX) {
5706 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005707 }
5708 }
5709 }
5710
5711 return LY_SUCCESS;
5712}
5713
5714/**
Michal Vaskod3678892020-05-21 10:06:58 +02005715 * @brief Move context @p set to a node and all its descendants. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
Michal Vasko03ff5a72019-09-11 13:49:33 +02005716 * Context position aware.
5717 *
5718 * @param[in] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005719 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02005720 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vaskocdad7122020-11-09 21:04:44 +01005721 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005722 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5723 */
5724static LY_ERR
Michal Vaskocdad7122020-11-09 21:04:44 +01005725moveto_node_alldesc(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005726{
5727 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005728 const struct lyd_node *next, *elem, *start;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005729 struct lyxp_set ret_set;
5730 LY_ERR rc;
5731
Michal Vaskod3678892020-05-21 10:06:58 +02005732 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005733 return LY_SUCCESS;
5734 }
5735
5736 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005737 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005738 return LY_EVALID;
5739 }
5740
Michal Vasko9f96a052020-03-10 09:41:45 +01005741 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vaskocdad7122020-11-09 21:04:44 +01005742 rc = moveto_node(set, NULL, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005743 LY_CHECK_RET(rc);
5744
Michal Vasko6346ece2019-09-24 13:12:53 +02005745 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005746 set_init(&ret_set, set);
5747 for (i = 0; i < set->used; ++i) {
5748
5749 /* TREE DFS */
5750 start = set->val.nodes[i].node;
5751 for (elem = next = start; elem; elem = next) {
Michal Vaskocdad7122020-11-09 21:04:44 +01005752 rc = moveto_node_check(elem, start, set, ncname, moveto_mod, options);
Michal Vasko6346ece2019-09-24 13:12:53 +02005753 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005754 /* add matching node into result set */
5755 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5756 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5757 /* the node is a duplicate, we'll process it later in the set */
5758 goto skip_children;
5759 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005760 } else if (rc == LY_EINCOMPLETE) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005761 return rc;
5762 } else if (rc == LY_EINVAL) {
5763 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005764 }
5765
5766 /* TREE DFS NEXT ELEM */
5767 /* select element for the next run - children first */
Radek Krejcia1c1e542020-09-29 16:06:52 +02005768 next = lyd_child(elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005769 if (!next) {
5770skip_children:
5771 /* no children, so try siblings, but only if it's not the start,
5772 * that is considered to be the root and it's siblings are not traversed */
5773 if (elem != start) {
5774 next = elem->next;
5775 } else {
5776 break;
5777 }
5778 }
5779 while (!next) {
5780 /* no siblings, go back through the parents */
5781 if ((struct lyd_node *)elem->parent == start) {
5782 /* we are done, no next element to process */
5783 break;
5784 }
5785 /* parent is already processed, go to its sibling */
5786 elem = (struct lyd_node *)elem->parent;
5787 next = elem->next;
5788 }
5789 }
5790 }
5791
5792 /* make the temporary set the current one */
5793 ret_set.ctx_pos = set->ctx_pos;
5794 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02005795 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005796 memcpy(set, &ret_set, sizeof *set);
5797
5798 return LY_SUCCESS;
5799}
5800
5801/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005802 * @brief Move context @p set to a schema node and all its descendants. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005803 *
5804 * @param[in] set Set to use.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005805 * @param[in] moveto_mod Matching node module, NULL for no prefix.
Michal Vaskod3678892020-05-21 10:06:58 +02005806 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005807 * @param[in] options XPath options.
5808 * @return LY_ERR
5809 */
5810static LY_ERR
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005811moveto_scnode_alldesc(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005812{
Radek Krejci1deb5be2020-08-26 16:43:36 +02005813 uint32_t i, orig_used;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005814 const struct lysc_node *next, *elem, *start;
Michal Vasko6346ece2019-09-24 13:12:53 +02005815 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005816
Michal Vaskod3678892020-05-21 10:06:58 +02005817 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005818 return LY_SUCCESS;
5819 }
5820
5821 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005822 LOGVAL(set->ctx, LY_VLOG_LYSC, set->cur_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005823 return LY_EVALID;
5824 }
5825
Michal Vasko03ff5a72019-09-11 13:49:33 +02005826 orig_used = set->used;
5827 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005828 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
5829 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005830 continue;
5831 }
5832
5833 /* remember context node */
Radek Krejcif13b87b2020-12-01 22:02:17 +01005834 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vaskoec4df482019-12-16 10:02:18 +01005835 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005836 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005837 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005838
5839 /* TREE DFS */
5840 start = set->val.scnodes[i].scnode;
5841 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005842 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5843 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005844 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005845 }
5846
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005847 rc = moveto_scnode_check(elem, start, set, ncname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005848 if (!rc) {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005849 uint32_t idx;
5850
5851 if (lyxp_set_scnode_contains(set, elem, LYXP_NODE_ELEM, i, &idx)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01005852 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Radek Krejci1deb5be2020-08-26 16:43:36 +02005853 if ((uint32_t)idx > i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005854 /* we will process it later in the set */
5855 goto skip_children;
5856 }
5857 } else {
Radek Krejciaa6b53f2020-08-27 15:19:03 +02005858 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM, NULL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005859 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005860 } else if (rc == LY_EINVAL) {
5861 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005862 }
5863
5864next_iter:
5865 /* TREE DFS NEXT ELEM */
5866 /* select element for the next run - children first */
5867 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005868 if (!next) {
5869skip_children:
5870 /* no children, so try siblings, but only if it's not the start,
5871 * that is considered to be the root and it's siblings are not traversed */
5872 if (elem != start) {
5873 next = elem->next;
5874 } else {
5875 break;
5876 }
5877 }
5878 while (!next) {
5879 /* no siblings, go back through the parents */
5880 if (elem->parent == start) {
5881 /* we are done, no next element to process */
5882 break;
5883 }
5884 /* parent is already processed, go to its sibling */
5885 elem = elem->parent;
5886 next = elem->next;
5887 }
5888 }
5889 }
5890
5891 return LY_SUCCESS;
5892}
5893
5894/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005895 * @brief Move context @p set to an attribute. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005896 * Indirectly context position aware.
5897 *
5898 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005899 * @param[in] mod Matching metadata module, NULL for any.
5900 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005901 * @return LY_ERR
5902 */
5903static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005904moveto_attr(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005905{
Michal Vasko9f96a052020-03-10 09:41:45 +01005906 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005907
Michal Vaskod3678892020-05-21 10:06:58 +02005908 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005909 return LY_SUCCESS;
5910 }
5911
5912 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005913 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005914 return LY_EVALID;
5915 }
5916
Radek Krejci1deb5be2020-08-26 16:43:36 +02005917 for (uint32_t i = 0; i < set->used; ) {
Radek Krejci857189e2020-09-01 13:26:36 +02005918 ly_bool replaced = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005919
5920 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5921 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005922 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005923 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005924
5925 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02005926 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005927 continue;
5928 }
5929
Michal Vaskod3678892020-05-21 10:06:58 +02005930 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005931 /* match */
5932 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005933 set->val.meta[i].meta = sub;
5934 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005935 /* pos does not change */
5936 replaced = 1;
5937 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005938 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 +02005939 }
5940 ++i;
5941 }
5942 }
5943 }
5944
5945 if (!replaced) {
5946 /* no match */
5947 set_remove_node(set, i);
5948 }
5949 }
5950
5951 return LY_SUCCESS;
5952}
5953
5954/**
5955 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
Michal Vasko61ac2f62020-05-25 12:39:51 +02005956 * Result is LYXP_SET_NODE_SET. Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005957 *
5958 * @param[in,out] set1 Set to use for the result.
5959 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005960 * @return LY_ERR
5961 */
5962static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005963moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005964{
5965 LY_ERR rc;
5966
Michal Vaskod3678892020-05-21 10:06:58 +02005967 if ((set1->type != LYXP_SET_NODE_SET) || (set2->type != LYXP_SET_NODE_SET)) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02005968 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->cur_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005969 return LY_EVALID;
5970 }
5971
5972 /* set2 is empty or both set1 and set2 */
Michal Vaskod3678892020-05-21 10:06:58 +02005973 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005974 return LY_SUCCESS;
5975 }
5976
Michal Vaskod3678892020-05-21 10:06:58 +02005977 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005978 memcpy(set1, set2, sizeof *set1);
5979 /* dynamic memory belongs to set1 now, do not free */
Michal Vaskod3678892020-05-21 10:06:58 +02005980 memset(set2, 0, sizeof *set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005981 return LY_SUCCESS;
5982 }
5983
5984 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005985 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005986
5987 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005988 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005989 LY_CHECK_RET(rc);
5990
5991 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005992 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005993
5994 return LY_SUCCESS;
5995}
5996
5997/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005998 * @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 +02005999 * Context position aware.
6000 *
6001 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02006002 * @param[in] mod Matching metadata module, NULL for any.
6003 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vaskocdad7122020-11-09 21:04:44 +01006004 * @param[in] options XPath options.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006005 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6006 */
6007static int
Michal Vaskocdad7122020-11-09 21:04:44 +01006008moveto_attr_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006009{
Michal Vasko9f96a052020-03-10 09:41:45 +01006010 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006011 struct lyxp_set *set_all_desc = NULL;
6012 LY_ERR rc;
6013
Michal Vaskod3678892020-05-21 10:06:58 +02006014 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006015 return LY_SUCCESS;
6016 }
6017
6018 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006019 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006020 return LY_EVALID;
6021 }
6022
Michal Vasko03ff5a72019-09-11 13:49:33 +02006023 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
6024 * but it likely won't be used much, so it's a waste of time */
6025 /* copy the context */
6026 set_all_desc = set_copy(set);
6027 /* get all descendant nodes (the original context nodes are removed) */
Michal Vaskocdad7122020-11-09 21:04:44 +01006028 rc = moveto_node_alldesc(set_all_desc, NULL, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006029 if (rc != LY_SUCCESS) {
6030 lyxp_set_free(set_all_desc);
6031 return rc;
6032 }
6033 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006034 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006035 if (rc != LY_SUCCESS) {
6036 lyxp_set_free(set_all_desc);
6037 return rc;
6038 }
6039 lyxp_set_free(set_all_desc);
6040
Radek Krejci1deb5be2020-08-26 16:43:36 +02006041 for (uint32_t i = 0; i < set->used; ) {
Radek Krejci857189e2020-09-01 13:26:36 +02006042 ly_bool replaced = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006043
6044 /* only attributes of an elem can be in the result, skip all the rest,
6045 * we have all attributes qualified in lyd tree */
6046 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01006047 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006048 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02006049 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006050 continue;
6051 }
6052
Michal Vaskod3678892020-05-21 10:06:58 +02006053 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006054 /* match */
6055 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01006056 set->val.meta[i].meta = sub;
6057 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006058 /* pos does not change */
6059 replaced = 1;
6060 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01006061 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 +02006062 }
6063 ++i;
6064 }
6065 }
6066 }
6067
6068 if (!replaced) {
6069 /* no match */
6070 set_remove_node(set, i);
6071 }
6072 }
6073
6074 return LY_SUCCESS;
6075}
6076
6077/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02006078 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET.
6079 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006080 *
6081 * @param[in] parent Current parent.
6082 * @param[in] parent_pos Position of @p parent.
6083 * @param[in] parent_type Node type of @p parent.
6084 * @param[in,out] to_set Set to use.
6085 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006086 * @param[in] options XPath options.
6087 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6088 */
6089static LY_ERR
6090moveto_self_add_children_r(const struct lyd_node *parent, uint32_t parent_pos, enum lyxp_node_type parent_type,
Radek Krejci1deb5be2020-08-26 16:43:36 +02006091 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006092{
Michal Vasko61ac2f62020-05-25 12:39:51 +02006093 const struct lyd_node *iter, *first;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006094 LY_ERR rc;
6095
6096 switch (parent_type) {
6097 case LYXP_NODE_ROOT:
6098 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko61ac2f62020-05-25 12:39:51 +02006099 assert(!parent);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006100
Michal Vasko61ac2f62020-05-25 12:39:51 +02006101 /* add all top-level nodes as elements */
6102 first = to_set->tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006103 break;
6104 case LYXP_NODE_ELEM:
Michal Vasko61ac2f62020-05-25 12:39:51 +02006105 /* add just the text node of this term element node */
6106 if (parent->schema->nodetype & (LYD_NODE_TERM | LYD_NODE_ANY)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006107 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
6108 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
6109 }
Michal Vasko61ac2f62020-05-25 12:39:51 +02006110 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006111 }
Michal Vasko61ac2f62020-05-25 12:39:51 +02006112
6113 /* add all the children of this node */
Radek Krejcia1c1e542020-09-29 16:06:52 +02006114 first = lyd_child(parent);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006115 break;
6116 default:
6117 LOGINT_RET(parent->schema->module->ctx);
6118 }
6119
Michal Vasko61ac2f62020-05-25 12:39:51 +02006120 /* add all top-level nodes as elements */
6121 LY_LIST_FOR(first, iter) {
6122 /* context check */
6123 if ((parent_type == LYXP_NODE_ROOT_CONFIG) && (iter->schema->flags & LYS_CONFIG_R)) {
6124 continue;
6125 }
6126
6127 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01006128 if (!(options & LYXP_IGNORE_WHEN) && lysc_has_when(iter->schema) && !(iter->flags & LYD_WHEN_TRUE)) {
Michal Vasko61ac2f62020-05-25 12:39:51 +02006129 return LY_EINCOMPLETE;
6130 }
6131
6132 if (!set_dup_node_check(dup_check_set, iter, LYXP_NODE_ELEM, -1)) {
6133 set_insert_node(to_set, iter, 0, LYXP_NODE_ELEM, to_set->used);
6134
6135 /* also add all the children of this node, recursively */
6136 rc = moveto_self_add_children_r(iter, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
6137 LY_CHECK_RET(rc);
6138 }
6139 }
6140
Michal Vasko03ff5a72019-09-11 13:49:33 +02006141 return LY_SUCCESS;
6142}
6143
6144/**
6145 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
6146 * (or LYXP_SET_EMPTY). Context position aware.
6147 *
6148 * @param[in,out] set Set to use.
6149 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6150 * @param[in] options XPath options.
6151 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6152 */
6153static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02006154moveto_self(struct lyxp_set *set, ly_bool all_desc, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006155{
Michal Vasko03ff5a72019-09-11 13:49:33 +02006156 struct lyxp_set ret_set;
6157 LY_ERR rc;
6158
Michal Vaskod3678892020-05-21 10:06:58 +02006159 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006160 return LY_SUCCESS;
6161 }
6162
6163 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006164 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006165 return LY_EVALID;
6166 }
6167
6168 /* nothing to do */
6169 if (!all_desc) {
6170 return LY_SUCCESS;
6171 }
6172
Michal Vasko03ff5a72019-09-11 13:49:33 +02006173 /* add all the children, they get added recursively */
6174 set_init(&ret_set, set);
Radek Krejci1deb5be2020-08-26 16:43:36 +02006175 for (uint32_t i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006176 /* copy the current node to tmp */
6177 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6178
6179 /* do not touch attributes and text nodes */
Michal Vasko9f96a052020-03-10 09:41:45 +01006180 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006181 continue;
6182 }
6183
Michal Vasko03ff5a72019-09-11 13:49:33 +02006184 /* add all the children */
6185 rc = moveto_self_add_children_r(set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, &ret_set,
Michal Vasko69730152020-10-09 16:30:07 +02006186 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006187 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006188 lyxp_set_free_content(&ret_set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006189 return rc;
6190 }
6191 }
6192
6193 /* use the temporary set as the current one */
6194 ret_set.ctx_pos = set->ctx_pos;
6195 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02006196 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006197 memcpy(set, &ret_set, sizeof *set);
6198
6199 return LY_SUCCESS;
6200}
6201
6202/**
6203 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6204 * (or LYXP_SET_EMPTY).
6205 *
6206 * @param[in,out] set Set to use.
6207 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6208 * @param[in] options XPath options.
6209 * @return LY_ERR
6210 */
6211static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02006212moveto_scnode_self(struct lyxp_set *set, ly_bool all_desc, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006213{
Radek Krejci1deb5be2020-08-26 16:43:36 +02006214 uint32_t getnext_opts;
6215 uint32_t mod_idx;
Michal Vasko519fd602020-05-26 12:17:39 +02006216 const struct lysc_node *iter, *start_parent;
6217 const struct lys_module *mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006218
Michal Vaskod3678892020-05-21 10:06:58 +02006219 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006220 return LY_SUCCESS;
6221 }
6222
6223 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006224 LOGVAL(set->ctx, LY_VLOG_LYSC, set->cur_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006225 return LY_EVALID;
6226 }
6227
6228 /* nothing to do */
6229 if (!all_desc) {
6230 return LY_SUCCESS;
6231 }
6232
Michal Vasko519fd602020-05-26 12:17:39 +02006233 /* getnext opts */
Michal Vasko7b1ad1a2020-11-02 15:41:27 +01006234 getnext_opts = 0;
Michal Vasko519fd602020-05-26 12:17:39 +02006235 if (options & LYXP_SCNODE_OUTPUT) {
6236 getnext_opts |= LYS_GETNEXT_OUTPUT;
6237 }
6238
6239 /* add all the children, recursively as they are being added into the same set */
Radek Krejci1deb5be2020-08-26 16:43:36 +02006240 for (uint32_t i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006241 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
6242 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006243 continue;
6244 }
6245
Michal Vasko519fd602020-05-26 12:17:39 +02006246 /* remember context node */
Radek Krejcif13b87b2020-12-01 22:02:17 +01006247 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vasko519fd602020-05-26 12:17:39 +02006248 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006249 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006250 }
6251
Michal Vasko519fd602020-05-26 12:17:39 +02006252 start_parent = set->val.scnodes[i].scnode;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006253
Michal Vasko519fd602020-05-26 12:17:39 +02006254 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
6255 /* it can actually be in any module, it's all <running> */
6256 mod_idx = 0;
6257 while ((mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
6258 iter = NULL;
6259 /* module may not be implemented */
6260 while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
6261 /* context check */
6262 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
6263 continue;
6264 }
6265
Radek Krejciaa6b53f2020-08-27 15:19:03 +02006266 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM, NULL));
Michal Vasko519fd602020-05-26 12:17:39 +02006267 /* throw away the insert index, we want to consider that node again, recursively */
6268 }
6269 }
6270
6271 } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6272 iter = NULL;
6273 while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006274 /* context check */
Michal Vasko519fd602020-05-26 12:17:39 +02006275 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006276 continue;
6277 }
6278
Radek Krejciaa6b53f2020-08-27 15:19:03 +02006279 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM, NULL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006280 }
6281 }
6282 }
6283
6284 return LY_SUCCESS;
6285}
6286
6287/**
6288 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6289 * (or LYXP_SET_EMPTY). Context position aware.
6290 *
6291 * @param[in] set Set to use.
6292 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6293 * @param[in] options XPath options.
6294 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6295 */
6296static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02006297moveto_parent(struct lyxp_set *set, ly_bool all_desc, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006298{
6299 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006300 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006301 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006302
Michal Vaskod3678892020-05-21 10:06:58 +02006303 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006304 return LY_SUCCESS;
6305 }
6306
6307 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006308 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006309 return LY_EVALID;
6310 }
6311
6312 if (all_desc) {
6313 /* <path>//.. == <path>//./.. */
6314 rc = moveto_self(set, 1, options);
6315 LY_CHECK_RET(rc);
6316 }
6317
Radek Krejci1deb5be2020-08-26 16:43:36 +02006318 for (uint32_t i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006319 node = set->val.nodes[i].node;
6320
6321 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6322 new_node = (struct lyd_node *)node->parent;
6323 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6324 new_node = node;
Michal Vasko9f96a052020-03-10 09:41:45 +01006325 } else if (set->val.nodes[i].type == LYXP_NODE_META) {
6326 new_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006327 if (!new_node) {
6328 LOGINT_RET(set->ctx);
6329 }
6330 } else {
6331 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006332 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006333 continue;
6334 }
6335
Michal Vaskoa1424542019-11-14 16:08:52 +01006336 /* when check */
Michal Vaskod5cfa6e2020-11-23 16:56:08 +01006337 if (!(options & LYXP_IGNORE_WHEN) && new_node && lysc_has_when(new_node->schema) && !(new_node->flags & LYD_WHEN_TRUE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006338 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006339 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006340
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006341 if (!new_node) {
Radek Krejcif6a11002020-08-21 13:29:07 +02006342 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006343 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006344
Michal Vasko03ff5a72019-09-11 13:49:33 +02006345 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02006346 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006347 new_type = LYXP_NODE_ELEM;
6348 }
6349
Michal Vasko03ff5a72019-09-11 13:49:33 +02006350 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006351 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006352 } else {
6353 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006354 }
6355 }
6356
Michal Vasko2caefc12019-11-14 16:07:56 +01006357 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006358 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006359
6360 return LY_SUCCESS;
6361}
6362
6363/**
6364 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6365 * (or LYXP_SET_EMPTY).
6366 *
6367 * @param[in] set Set to use.
6368 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6369 * @param[in] options XPath options.
6370 * @return LY_ERR
6371 */
6372static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02006373moveto_scnode_parent(struct lyxp_set *set, ly_bool all_desc, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006374{
Radek Krejciaa6b53f2020-08-27 15:19:03 +02006375 uint32_t i, orig_used, idx;
Radek Krejci857189e2020-09-01 13:26:36 +02006376 ly_bool temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006377 const struct lysc_node *node, *new_node;
6378 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006379
Michal Vaskod3678892020-05-21 10:06:58 +02006380 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006381 return LY_SUCCESS;
6382 }
6383
6384 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006385 LOGVAL(set->ctx, LY_VLOG_LYSC, set->cur_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006386 return LY_EVALID;
6387 }
6388
6389 if (all_desc) {
6390 /* <path>//.. == <path>//./.. */
Radek Krejci1deb5be2020-08-26 16:43:36 +02006391 LY_CHECK_RET(moveto_scnode_self(set, 1, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006392 }
6393
Michal Vasko03ff5a72019-09-11 13:49:33 +02006394 orig_used = set->used;
6395 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006396 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_ATOM_CTX) {
6397 if (set->val.scnodes[i].in_ctx != LYXP_SET_SCNODE_START) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006398 continue;
6399 }
6400
6401 /* remember context node */
Radek Krejcif13b87b2020-12-01 22:02:17 +01006402 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_START_USED;
Michal Vaskoec4df482019-12-16 10:02:18 +01006403 } else {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006404 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006405 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006406
6407 node = set->val.scnodes[i].scnode;
6408
6409 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vaskod3678892020-05-21 10:06:58 +02006410 new_node = lysc_data_parent(node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006411 } else {
6412 /* root does not have a parent */
6413 continue;
6414 }
6415
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006416 if (!new_node) {
Radek Krejcif6a11002020-08-21 13:29:07 +02006417 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006418 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006419
Michal Vasko03ff5a72019-09-11 13:49:33 +02006420 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02006421 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006422 new_type = LYXP_NODE_ELEM;
6423 }
6424
Radek Krejciaa6b53f2020-08-27 15:19:03 +02006425 LY_CHECK_RET(lyxp_set_scnode_insert_node(set, new_node, new_type, &idx));
6426 if ((idx < orig_used) && (idx > i)) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006427 set->val.scnodes[idx].in_ctx = LYXP_SET_SCNODE_ATOM_NEW_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006428 temp_ctx = 1;
6429 }
6430 }
6431
6432 if (temp_ctx) {
6433 for (i = 0; i < orig_used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006434 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NEW_CTX) {
6435 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006436 }
6437 }
6438 }
6439
6440 return LY_SUCCESS;
6441}
6442
6443/**
6444 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6445 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6446 *
6447 * @param[in,out] set1 Set to use for the result.
6448 * @param[in] set2 Set acting as the second operand for @p op.
6449 * @param[in] op Comparison operator to process.
6450 * @param[in] options XPath options.
6451 * @return LY_ERR
6452 */
6453static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02006454moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006455{
6456 /*
6457 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6458 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6459 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6460 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6461 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6462 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6463 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6464 *
6465 * '=' or '!='
6466 * BOOLEAN + BOOLEAN
6467 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6468 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6469 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6470 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6471 * NUMBER + NUMBER
6472 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6473 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6474 * STRING + STRING
6475 *
6476 * '<=', '<', '>=', '>'
6477 * NUMBER + NUMBER
6478 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6479 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6480 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6481 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6482 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6483 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6484 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6485 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6486 */
6487 struct lyxp_set iter1, iter2;
6488 int result;
6489 int64_t i;
6490 LY_ERR rc;
6491
Michal Vasko004d3152020-06-11 19:59:22 +02006492 memset(&iter1, 0, sizeof iter1);
6493 memset(&iter2, 0, sizeof iter2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006494
6495 /* iterative evaluation with node-sets */
6496 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6497 if (set1->type == LYXP_SET_NODE_SET) {
6498 for (i = 0; i < set1->used; ++i) {
Michal Vasko4c7763f2020-07-27 17:40:37 +02006499 /* cast set1 */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006500 switch (set2->type) {
6501 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006502 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006503 break;
6504 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006505 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006506 break;
6507 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006508 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006509 break;
6510 }
6511 LY_CHECK_RET(rc);
6512
Michal Vasko4c7763f2020-07-27 17:40:37 +02006513 /* canonize set2 */
6514 LY_CHECK_ERR_RET(rc = set_comp_canonize(&iter2, set2, &set1->val.nodes[i]), lyxp_set_free_content(&iter1), rc);
6515
6516 /* compare recursively */
6517 rc = moveto_op_comp(&iter1, &iter2, op, options);
6518 lyxp_set_free_content(&iter2);
6519 LY_CHECK_ERR_RET(rc, lyxp_set_free_content(&iter1), rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006520
6521 /* lazy evaluation until true */
Michal Vasko004d3152020-06-11 19:59:22 +02006522 if (iter1.val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006523 set_fill_boolean(set1, 1);
6524 return LY_SUCCESS;
6525 }
6526 }
6527 } else {
6528 for (i = 0; i < set2->used; ++i) {
Michal Vasko4c7763f2020-07-27 17:40:37 +02006529 /* set set2 */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006530 switch (set1->type) {
Michal Vasko4c7763f2020-07-27 17:40:37 +02006531 case LYXP_SET_NUMBER:
6532 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
6533 break;
6534 case LYXP_SET_BOOLEAN:
6535 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
6536 break;
6537 default:
6538 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
6539 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006540 }
6541 LY_CHECK_RET(rc);
6542
Michal Vasko4c7763f2020-07-27 17:40:37 +02006543 /* canonize set1 */
6544 LY_CHECK_ERR_RET(rc = set_comp_canonize(&iter1, set1, &set2->val.nodes[i]), lyxp_set_free_content(&iter2), rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006545
Michal Vasko4c7763f2020-07-27 17:40:37 +02006546 /* compare recursively */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006547 rc = moveto_op_comp(&iter1, &iter2, op, options);
Michal Vaskod3678892020-05-21 10:06:58 +02006548 lyxp_set_free_content(&iter2);
Michal Vasko4c7763f2020-07-27 17:40:37 +02006549 LY_CHECK_ERR_RET(rc, lyxp_set_free_content(&iter1), rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006550
6551 /* lazy evaluation until true */
Michal Vasko004d3152020-06-11 19:59:22 +02006552 if (iter1.val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006553 set_fill_boolean(set1, 1);
6554 return LY_SUCCESS;
6555 }
6556 }
6557 }
6558
6559 /* false for all nodes */
6560 set_fill_boolean(set1, 0);
6561 return LY_SUCCESS;
6562 }
6563
6564 /* first convert properly */
6565 if ((op[0] == '=') || (op[0] == '!')) {
6566 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006567 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6568 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006569 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006570 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006571 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006572 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006573 LY_CHECK_RET(rc);
6574 } /* else we have 2 strings */
6575 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006576 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006577 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006578 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006579 LY_CHECK_RET(rc);
6580 }
6581
6582 assert(set1->type == set2->type);
6583
6584 /* compute result */
6585 if (op[0] == '=') {
6586 if (set1->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +02006587 result = (set1->val.bln == set2->val.bln);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006588 } else if (set1->type == LYXP_SET_NUMBER) {
6589 result = (set1->val.num == set2->val.num);
6590 } else {
6591 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006592 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006593 }
6594 } else if (op[0] == '!') {
6595 if (set1->type == LYXP_SET_BOOLEAN) {
Michal Vasko004d3152020-06-11 19:59:22 +02006596 result = (set1->val.bln != set2->val.bln);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006597 } else if (set1->type == LYXP_SET_NUMBER) {
6598 result = (set1->val.num != set2->val.num);
6599 } else {
6600 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoc2058432020-11-06 17:26:21 +01006601 result = strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006602 }
6603 } else {
6604 assert(set1->type == LYXP_SET_NUMBER);
6605 if (op[0] == '<') {
6606 if (op[1] == '=') {
6607 result = (set1->val.num <= set2->val.num);
6608 } else {
6609 result = (set1->val.num < set2->val.num);
6610 }
6611 } else {
6612 if (op[1] == '=') {
6613 result = (set1->val.num >= set2->val.num);
6614 } else {
6615 result = (set1->val.num > set2->val.num);
6616 }
6617 }
6618 }
6619
6620 /* assign result */
6621 if (result) {
6622 set_fill_boolean(set1, 1);
6623 } else {
6624 set_fill_boolean(set1, 0);
6625 }
6626
6627 return LY_SUCCESS;
6628}
6629
6630/**
6631 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6632 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6633 *
6634 * @param[in,out] set1 Set to use for the result.
6635 * @param[in] set2 Set acting as the second operand for @p op.
6636 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006637 * @return LY_ERR
6638 */
6639static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006640moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006641{
6642 LY_ERR rc;
6643
6644 /* unary '-' */
6645 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006646 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006647 LY_CHECK_RET(rc);
6648 set1->val.num *= -1;
6649 lyxp_set_free(set2);
6650 return LY_SUCCESS;
6651 }
6652
6653 assert(set1 && set2);
6654
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006655 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006656 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006657 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006658 LY_CHECK_RET(rc);
6659
6660 switch (op[0]) {
6661 /* '+' */
6662 case '+':
6663 set1->val.num += set2->val.num;
6664 break;
6665
6666 /* '-' */
6667 case '-':
6668 set1->val.num -= set2->val.num;
6669 break;
6670
6671 /* '*' */
6672 case '*':
6673 set1->val.num *= set2->val.num;
6674 break;
6675
6676 /* 'div' */
6677 case 'd':
6678 set1->val.num /= set2->val.num;
6679 break;
6680
6681 /* 'mod' */
6682 case 'm':
6683 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6684 break;
6685
6686 default:
6687 LOGINT_RET(set1->ctx);
6688 }
6689
6690 return LY_SUCCESS;
6691}
6692
6693/*
6694 * eval functions
6695 *
6696 * They execute a parsed XPath expression on some data subtree.
6697 */
6698
6699/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02006700 * @brief Evaluate Predicate. Logs directly on error.
6701 *
Michal Vaskod3678892020-05-21 10:06:58 +02006702 * [9] Predicate ::= '[' Expr ']'
Michal Vasko03ff5a72019-09-11 13:49:33 +02006703 *
6704 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02006705 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006706 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6707 * @param[in] options XPath options.
6708 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6709 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6710 */
6711static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02006712eval_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set, uint32_t options, ly_bool parent_pos_pred)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006713{
6714 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006715 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006716 uint32_t orig_pos, orig_size;
6717 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006718 struct lyxp_set set2;
6719 struct lyd_node *orig_parent;
6720
6721 /* '[' */
6722 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02006723 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02006724 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006725
6726 if (!set) {
6727only_parse:
Michal Vasko004d3152020-06-11 19:59:22 +02006728 rc = eval_expr_select(exp, tok_idx, 0, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006729 LY_CHECK_RET(rc);
6730 } else if (set->type == LYXP_SET_NODE_SET) {
6731 /* 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 +01006732 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006733
6734 /* empty set, nothing to evaluate */
6735 if (!set->used) {
6736 goto only_parse;
6737 }
6738
Michal Vasko004d3152020-06-11 19:59:22 +02006739 orig_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006740 orig_pos = 0;
6741 orig_size = set->used;
6742 orig_parent = NULL;
Michal Vasko39dbf352020-05-21 10:08:59 +02006743 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006744 set_init(&set2, set);
6745 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6746 /* remember the node context position for position() and context size for last(),
6747 * predicates should always be evaluated with respect to the child axis (since we do
6748 * not support explicit axes) so we assign positions based on their parents */
6749 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6750 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6751 orig_pos = 1;
6752 } else {
6753 ++orig_pos;
6754 }
6755
6756 set2.ctx_pos = orig_pos;
6757 set2.ctx_size = orig_size;
Michal Vasko004d3152020-06-11 19:59:22 +02006758 *tok_idx = orig_exp;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006759
Michal Vasko004d3152020-06-11 19:59:22 +02006760 rc = eval_expr_select(exp, tok_idx, 0, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006761 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006762 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006763 return rc;
6764 }
6765
6766 /* number is a position */
6767 if (set2.type == LYXP_SET_NUMBER) {
6768 if ((long long)set2.val.num == orig_pos) {
6769 set2.val.num = 1;
6770 } else {
6771 set2.val.num = 0;
6772 }
6773 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006774 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006775
6776 /* predicate satisfied or not? */
Michal Vasko004d3152020-06-11 19:59:22 +02006777 if (!set2.val.bln) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006778 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006779 }
6780 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006781 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006782
6783 } else if (set->type == LYXP_SET_SCNODE_SET) {
6784 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006785 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006786 /* there is a currently-valid node */
6787 break;
6788 }
6789 }
6790 /* empty set, nothing to evaluate */
6791 if (i == set->used) {
6792 goto only_parse;
6793 }
6794
Michal Vasko004d3152020-06-11 19:59:22 +02006795 orig_exp = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006796
Michal Vasko03ff5a72019-09-11 13:49:33 +02006797 /* set special in_ctx to all the valid snodes */
6798 pred_in_ctx = set_scnode_new_in_ctx(set);
6799
6800 /* use the valid snodes one-by-one */
6801 for (i = 0; i < set->used; ++i) {
6802 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6803 continue;
6804 }
Radek Krejcif13b87b2020-12-01 22:02:17 +01006805 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006806
Michal Vasko004d3152020-06-11 19:59:22 +02006807 *tok_idx = orig_exp;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006808
Michal Vasko004d3152020-06-11 19:59:22 +02006809 rc = eval_expr_select(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006810 LY_CHECK_RET(rc);
6811
6812 set->val.scnodes[i].in_ctx = pred_in_ctx;
6813 }
6814
6815 /* restore the state as it was before the predicate */
6816 for (i = 0; i < set->used; ++i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006817 if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
6818 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006819 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01006820 set->val.scnodes[i].in_ctx = LYXP_SET_SCNODE_ATOM_CTX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006821 }
6822 }
6823
6824 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02006825 set2.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006826 set_fill_set(&set2, set);
6827
Michal Vasko004d3152020-06-11 19:59:22 +02006828 rc = eval_expr_select(exp, tok_idx, 0, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006829 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006830 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006831 return rc;
6832 }
6833
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006834 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko004d3152020-06-11 19:59:22 +02006835 if (!set2.val.bln) {
Michal Vaskod3678892020-05-21 10:06:58 +02006836 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006837 }
Michal Vaskod3678892020-05-21 10:06:58 +02006838 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006839 }
6840
6841 /* ']' */
Michal Vasko004d3152020-06-11 19:59:22 +02006842 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006843 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02006844 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02006845 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006846
6847 return LY_SUCCESS;
6848}
6849
6850/**
Michal Vaskod3678892020-05-21 10:06:58 +02006851 * @brief Evaluate Literal. Logs directly on error.
6852 *
6853 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02006854 * @param[in] tok_idx Position in the expression @p exp.
Michal Vaskod3678892020-05-21 10:06:58 +02006855 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6856 */
6857static void
Michal Vasko40308e72020-10-20 16:38:40 +02006858eval_literal(const struct lyxp_expr *exp, uint16_t *tok_idx, struct lyxp_set *set)
Michal Vaskod3678892020-05-21 10:06:58 +02006859{
6860 if (set) {
Michal Vasko004d3152020-06-11 19:59:22 +02006861 if (exp->tok_len[*tok_idx] == 2) {
Michal Vaskod3678892020-05-21 10:06:58 +02006862 set_fill_string(set, "", 0);
6863 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02006864 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 +02006865 }
6866 }
6867 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02006868 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02006869 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02006870}
6871
6872/**
Michal Vasko004d3152020-06-11 19:59:22 +02006873 * @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 +02006874 *
Michal Vasko004d3152020-06-11 19:59:22 +02006875 * @param[in] exp Full parsed XPath expression.
6876 * @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 +02006877 * @param[in] ctx_node Found schema node as the context for the predicate.
6878 * @param[in] cur_mod Current module for the expression.
6879 * @param[in] cur_node Current (original context) node.
Michal Vasko004d3152020-06-11 19:59:22 +02006880 * @param[in] format Format of any prefixes in key names/values.
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006881 * @param[in] prefix_data Format-specific prefix data (see ::ly_resolve_prefix).
Michal Vasko004d3152020-06-11 19:59:22 +02006882 * @param[out] predicates Parsed predicates.
6883 * @param[out] pred_type Type of @p predicates.
6884 * @return LY_SUCCESS on success,
6885 * @return LY_ERR on any error.
Michal Vaskod3678892020-05-21 10:06:58 +02006886 */
6887static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02006888eval_name_test_try_compile_predicates(const struct lyxp_expr *exp, uint16_t *tok_idx, const struct lysc_node *ctx_node,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006889 const struct lys_module *cur_mod, const struct lysc_node *cur_node, LY_PREFIX_FORMAT format, void *prefix_data,
6890 struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
Michal Vaskod3678892020-05-21 10:06:58 +02006891{
Michal Vasko004d3152020-06-11 19:59:22 +02006892 LY_ERR ret = LY_SUCCESS;
6893 uint16_t key_count, e_idx, pred_idx = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02006894 const struct lysc_node *key;
Michal Vasko004d3152020-06-11 19:59:22 +02006895 size_t pred_len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02006896 uint32_t prev_lo;
Michal Vasko004d3152020-06-11 19:59:22 +02006897 struct lyxp_expr *exp2 = NULL;
Michal Vaskod3678892020-05-21 10:06:58 +02006898
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006899 assert(ctx_node->nodetype & (LYS_LIST | LYS_LEAFLIST));
Michal Vaskod3678892020-05-21 10:06:58 +02006900
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006901 if (ctx_node->nodetype == LYS_LIST) {
Michal Vasko004d3152020-06-11 19:59:22 +02006902 /* get key count */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006903 if (ctx_node->flags & LYS_KEYLESS) {
Michal Vasko004d3152020-06-11 19:59:22 +02006904 return LY_EINVAL;
6905 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006906 for (key_count = 0, key = lysc_node_children(ctx_node, 0); key && (key->flags & LYS_KEY); key = key->next, ++key_count) {}
Michal Vasko004d3152020-06-11 19:59:22 +02006907 assert(key_count);
Michal Vaskod3678892020-05-21 10:06:58 +02006908
Michal Vasko004d3152020-06-11 19:59:22 +02006909 /* learn where the predicates end */
6910 e_idx = *tok_idx;
6911 while (key_count) {
6912 /* '[' */
6913 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK1)) {
6914 return LY_EINVAL;
6915 }
6916 ++e_idx;
6917
6918 /* ']' */
6919 while (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK2)) {
6920 ++e_idx;
6921 }
6922 ++e_idx;
6923
6924 /* another presumably key predicate parsed */
6925 --key_count;
6926 }
Michal Vasko004d3152020-06-11 19:59:22 +02006927 } else {
6928 /* learn just where this single predicate ends */
6929 e_idx = *tok_idx;
6930
Michal Vaskod3678892020-05-21 10:06:58 +02006931 /* '[' */
Michal Vasko004d3152020-06-11 19:59:22 +02006932 if (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK1)) {
6933 return LY_EINVAL;
6934 }
6935 ++e_idx;
Michal Vaskod3678892020-05-21 10:06:58 +02006936
6937 /* ']' */
Michal Vasko004d3152020-06-11 19:59:22 +02006938 while (lyxp_check_token(NULL, exp, e_idx, LYXP_TOKEN_BRACK2)) {
6939 ++e_idx;
6940 }
6941 ++e_idx;
Michal Vaskod3678892020-05-21 10:06:58 +02006942 }
6943
Michal Vasko004d3152020-06-11 19:59:22 +02006944 /* get the joined length of all the keys predicates/of the single leaf-list predicate */
6945 pred_len = (exp->tok_pos[e_idx - 1] + exp->tok_len[e_idx - 1]) - exp->tok_pos[*tok_idx];
6946
6947 /* turn logging off */
6948 prev_lo = ly_log_options(0);
6949
6950 /* parse the predicate(s) */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006951 LY_CHECK_GOTO(ret = ly_path_parse_predicate(ctx_node->module->ctx, ctx_node, exp->expr + exp->tok_pos[*tok_idx],
6952 pred_len, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &exp2), cleanup);
Michal Vasko004d3152020-06-11 19:59:22 +02006953
6954 /* compile */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006955 ret = ly_path_compile_predicate(ctx_node->module->ctx, cur_node, cur_mod, ctx_node, exp2, &pred_idx, format,
6956 prefix_data, predicates, pred_type);
Michal Vasko004d3152020-06-11 19:59:22 +02006957 LY_CHECK_GOTO(ret, cleanup);
6958
6959 /* success, the predicate must include all the needed information for hash-based search */
6960 *tok_idx = e_idx;
6961
6962cleanup:
6963 ly_log_options(prev_lo);
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006964 lyxp_expr_free(ctx_node->module->ctx, exp2);
Michal Vasko004d3152020-06-11 19:59:22 +02006965 return ret;
Michal Vaskod3678892020-05-21 10:06:58 +02006966}
6967
6968/**
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006969 * @brief Search for/check the next schema node that could be the only matching schema node meaning the
6970 * data node(s) could be found using a single hash-based search.
6971 *
6972 * @param[in] node Next context node to check.
6973 * @param[in] name Expected node name.
6974 * @param[in] name_len Length of @p name.
6975 * @param[in] moveto_mod Expected node module.
6976 * @param[in] root_type XPath root type.
6977 * @param[in] no_prefix Whether the node name was unprefixed.
6978 * @param[in] format Prefix format.
6979 * @param[in,out] found Previously found node, is updated.
6980 * @return LY_SUCCESS on success,
6981 * @return LY_ENOT if the whole check failed and hashes cannot be used.
6982 */
6983static LY_ERR
6984eval_name_test_with_predicate_get_scnode(const struct lyd_node *node, const char *name, uint16_t name_len,
6985 const struct lys_module *moveto_mod, enum lyxp_node_type root_type, ly_bool no_prefix, LY_PREFIX_FORMAT format,
6986 const struct lysc_node **found)
6987{
6988 const struct lysc_node *scnode;
6989 const struct lys_module *mod;
6990 uint32_t idx = 0;
6991
6992continue_search:
Michal Vasko7d1d0912020-10-16 08:38:30 +02006993 scnode = NULL;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02006994 if (!node) {
6995 if (no_prefix && (format == LY_PREF_JSON)) {
6996 /* search all modules for a single match */
6997 while ((mod = ly_ctx_get_module_iter(moveto_mod->ctx, &idx))) {
6998 scnode = lys_find_child(NULL, mod, name, name_len, 0, 0);
6999 if (scnode) {
7000 /* we have found a match */
7001 break;
7002 }
7003 }
7004
Michal Vasko7d1d0912020-10-16 08:38:30 +02007005 if (!scnode) {
7006 /* all modules searched */
7007 idx = 0;
7008 }
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007009 } else {
7010 /* search in top-level */
7011 scnode = lys_find_child(NULL, moveto_mod, name, name_len, 0, 0);
7012 }
7013 } else if (!*found || (lysc_data_parent(*found) != node->schema)) {
7014 if (no_prefix && (format == LY_PREF_JSON)) {
7015 /* we must adjust the module to inherit the one from the context node */
7016 moveto_mod = node->schema->module;
7017 }
7018
7019 /* search in children, do not repeat the same search */
7020 scnode = lys_find_child(node->schema, moveto_mod, name, name_len, 0, 0);
Michal Vasko7d1d0912020-10-16 08:38:30 +02007021 } /* else skip redundant search */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007022
7023 /* additional context check */
7024 if (scnode && (root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
7025 scnode = NULL;
7026 }
7027
7028 if (scnode) {
7029 if (*found) {
7030 /* we found a schema node with the same name but at different level, give up, too complicated
7031 * (more hash-based searches would be required, not supported) */
7032 return LY_ENOT;
7033 } else {
7034 /* remember the found schema node and continue to make sure it can be used */
7035 *found = scnode;
7036 }
7037 }
7038
7039 if (idx) {
7040 /* continue searching all the following models */
7041 goto continue_search;
7042 }
7043
7044 return LY_SUCCESS;
7045}
7046
7047/**
Michal Vaskod3678892020-05-21 10:06:58 +02007048 * @brief Evaluate NameTest and any following Predicates. Logs directly on error.
7049 *
7050 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
7051 * [6] NodeTest ::= NameTest | NodeType '(' ')'
7052 * [7] NameTest ::= '*' | NCName ':' '*' | QName
7053 *
7054 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007055 * @param[in] tok_idx Position in the expression @p exp.
Michal Vaskod3678892020-05-21 10:06:58 +02007056 * @param[in] attr_axis Whether to search attributes or standard nodes.
7057 * @param[in] all_desc Whether to search all the descendants or children only.
7058 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7059 * @param[in] options XPath options.
7060 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7061 */
7062static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007063eval_name_test_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007064 struct lyxp_set *set, uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02007065{
Michal Vaskod3678892020-05-21 10:06:58 +02007066 char *path;
Michal Vasko004d3152020-06-11 19:59:22 +02007067 const char *ncname, *ncname_dict = NULL;
7068 uint16_t ncname_len;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007069 const struct lys_module *moveto_mod = NULL;
7070 const struct lysc_node *scnode = NULL, *ctx_scnode;
Michal Vasko004d3152020-06-11 19:59:22 +02007071 struct ly_path_predicate *predicates = NULL;
7072 enum ly_path_pred_type pred_type = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02007073 LY_ERR rc = LY_SUCCESS;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007074 ly_bool no_prefix;
Michal Vaskod3678892020-05-21 10:06:58 +02007075
7076 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007077 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007078 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007079
7080 if (!set) {
7081 goto moveto;
7082 }
7083
Michal Vasko004d3152020-06-11 19:59:22 +02007084 ncname = &exp->expr[exp->tok_pos[*tok_idx - 1]];
7085 ncname_len = exp->tok_len[*tok_idx - 1];
Michal Vaskod3678892020-05-21 10:06:58 +02007086
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007087 /* get the first schema context node */
7088 if (set->used) {
7089 if (set->type == LYXP_SET_NODE_SET) {
7090 ctx_scnode = set->val.nodes[0].node ? set->val.nodes[0].node->schema : NULL;
7091 } else {
7092 ctx_scnode = set->val.scnodes[0].scnode;
7093 }
7094 } else {
7095 ctx_scnode = NULL;
7096 }
7097
7098 /* parse (and skip) module name, use any context node (if available) just so we get some moveto_mod if there
7099 * is no prefix for ::LY_PREF_JSON */
7100 rc = moveto_resolve_model(&ncname, &ncname_len, set, ctx_scnode, &moveto_mod);
Michal Vaskod3678892020-05-21 10:06:58 +02007101 LY_CHECK_GOTO(rc, cleanup);
7102
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007103 if (ncname_len == exp->tok_len[*tok_idx - 1]) {
7104 /* remember that there is no prefix */
7105 no_prefix = 1;
7106 } else {
7107 no_prefix = 0;
7108 }
7109
Michal Vaskod3678892020-05-21 10:06:58 +02007110 if (moveto_mod && !attr_axis && !all_desc && (set->type == LYXP_SET_NODE_SET)) {
7111 /* find the matching schema node in some parent in the context */
Radek Krejci1deb5be2020-08-26 16:43:36 +02007112 for (uint32_t i = 0; i < set->used; ++i) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007113 if (eval_name_test_with_predicate_get_scnode(set->val.nodes[i].node, ncname, ncname_len, moveto_mod,
7114 set->root_type, no_prefix, set->format, &scnode)) {
7115 /* check failed */
7116 scnode = NULL;
7117 break;
Michal Vaskod3678892020-05-21 10:06:58 +02007118 }
7119 }
7120
Michal Vasko004d3152020-06-11 19:59:22 +02007121 if (scnode && (scnode->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
7122 /* try to create the predicates */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007123 if (eval_name_test_try_compile_predicates(exp, tok_idx, scnode, set->cur_mod, set->cur_node ?
7124 set->cur_node->schema : NULL, set->format, set->prefix_data, &predicates, &pred_type)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007125 /* hashes cannot be used */
Michal Vaskod3678892020-05-21 10:06:58 +02007126 scnode = NULL;
7127 }
7128 }
7129 }
7130
Michal Vasko004d3152020-06-11 19:59:22 +02007131 if (!scnode && moveto_mod) {
7132 /* we are not able to match based on a schema node and not all the modules match,
7133 * use dictionary for efficient comparison */
Radek Krejci011e4aa2020-09-04 15:22:31 +02007134 LY_CHECK_GOTO(rc = lydict_insert(set->ctx, ncname, ncname_len, &ncname_dict), cleanup);
Michal Vaskod3678892020-05-21 10:06:58 +02007135 }
7136
Michal Vasko97ea1632020-11-23 17:00:09 +01007137 if ((set->format == LY_PREF_JSON) && no_prefix) {
7138 /* do not set moveto_mod if there is no explicit prefix for JSON, it should be inherited from
7139 * the specific context node */
7140 moveto_mod = NULL;
7141 }
7142
Michal Vaskod3678892020-05-21 10:06:58 +02007143moveto:
7144 /* move to the attribute(s), data node(s), or schema node(s) */
7145 if (attr_axis) {
7146 if (set && (options & LYXP_SCNODE_ALL)) {
7147 set_scnode_clear_ctx(set);
7148 } else {
7149 if (all_desc) {
Michal Vaskocdad7122020-11-09 21:04:44 +01007150 rc = moveto_attr_alldesc(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007151 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007152 rc = moveto_attr(set, moveto_mod, ncname_dict);
Michal Vaskod3678892020-05-21 10:06:58 +02007153 }
7154 LY_CHECK_GOTO(rc, cleanup);
7155 }
7156 } else {
7157 if (set && (options & LYXP_SCNODE_ALL)) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02007158 int64_t i;
7159
Michal Vaskod3678892020-05-21 10:06:58 +02007160 if (all_desc) {
Michal Vasko004d3152020-06-11 19:59:22 +02007161 rc = moveto_scnode_alldesc(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007162 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007163 rc = moveto_scnode(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007164 }
7165 LY_CHECK_GOTO(rc, cleanup);
7166
7167 for (i = set->used - 1; i > -1; --i) {
Radek Krejcif13b87b2020-12-01 22:02:17 +01007168 if (set->val.scnodes[i].in_ctx > LYXP_SET_SCNODE_ATOM) {
Michal Vaskod3678892020-05-21 10:06:58 +02007169 break;
7170 }
7171 }
7172 if (i == -1) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007173 path = lysc_path(set->cur_scnode, LYSC_PATH_LOG, NULL, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02007174 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02007175 ncname_len, ncname, ncname - exp->expr, exp->expr, path);
Michal Vaskod3678892020-05-21 10:06:58 +02007176 free(path);
7177 }
7178 } else {
7179 if (all_desc) {
Michal Vaskocdad7122020-11-09 21:04:44 +01007180 rc = moveto_node_alldesc(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007181 } else {
7182 if (scnode) {
7183 /* we can find the nodes using hashes */
Michal Vaskocdad7122020-11-09 21:04:44 +01007184 rc = moveto_node_hash(set, scnode, predicates, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007185 } else {
Michal Vaskocdad7122020-11-09 21:04:44 +01007186 rc = moveto_node(set, moveto_mod, ncname_dict, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007187 }
7188 }
7189 LY_CHECK_GOTO(rc, cleanup);
7190 }
7191 }
7192
7193 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007194 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
7195 rc = eval_predicate(exp, tok_idx, set, options, 1);
Michal Vaskod3678892020-05-21 10:06:58 +02007196 LY_CHECK_RET(rc);
7197 }
7198
7199cleanup:
Michal Vaskodb51a8d2020-05-27 15:22:29 +02007200 if (set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007201 lydict_remove(set->ctx, ncname_dict);
Michal Vaskof7e16e22020-10-21 09:24:39 +02007202 ly_path_predicates_free(set->ctx, pred_type, predicates);
Michal Vaskodb51a8d2020-05-27 15:22:29 +02007203 }
Michal Vaskod3678892020-05-21 10:06:58 +02007204 return rc;
7205}
7206
7207/**
7208 * @brief Evaluate NodeType and any following Predicates. Logs directly on error.
7209 *
7210 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
7211 * [6] NodeTest ::= NameTest | NodeType '(' ')'
7212 * [8] NodeType ::= 'text' | 'node'
7213 *
7214 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007215 * @param[in] tok_idx Position in the expression @p exp.
Michal Vaskod3678892020-05-21 10:06:58 +02007216 * @param[in] attr_axis Whether to search attributes or standard nodes.
7217 * @param[in] all_desc Whether to search all the descendants or children only.
7218 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7219 * @param[in] options XPath options.
7220 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7221 */
7222static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007223eval_node_type_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
Radek Krejci1deb5be2020-08-26 16:43:36 +02007224 struct lyxp_set *set, uint32_t options)
Michal Vaskod3678892020-05-21 10:06:58 +02007225{
7226 LY_ERR rc;
7227
7228 /* TODO */
7229 (void)attr_axis;
7230 (void)all_desc;
7231
7232 if (set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007233 assert(exp->tok_len[*tok_idx] == 4);
Michal Vaskod3678892020-05-21 10:06:58 +02007234 if (set->type == LYXP_SET_SCNODE_SET) {
7235 set_scnode_clear_ctx(set);
7236 /* just for the debug message below */
7237 set = NULL;
7238 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007239 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "node", 4)) {
Michal Vaskod3678892020-05-21 10:06:58 +02007240 rc = xpath_node(NULL, 0, set, options);
7241 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007242 assert(!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "text", 4));
Michal Vaskod3678892020-05-21 10:06:58 +02007243 rc = xpath_text(NULL, 0, set, options);
7244 }
7245 LY_CHECK_RET(rc);
7246 }
7247 }
7248 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007249 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007250 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007251
7252 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02007253 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
Michal Vaskod3678892020-05-21 10:06:58 +02007254 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007255 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007256 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007257
7258 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02007259 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
Michal Vaskod3678892020-05-21 10:06:58 +02007260 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007261 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007262 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007263
7264 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007265 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
7266 rc = eval_predicate(exp, tok_idx, set, options, 1);
Michal Vaskod3678892020-05-21 10:06:58 +02007267 LY_CHECK_RET(rc);
7268 }
7269
7270 return LY_SUCCESS;
7271}
7272
7273/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02007274 * @brief Evaluate RelativeLocationPath. Logs directly on error.
7275 *
7276 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
7277 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
Michal Vaskod3678892020-05-21 10:06:58 +02007278 * [6] NodeTest ::= NameTest | NodeType '(' ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007279 *
7280 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007281 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007282 * @param[in] all_desc Whether to search all the descendants or children only.
7283 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7284 * @param[in] options XPath options.
7285 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
7286 */
7287static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007288eval_relative_location_path(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool all_desc, struct lyxp_set *set,
7289 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007290{
Radek Krejci857189e2020-09-01 13:26:36 +02007291 ly_bool attr_axis;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007292 LY_ERR rc;
7293
7294 goto step;
7295 do {
7296 /* evaluate '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02007297 if (exp->tok_len[*tok_idx] == 1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007298 all_desc = 0;
7299 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007300 assert(exp->tok_len[*tok_idx] == 2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007301 all_desc = 1;
7302 }
7303 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007304 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007305 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007306
7307step:
Michal Vaskod3678892020-05-21 10:06:58 +02007308 /* evaluate abbreviated axis '@'? if any */
Michal Vasko004d3152020-06-11 19:59:22 +02007309 if (exp->tokens[*tok_idx] == LYXP_TOKEN_AT) {
Michal Vaskod3678892020-05-21 10:06:58 +02007310 attr_axis = 1;
7311
7312 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007313 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007314 ++(*tok_idx);
Michal Vaskod3678892020-05-21 10:06:58 +02007315 } else {
7316 attr_axis = 0;
7317 }
7318
Michal Vasko03ff5a72019-09-11 13:49:33 +02007319 /* Step */
Michal Vasko004d3152020-06-11 19:59:22 +02007320 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007321 case LYXP_TOKEN_DOT:
7322 /* evaluate '.' */
7323 if (set && (options & LYXP_SCNODE_ALL)) {
7324 rc = moveto_scnode_self(set, all_desc, options);
7325 } else {
7326 rc = moveto_self(set, all_desc, options);
7327 }
7328 LY_CHECK_RET(rc);
7329 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007330 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007331 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007332 break;
7333
7334 case LYXP_TOKEN_DDOT:
7335 /* evaluate '..' */
7336 if (set && (options & LYXP_SCNODE_ALL)) {
7337 rc = moveto_scnode_parent(set, all_desc, options);
7338 } else {
7339 rc = moveto_parent(set, all_desc, options);
7340 }
7341 LY_CHECK_RET(rc);
7342 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007343 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007344 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007345 break;
7346
Michal Vasko03ff5a72019-09-11 13:49:33 +02007347 case LYXP_TOKEN_NAMETEST:
Michal Vaskod3678892020-05-21 10:06:58 +02007348 /* evaluate NameTest Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007349 rc = eval_name_test_with_predicate(exp, tok_idx, attr_axis, all_desc, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007350 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02007351 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007352
Michal Vaskod3678892020-05-21 10:06:58 +02007353 case LYXP_TOKEN_NODETYPE:
7354 /* evaluate NodeType Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007355 rc = eval_node_type_with_predicate(exp, tok_idx, attr_axis, all_desc, set, options);
Michal Vaskod3678892020-05-21 10:06:58 +02007356 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007357 break;
7358
7359 default:
Michal Vasko02a77382019-09-12 11:47:35 +02007360 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007361 }
Michal Vasko004d3152020-06-11 19:59:22 +02007362 } while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007363
7364 return LY_SUCCESS;
7365}
7366
7367/**
7368 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
7369 *
7370 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
7371 *
7372 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007373 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007374 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7375 * @param[in] options XPath options.
7376 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7377 */
7378static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007379eval_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 +02007380{
Radek Krejci857189e2020-09-01 13:26:36 +02007381 ly_bool all_desc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007382
7383 if (set) {
7384 /* no matter what tokens follow, we need to be at the root */
Michal Vaskob0099a92020-08-31 14:55:23 +02007385 LY_CHECK_RET(moveto_root(set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007386 }
7387
7388 /* '/' RelativeLocationPath? */
Michal Vasko004d3152020-06-11 19:59:22 +02007389 if (exp->tok_len[*tok_idx] == 1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007390 /* evaluate '/' - deferred */
7391 all_desc = 0;
7392 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007393 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007394 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007395
Michal Vasko004d3152020-06-11 19:59:22 +02007396 if (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007397 return LY_SUCCESS;
7398 }
Michal Vasko004d3152020-06-11 19:59:22 +02007399 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007400 case LYXP_TOKEN_DOT:
7401 case LYXP_TOKEN_DDOT:
7402 case LYXP_TOKEN_AT:
7403 case LYXP_TOKEN_NAMETEST:
7404 case LYXP_TOKEN_NODETYPE:
Michal Vaskob0099a92020-08-31 14:55:23 +02007405 LY_CHECK_RET(eval_relative_location_path(exp, tok_idx, all_desc, set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007406 break;
7407 default:
7408 break;
7409 }
7410
Michal Vasko03ff5a72019-09-11 13:49:33 +02007411 } else {
Radek Krejcif6a11002020-08-21 13:29:07 +02007412 /* '//' RelativeLocationPath */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007413 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
7414 all_desc = 1;
7415 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007416 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007417 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007418
Michal Vaskob0099a92020-08-31 14:55:23 +02007419 LY_CHECK_RET(eval_relative_location_path(exp, tok_idx, all_desc, set, options));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007420 }
7421
7422 return LY_SUCCESS;
7423}
7424
7425/**
7426 * @brief Evaluate FunctionCall. Logs directly on error.
7427 *
Michal Vaskod3678892020-05-21 10:06:58 +02007428 * [11] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007429 *
7430 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007431 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007432 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7433 * @param[in] options XPath options.
7434 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7435 */
7436static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007437eval_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 +02007438{
7439 LY_ERR rc;
Michal Vasko69730152020-10-09 16:30:07 +02007440
Radek Krejci1deb5be2020-08-26 16:43:36 +02007441 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, uint32_t) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007442 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007443 struct lyxp_set **args = NULL, **args_aux;
7444
7445 if (set) {
7446 /* FunctionName */
Michal Vasko004d3152020-06-11 19:59:22 +02007447 switch (exp->tok_len[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007448 case 3:
Michal Vasko004d3152020-06-11 19:59:22 +02007449 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "not", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007450 xpath_func = &xpath_not;
Michal Vasko004d3152020-06-11 19:59:22 +02007451 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "sum", 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007452 xpath_func = &xpath_sum;
7453 }
7454 break;
7455 case 4:
Michal Vasko004d3152020-06-11 19:59:22 +02007456 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "lang", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007457 xpath_func = &xpath_lang;
Michal Vasko004d3152020-06-11 19:59:22 +02007458 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "last", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007459 xpath_func = &xpath_last;
Michal Vasko004d3152020-06-11 19:59:22 +02007460 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "name", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007461 xpath_func = &xpath_name;
Michal Vasko004d3152020-06-11 19:59:22 +02007462 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "true", 4)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007463 xpath_func = &xpath_true;
7464 }
7465 break;
7466 case 5:
Michal Vasko004d3152020-06-11 19:59:22 +02007467 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "count", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007468 xpath_func = &xpath_count;
Michal Vasko004d3152020-06-11 19:59:22 +02007469 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "false", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007470 xpath_func = &xpath_false;
Michal Vasko004d3152020-06-11 19:59:22 +02007471 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "floor", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007472 xpath_func = &xpath_floor;
Michal Vasko004d3152020-06-11 19:59:22 +02007473 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "round", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007474 xpath_func = &xpath_round;
Michal Vasko004d3152020-06-11 19:59:22 +02007475 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007476 xpath_func = &xpath_deref;
7477 }
7478 break;
7479 case 6:
Michal Vasko004d3152020-06-11 19:59:22 +02007480 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "concat", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007481 xpath_func = &xpath_concat;
Michal Vasko004d3152020-06-11 19:59:22 +02007482 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "number", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007483 xpath_func = &xpath_number;
Michal Vasko004d3152020-06-11 19:59:22 +02007484 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string", 6)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007485 xpath_func = &xpath_string;
7486 }
7487 break;
7488 case 7:
Michal Vasko004d3152020-06-11 19:59:22 +02007489 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "boolean", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007490 xpath_func = &xpath_boolean;
Michal Vasko004d3152020-06-11 19:59:22 +02007491 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "ceiling", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007492 xpath_func = &xpath_ceiling;
Michal Vasko004d3152020-06-11 19:59:22 +02007493 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "current", 7)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007494 xpath_func = &xpath_current;
7495 }
7496 break;
7497 case 8:
Michal Vasko004d3152020-06-11 19:59:22 +02007498 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "contains", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007499 xpath_func = &xpath_contains;
Michal Vasko004d3152020-06-11 19:59:22 +02007500 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "position", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007501 xpath_func = &xpath_position;
Michal Vasko004d3152020-06-11 19:59:22 +02007502 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "re-match", 8)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007503 xpath_func = &xpath_re_match;
7504 }
7505 break;
7506 case 9:
Michal Vasko004d3152020-06-11 19:59:22 +02007507 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007508 xpath_func = &xpath_substring;
Michal Vasko004d3152020-06-11 19:59:22 +02007509 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "translate", 9)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007510 xpath_func = &xpath_translate;
7511 }
7512 break;
7513 case 10:
Michal Vasko004d3152020-06-11 19:59:22 +02007514 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "local-name", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007515 xpath_func = &xpath_local_name;
Michal Vasko004d3152020-06-11 19:59:22 +02007516 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "enum-value", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007517 xpath_func = &xpath_enum_value;
Michal Vasko004d3152020-06-11 19:59:22 +02007518 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "bit-is-set", 10)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007519 xpath_func = &xpath_bit_is_set;
7520 }
7521 break;
7522 case 11:
Michal Vasko004d3152020-06-11 19:59:22 +02007523 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "starts-with", 11)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007524 xpath_func = &xpath_starts_with;
7525 }
7526 break;
7527 case 12:
Michal Vasko004d3152020-06-11 19:59:22 +02007528 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from", 12)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007529 xpath_func = &xpath_derived_from;
7530 }
7531 break;
7532 case 13:
Michal Vasko004d3152020-06-11 19:59:22 +02007533 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "namespace-uri", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007534 xpath_func = &xpath_namespace_uri;
Michal Vasko004d3152020-06-11 19:59:22 +02007535 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "string-length", 13)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007536 xpath_func = &xpath_string_length;
7537 }
7538 break;
7539 case 15:
Michal Vasko004d3152020-06-11 19:59:22 +02007540 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "normalize-space", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007541 xpath_func = &xpath_normalize_space;
Michal Vasko004d3152020-06-11 19:59:22 +02007542 } else if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-after", 15)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007543 xpath_func = &xpath_substring_after;
7544 }
7545 break;
7546 case 16:
Michal Vasko004d3152020-06-11 19:59:22 +02007547 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "substring-before", 16)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007548 xpath_func = &xpath_substring_before;
7549 }
7550 break;
7551 case 20:
Michal Vasko004d3152020-06-11 19:59:22 +02007552 if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "derived-from-or-self", 20)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007553 xpath_func = &xpath_derived_from_or_self;
7554 }
7555 break;
7556 }
7557
7558 if (!xpath_func) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007559 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INFUNC, exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007560 return LY_EVALID;
7561 }
7562 }
7563
7564 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007565 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007566 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007567
7568 /* '(' */
Michal Vasko004d3152020-06-11 19:59:22 +02007569 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007570 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007571 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007572 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007573
7574 /* ( Expr ( ',' Expr )* )? */
Michal Vasko004d3152020-06-11 19:59:22 +02007575 if (exp->tokens[*tok_idx] != LYXP_TOKEN_PAR2) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007576 if (set) {
7577 args = malloc(sizeof *args);
7578 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7579 arg_count = 1;
7580 args[0] = set_copy(set);
7581 if (!args[0]) {
7582 rc = LY_EMEM;
7583 goto cleanup;
7584 }
7585
Michal Vasko004d3152020-06-11 19:59:22 +02007586 rc = eval_expr_select(exp, tok_idx, 0, args[0], options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007587 LY_CHECK_GOTO(rc, cleanup);
7588 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007589 rc = eval_expr_select(exp, tok_idx, 0, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007590 LY_CHECK_GOTO(rc, cleanup);
7591 }
7592 }
Michal Vasko004d3152020-06-11 19:59:22 +02007593 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_COMMA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007594 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007595 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007596 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007597
7598 if (set) {
7599 ++arg_count;
7600 args_aux = realloc(args, arg_count * sizeof *args);
7601 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7602 args = args_aux;
7603 args[arg_count - 1] = set_copy(set);
7604 if (!args[arg_count - 1]) {
7605 rc = LY_EMEM;
7606 goto cleanup;
7607 }
7608
Michal Vasko004d3152020-06-11 19:59:22 +02007609 rc = eval_expr_select(exp, tok_idx, 0, args[arg_count - 1], options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007610 LY_CHECK_GOTO(rc, cleanup);
7611 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007612 rc = eval_expr_select(exp, tok_idx, 0, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007613 LY_CHECK_GOTO(rc, cleanup);
7614 }
7615 }
7616
7617 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02007618 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007619 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007620 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007621 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007622
7623 if (set) {
7624 /* evaluate function */
7625 rc = xpath_func(args, arg_count, set, options);
7626
7627 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007628 /* merge all nodes from arg evaluations */
7629 for (i = 0; i < arg_count; ++i) {
7630 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007631 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007632 }
7633 }
7634 } else {
7635 rc = LY_SUCCESS;
7636 }
7637
7638cleanup:
7639 for (i = 0; i < arg_count; ++i) {
7640 lyxp_set_free(args[i]);
7641 }
7642 free(args);
7643
7644 return rc;
7645}
7646
7647/**
7648 * @brief Evaluate Number. Logs directly on error.
7649 *
7650 * @param[in] ctx Context for errors.
7651 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007652 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007653 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7654 * @return LY_ERR
7655 */
7656static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007657eval_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 +02007658{
7659 long double num;
7660 char *endptr;
7661
7662 if (set) {
7663 errno = 0;
Michal Vasko004d3152020-06-11 19:59:22 +02007664 num = strtold(&exp->expr[exp->tok_pos[*tok_idx]], &endptr);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007665 if (errno) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007666 LOGVAL(ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*tok_idx]]);
7667 LOGVAL(ctx, LY_VLOG_LYD, set->cur_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02007668 exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]], strerror(errno));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007669 return LY_EVALID;
Michal Vasko004d3152020-06-11 19:59:22 +02007670 } else if (endptr - &exp->expr[exp->tok_pos[*tok_idx]] != exp->tok_len[*tok_idx]) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007671 LOGVAL(ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*tok_idx]]);
7672 LOGVAL(ctx, LY_VLOG_LYD, set->cur_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
Michal Vasko69730152020-10-09 16:30:07 +02007673 exp->tok_len[*tok_idx], &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007674 return LY_EVALID;
7675 }
7676
7677 set_fill_number(set, num);
7678 }
7679
7680 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007681 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007682 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007683 return LY_SUCCESS;
7684}
7685
7686/**
7687 * @brief Evaluate PathExpr. Logs directly on error.
7688 *
Michal Vaskod3678892020-05-21 10:06:58 +02007689 * [12] PathExpr ::= LocationPath | PrimaryExpr Predicate*
Michal Vasko03ff5a72019-09-11 13:49:33 +02007690 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7691 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7692 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
Michal Vaskod3678892020-05-21 10:06:58 +02007693 * [10] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
Michal Vasko03ff5a72019-09-11 13:49:33 +02007694 *
7695 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007696 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007697 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7698 * @param[in] options XPath options.
7699 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7700 */
7701static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007702eval_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 +02007703{
Radek Krejci857189e2020-09-01 13:26:36 +02007704 ly_bool all_desc, parent_pos_pred;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007705 LY_ERR rc;
7706
Michal Vasko004d3152020-06-11 19:59:22 +02007707 switch (exp->tokens[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007708 case LYXP_TOKEN_PAR1:
7709 /* '(' Expr ')' */
7710
7711 /* '(' */
7712 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007713 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007714 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007715
7716 /* Expr */
Michal Vasko004d3152020-06-11 19:59:22 +02007717 rc = eval_expr_select(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007718 LY_CHECK_RET(rc);
7719
7720 /* ')' */
Michal Vasko004d3152020-06-11 19:59:22 +02007721 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007722 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007723 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007724 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007725
7726 parent_pos_pred = 0;
7727 goto predicate;
7728
7729 case LYXP_TOKEN_DOT:
7730 case LYXP_TOKEN_DDOT:
7731 case LYXP_TOKEN_AT:
7732 case LYXP_TOKEN_NAMETEST:
7733 case LYXP_TOKEN_NODETYPE:
7734 /* RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02007735 rc = eval_relative_location_path(exp, tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007736 LY_CHECK_RET(rc);
7737 break;
7738
7739 case LYXP_TOKEN_FUNCNAME:
7740 /* FunctionCall */
7741 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007742 rc = eval_function_call(exp, tok_idx, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007743 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007744 rc = eval_function_call(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007745 }
7746 LY_CHECK_RET(rc);
7747
7748 parent_pos_pred = 1;
7749 goto predicate;
7750
Michal Vasko3e48bf32020-06-01 08:39:07 +02007751 case LYXP_TOKEN_OPER_PATH:
7752 case LYXP_TOKEN_OPER_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02007753 /* AbsoluteLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02007754 rc = eval_absolute_location_path(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007755 LY_CHECK_RET(rc);
7756 break;
7757
7758 case LYXP_TOKEN_LITERAL:
7759 /* Literal */
7760 if (!set || (options & LYXP_SCNODE_ALL)) {
7761 if (set) {
7762 set_scnode_clear_ctx(set);
7763 }
Michal Vasko004d3152020-06-11 19:59:22 +02007764 eval_literal(exp, tok_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007765 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007766 eval_literal(exp, tok_idx, set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007767 }
7768
7769 parent_pos_pred = 1;
7770 goto predicate;
7771
7772 case LYXP_TOKEN_NUMBER:
7773 /* Number */
7774 if (!set || (options & LYXP_SCNODE_ALL)) {
7775 if (set) {
7776 set_scnode_clear_ctx(set);
7777 }
Michal Vasko004d3152020-06-11 19:59:22 +02007778 rc = eval_number(NULL, exp, tok_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007779 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02007780 rc = eval_number(set->ctx, exp, tok_idx, set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007781 }
7782 LY_CHECK_RET(rc);
7783
7784 parent_pos_pred = 1;
7785 goto predicate;
7786
7787 default:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02007788 LOGVAL(set->ctx, LY_VLOG_LYD, set->cur_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]),
Michal Vasko69730152020-10-09 16:30:07 +02007789 &exp->expr[exp->tok_pos[*tok_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007790 return LY_EVALID;
7791 }
7792
7793 return LY_SUCCESS;
7794
7795predicate:
7796 /* Predicate* */
Michal Vasko004d3152020-06-11 19:59:22 +02007797 while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
7798 rc = eval_predicate(exp, tok_idx, set, options, parent_pos_pred);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007799 LY_CHECK_RET(rc);
7800 }
7801
7802 /* ('/' or '//') RelativeLocationPath */
Michal Vasko004d3152020-06-11 19:59:22 +02007803 if (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007804
7805 /* evaluate '/' or '//' */
Michal Vasko004d3152020-06-11 19:59:22 +02007806 if (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007807 all_desc = 0;
7808 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007809 all_desc = 1;
7810 }
7811
7812 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007813 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007814 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007815
Michal Vasko004d3152020-06-11 19:59:22 +02007816 rc = eval_relative_location_path(exp, tok_idx, all_desc, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007817 LY_CHECK_RET(rc);
7818 }
7819
7820 return LY_SUCCESS;
7821}
7822
7823/**
7824 * @brief Evaluate UnionExpr. Logs directly on error.
7825 *
Michal Vaskod3678892020-05-21 10:06:58 +02007826 * [20] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007827 *
7828 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007829 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007830 * @param[in] repeat How many times this expression is repeated.
7831 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7832 * @param[in] options XPath options.
7833 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7834 */
7835static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007836eval_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 +02007837{
7838 LY_ERR rc = LY_SUCCESS;
7839 struct lyxp_set orig_set, set2;
7840 uint16_t i;
7841
7842 assert(repeat);
7843
7844 set_init(&orig_set, set);
7845 set_init(&set2, set);
7846
7847 set_fill_set(&orig_set, set);
7848
Michal Vasko004d3152020-06-11 19:59:22 +02007849 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007850 LY_CHECK_GOTO(rc, cleanup);
7851
7852 /* ('|' PathExpr)* */
7853 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02007854 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_UNI);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007855 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007856 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007857 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007858
7859 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007860 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007861 LY_CHECK_GOTO(rc, cleanup);
7862 continue;
7863 }
7864
7865 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02007866 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNION, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007867 LY_CHECK_GOTO(rc, cleanup);
7868
7869 /* eval */
7870 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007871 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007872 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007873 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007874 LY_CHECK_GOTO(rc, cleanup);
7875 }
7876 }
7877
7878cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007879 lyxp_set_free_content(&orig_set);
7880 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007881 return rc;
7882}
7883
7884/**
7885 * @brief Evaluate UnaryExpr. Logs directly on error.
7886 *
Michal Vaskod3678892020-05-21 10:06:58 +02007887 * [19] UnaryExpr ::= UnionExpr | '-' UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007888 *
7889 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007890 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007891 * @param[in] repeat How many times this expression is repeated.
7892 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7893 * @param[in] options XPath options.
7894 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7895 */
7896static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007897eval_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 +02007898{
7899 LY_ERR rc;
7900 uint16_t this_op, i;
7901
7902 assert(repeat);
7903
7904 /* ('-')+ */
Michal Vasko004d3152020-06-11 19:59:22 +02007905 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007906 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02007907 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 +02007908
7909 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007910 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007911 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007912 }
7913
Michal Vasko004d3152020-06-11 19:59:22 +02007914 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_UNARY, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007915 LY_CHECK_RET(rc);
7916
7917 if (set && (repeat % 2)) {
7918 if (options & LYXP_SCNODE_ALL) {
7919 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7920 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007921 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007922 LY_CHECK_RET(rc);
7923 }
7924 }
7925
7926 return LY_SUCCESS;
7927}
7928
7929/**
7930 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7931 *
Michal Vaskod3678892020-05-21 10:06:58 +02007932 * [18] MultiplicativeExpr ::= UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007933 * | MultiplicativeExpr '*' UnaryExpr
7934 * | MultiplicativeExpr 'div' UnaryExpr
7935 * | MultiplicativeExpr 'mod' UnaryExpr
7936 *
7937 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02007938 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02007939 * @param[in] repeat How many times this expression is repeated.
7940 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7941 * @param[in] options XPath options.
7942 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7943 */
7944static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02007945eval_multiplicative_expr(const struct lyxp_expr *exp, uint16_t *tok_idx, uint16_t repeat, struct lyxp_set *set,
7946 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02007947{
7948 LY_ERR rc;
7949 uint16_t this_op;
7950 struct lyxp_set orig_set, set2;
7951 uint16_t i;
7952
7953 assert(repeat);
7954
7955 set_init(&orig_set, set);
7956 set_init(&set2, set);
7957
7958 set_fill_set(&orig_set, set);
7959
Michal Vasko004d3152020-06-11 19:59:22 +02007960 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007961 LY_CHECK_GOTO(rc, cleanup);
7962
7963 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7964 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02007965 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007966
Michal Vasko004d3152020-06-11 19:59:22 +02007967 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_MATH);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007968 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02007969 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02007970 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007971
7972 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02007973 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007974 LY_CHECK_GOTO(rc, cleanup);
7975 continue;
7976 }
7977
7978 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02007979 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007980 LY_CHECK_GOTO(rc, cleanup);
7981
7982 /* eval */
7983 if (options & LYXP_SCNODE_ALL) {
7984 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007985 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007986 set_scnode_clear_ctx(set);
7987 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007988 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007989 LY_CHECK_GOTO(rc, cleanup);
7990 }
7991 }
7992
7993cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007994 lyxp_set_free_content(&orig_set);
7995 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007996 return rc;
7997}
7998
7999/**
8000 * @brief Evaluate AdditiveExpr. Logs directly on error.
8001 *
Michal Vaskod3678892020-05-21 10:06:58 +02008002 * [17] AdditiveExpr ::= MultiplicativeExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008003 * | AdditiveExpr '+' MultiplicativeExpr
8004 * | AdditiveExpr '-' MultiplicativeExpr
8005 *
8006 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008007 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008008 * @param[in] repeat How many times this expression is repeated.
8009 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8010 * @param[in] options XPath options.
8011 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8012 */
8013static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008014eval_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 +02008015{
8016 LY_ERR rc;
8017 uint16_t this_op;
8018 struct lyxp_set orig_set, set2;
8019 uint16_t i;
8020
8021 assert(repeat);
8022
8023 set_init(&orig_set, set);
8024 set_init(&set2, set);
8025
8026 set_fill_set(&orig_set, set);
8027
Michal Vasko004d3152020-06-11 19:59:22 +02008028 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008029 LY_CHECK_GOTO(rc, cleanup);
8030
8031 /* ('+' / '-' MultiplicativeExpr)* */
8032 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008033 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008034
Michal Vasko004d3152020-06-11 19:59:22 +02008035 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_MATH);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008036 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02008037 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008038 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008039
8040 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02008041 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008042 LY_CHECK_GOTO(rc, cleanup);
8043 continue;
8044 }
8045
8046 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008047 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_ADDITIVE, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008048 LY_CHECK_GOTO(rc, cleanup);
8049
8050 /* eval */
8051 if (options & LYXP_SCNODE_ALL) {
8052 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008053 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008054 set_scnode_clear_ctx(set);
8055 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008056 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008057 LY_CHECK_GOTO(rc, cleanup);
8058 }
8059 }
8060
8061cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008062 lyxp_set_free_content(&orig_set);
8063 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008064 return rc;
8065}
8066
8067/**
8068 * @brief Evaluate RelationalExpr. Logs directly on error.
8069 *
Michal Vaskod3678892020-05-21 10:06:58 +02008070 * [16] RelationalExpr ::= AdditiveExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008071 * | RelationalExpr '<' AdditiveExpr
8072 * | RelationalExpr '>' AdditiveExpr
8073 * | RelationalExpr '<=' AdditiveExpr
8074 * | RelationalExpr '>=' AdditiveExpr
8075 *
8076 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008077 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008078 * @param[in] repeat How many times this expression is repeated.
8079 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8080 * @param[in] options XPath options.
8081 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8082 */
8083static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008084eval_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 +02008085{
8086 LY_ERR rc;
8087 uint16_t this_op;
8088 struct lyxp_set orig_set, set2;
8089 uint16_t i;
8090
8091 assert(repeat);
8092
8093 set_init(&orig_set, set);
8094 set_init(&set2, set);
8095
8096 set_fill_set(&orig_set, set);
8097
Michal Vasko004d3152020-06-11 19:59:22 +02008098 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008099 LY_CHECK_GOTO(rc, cleanup);
8100
8101 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
8102 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008103 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008104
Michal Vasko004d3152020-06-11 19:59:22 +02008105 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_COMP);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008106 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02008107 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008108 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008109
8110 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02008111 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008112 LY_CHECK_GOTO(rc, cleanup);
8113 continue;
8114 }
8115
8116 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008117 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_RELATIONAL, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008118 LY_CHECK_GOTO(rc, cleanup);
8119
8120 /* eval */
8121 if (options & LYXP_SCNODE_ALL) {
8122 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008123 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008124 set_scnode_clear_ctx(set);
8125 } else {
8126 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
8127 LY_CHECK_GOTO(rc, cleanup);
8128 }
8129 }
8130
8131cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008132 lyxp_set_free_content(&orig_set);
8133 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008134 return rc;
8135}
8136
8137/**
8138 * @brief Evaluate EqualityExpr. Logs directly on error.
8139 *
Michal Vaskod3678892020-05-21 10:06:58 +02008140 * [15] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008141 * | EqualityExpr '!=' RelationalExpr
8142 *
8143 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008144 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008145 * @param[in] repeat How many times this expression is repeated.
8146 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8147 * @param[in] options XPath options.
8148 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8149 */
8150static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008151eval_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 +02008152{
8153 LY_ERR rc;
8154 uint16_t this_op;
8155 struct lyxp_set orig_set, set2;
8156 uint16_t i;
8157
8158 assert(repeat);
8159
8160 set_init(&orig_set, set);
8161 set_init(&set2, set);
8162
8163 set_fill_set(&orig_set, set);
8164
Michal Vasko004d3152020-06-11 19:59:22 +02008165 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008166 LY_CHECK_GOTO(rc, cleanup);
8167
8168 /* ('=' / '!=' RelationalExpr)* */
8169 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008170 this_op = *tok_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008171
Michal Vasko004d3152020-06-11 19:59:22 +02008172 assert((exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL) || (exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_NEQUAL));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008173 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko69730152020-10-09 16:30:07 +02008174 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008175 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008176
8177 if (!set) {
Michal Vasko004d3152020-06-11 19:59:22 +02008178 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008179 LY_CHECK_GOTO(rc, cleanup);
8180 continue;
8181 }
8182
8183 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008184 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_EQUALITY, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008185 LY_CHECK_GOTO(rc, cleanup);
8186
8187 /* eval */
8188 if (options & LYXP_SCNODE_ALL) {
8189 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vasko004d3152020-06-11 19:59:22 +02008190 warn_equality_value(exp, set, *tok_idx - 1, this_op - 1, *tok_idx - 1);
8191 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *tok_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008192 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008193 set_scnode_clear_ctx(set);
8194 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008195 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
8196 LY_CHECK_GOTO(rc, cleanup);
8197 }
8198 }
8199
8200cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008201 lyxp_set_free_content(&orig_set);
8202 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008203 return rc;
8204}
8205
8206/**
8207 * @brief Evaluate AndExpr. Logs directly on error.
8208 *
Michal Vaskod3678892020-05-21 10:06:58 +02008209 * [14] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008210 *
8211 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008212 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008213 * @param[in] repeat How many times this expression is repeated.
8214 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8215 * @param[in] options XPath options.
8216 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8217 */
8218static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008219eval_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 +02008220{
8221 LY_ERR rc;
8222 struct lyxp_set orig_set, set2;
8223 uint16_t i;
8224
8225 assert(repeat);
8226
8227 set_init(&orig_set, set);
8228 set_init(&set2, set);
8229
8230 set_fill_set(&orig_set, set);
8231
Michal Vasko004d3152020-06-11 19:59:22 +02008232 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008233 LY_CHECK_GOTO(rc, cleanup);
8234
8235 /* cast to boolean, we know that will be the final result */
8236 if (set && (options & LYXP_SCNODE_ALL)) {
8237 set_scnode_clear_ctx(set);
8238 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008239 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008240 }
8241
8242 /* ('and' EqualityExpr)* */
8243 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008244 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_LOG);
8245 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bln ? "skipped" : "parsed"),
Michal Vasko69730152020-10-09 16:30:07 +02008246 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008247 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008248
8249 /* lazy evaluation */
Michal Vasko004d3152020-06-11 19:59:22 +02008250 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bln)) {
8251 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008252 LY_CHECK_GOTO(rc, cleanup);
8253 continue;
8254 }
8255
8256 set_fill_set(&set2, &orig_set);
Michal Vasko004d3152020-06-11 19:59:22 +02008257 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_AND, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008258 LY_CHECK_GOTO(rc, cleanup);
8259
8260 /* eval - just get boolean value actually */
8261 if (set->type == LYXP_SET_SCNODE_SET) {
8262 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008263 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008264 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008265 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008266 set_fill_set(set, &set2);
8267 }
8268 }
8269
8270cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008271 lyxp_set_free_content(&orig_set);
8272 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008273 return rc;
8274}
8275
8276/**
8277 * @brief Evaluate OrExpr. Logs directly on error.
8278 *
Michal Vaskod3678892020-05-21 10:06:58 +02008279 * [13] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008280 *
8281 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008282 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008283 * @param[in] repeat How many times this expression is repeated.
8284 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8285 * @param[in] options XPath options.
8286 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8287 */
8288static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008289eval_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 +02008290{
8291 LY_ERR rc;
8292 struct lyxp_set orig_set, set2;
8293 uint16_t i;
8294
8295 assert(repeat);
8296
8297 set_init(&orig_set, set);
8298 set_init(&set2, set);
8299
8300 set_fill_set(&orig_set, set);
8301
Michal Vasko004d3152020-06-11 19:59:22 +02008302 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008303 LY_CHECK_GOTO(rc, cleanup);
8304
8305 /* cast to boolean, we know that will be the final result */
8306 if (set && (options & LYXP_SCNODE_ALL)) {
8307 set_scnode_clear_ctx(set);
8308 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008309 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008310 }
8311
8312 /* ('or' AndExpr)* */
8313 for (i = 0; i < repeat; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008314 assert(exp->tokens[*tok_idx] == LYXP_TOKEN_OPER_LOG);
8315 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bln ? "skipped" : "parsed"),
Michal Vasko69730152020-10-09 16:30:07 +02008316 lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
Michal Vasko004d3152020-06-11 19:59:22 +02008317 ++(*tok_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008318
8319 /* lazy evaluation */
Michal Vasko004d3152020-06-11 19:59:22 +02008320 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bln)) {
8321 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008322 LY_CHECK_GOTO(rc, cleanup);
8323 continue;
8324 }
8325
8326 set_fill_set(&set2, &orig_set);
8327 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
8328 * but it does not matter */
Michal Vasko004d3152020-06-11 19:59:22 +02008329 rc = eval_expr_select(exp, tok_idx, LYXP_EXPR_OR, &set2, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008330 LY_CHECK_GOTO(rc, cleanup);
8331
8332 /* eval - just get boolean value actually */
8333 if (set->type == LYXP_SET_SCNODE_SET) {
8334 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008335 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008336 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008337 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008338 set_fill_set(set, &set2);
8339 }
8340 }
8341
8342cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008343 lyxp_set_free_content(&orig_set);
8344 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008345 return rc;
8346}
8347
8348/**
Michal Vasko004d3152020-06-11 19:59:22 +02008349 * @brief Decide what expression is at the pointer @p tok_idx and evaluate it accordingly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008350 *
8351 * @param[in] exp Parsed XPath expression.
Michal Vasko004d3152020-06-11 19:59:22 +02008352 * @param[in] tok_idx Position in the expression @p exp.
Michal Vasko03ff5a72019-09-11 13:49:33 +02008353 * @param[in] etype Expression type to evaluate.
8354 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8355 * @param[in] options XPath options.
8356 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8357 */
8358static LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008359eval_expr_select(const struct lyxp_expr *exp, uint16_t *tok_idx, enum lyxp_expr_type etype, struct lyxp_set *set,
8360 uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008361{
8362 uint16_t i, count;
8363 enum lyxp_expr_type next_etype;
8364 LY_ERR rc;
8365
8366 /* process operator repeats */
Michal Vasko004d3152020-06-11 19:59:22 +02008367 if (!exp->repeat[*tok_idx]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008368 next_etype = LYXP_EXPR_NONE;
8369 } else {
8370 /* find etype repeat */
Radek Krejci1e008d22020-08-17 11:37:37 +02008371 for (i = 0; exp->repeat[*tok_idx][i] > etype; ++i) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02008372
8373 /* select one-priority lower because etype expression called us */
8374 if (i) {
Michal Vasko004d3152020-06-11 19:59:22 +02008375 next_etype = exp->repeat[*tok_idx][i - 1];
Michal Vasko03ff5a72019-09-11 13:49:33 +02008376 /* count repeats for that expression */
Radek Krejci1e008d22020-08-17 11:37:37 +02008377 for (count = 0; i && exp->repeat[*tok_idx][i - 1] == next_etype; ++count, --i) {}
Michal Vasko03ff5a72019-09-11 13:49:33 +02008378 } else {
8379 next_etype = LYXP_EXPR_NONE;
8380 }
8381 }
8382
8383 /* decide what expression are we parsing based on the repeat */
8384 switch (next_etype) {
8385 case LYXP_EXPR_OR:
Michal Vasko004d3152020-06-11 19:59:22 +02008386 rc = eval_or_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008387 break;
8388 case LYXP_EXPR_AND:
Michal Vasko004d3152020-06-11 19:59:22 +02008389 rc = eval_and_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008390 break;
8391 case LYXP_EXPR_EQUALITY:
Michal Vasko004d3152020-06-11 19:59:22 +02008392 rc = eval_equality_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008393 break;
8394 case LYXP_EXPR_RELATIONAL:
Michal Vasko004d3152020-06-11 19:59:22 +02008395 rc = eval_relational_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008396 break;
8397 case LYXP_EXPR_ADDITIVE:
Michal Vasko004d3152020-06-11 19:59:22 +02008398 rc = eval_additive_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008399 break;
8400 case LYXP_EXPR_MULTIPLICATIVE:
Michal Vasko004d3152020-06-11 19:59:22 +02008401 rc = eval_multiplicative_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008402 break;
8403 case LYXP_EXPR_UNARY:
Michal Vasko004d3152020-06-11 19:59:22 +02008404 rc = eval_unary_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008405 break;
8406 case LYXP_EXPR_UNION:
Michal Vasko004d3152020-06-11 19:59:22 +02008407 rc = eval_union_expr(exp, tok_idx, count, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008408 break;
8409 case LYXP_EXPR_NONE:
Michal Vasko004d3152020-06-11 19:59:22 +02008410 rc = eval_path_expr(exp, tok_idx, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008411 break;
8412 default:
8413 LOGINT_RET(set->ctx);
8414 }
8415
8416 return rc;
8417}
8418
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008419/**
8420 * @brief Get root type.
8421 *
8422 * @param[in] ctx_node Context node.
8423 * @param[in] ctx_scnode Schema context node.
8424 * @param[in] options XPath options.
8425 * @return Root type.
8426 */
8427static enum lyxp_node_type
Radek Krejci1deb5be2020-08-26 16:43:36 +02008428lyxp_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 +01008429{
Michal Vasko6b26e742020-07-17 15:02:10 +02008430 const struct lysc_node *op;
8431
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008432 if (options & LYXP_SCNODE_ALL) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008433 /* schema */
Radek Krejci1e008d22020-08-17 11:37:37 +02008434 for (op = ctx_scnode; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02008435
8436 if (op || (options & LYXP_SCNODE)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008437 /* general root that can access everything */
8438 return LYXP_NODE_ROOT;
8439 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8440 /* root context node can access only config data (because we said so, it is unspecified) */
8441 return LYXP_NODE_ROOT_CONFIG;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008442 }
Michal Vasko6b26e742020-07-17 15:02:10 +02008443 return LYXP_NODE_ROOT;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008444 }
8445
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008446 /* data */
Michal Vasko6b26e742020-07-17 15:02:10 +02008447 op = ctx_node ? ctx_node->schema : NULL;
Michal Vaskod989ba02020-08-24 10:59:24 +02008448 for ( ; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02008449
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008450 if (op || !(options & LYXP_SCHEMA)) {
8451 /* general root that can access everything */
8452 return LYXP_NODE_ROOT;
8453 } else if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008454 /* root context node can access only config data (because we said so, it is unspecified) */
8455 return LYXP_NODE_ROOT_CONFIG;
8456 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008457 return LYXP_NODE_ROOT;
8458}
8459
Michal Vasko03ff5a72019-09-11 13:49:33 +02008460LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008461lyxp_eval(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008462 const struct lyd_node *ctx_node, const struct lyd_node *tree, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008463{
Michal Vasko004d3152020-06-11 19:59:22 +02008464 uint16_t tok_idx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008465 LY_ERR rc;
8466
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008467 LY_CHECK_ARG_RET(NULL, exp, set, LY_EINVAL);
8468 if (!cur_mod && ((format == LY_PREF_SCHEMA) || (format == LY_PREF_SCHEMA_RESOLVED))) {
8469 LOGARG(NULL, "Current module must be set if schema format is used.");
8470 return LY_EINVAL;
Michal Vasko004d3152020-06-11 19:59:22 +02008471 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008472
8473 /* prepare set for evaluation */
Michal Vasko03ff5a72019-09-11 13:49:33 +02008474 memset(set, 0, sizeof *set);
Michal Vaskod3678892020-05-21 10:06:58 +02008475 set->type = LYXP_SET_NODE_SET;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008476 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
8477 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node ? LYXP_NODE_ELEM : set->root_type, 0);
8478
8479 set->ctx = (struct ly_ctx *)(cur_mod ? cur_mod->ctx : (ctx_node ? LYD_CTX(ctx_node) : (tree ? LYD_CTX(tree) : NULL)));
8480 set->cur_node = ctx_node;
8481 for (set->context_op = ctx_node ? ctx_node->schema : NULL;
Radek Krejci0f969882020-08-21 16:56:47 +02008482 set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
8483 set->context_op = set->context_op->parent) {}
Michal Vaskof03ed032020-03-04 13:31:44 +01008484 set->tree = tree;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008485 set->cur_mod = cur_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008486 set->format = format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008487 set->prefix_data = prefix_data;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008488
8489 /* evaluate */
Michal Vasko004d3152020-06-11 19:59:22 +02008490 rc = eval_expr_select(exp, &tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008491 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02008492 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008493 }
8494
Michal Vasko03ff5a72019-09-11 13:49:33 +02008495 return rc;
8496}
8497
8498#if 0
8499
8500/* full xml printing of set elements, not used currently */
8501
8502void
8503lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8504{
8505 uint32_t i;
8506 char *str_num;
8507 struct lyout out;
8508
8509 memset(&out, 0, sizeof out);
8510
8511 out.type = LYOUT_STREAM;
8512 out.method.f = f;
8513
8514 switch (set->type) {
8515 case LYXP_SET_EMPTY:
Michal Vasko5233e962020-08-14 14:26:20 +02008516 ly_print_(&out, "Empty XPath set\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008517 break;
8518 case LYXP_SET_BOOLEAN:
Michal Vasko5233e962020-08-14 14:26:20 +02008519 ly_print_(&out, "Boolean XPath set:\n");
8520 ly_print_(&out, "%s\n\n", set->value.bool ? "true" : "false");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008521 break;
8522 case LYXP_SET_STRING:
Michal Vasko5233e962020-08-14 14:26:20 +02008523 ly_print_(&out, "String XPath set:\n");
8524 ly_print_(&out, "\"%s\"\n\n", set->value.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008525 break;
8526 case LYXP_SET_NUMBER:
Michal Vasko5233e962020-08-14 14:26:20 +02008527 ly_print_(&out, "Number XPath set:\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008528
8529 if (isnan(set->value.num)) {
8530 str_num = strdup("NaN");
8531 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8532 str_num = strdup("0");
8533 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8534 str_num = strdup("Infinity");
8535 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8536 str_num = strdup("-Infinity");
8537 } else if ((long long)set->value.num == set->value.num) {
8538 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8539 str_num = NULL;
8540 }
8541 } else {
8542 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8543 str_num = NULL;
8544 }
8545 }
8546 if (!str_num) {
8547 LOGMEM;
8548 return;
8549 }
Michal Vasko5233e962020-08-14 14:26:20 +02008550 ly_print_(&out, "%s\n\n", str_num);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008551 free(str_num);
8552 break;
8553 case LYXP_SET_NODE_SET:
Michal Vasko5233e962020-08-14 14:26:20 +02008554 ly_print_(&out, "Node XPath set:\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008555
8556 for (i = 0; i < set->used; ++i) {
Michal Vasko5233e962020-08-14 14:26:20 +02008557 ly_print_(&out, "%d. ", i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008558 switch (set->node_type[i]) {
8559 case LYXP_NODE_ROOT_ALL:
Michal Vasko5233e962020-08-14 14:26:20 +02008560 ly_print_(&out, "ROOT all\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008561 break;
8562 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5233e962020-08-14 14:26:20 +02008563 ly_print_(&out, "ROOT config\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008564 break;
8565 case LYXP_NODE_ROOT_STATE:
Michal Vasko5233e962020-08-14 14:26:20 +02008566 ly_print_(&out, "ROOT state\n\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008567 break;
8568 case LYXP_NODE_ROOT_NOTIF:
Michal Vasko5233e962020-08-14 14:26:20 +02008569 ly_print_(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008570 break;
8571 case LYXP_NODE_ROOT_RPC:
Michal Vasko5233e962020-08-14 14:26:20 +02008572 ly_print_(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008573 break;
8574 case LYXP_NODE_ROOT_OUTPUT:
Michal Vasko5233e962020-08-14 14:26:20 +02008575 ly_print_(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008576 break;
8577 case LYXP_NODE_ELEM:
Michal Vasko5233e962020-08-14 14:26:20 +02008578 ly_print_(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008579 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
Michal Vasko5233e962020-08-14 14:26:20 +02008580 ly_print_(&out, "\n");
Michal Vasko03ff5a72019-09-11 13:49:33 +02008581 break;
8582 case LYXP_NODE_TEXT:
Michal Vasko5233e962020-08-14 14:26:20 +02008583 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 +02008584 break;
8585 case LYXP_NODE_ATTR:
Michal Vasko5233e962020-08-14 14:26:20 +02008586 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 +02008587 break;
8588 }
8589 }
8590 break;
8591 }
8592}
8593
8594#endif
8595
8596LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008597lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008598{
8599 long double num;
8600 char *str;
8601 LY_ERR rc;
8602
8603 if (!set || (set->type == target)) {
8604 return LY_SUCCESS;
8605 }
8606
8607 /* it's not possible to convert anything into a node set */
Michal Vaskod3678892020-05-21 10:06:58 +02008608 assert(target != LYXP_SET_NODE_SET);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008609
8610 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02008611 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008612 return LY_EINVAL;
8613 }
8614
8615 /* to STRING */
Michal Vaskod3678892020-05-21 10:06:58 +02008616 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER) && (set->type == LYXP_SET_NODE_SET))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008617 switch (set->type) {
8618 case LYXP_SET_NUMBER:
8619 if (isnan(set->val.num)) {
8620 set->val.str = strdup("NaN");
8621 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8622 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8623 set->val.str = strdup("0");
8624 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8625 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8626 set->val.str = strdup("Infinity");
8627 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8628 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8629 set->val.str = strdup("-Infinity");
8630 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8631 } else if ((long long)set->val.num == set->val.num) {
8632 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8633 LOGMEM_RET(set->ctx);
8634 }
8635 set->val.str = str;
8636 } else {
8637 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8638 LOGMEM_RET(set->ctx);
8639 }
8640 set->val.str = str;
8641 }
8642 break;
8643 case LYXP_SET_BOOLEAN:
Michal Vasko004d3152020-06-11 19:59:22 +02008644 if (set->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008645 set->val.str = strdup("true");
8646 } else {
8647 set->val.str = strdup("false");
8648 }
8649 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8650 break;
8651 case LYXP_SET_NODE_SET:
8652 assert(set->used);
8653
8654 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008655 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008656
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008657 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008658 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02008659 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008660 set->val.str = str;
8661 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008662 default:
8663 LOGINT_RET(set->ctx);
8664 }
8665 set->type = LYXP_SET_STRING;
8666 }
8667
8668 /* to NUMBER */
8669 if (target == LYXP_SET_NUMBER) {
8670 switch (set->type) {
8671 case LYXP_SET_STRING:
8672 num = cast_string_to_number(set->val.str);
Michal Vaskod3678892020-05-21 10:06:58 +02008673 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008674 set->val.num = num;
8675 break;
8676 case LYXP_SET_BOOLEAN:
Michal Vasko004d3152020-06-11 19:59:22 +02008677 if (set->val.bln) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008678 set->val.num = 1;
8679 } else {
8680 set->val.num = 0;
8681 }
8682 break;
8683 default:
8684 LOGINT_RET(set->ctx);
8685 }
8686 set->type = LYXP_SET_NUMBER;
8687 }
8688
8689 /* to BOOLEAN */
8690 if (target == LYXP_SET_BOOLEAN) {
8691 switch (set->type) {
8692 case LYXP_SET_NUMBER:
8693 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
Michal Vasko004d3152020-06-11 19:59:22 +02008694 set->val.bln = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008695 } else {
Michal Vasko004d3152020-06-11 19:59:22 +02008696 set->val.bln = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008697 }
8698 break;
8699 case LYXP_SET_STRING:
8700 if (set->val.str[0]) {
Michal Vaskod3678892020-05-21 10:06:58 +02008701 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02008702 set->val.bln = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008703 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02008704 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02008705 set->val.bln = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008706 }
8707 break;
8708 case LYXP_SET_NODE_SET:
Michal Vaskod3678892020-05-21 10:06:58 +02008709 if (set->used) {
8710 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02008711 set->val.bln = 1;
Michal Vaskod3678892020-05-21 10:06:58 +02008712 } else {
8713 lyxp_set_free_content(set);
Michal Vasko004d3152020-06-11 19:59:22 +02008714 set->val.bln = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02008715 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008716 break;
8717 default:
8718 LOGINT_RET(set->ctx);
8719 }
8720 set->type = LYXP_SET_BOOLEAN;
8721 }
8722
Michal Vasko03ff5a72019-09-11 13:49:33 +02008723 return LY_SUCCESS;
8724}
8725
8726LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +02008727lyxp_atomize(const struct lyxp_expr *exp, const struct lys_module *cur_mod, LY_PREFIX_FORMAT format, void *prefix_data,
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008728 const struct lysc_node *ctx_scnode, struct lyxp_set *set, uint32_t options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008729{
Michal Vasko004d3152020-06-11 19:59:22 +02008730 uint16_t tok_idx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008731
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008732 LY_CHECK_ARG_RET(NULL, exp, set, LY_EINVAL);
8733 if (!cur_mod && ((format == LY_PREF_SCHEMA) || (format == LY_PREF_SCHEMA_RESOLVED))) {
8734 LOGARG(NULL, "Current module must be set if schema format is used.");
8735 return LY_EINVAL;
Michal Vasko004d3152020-06-11 19:59:22 +02008736 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008737
8738 /* prepare set for evaluation */
Michal Vasko03ff5a72019-09-11 13:49:33 +02008739 memset(set, 0, sizeof *set);
8740 set->type = LYXP_SET_SCNODE_SET;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008741 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
8742 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 +01008743 set->val.scnodes[0].in_ctx = LYXP_SET_SCNODE_START;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008744
8745 set->ctx = cur_mod ? cur_mod->ctx : (ctx_scnode ? ctx_scnode->module->ctx : NULL);
8746 set->cur_scnode = ctx_scnode;
Michal Vasko6b26e742020-07-17 15:02:10 +02008747 for (set->context_op = ctx_scnode;
Radek Krejci0f969882020-08-21 16:56:47 +02008748 set->context_op && !(set->context_op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF));
8749 set->context_op = set->context_op->parent) {}
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008750 set->cur_mod = cur_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008751 set->format = format;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02008752 set->prefix_data = prefix_data;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008753
8754 /* evaluate */
Michal Vasko004d3152020-06-11 19:59:22 +02008755 return eval_expr_select(exp, &tok_idx, 0, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008756}
Michal Vaskod43d71a2020-08-07 14:54:58 +02008757
8758API const char *
8759lyxp_get_expr(const struct lyxp_expr *path)
8760{
8761 if (!path) {
8762 return NULL;
8763 }
8764
8765 return path->expr;
8766}