blob: 494aa37d31a4d3767b9381bd4cd6a70ca3c47cd9 [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
15
16/* needed by libmath functions isfinite(), isinf(), isnan(), signbit(), ... */
17#define _ISOC99_SOURCE
Radek Krejcib1646a92018-11-02 16:08:26 +010018
Radek Krejci535ea9f2020-05-29 16:01:05 +020019#include "xpath.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010020
Radek Krejci535ea9f2020-05-29 16:01:05 +020021#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010022#include <ctype.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include <errno.h>
24#include <limits.h>
25#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"
32#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020033#include "dict.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "hash_table.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020035#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "printer.h"
37#include "printer_data.h"
38#include "tree.h"
39#include "tree_data_internal.h"
40#include "tree_schema_internal.h"
41#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020042
Michal Vasko14676352020-05-29 11:35:55 +020043static LY_ERR reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +020044static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
45
46/**
47 * @brief Print the type of an XPath \p set.
48 *
49 * @param[in] set Set to use.
50 * @return Set type string.
51 */
52static const char *
53print_set_type(struct lyxp_set *set)
54{
55 switch (set->type) {
Michal Vasko03ff5a72019-09-11 13:49:33 +020056 case LYXP_SET_NODE_SET:
57 return "node set";
58 case LYXP_SET_SCNODE_SET:
59 return "schema node set";
60 case LYXP_SET_BOOLEAN:
61 return "boolean";
62 case LYXP_SET_NUMBER:
63 return "number";
64 case LYXP_SET_STRING:
65 return "string";
66 }
67
68 return NULL;
69}
70
Michal Vasko24cddf82020-06-01 08:17:01 +020071const char *
72lyxp_print_token(enum lyxp_token tok)
Michal Vasko03ff5a72019-09-11 13:49:33 +020073{
74 switch (tok) {
75 case LYXP_TOKEN_PAR1:
76 return "(";
77 case LYXP_TOKEN_PAR2:
78 return ")";
79 case LYXP_TOKEN_BRACK1:
80 return "[";
81 case LYXP_TOKEN_BRACK2:
82 return "]";
83 case LYXP_TOKEN_DOT:
84 return ".";
85 case LYXP_TOKEN_DDOT:
86 return "..";
87 case LYXP_TOKEN_AT:
88 return "@";
89 case LYXP_TOKEN_COMMA:
90 return ",";
91 case LYXP_TOKEN_NAMETEST:
92 return "NameTest";
93 case LYXP_TOKEN_NODETYPE:
94 return "NodeType";
95 case LYXP_TOKEN_FUNCNAME:
96 return "FunctionName";
97 case LYXP_TOKEN_OPERATOR_LOG:
98 return "Operator(Logic)";
99 case LYXP_TOKEN_OPERATOR_COMP:
100 return "Operator(Comparison)";
101 case LYXP_TOKEN_OPERATOR_MATH:
102 return "Operator(Math)";
103 case LYXP_TOKEN_OPERATOR_UNI:
104 return "Operator(Union)";
105 case LYXP_TOKEN_OPERATOR_PATH:
106 return "Operator(Path)";
Michal Vasko14676352020-05-29 11:35:55 +0200107 case LYXP_TOKEN_OPERATOR_RPATH:
108 return "Operator(Recursive Path)";
Michal Vasko03ff5a72019-09-11 13:49:33 +0200109 case LYXP_TOKEN_LITERAL:
110 return "Literal";
111 case LYXP_TOKEN_NUMBER:
112 return "Number";
113 default:
114 LOGINT(NULL);
115 return "";
116 }
117}
118
119/**
120 * @brief Print the whole expression \p exp to debug output.
121 *
122 * @param[in] exp Expression to use.
123 */
124static void
125print_expr_struct_debug(struct lyxp_expr *exp)
126{
127 uint16_t i, j;
128 char tmp[128];
129
130 if (!exp || (ly_log_level < LY_LLDBG)) {
131 return;
132 }
133
134 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
135 for (i = 0; i < exp->used; ++i) {
Michal Vasko24cddf82020-06-01 08:17:01 +0200136 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", lyxp_print_token(exp->tokens[i]), exp->tok_len[i],
Michal Vasko03ff5a72019-09-11 13:49:33 +0200137 &exp->expr[exp->tok_pos[i]]);
138 if (exp->repeat[i]) {
139 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
140 for (j = 1; exp->repeat[i][j]; ++j) {
141 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
142 }
143 strcat(tmp, ")");
144 }
145 LOGDBG(LY_LDGXPATH, tmp);
146 }
147}
148
149#ifndef NDEBUG
150
151/**
152 * @brief Print XPath set content to debug output.
153 *
154 * @param[in] set Set to print.
155 */
156static void
157print_set_debug(struct lyxp_set *set)
158{
159 uint32_t i;
160 char *str;
161 int dynamic;
162 struct lyxp_set_node *item;
163 struct lyxp_set_scnode *sitem;
164
165 if (ly_log_level < LY_LLDBG) {
166 return;
167 }
168
169 switch (set->type) {
170 case LYXP_SET_NODE_SET:
171 LOGDBG(LY_LDGXPATH, "set NODE SET:");
172 for (i = 0; i < set->used; ++i) {
173 item = &set->val.nodes[i];
174
175 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100176 case LYXP_NODE_NONE:
177 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
178 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200179 case LYXP_NODE_ROOT:
180 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
181 break;
182 case LYXP_NODE_ROOT_CONFIG:
183 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
184 break;
185 case LYXP_NODE_ELEM:
186 if ((item->node->schema->nodetype == LYS_LIST)
187 && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
188 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
189 item->node->schema->name,
190 (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node), &dynamic)));
191 if (dynamic) {
192 free(str);
193 }
194 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
195 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
196 item->node->schema->name,
197 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
198 if (dynamic) {
199 free(str);
200 }
201 } else {
202 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
203 }
204 break;
205 case LYXP_NODE_TEXT:
206 if (item->node->schema->nodetype & LYS_ANYDATA) {
207 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
208 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
209 } else {
210 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
211 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
212 if (dynamic) {
213 free(str);
214 }
215 }
216 break;
Michal Vasko9f96a052020-03-10 09:41:45 +0100217 case LYXP_NODE_META:
218 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): META %s = %s", i + 1, item->pos, set->val.meta[i].meta->name,
219 set->val.meta[i].meta->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200220 break;
221 }
222 }
223 break;
224
225 case LYXP_SET_SCNODE_SET:
226 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
227 for (i = 0; i < set->used; ++i) {
228 sitem = &set->val.scnodes[i];
229
230 switch (sitem->type) {
231 case LYXP_NODE_ROOT:
232 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
233 break;
234 case LYXP_NODE_ROOT_CONFIG:
235 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
236 break;
237 case LYXP_NODE_ELEM:
238 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
239 break;
240 default:
241 LOGINT(NULL);
242 break;
243 }
244 }
245 break;
246
Michal Vasko03ff5a72019-09-11 13:49:33 +0200247 case LYXP_SET_BOOLEAN:
248 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
249 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
250 break;
251
252 case LYXP_SET_STRING:
253 LOGDBG(LY_LDGXPATH, "set STRING");
254 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
255 break;
256
257 case LYXP_SET_NUMBER:
258 LOGDBG(LY_LDGXPATH, "set NUMBER");
259
260 if (isnan(set->val.num)) {
261 str = strdup("NaN");
262 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
263 str = strdup("0");
264 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
265 str = strdup("Infinity");
266 } else if (isinf(set->val.num) && signbit(set->val.num)) {
267 str = strdup("-Infinity");
268 } else if ((long long)set->val.num == set->val.num) {
269 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
270 str = NULL;
271 }
272 } else {
273 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
274 str = NULL;
275 }
276 }
277 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
278
279 LOGDBG(LY_LDGXPATH, "\t%s", str);
280 free(str);
281 }
282}
283
284#endif
285
286/**
287 * @brief Realloc the string \p str.
288 *
289 * @param[in] ctx libyang context for logging.
290 * @param[in] needed How much free space is required.
291 * @param[in,out] str Pointer to the string to use.
292 * @param[in,out] used Used bytes in \p str.
293 * @param[in,out] size Allocated bytes in \p str.
294 * @return LY_ERR
295 */
296static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100297cast_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 +0200298{
299 if (*size - *used < needed) {
300 do {
301 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
302 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
303 return LY_EINVAL;
304 }
305 *size += LYXP_STRING_CAST_SIZE_STEP;
306 } while (*size - *used < needed);
307 *str = ly_realloc(*str, *size * sizeof(char));
308 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
309 }
310
311 return LY_SUCCESS;
312}
313
314/**
315 * @brief Cast nodes recursively to one string @p str.
316 *
317 * @param[in] node Node to cast.
318 * @param[in] fake_cont Whether to put the data into a "fake" container.
319 * @param[in] root_type Type of the XPath root.
320 * @param[in] indent Current indent.
321 * @param[in,out] str Resulting string.
322 * @param[in,out] used Used bytes in @p str.
323 * @param[in,out] size Allocated bytes in @p str.
324 * @return LY_ERR
325 */
326static LY_ERR
327cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
328 uint16_t *used, uint16_t *size)
329{
330 char *buf, *line, *ptr;
331 const char *value_str;
332 int dynamic;
333 const struct lyd_node *child;
334 struct lyd_node_any *any;
335 LY_ERR rc;
336
337 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
338 return LY_SUCCESS;
339 }
340
341 if (fake_cont) {
342 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
343 LY_CHECK_RET(rc);
344 strcpy(*str + (*used - 1), "\n");
345 ++(*used);
346
347 ++indent;
348 }
349
350 switch (node->schema->nodetype) {
351 case LYS_CONTAINER:
352 case LYS_LIST:
353 case LYS_RPC:
354 case LYS_NOTIF:
355 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
356 LY_CHECK_RET(rc);
357 strcpy(*str + (*used - 1), "\n");
358 ++(*used);
359
360 for (child = lyd_node_children(node); child; child = child->next) {
361 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
362 LY_CHECK_RET(rc);
363 }
364
365 break;
366
367 case LYS_LEAF:
368 case LYS_LEAFLIST:
369 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
370
371 /* print indent */
372 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
373 if (rc != LY_SUCCESS) {
374 if (dynamic) {
375 free((char *)value_str);
376 }
377 return rc;
378 }
379 memset(*str + (*used - 1), ' ', indent * 2);
380 *used += indent * 2;
381
382 /* print value */
383 if (*used == 1) {
384 sprintf(*str + (*used - 1), "%s", value_str);
385 *used += strlen(value_str);
386 } else {
387 sprintf(*str + (*used - 1), "%s\n", value_str);
388 *used += strlen(value_str) + 1;
389 }
390 if (dynamic) {
391 free((char *)value_str);
392 }
393
394 break;
395
396 case LYS_ANYXML:
397 case LYS_ANYDATA:
398 any = (struct lyd_node_any *)node;
399 if (!(void *)any->value.tree) {
400 /* no content */
401 buf = strdup("");
402 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
403 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200404 struct ly_out *out;
Radek Krejcia5bba312020-01-09 15:41:20 +0100405
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);
411 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
412 break;
413 case LYD_ANYDATA_DATATREE:
Radek Krejci241f6b52020-05-21 18:13:49 +0200414 out = ly_out_new_memory(&buf, 0);
Radek Krejcia5bba312020-01-09 15:41:20 +0100415 rc = lyd_print(out, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
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;
419 /* TODO case LYD_ANYDATA_LYB:
420 LOGERR(LYD_NODE_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
421 return -1;*/
422 }
423 }
424
425 line = strtok_r(buf, "\n", &ptr);
426 do {
427 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
428 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:
446 LOGINT_RET(LYD_NODE_CTX(node));
447 }
448
449 if (fake_cont) {
450 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
451 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
471cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, char **str)
472{
473 uint16_t used, size;
474 LY_ERR rc;
475
476 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
477 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
478 (*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));
490 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
491 }
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 int dynamic;
507
Michal Vasko03ff5a72019-09-11 13:49:33 +0200508 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100509 case LYXP_NODE_NONE:
510 /* invalid */
511 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200512 case LYXP_NODE_ROOT:
513 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100514 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200515 case LYXP_NODE_ELEM:
516 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100517 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko9f96a052020-03-10 09:41:45 +0100518 case LYXP_NODE_META:
519 *str = (char *)lyd_meta2str(set->val.meta[0].meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200520 if (!dynamic) {
521 *str = strdup(*str);
522 if (!*str) {
523 LOGMEM_RET(set->ctx);
524 }
525 }
526 return LY_SUCCESS;
527 }
528
529 LOGINT_RET(set->ctx);
530}
531
532/**
533 * @brief Cast a string into an XPath number.
534 *
535 * @param[in] str String to use.
536 * @return Cast number.
537 */
538static long double
539cast_string_to_number(const char *str)
540{
541 long double num;
542 char *ptr;
543
544 errno = 0;
545 num = strtold(str, &ptr);
546 if (errno || *ptr) {
547 num = NAN;
548 }
549 return num;
550}
551
552/**
553 * @brief Callback for checking value equality.
554 *
555 * @param[in] val1_p First value.
556 * @param[in] val2_p Second value.
557 * @param[in] mod Whether hash table is being modified.
558 * @param[in] cb_data Callback data.
559 * @return 0 if not equal, non-zero if equal.
560 */
561static int
562set_values_equal_cb(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
563{
564 struct lyxp_set_hash_node *val1, *val2;
565
566 val1 = (struct lyxp_set_hash_node *)val1_p;
567 val2 = (struct lyxp_set_hash_node *)val2_p;
568
569 if ((val1->node == val2->node) && (val1->type == val2->type)) {
570 return 1;
571 }
572
573 return 0;
574}
575
576/**
577 * @brief Insert node and its hash into set.
578 *
579 * @param[in] set et to insert to.
580 * @param[in] node Node with hash.
581 * @param[in] type Node type.
582 */
583static void
584set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
585{
586 int r;
587 uint32_t i, hash;
588 struct lyxp_set_hash_node hnode;
589
590 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
591 /* create hash table and add all the nodes */
592 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
593 for (i = 0; i < set->used; ++i) {
594 hnode.node = set->val.nodes[i].node;
595 hnode.type = set->val.nodes[i].type;
596
597 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
598 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
599 hash = dict_hash_multi(hash, NULL, 0);
600
601 r = lyht_insert(set->ht, &hnode, hash, NULL);
602 assert(!r);
603 (void)r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200604
Michal Vasko9d6befd2019-12-11 14:56:56 +0100605 if (hnode.node == node) {
606 /* it was just added, do not add it twice */
607 node = NULL;
608 }
609 }
610 }
611
612 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200613 /* add the new node into hash table */
614 hnode.node = node;
615 hnode.type = type;
616
617 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
618 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
619 hash = dict_hash_multi(hash, NULL, 0);
620
621 r = lyht_insert(set->ht, &hnode, hash, NULL);
622 assert(!r);
623 (void)r;
624 }
625}
626
627/**
628 * @brief Remove node and its hash from set.
629 *
630 * @param[in] set Set to remove from.
631 * @param[in] node Node to remove.
632 * @param[in] type Node type.
633 */
634static void
635set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
636{
637 int r;
638 struct lyxp_set_hash_node hnode;
639 uint32_t hash;
640
641 if (set->ht) {
642 hnode.node = node;
643 hnode.type = type;
644
645 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
646 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
647 hash = dict_hash_multi(hash, NULL, 0);
648
649 r = lyht_remove(set->ht, &hnode, hash);
650 assert(!r);
651 (void)r;
652
653 if (!set->ht->used) {
654 lyht_free(set->ht);
655 set->ht = NULL;
656 }
657 }
658}
659
660/**
661 * @brief Check whether node is in set based on its hash.
662 *
663 * @param[in] set Set to search in.
664 * @param[in] node Node to search for.
665 * @param[in] type Node type.
666 * @param[in] skip_idx Index in @p set to skip.
667 * @return LY_ERR
668 */
669static LY_ERR
670set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
671{
672 struct lyxp_set_hash_node hnode, *match_p;
673 uint32_t hash;
674
675 hnode.node = node;
676 hnode.type = type;
677
678 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
679 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
680 hash = dict_hash_multi(hash, NULL, 0);
681
682 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
683 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
684 /* we found it on the index that should be skipped, find another */
685 hnode = *match_p;
686 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
687 /* none other found */
688 return LY_SUCCESS;
689 }
690 }
691
692 return LY_EEXIST;
693 }
694
695 /* not found */
696 return LY_SUCCESS;
697}
698
Michal Vaskod3678892020-05-21 10:06:58 +0200699void
700lyxp_set_free_content(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200701{
702 if (!set) {
703 return;
704 }
705
706 if (set->type == LYXP_SET_NODE_SET) {
707 free(set->val.nodes);
708 lyht_free(set->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200709 } else if (set->type == LYXP_SET_SCNODE_SET) {
710 free(set->val.scnodes);
Michal Vaskod3678892020-05-21 10:06:58 +0200711 lyht_free(set->ht);
712 } else {
713 if (set->type == LYXP_SET_STRING) {
714 free(set->val.str);
715 }
716 set->type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200717 }
Michal Vaskod3678892020-05-21 10:06:58 +0200718
719 set->val.nodes = NULL;
720 set->used = 0;
721 set->size = 0;
722 set->ht = NULL;
723 set->ctx_pos = 0;
724 set->ctx_pos = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200725}
726
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100727/**
728 * @brief Free dynamically-allocated set.
729 *
730 * @param[in] set Set to free.
731 */
732static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200733lyxp_set_free(struct lyxp_set *set)
734{
735 if (!set) {
736 return;
737 }
738
Michal Vaskod3678892020-05-21 10:06:58 +0200739 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200740 free(set);
741}
742
743/**
744 * @brief Initialize set context.
745 *
746 * @param[in] new Set to initialize.
747 * @param[in] set Arbitrary initialized set.
748 */
749static void
750set_init(struct lyxp_set *new, struct lyxp_set *set)
751{
752 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200753 if (set) {
754 new->ctx = set->ctx;
755 new->ctx_node = set->ctx_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100756 new->root_type = set->root_type;
Michal Vasko02a77382019-09-12 11:47:35 +0200757 new->local_mod = set->local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +0100758 new->tree = set->tree;
Michal Vasko02a77382019-09-12 11:47:35 +0200759 new->format = set->format;
760 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200761}
762
763/**
764 * @brief Create a deep copy of a set.
765 *
766 * @param[in] set Set to copy.
767 * @return Copy of @p set.
768 */
769static struct lyxp_set *
770set_copy(struct lyxp_set *set)
771{
772 struct lyxp_set *ret;
773 uint16_t i;
Michal Vaskoba716542019-12-16 10:01:58 +0100774 int idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200775
776 if (!set) {
777 return NULL;
778 }
779
780 ret = malloc(sizeof *ret);
781 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
782 set_init(ret, set);
783
784 if (set->type == LYXP_SET_SCNODE_SET) {
785 ret->type = set->type;
786
787 for (i = 0; i < set->used; ++i) {
Michal Vaskoba716542019-12-16 10:01:58 +0100788 if ((set->val.scnodes[i].in_ctx == 1) || (set->val.scnodes[i].in_ctx == -2)) {
789 idx = lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type);
Michal Vasko3f27c522020-01-06 08:37:49 +0100790 /* coverity seems to think scnodes can be NULL */
791 if ((idx == -1) || !ret->val.scnodes) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200792 lyxp_set_free(ret);
793 return NULL;
794 }
Michal Vaskoba716542019-12-16 10:01:58 +0100795 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200796 }
797 }
798 } else if (set->type == LYXP_SET_NODE_SET) {
799 ret->type = set->type;
800 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
801 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
802 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
803
804 ret->used = ret->size = set->used;
805 ret->ctx_pos = set->ctx_pos;
806 ret->ctx_size = set->ctx_size;
807 ret->ht = lyht_dup(set->ht);
808 } else {
809 memcpy(ret, set, sizeof *ret);
810 if (set->type == LYXP_SET_STRING) {
811 ret->val.str = strdup(set->val.str);
812 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
813 }
814 }
815
816 return ret;
817}
818
819/**
820 * @brief Fill XPath set with a string. Any current data are disposed of.
821 *
822 * @param[in] set Set to fill.
823 * @param[in] string String to fill into \p set.
824 * @param[in] str_len Length of \p string. 0 is a valid value!
825 */
826static void
827set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
828{
Michal Vaskod3678892020-05-21 10:06:58 +0200829 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200830
831 set->type = LYXP_SET_STRING;
832 if ((str_len == 0) && (string[0] != '\0')) {
833 string = "";
834 }
835 set->val.str = strndup(string, str_len);
836}
837
838/**
839 * @brief Fill XPath set with a number. Any current data are disposed of.
840 *
841 * @param[in] set Set to fill.
842 * @param[in] number Number to fill into \p set.
843 */
844static void
845set_fill_number(struct lyxp_set *set, long double number)
846{
Michal Vaskod3678892020-05-21 10:06:58 +0200847 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200848
849 set->type = LYXP_SET_NUMBER;
850 set->val.num = number;
851}
852
853/**
854 * @brief Fill XPath set with a boolean. Any current data are disposed of.
855 *
856 * @param[in] set Set to fill.
857 * @param[in] boolean Boolean to fill into \p set.
858 */
859static void
860set_fill_boolean(struct lyxp_set *set, int boolean)
861{
Michal Vaskod3678892020-05-21 10:06:58 +0200862 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200863
864 set->type = LYXP_SET_BOOLEAN;
865 set->val.bool = boolean;
866}
867
868/**
869 * @brief Fill XPath set with the value from another set (deep assign).
870 * Any current data are disposed of.
871 *
872 * @param[in] trg Set to fill.
873 * @param[in] src Source set to copy into \p trg.
874 */
875static void
876set_fill_set(struct lyxp_set *trg, struct lyxp_set *src)
877{
878 if (!trg || !src) {
879 return;
880 }
881
882 if (trg->type == LYXP_SET_NODE_SET) {
883 free(trg->val.nodes);
884 } else if (trg->type == LYXP_SET_STRING) {
885 free(trg->val.str);
886 }
887 set_init(trg, src);
888
889 if (src->type == LYXP_SET_SCNODE_SET) {
890 trg->type = LYXP_SET_SCNODE_SET;
891 trg->used = src->used;
892 trg->size = src->used;
893
894 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
895 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
896 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
897 } else if (src->type == LYXP_SET_BOOLEAN) {
898 set_fill_boolean(trg, src->val.bool);
899 } else if (src->type == LYXP_SET_NUMBER) {
900 set_fill_number(trg, src->val.num);
901 } else if (src->type == LYXP_SET_STRING) {
902 set_fill_string(trg, src->val.str, strlen(src->val.str));
903 } else {
904 if (trg->type == LYXP_SET_NODE_SET) {
905 free(trg->val.nodes);
906 } else if (trg->type == LYXP_SET_STRING) {
907 free(trg->val.str);
908 }
909
Michal Vaskod3678892020-05-21 10:06:58 +0200910 assert(src->type == LYXP_SET_NODE_SET);
911
912 trg->type = LYXP_SET_NODE_SET;
913 trg->used = src->used;
914 trg->size = src->used;
915 trg->ctx_pos = src->ctx_pos;
916 trg->ctx_size = src->ctx_size;
917
918 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
919 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
920 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
921 if (src->ht) {
922 trg->ht = lyht_dup(src->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200923 } else {
Michal Vaskod3678892020-05-21 10:06:58 +0200924 trg->ht = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200925 }
926 }
927}
928
929/**
930 * @brief Clear context of all schema nodes.
931 *
932 * @param[in] set Set to clear.
933 */
934static void
935set_scnode_clear_ctx(struct lyxp_set *set)
936{
937 uint32_t i;
938
939 for (i = 0; i < set->used; ++i) {
940 if (set->val.scnodes[i].in_ctx == 1) {
941 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100942 } else if (set->val.scnodes[i].in_ctx == -2) {
943 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200944 }
945 }
946}
947
948/**
949 * @brief Remove a node from a set. Removing last node changes
950 * set into LYXP_SET_EMPTY. Context position aware.
951 *
952 * @param[in] set Set to use.
953 * @param[in] idx Index from @p set of the node to be removed.
954 */
955static void
956set_remove_node(struct lyxp_set *set, uint32_t idx)
957{
958 assert(set && (set->type == LYXP_SET_NODE_SET));
959 assert(idx < set->used);
960
961 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
962
963 --set->used;
964 if (set->used) {
965 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
966 (set->used - idx) * sizeof *set->val.nodes);
967 } else {
Michal Vaskod3678892020-05-21 10:06:58 +0200968 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200969 }
970}
971
972/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100973 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200974 *
975 * @param[in] set Set to use.
976 * @param[in] idx Index from @p set of the node to be removed.
977 */
978static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100979set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200980{
981 assert(set && (set->type == LYXP_SET_NODE_SET));
982 assert(idx < set->used);
983
Michal Vasko2caefc12019-11-14 16:07:56 +0100984 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
985 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
986 }
987 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200988}
989
990/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100991 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200992 * set into LYXP_SET_EMPTY. Context position aware.
993 *
994 * @param[in] set Set to consolidate.
995 */
996static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100997set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200998{
999 uint16_t i, orig_used, end;
1000 int32_t start;
1001
Michal Vaskod3678892020-05-21 10:06:58 +02001002 assert(set);
Michal Vasko57eab132019-09-24 11:46:26 +02001003
1004 orig_used = set->used;
1005 set->used = 0;
1006 for (i = 0; i < orig_used;) {
1007 start = -1;
1008 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001009 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001010 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001011 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001012 end = i;
1013 ++i;
1014 break;
1015 }
1016
1017 ++i;
1018 if (i == orig_used) {
1019 end = i;
1020 }
1021 } while (i < orig_used);
1022
1023 if (start > -1) {
1024 /* move the whole chunk of valid nodes together */
1025 if (set->used != (unsigned)start) {
1026 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1027 }
1028 set->used += end - start;
1029 }
1030 }
Michal Vasko57eab132019-09-24 11:46:26 +02001031}
1032
1033/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001034 * @brief Check for duplicates in a node set.
1035 *
1036 * @param[in] set Set to check.
1037 * @param[in] node Node to look for in @p set.
1038 * @param[in] node_type Type of @p node.
1039 * @param[in] skip_idx Index from @p set to skip.
1040 * @return LY_ERR
1041 */
1042static LY_ERR
1043set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1044{
1045 uint32_t i;
1046
Michal Vasko2caefc12019-11-14 16:07:56 +01001047 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001048 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1049 }
1050
1051 for (i = 0; i < set->used; ++i) {
1052 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1053 continue;
1054 }
1055
1056 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1057 return LY_EEXIST;
1058 }
1059 }
1060
1061 return LY_SUCCESS;
1062}
1063
Michal Vaskoecd62de2019-11-13 12:35:11 +01001064int
1065lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001066{
1067 uint32_t i;
1068
1069 for (i = 0; i < set->used; ++i) {
1070 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1071 continue;
1072 }
1073
1074 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1075 return i;
1076 }
1077 }
1078
1079 return -1;
1080}
1081
Michal Vaskoecd62de2019-11-13 12:35:11 +01001082void
1083lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001084{
1085 uint32_t orig_used, i, j;
1086
Michal Vaskod3678892020-05-21 10:06:58 +02001087 assert((set1->type == LYXP_SET_SCNODE_SET) && (set2->type == LYXP_SET_SCNODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001088
Michal Vaskod3678892020-05-21 10:06:58 +02001089 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001090 return;
1091 }
1092
Michal Vaskod3678892020-05-21 10:06:58 +02001093 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001094 memcpy(set1, set2, sizeof *set1);
1095 return;
1096 }
1097
1098 if (set1->used + set2->used > set1->size) {
1099 set1->size = set1->used + set2->used;
1100 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1101 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1102 }
1103
1104 orig_used = set1->used;
1105
1106 for (i = 0; i < set2->used; ++i) {
1107 for (j = 0; j < orig_used; ++j) {
1108 /* detect duplicities */
1109 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1110 break;
1111 }
1112 }
1113
1114 if (j == orig_used) {
1115 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1116 ++set1->used;
1117 }
1118 }
1119
Michal Vaskod3678892020-05-21 10:06:58 +02001120 lyxp_set_free_content(set2);
1121 set2->type = LYXP_SET_SCNODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001122}
1123
1124/**
1125 * @brief Insert a node into a set. Context position aware.
1126 *
1127 * @param[in] set Set to use.
1128 * @param[in] node Node to insert to @p set.
1129 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1130 * @param[in] node_type Node type of @p node.
1131 * @param[in] idx Index in @p set to insert into.
1132 */
1133static void
1134set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1135{
Michal Vaskod3678892020-05-21 10:06:58 +02001136 assert(set && (set->type == LYXP_SET_NODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001137
Michal Vaskod3678892020-05-21 10:06:58 +02001138 if (!set->size) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001139 /* first item */
1140 if (idx) {
1141 /* no real harm done, but it is a bug */
1142 LOGINT(set->ctx);
1143 idx = 0;
1144 }
1145 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1146 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1147 set->type = LYXP_SET_NODE_SET;
1148 set->used = 0;
1149 set->size = LYXP_SET_SIZE_START;
1150 set->ctx_pos = 1;
1151 set->ctx_size = 1;
1152 set->ht = NULL;
1153 } else {
1154 /* not an empty set */
1155 if (set->used == set->size) {
1156
1157 /* set is full */
1158 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1159 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1160 set->size += LYXP_SET_SIZE_STEP;
1161 }
1162
1163 if (idx > set->used) {
1164 LOGINT(set->ctx);
1165 idx = set->used;
1166 }
1167
1168 /* make space for the new node */
1169 if (idx < set->used) {
1170 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1171 }
1172 }
1173
1174 /* finally assign the value */
1175 set->val.nodes[idx].node = (struct lyd_node *)node;
1176 set->val.nodes[idx].type = node_type;
1177 set->val.nodes[idx].pos = pos;
1178 ++set->used;
1179
Michal Vasko2caefc12019-11-14 16:07:56 +01001180 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1181 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1182 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001183}
1184
Michal Vaskoecd62de2019-11-13 12:35:11 +01001185int
1186lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001187{
1188 int ret;
1189
1190 assert(set->type == LYXP_SET_SCNODE_SET);
1191
Michal Vaskoecd62de2019-11-13 12:35:11 +01001192 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001193 if (ret > -1) {
1194 set->val.scnodes[ret].in_ctx = 1;
1195 } else {
1196 if (set->used == set->size) {
1197 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1198 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1199 set->size += LYXP_SET_SIZE_STEP;
1200 }
1201
1202 ret = set->used;
1203 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1204 set->val.scnodes[ret].type = node_type;
1205 set->val.scnodes[ret].in_ctx = 1;
1206 ++set->used;
1207 }
1208
1209 return ret;
1210}
1211
1212/**
1213 * @brief Replace a node in a set with another. Context position aware.
1214 *
1215 * @param[in] set Set to use.
1216 * @param[in] node Node to insert to @p set.
1217 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1218 * @param[in] node_type Node type of @p node.
1219 * @param[in] idx Index in @p set of the node to replace.
1220 */
1221static void
1222set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1223{
1224 assert(set && (idx < set->used));
1225
Michal Vasko2caefc12019-11-14 16:07:56 +01001226 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1227 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1228 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001229 set->val.nodes[idx].node = (struct lyd_node *)node;
1230 set->val.nodes[idx].type = node_type;
1231 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001232 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1233 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1234 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001235}
1236
1237/**
1238 * @brief Set all nodes with ctx 1 to a new unique context value.
1239 *
1240 * @param[in] set Set to modify.
1241 * @return New context value.
1242 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001243static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001244set_scnode_new_in_ctx(struct lyxp_set *set)
1245{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001246 uint32_t i;
1247 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001248
1249 assert(set->type == LYXP_SET_SCNODE_SET);
1250
1251 ret_ctx = 3;
1252retry:
1253 for (i = 0; i < set->used; ++i) {
1254 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1255 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1256 goto retry;
1257 }
1258 }
1259 for (i = 0; i < set->used; ++i) {
1260 if (set->val.scnodes[i].in_ctx == 1) {
1261 set->val.scnodes[i].in_ctx = ret_ctx;
1262 }
1263 }
1264
1265 return ret_ctx;
1266}
1267
1268/**
1269 * @brief Get unique @p node position in the data.
1270 *
1271 * @param[in] node Node to find.
1272 * @param[in] node_type Node type of @p node.
1273 * @param[in] root Root node.
1274 * @param[in] root_type Type of the XPath @p root node.
1275 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1276 * be used to increase efficiency and start the DFS from this node.
1277 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1278 * @return Node position.
1279 */
1280static uint32_t
1281get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1282 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1283{
1284 const struct lyd_node *next, *elem, *top_sibling;
1285 uint32_t pos = 1;
1286
1287 assert(prev && prev_pos && !root->prev->next);
1288
1289 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1290 return 0;
1291 }
1292
1293 if (*prev) {
1294 /* start from the previous element instead from the root */
1295 elem = next = *prev;
1296 pos = *prev_pos;
1297 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1298 goto dfs_search;
1299 }
1300
1301 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1302 /* TREE DFS */
1303 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1304dfs_search:
1305 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1306 goto skip_children;
1307 }
1308
1309 if (elem == node) {
1310 break;
1311 }
1312 ++pos;
1313
1314 /* TREE DFS END */
1315 /* select element for the next run - children first,
1316 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1317 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1318 next = NULL;
1319 } else {
1320 next = lyd_node_children(elem);
1321 }
1322 if (!next) {
1323skip_children:
1324 /* no children */
1325 if (elem == top_sibling) {
1326 /* we are done, root has no children */
1327 elem = NULL;
1328 break;
1329 }
1330 /* try siblings */
1331 next = elem->next;
1332 }
1333 while (!next) {
1334 /* no siblings, go back through parents */
1335 if (elem->parent == top_sibling->parent) {
1336 /* we are done, no next element to process */
1337 elem = NULL;
1338 break;
1339 }
1340 /* parent is already processed, go to its sibling */
1341 elem = (struct lyd_node *)elem->parent;
1342 next = elem->next;
1343 }
1344 }
1345
1346 /* node found */
1347 if (elem) {
1348 break;
1349 }
1350 }
1351
1352 if (!elem) {
1353 if (!(*prev)) {
1354 /* we went from root and failed to find it, cannot be */
1355 LOGINT(node->schema->module->ctx);
1356 return 0;
1357 } else {
1358 *prev = NULL;
1359 *prev_pos = 0;
1360
1361 elem = next = top_sibling = root;
1362 pos = 1;
1363 goto dfs_search;
1364 }
1365 }
1366
1367 /* remember the last found node for next time */
1368 *prev = node;
1369 *prev_pos = pos;
1370
1371 return pos;
1372}
1373
1374/**
1375 * @brief Assign (fill) missing node positions.
1376 *
1377 * @param[in] set Set to fill positions in.
1378 * @param[in] root Context root node.
1379 * @param[in] root_type Context root type.
1380 * @return LY_ERR
1381 */
1382static LY_ERR
1383set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1384{
1385 const struct lyd_node *prev = NULL, *tmp_node;
1386 uint32_t i, tmp_pos = 0;
1387
1388 for (i = 0; i < set->used; ++i) {
1389 if (!set->val.nodes[i].pos) {
1390 tmp_node = NULL;
1391 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001392 case LYXP_NODE_META:
1393 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001394 if (!tmp_node) {
1395 LOGINT_RET(root->schema->module->ctx);
1396 }
1397 /* fallthrough */
1398 case LYXP_NODE_ELEM:
1399 case LYXP_NODE_TEXT:
1400 if (!tmp_node) {
1401 tmp_node = set->val.nodes[i].node;
1402 }
1403 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1404 break;
1405 default:
1406 /* all roots have position 0 */
1407 break;
1408 }
1409 }
1410 }
1411
1412 return LY_SUCCESS;
1413}
1414
1415/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001416 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001417 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001418 * @param[in] meta Metadata to use.
1419 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001420 */
1421static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001422get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001423{
1424 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001425 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001426
Michal Vasko9f96a052020-03-10 09:41:45 +01001427 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001428 ++pos;
1429 }
1430
Michal Vasko9f96a052020-03-10 09:41:45 +01001431 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001432 return pos;
1433}
1434
1435/**
1436 * @brief Compare 2 nodes in respect to XPath document order.
1437 *
1438 * @param[in] item1 1st node.
1439 * @param[in] item2 2nd node.
1440 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1441 */
1442static int
1443set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1444{
Michal Vasko9f96a052020-03-10 09:41:45 +01001445 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001446
1447 if (item1->pos < item2->pos) {
1448 return -1;
1449 }
1450
1451 if (item1->pos > item2->pos) {
1452 return 1;
1453 }
1454
1455 /* node positions are equal, the fun case */
1456
1457 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1458 /* special case since text nodes are actually saved as their parents */
1459 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1460 if (item1->type == LYXP_NODE_ELEM) {
1461 assert(item2->type == LYXP_NODE_TEXT);
1462 return -1;
1463 } else {
1464 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1465 return 1;
1466 }
1467 }
1468
Michal Vasko9f96a052020-03-10 09:41:45 +01001469 /* we need meta positions now */
1470 if (item1->type == LYXP_NODE_META) {
1471 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001472 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001473 if (item2->type == LYXP_NODE_META) {
1474 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001475 }
1476
Michal Vasko9f96a052020-03-10 09:41:45 +01001477 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001478 /* check for duplicates */
1479 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001480 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001481 return 0;
1482 }
1483
Michal Vasko9f96a052020-03-10 09:41:45 +01001484 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001485 /* elem is always first, 2nd node is after it */
1486 if (item1->type == LYXP_NODE_ELEM) {
1487 assert(item2->type != LYXP_NODE_ELEM);
1488 return -1;
1489 }
1490
Michal Vasko9f96a052020-03-10 09:41:45 +01001491 /* 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 +02001492 /* 2nd is before 1st */
1493 if (((item1->type == LYXP_NODE_TEXT)
Michal Vasko9f96a052020-03-10 09:41:45 +01001494 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META)))
1495 || ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM))
1496 || (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META))
1497 && (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001498 return 1;
1499 }
1500
Michal Vasko9f96a052020-03-10 09:41:45 +01001501 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001502 /* 2nd is after 1st */
1503 return -1;
1504}
1505
1506/**
1507 * @brief Set cast for comparisons.
1508 *
1509 * @param[in] trg Target set to cast source into.
1510 * @param[in] src Source set.
1511 * @param[in] type Target set type.
1512 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001513 * @return LY_ERR
1514 */
1515static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001516set_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 +02001517{
1518 assert(src->type == LYXP_SET_NODE_SET);
1519
1520 set_init(trg, src);
1521
1522 /* insert node into target set */
1523 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1524
1525 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001526 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001527}
1528
1529#ifndef NDEBUG
1530
1531/**
1532 * @brief Bubble sort @p set into XPath document order.
1533 * Context position aware. Unused in the 'Release' build target.
1534 *
1535 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001536 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1537 */
1538static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001539set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001540{
1541 uint32_t i, j;
1542 int ret = 0, cmp, inverted, change;
1543 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001544 struct lyxp_set_node item;
1545 struct lyxp_set_hash_node hnode;
1546 uint64_t hash;
1547
Michal Vasko3cf8fbf2020-05-27 15:21:21 +02001548 if ((set->type != LYXP_SET_NODE_SET) || (set->used < 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001549 return 0;
1550 }
1551
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001552 /* find first top-level node to be used as anchor for positions */
1553 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1554 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001555
1556 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001557 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001558 return -1;
1559 }
1560
1561 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1562 print_set_debug(set);
1563
1564 for (i = 0; i < set->used; ++i) {
1565 inverted = 0;
1566 change = 0;
1567
1568 for (j = 1; j < set->used - i; ++j) {
1569 /* compare node positions */
1570 if (inverted) {
1571 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1572 } else {
1573 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1574 }
1575
1576 /* swap if needed */
1577 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1578 change = 1;
1579
1580 item = set->val.nodes[j - 1];
1581 set->val.nodes[j - 1] = set->val.nodes[j];
1582 set->val.nodes[j] = item;
1583 } else {
1584 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1585 inverted = !inverted;
1586 }
1587 }
1588
1589 ++ret;
1590
1591 if (!change) {
1592 break;
1593 }
1594 }
1595
1596 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1597 print_set_debug(set);
1598
1599 /* check node hashes */
1600 if (set->used >= LYD_HT_MIN_ITEMS) {
1601 assert(set->ht);
1602 for (i = 0; i < set->used; ++i) {
1603 hnode.node = set->val.nodes[i].node;
1604 hnode.type = set->val.nodes[i].type;
1605
1606 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1607 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1608 hash = dict_hash_multi(hash, NULL, 0);
1609
1610 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1611 }
1612 }
1613
1614 return ret - 1;
1615}
1616
1617/**
1618 * @brief Remove duplicate entries in a sorted node set.
1619 *
1620 * @param[in] set Sorted set to check.
1621 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1622 */
1623static LY_ERR
1624set_sorted_dup_node_clean(struct lyxp_set *set)
1625{
1626 uint32_t i = 0;
1627 LY_ERR ret = LY_SUCCESS;
1628
1629 if (set->used > 1) {
1630 while (i < set->used - 1) {
1631 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1632 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001633 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001634 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001635 }
Michal Vasko57eab132019-09-24 11:46:26 +02001636 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001637 }
1638 }
1639
Michal Vasko2caefc12019-11-14 16:07:56 +01001640 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001641 return ret;
1642}
1643
1644#endif
1645
1646/**
1647 * @brief Merge 2 sorted sets into one.
1648 *
1649 * @param[in,out] trg Set to merge into. Duplicates are removed.
1650 * @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 +02001651 * @return LY_ERR
1652 */
1653static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001654set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001655{
1656 uint32_t i, j, k, count, dup_count;
1657 int cmp;
1658 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001659
Michal Vaskod3678892020-05-21 10:06:58 +02001660 if ((trg->type != LYXP_SET_NODE_SET) || (src->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001661 return LY_EINVAL;
1662 }
1663
Michal Vaskod3678892020-05-21 10:06:58 +02001664 if (!src->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001665 return LY_SUCCESS;
Michal Vaskod3678892020-05-21 10:06:58 +02001666 } else if (!trg->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001667 set_fill_set(trg, src);
Michal Vaskod3678892020-05-21 10:06:58 +02001668 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001669 return LY_SUCCESS;
1670 }
1671
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001672 /* find first top-level node to be used as anchor for positions */
1673 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1674 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001675
1676 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001677 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001678 return LY_EINT;
1679 }
1680
1681#ifndef NDEBUG
1682 LOGDBG(LY_LDGXPATH, "MERGE target");
1683 print_set_debug(trg);
1684 LOGDBG(LY_LDGXPATH, "MERGE source");
1685 print_set_debug(src);
1686#endif
1687
1688 /* make memory for the merge (duplicates are not detected yet, so space
1689 * will likely be wasted on them, too bad) */
1690 if (trg->size - trg->used < src->used) {
1691 trg->size = trg->used + src->used;
1692
1693 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1694 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1695 }
1696
1697 i = 0;
1698 j = 0;
1699 count = 0;
1700 dup_count = 0;
1701 do {
1702 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1703 if (!cmp) {
1704 if (!count) {
1705 /* duplicate, just skip it */
1706 ++i;
1707 ++j;
1708 } else {
1709 /* we are copying something already, so let's copy the duplicate too,
1710 * we are hoping that afterwards there are some more nodes to
1711 * copy and this way we can copy them all together */
1712 ++count;
1713 ++dup_count;
1714 ++i;
1715 ++j;
1716 }
1717 } else if (cmp < 0) {
1718 /* inserting src node into trg, just remember it for now */
1719 ++count;
1720 ++i;
1721
1722 /* insert the hash now */
1723 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1724 } else if (count) {
1725copy_nodes:
1726 /* time to actually copy the nodes, we have found the largest block of nodes */
1727 memmove(&trg->val.nodes[j + (count - dup_count)],
1728 &trg->val.nodes[j],
1729 (trg->used - j) * sizeof *trg->val.nodes);
1730 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1731
1732 trg->used += count - dup_count;
1733 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1734 j += count - dup_count;
1735
1736 count = 0;
1737 dup_count = 0;
1738 } else {
1739 ++j;
1740 }
1741 } while ((i < src->used) && (j < trg->used));
1742
1743 if ((i < src->used) || count) {
1744 /* insert all the hashes first */
1745 for (k = i; k < src->used; ++k) {
1746 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1747 }
1748
1749 /* loop ended, but we need to copy something at trg end */
1750 count += src->used - i;
1751 i = src->used;
1752 goto copy_nodes;
1753 }
1754
1755 /* we are inserting hashes before the actual node insert, which causes
1756 * situations when there were initially not enough items for a hash table,
1757 * but even after some were inserted, hash table was not created (during
1758 * insertion the number of items is not updated yet) */
1759 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1760 set_insert_node_hash(trg, NULL, 0);
1761 }
1762
1763#ifndef NDEBUG
1764 LOGDBG(LY_LDGXPATH, "MERGE result");
1765 print_set_debug(trg);
1766#endif
1767
Michal Vaskod3678892020-05-21 10:06:58 +02001768 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001769 return LY_SUCCESS;
1770}
1771
1772/*
1773 * (re)parse functions
1774 *
1775 * Parse functions parse the expression into
1776 * tokens (syntactic analysis).
1777 *
1778 * Reparse functions perform semantic analysis
1779 * (do not save the result, just a check) of
1780 * the expression and fill repeat indices.
1781 */
1782
Michal Vasko14676352020-05-29 11:35:55 +02001783LY_ERR
Michal Vasko24cddf82020-06-01 08:17:01 +02001784lyxp_check_token(const struct ly_ctx *ctx, const struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001785{
1786 if (exp->used == exp_idx) {
Michal Vasko14676352020-05-29 11:35:55 +02001787 if (ctx) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001788 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1789 }
Michal Vasko14676352020-05-29 11:35:55 +02001790 return LY_EINCOMPLETE;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001791 }
1792
1793 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
Michal Vasko14676352020-05-29 11:35:55 +02001794 if (ctx) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001795 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko24cddf82020-06-01 08:17:01 +02001796 lyxp_print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001797 }
Michal Vasko14676352020-05-29 11:35:55 +02001798 return LY_ENOT;
1799 }
1800
1801 return LY_SUCCESS;
1802}
1803
1804/* just like lyxp_check_token() but tests for 2 tokens */
1805static LY_ERR
1806exp_check_token2(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok1,
1807 enum lyxp_token want_tok2)
1808{
1809 if (exp->used == exp_idx) {
1810 if (ctx) {
1811 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1812 }
1813 return LY_EINCOMPLETE;
1814 }
1815
1816 if ((exp->tokens[exp_idx] != want_tok1) && (exp->tokens[exp_idx] != want_tok2)) {
1817 if (ctx) {
1818 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko24cddf82020-06-01 08:17:01 +02001819 lyxp_print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
Michal Vasko14676352020-05-29 11:35:55 +02001820 }
1821 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001822 }
1823
1824 return LY_SUCCESS;
1825}
1826
1827/**
1828 * @brief Stack operation push on the repeat array.
1829 *
1830 * @param[in] exp Expression to use.
1831 * @param[in] exp_idx Position in the expresion \p exp.
1832 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1833 */
1834static void
1835exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1836{
1837 uint16_t i;
1838
1839 if (exp->repeat[exp_idx]) {
1840 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1841 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1842 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1843 exp->repeat[exp_idx][i] = repeat_op_idx;
1844 exp->repeat[exp_idx][i + 1] = 0;
1845 } else {
1846 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1847 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1848 exp->repeat[exp_idx][0] = repeat_op_idx;
1849 }
1850}
1851
1852/**
1853 * @brief Reparse Predicate. Logs directly on error.
1854 *
1855 * [7] Predicate ::= '[' Expr ']'
1856 *
1857 * @param[in] ctx Context for logging.
1858 * @param[in] exp Parsed XPath expression.
1859 * @param[in] exp_idx Position in the expression @p exp.
1860 * @return LY_ERR
1861 */
1862static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02001863reparse_predicate(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001864{
1865 LY_ERR rc;
1866
Michal Vasko14676352020-05-29 11:35:55 +02001867 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001868 LY_CHECK_RET(rc);
1869 ++(*exp_idx);
1870
1871 rc = reparse_or_expr(ctx, exp, exp_idx);
1872 LY_CHECK_RET(rc);
1873
Michal Vasko14676352020-05-29 11:35:55 +02001874 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001875 LY_CHECK_RET(rc);
1876 ++(*exp_idx);
1877
1878 return LY_SUCCESS;
1879}
1880
1881/**
1882 * @brief Reparse RelativeLocationPath. Logs directly on error.
1883 *
1884 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1885 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1886 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1887 *
1888 * @param[in] ctx Context for logging.
1889 * @param[in] exp Parsed XPath expression.
1890 * @param[in] exp_idx Position in the expression \p exp.
1891 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1892 */
1893static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02001894reparse_relative_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001895{
1896 LY_ERR rc;
1897
Michal Vasko14676352020-05-29 11:35:55 +02001898 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001899 LY_CHECK_RET(rc);
1900
1901 goto step;
1902 do {
1903 /* '/' or '//' */
1904 ++(*exp_idx);
1905
Michal Vasko14676352020-05-29 11:35:55 +02001906 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001907 LY_CHECK_RET(rc);
1908step:
1909 /* Step */
1910 switch (exp->tokens[*exp_idx]) {
1911 case LYXP_TOKEN_DOT:
1912 ++(*exp_idx);
1913 break;
1914
1915 case LYXP_TOKEN_DDOT:
1916 ++(*exp_idx);
1917 break;
1918
1919 case LYXP_TOKEN_AT:
1920 ++(*exp_idx);
1921
Michal Vasko14676352020-05-29 11:35:55 +02001922 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001923 LY_CHECK_RET(rc);
1924 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1925 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko24cddf82020-06-01 08:17:01 +02001926 lyxp_print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001927 return LY_EVALID;
1928 }
1929 /* fall through */
1930 case LYXP_TOKEN_NAMETEST:
1931 ++(*exp_idx);
1932 goto reparse_predicate;
1933 break;
1934
1935 case LYXP_TOKEN_NODETYPE:
1936 ++(*exp_idx);
1937
1938 /* '(' */
Michal Vasko14676352020-05-29 11:35:55 +02001939 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001940 LY_CHECK_RET(rc);
1941 ++(*exp_idx);
1942
1943 /* ')' */
Michal Vasko14676352020-05-29 11:35:55 +02001944 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001945 LY_CHECK_RET(rc);
1946 ++(*exp_idx);
1947
1948reparse_predicate:
1949 /* Predicate* */
Michal Vasko14676352020-05-29 11:35:55 +02001950 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001951 rc = reparse_predicate(ctx, exp, exp_idx);
1952 LY_CHECK_RET(rc);
1953 }
1954 break;
1955 default:
1956 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko24cddf82020-06-01 08:17:01 +02001957 lyxp_print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001958 return LY_EVALID;
1959 }
Michal Vasko14676352020-05-29 11:35:55 +02001960 } while (!exp_check_token2(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, LYXP_TOKEN_OPERATOR_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001961
1962 return LY_SUCCESS;
1963}
1964
1965/**
1966 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1967 *
1968 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1969 *
1970 * @param[in] ctx Context for logging.
1971 * @param[in] exp Parsed XPath expression.
1972 * @param[in] exp_idx Position in the expression \p exp.
1973 * @return LY_ERR
1974 */
1975static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02001976reparse_absolute_location_path(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001977{
1978 LY_ERR rc;
1979
Michal Vasko14676352020-05-29 11:35:55 +02001980 rc = exp_check_token2(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, LYXP_TOKEN_OPERATOR_RPATH);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001981 LY_CHECK_RET(rc);
1982
1983 /* '/' RelativeLocationPath? */
Michal Vasko14676352020-05-29 11:35:55 +02001984 if (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001985 /* '/' */
1986 ++(*exp_idx);
1987
Michal Vasko14676352020-05-29 11:35:55 +02001988 if (lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001989 return LY_SUCCESS;
1990 }
1991 switch (exp->tokens[*exp_idx]) {
1992 case LYXP_TOKEN_DOT:
1993 case LYXP_TOKEN_DDOT:
1994 case LYXP_TOKEN_AT:
1995 case LYXP_TOKEN_NAMETEST:
1996 case LYXP_TOKEN_NODETYPE:
1997 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1998 LY_CHECK_RET(rc);
1999 /* fall through */
2000 default:
2001 break;
2002 }
2003
2004 /* '//' RelativeLocationPath */
2005 } else {
2006 /* '//' */
2007 ++(*exp_idx);
2008
2009 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2010 LY_CHECK_RET(rc);
2011 }
2012
2013 return LY_SUCCESS;
2014}
2015
2016/**
2017 * @brief Reparse FunctionCall. Logs directly on error.
2018 *
2019 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2020 *
2021 * @param[in] ctx Context for logging.
2022 * @param[in] exp Parsed XPath expression.
2023 * @param[in] exp_idx Position in the expression @p exp.
2024 * @return LY_ERR
2025 */
2026static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002027reparse_function_call(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002028{
2029 int min_arg_count = -1, max_arg_count, arg_count;
2030 uint16_t func_exp_idx;
2031 LY_ERR rc;
2032
Michal Vasko14676352020-05-29 11:35:55 +02002033 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002034 LY_CHECK_RET(rc);
2035 func_exp_idx = *exp_idx;
2036 switch (exp->tok_len[*exp_idx]) {
2037 case 3:
2038 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2039 min_arg_count = 1;
2040 max_arg_count = 1;
2041 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2042 min_arg_count = 1;
2043 max_arg_count = 1;
2044 }
2045 break;
2046 case 4:
2047 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2048 min_arg_count = 1;
2049 max_arg_count = 1;
2050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2051 min_arg_count = 0;
2052 max_arg_count = 0;
2053 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2054 min_arg_count = 0;
2055 max_arg_count = 1;
2056 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2057 min_arg_count = 0;
2058 max_arg_count = 0;
2059 }
2060 break;
2061 case 5:
2062 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2063 min_arg_count = 1;
2064 max_arg_count = 1;
2065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2066 min_arg_count = 0;
2067 max_arg_count = 0;
2068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2069 min_arg_count = 1;
2070 max_arg_count = 1;
2071 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2072 min_arg_count = 1;
2073 max_arg_count = 1;
2074 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2075 min_arg_count = 1;
2076 max_arg_count = 1;
2077 }
2078 break;
2079 case 6:
2080 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2081 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002082 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002083 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2084 min_arg_count = 0;
2085 max_arg_count = 1;
2086 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2087 min_arg_count = 0;
2088 max_arg_count = 1;
2089 }
2090 break;
2091 case 7:
2092 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2093 min_arg_count = 1;
2094 max_arg_count = 1;
2095 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2096 min_arg_count = 1;
2097 max_arg_count = 1;
2098 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2099 min_arg_count = 0;
2100 max_arg_count = 0;
2101 }
2102 break;
2103 case 8:
2104 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2105 min_arg_count = 2;
2106 max_arg_count = 2;
2107 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2108 min_arg_count = 0;
2109 max_arg_count = 0;
2110 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2111 min_arg_count = 2;
2112 max_arg_count = 2;
2113 }
2114 break;
2115 case 9:
2116 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2117 min_arg_count = 2;
2118 max_arg_count = 3;
2119 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2120 min_arg_count = 3;
2121 max_arg_count = 3;
2122 }
2123 break;
2124 case 10:
2125 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2126 min_arg_count = 0;
2127 max_arg_count = 1;
2128 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2129 min_arg_count = 1;
2130 max_arg_count = 1;
2131 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2132 min_arg_count = 2;
2133 max_arg_count = 2;
2134 }
2135 break;
2136 case 11:
2137 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2138 min_arg_count = 2;
2139 max_arg_count = 2;
2140 }
2141 break;
2142 case 12:
2143 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2144 min_arg_count = 2;
2145 max_arg_count = 2;
2146 }
2147 break;
2148 case 13:
2149 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2150 min_arg_count = 0;
2151 max_arg_count = 1;
2152 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2153 min_arg_count = 0;
2154 max_arg_count = 1;
2155 }
2156 break;
2157 case 15:
2158 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2159 min_arg_count = 0;
2160 max_arg_count = 1;
2161 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2162 min_arg_count = 2;
2163 max_arg_count = 2;
2164 }
2165 break;
2166 case 16:
2167 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2168 min_arg_count = 2;
2169 max_arg_count = 2;
2170 }
2171 break;
2172 case 20:
2173 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2174 min_arg_count = 2;
2175 max_arg_count = 2;
2176 }
2177 break;
2178 }
2179 if (min_arg_count == -1) {
2180 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2181 return LY_EINVAL;
2182 }
2183 ++(*exp_idx);
2184
2185 /* '(' */
Michal Vasko14676352020-05-29 11:35:55 +02002186 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002187 LY_CHECK_RET(rc);
2188 ++(*exp_idx);
2189
2190 /* ( Expr ( ',' Expr )* )? */
2191 arg_count = 0;
Michal Vasko14676352020-05-29 11:35:55 +02002192 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002193 LY_CHECK_RET(rc);
2194 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2195 ++arg_count;
2196 rc = reparse_or_expr(ctx, exp, exp_idx);
2197 LY_CHECK_RET(rc);
2198 }
Michal Vasko14676352020-05-29 11:35:55 +02002199 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_COMMA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002200 ++(*exp_idx);
2201
2202 ++arg_count;
2203 rc = reparse_or_expr(ctx, exp, exp_idx);
2204 LY_CHECK_RET(rc);
2205 }
2206
2207 /* ')' */
Michal Vasko14676352020-05-29 11:35:55 +02002208 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002209 LY_CHECK_RET(rc);
2210 ++(*exp_idx);
2211
2212 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2213 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2214 &exp->expr[exp->tok_pos[func_exp_idx]]);
2215 return LY_EVALID;
2216 }
2217
2218 return LY_SUCCESS;
2219}
2220
2221/**
2222 * @brief Reparse PathExpr. Logs directly on error.
2223 *
2224 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2225 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2226 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2227 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2228 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2229 *
2230 * @param[in] ctx Context for logging.
2231 * @param[in] exp Parsed XPath expression.
2232 * @param[in] exp_idx Position in the expression @p exp.
2233 * @return LY_ERR
2234 */
2235static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002236reparse_path_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002237{
2238 LY_ERR rc;
2239
Michal Vasko14676352020-05-29 11:35:55 +02002240 if (lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE)) {
2241 return LY_EVALID;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002242 }
2243
2244 switch (exp->tokens[*exp_idx]) {
2245 case LYXP_TOKEN_PAR1:
2246 /* '(' Expr ')' Predicate* */
2247 ++(*exp_idx);
2248
2249 rc = reparse_or_expr(ctx, exp, exp_idx);
2250 LY_CHECK_RET(rc);
2251
Michal Vasko14676352020-05-29 11:35:55 +02002252 rc = lyxp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002253 LY_CHECK_RET(rc);
2254 ++(*exp_idx);
2255 goto predicate;
2256 break;
2257 case LYXP_TOKEN_DOT:
2258 case LYXP_TOKEN_DDOT:
2259 case LYXP_TOKEN_AT:
2260 case LYXP_TOKEN_NAMETEST:
2261 case LYXP_TOKEN_NODETYPE:
2262 /* RelativeLocationPath */
2263 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2264 LY_CHECK_RET(rc);
2265 break;
2266 case LYXP_TOKEN_FUNCNAME:
2267 /* FunctionCall */
2268 rc = reparse_function_call(ctx, exp, exp_idx);
2269 LY_CHECK_RET(rc);
2270 goto predicate;
2271 break;
2272 case LYXP_TOKEN_OPERATOR_PATH:
Michal Vasko14676352020-05-29 11:35:55 +02002273 case LYXP_TOKEN_OPERATOR_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02002274 /* AbsoluteLocationPath */
2275 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2276 LY_CHECK_RET(rc);
2277 break;
2278 case LYXP_TOKEN_LITERAL:
2279 /* Literal */
2280 ++(*exp_idx);
2281 goto predicate;
2282 break;
2283 case LYXP_TOKEN_NUMBER:
2284 /* Number */
2285 ++(*exp_idx);
2286 goto predicate;
2287 break;
2288 default:
2289 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
Michal Vasko24cddf82020-06-01 08:17:01 +02002290 lyxp_print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002291 return LY_EVALID;
2292 }
2293
2294 return LY_SUCCESS;
2295
2296predicate:
2297 /* Predicate* */
Michal Vasko14676352020-05-29 11:35:55 +02002298 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002299 rc = reparse_predicate(ctx, exp, exp_idx);
2300 LY_CHECK_RET(rc);
2301 }
2302
2303 /* ('/' or '//') RelativeLocationPath */
Michal Vasko14676352020-05-29 11:35:55 +02002304 if (!exp_check_token2(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, LYXP_TOKEN_OPERATOR_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002305
2306 /* '/' or '//' */
2307 ++(*exp_idx);
2308
2309 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2310 LY_CHECK_RET(rc);
2311 }
2312
2313 return LY_SUCCESS;
2314}
2315
2316/**
2317 * @brief Reparse UnaryExpr. Logs directly on error.
2318 *
2319 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2320 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2321 *
2322 * @param[in] ctx Context for logging.
2323 * @param[in] exp Parsed XPath expression.
2324 * @param[in] exp_idx Position in the expression @p exp.
2325 * @return LY_ERR
2326 */
2327static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002328reparse_unary_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002329{
2330 uint16_t prev_exp;
2331 LY_ERR rc;
2332
2333 /* ('-')* */
2334 prev_exp = *exp_idx;
Michal Vasko14676352020-05-29 11:35:55 +02002335 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002336 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2337 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2338 ++(*exp_idx);
2339 }
2340
2341 /* PathExpr */
2342 prev_exp = *exp_idx;
2343 rc = reparse_path_expr(ctx, exp, exp_idx);
2344 LY_CHECK_RET(rc);
2345
2346 /* ('|' PathExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002347 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002348 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2349 ++(*exp_idx);
2350
2351 rc = reparse_path_expr(ctx, exp, exp_idx);
2352 LY_CHECK_RET(rc);
2353 }
2354
2355 return LY_SUCCESS;
2356}
2357
2358/**
2359 * @brief Reparse AdditiveExpr. Logs directly on error.
2360 *
2361 * [15] AdditiveExpr ::= MultiplicativeExpr
2362 * | AdditiveExpr '+' MultiplicativeExpr
2363 * | AdditiveExpr '-' MultiplicativeExpr
2364 * [16] MultiplicativeExpr ::= UnaryExpr
2365 * | MultiplicativeExpr '*' UnaryExpr
2366 * | MultiplicativeExpr 'div' UnaryExpr
2367 * | MultiplicativeExpr 'mod' UnaryExpr
2368 *
2369 * @param[in] ctx Context for logging.
2370 * @param[in] exp Parsed XPath expression.
2371 * @param[in] exp_idx Position in the expression @p exp.
2372 * @return LY_ERR
2373 */
2374static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002375reparse_additive_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002376{
2377 uint16_t prev_add_exp, prev_mul_exp;
2378 LY_ERR rc;
2379
2380 prev_add_exp = *exp_idx;
2381 goto reparse_multiplicative_expr;
2382
2383 /* ('+' / '-' MultiplicativeExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002384 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002385 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2386 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2387 ++(*exp_idx);
2388
2389reparse_multiplicative_expr:
2390 /* UnaryExpr */
2391 prev_mul_exp = *exp_idx;
2392 rc = reparse_unary_expr(ctx, exp, exp_idx);
2393 LY_CHECK_RET(rc);
2394
2395 /* ('*' / 'div' / 'mod' UnaryExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002396 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002397 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2398 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2399 ++(*exp_idx);
2400
2401 rc = reparse_unary_expr(ctx, exp, exp_idx);
2402 LY_CHECK_RET(rc);
2403 }
2404 }
2405
2406 return LY_SUCCESS;
2407}
2408
2409/**
2410 * @brief Reparse EqualityExpr. Logs directly on error.
2411 *
2412 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2413 * | EqualityExpr '!=' RelationalExpr
2414 * [14] RelationalExpr ::= AdditiveExpr
2415 * | RelationalExpr '<' AdditiveExpr
2416 * | RelationalExpr '>' AdditiveExpr
2417 * | RelationalExpr '<=' AdditiveExpr
2418 * | RelationalExpr '>=' AdditiveExpr
2419 *
2420 * @param[in] ctx Context for logging.
2421 * @param[in] exp Parsed XPath expression.
2422 * @param[in] exp_idx Position in the expression @p exp.
2423 * @return LY_ERR
2424 */
2425static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002426reparse_equality_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002427{
2428 uint16_t prev_eq_exp, prev_rel_exp;
2429 LY_ERR rc;
2430
2431 prev_eq_exp = *exp_idx;
2432 goto reparse_additive_expr;
2433
2434 /* ('=' / '!=' RelationalExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002435 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002436 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2437 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2438 ++(*exp_idx);
2439
2440reparse_additive_expr:
2441 /* AdditiveExpr */
2442 prev_rel_exp = *exp_idx;
2443 rc = reparse_additive_expr(ctx, exp, exp_idx);
2444 LY_CHECK_RET(rc);
2445
2446 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002447 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002448 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2449 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2450 ++(*exp_idx);
2451
2452 rc = reparse_additive_expr(ctx, exp, exp_idx);
2453 LY_CHECK_RET(rc);
2454 }
2455 }
2456
2457 return LY_SUCCESS;
2458}
2459
2460/**
2461 * @brief Reparse OrExpr. Logs directly on error.
2462 *
2463 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2464 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2465 *
2466 * @param[in] ctx Context for logging.
2467 * @param[in] exp Parsed XPath expression.
2468 * @param[in] exp_idx Position in the expression @p exp.
2469 * @return LY_ERR
2470 */
2471static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002472reparse_or_expr(const struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02002473{
2474 uint16_t prev_or_exp, prev_and_exp;
2475 LY_ERR rc;
2476
2477 prev_or_exp = *exp_idx;
2478 goto reparse_equality_expr;
2479
2480 /* ('or' AndExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002481 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG) && (exp->tok_len[*exp_idx] == 2)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002482 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2483 ++(*exp_idx);
2484
2485reparse_equality_expr:
2486 /* EqualityExpr */
2487 prev_and_exp = *exp_idx;
2488 rc = reparse_equality_expr(ctx, exp, exp_idx);
2489 LY_CHECK_RET(rc);
2490
2491 /* ('and' EqualityExpr)* */
Michal Vasko14676352020-05-29 11:35:55 +02002492 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG) && (exp->tok_len[*exp_idx] == 3)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002493 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2494 ++(*exp_idx);
2495
2496 rc = reparse_equality_expr(ctx, exp, exp_idx);
2497 LY_CHECK_RET(rc);
2498 }
2499 }
2500
2501 return LY_SUCCESS;
2502}
Radek Krejcib1646a92018-11-02 16:08:26 +01002503
2504/**
2505 * @brief Parse NCName.
2506 *
2507 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002508 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002509 */
Radek Krejcid4270262019-01-07 15:07:25 +01002510static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002511parse_ncname(const char *ncname)
2512{
2513 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002514 size_t size;
2515 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002516
2517 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2518 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2519 return len;
2520 }
2521
2522 do {
2523 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002524 if (!*ncname) {
2525 break;
2526 }
Radek Krejcid4270262019-01-07 15:07:25 +01002527 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002528 } while (is_xmlqnamechar(uc) && (uc != ':'));
2529
2530 return len;
2531}
2532
2533/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002534 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002535 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002536 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002537 * @param[in] exp Expression to use.
2538 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002539 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002540 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002541 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002542 */
2543static LY_ERR
Michal Vasko14676352020-05-29 11:35:55 +02002544exp_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 +01002545{
2546 uint32_t prev;
2547
2548 if (exp->used == exp->size) {
2549 prev = exp->size;
2550 exp->size += LYXP_EXPR_SIZE_STEP;
2551 if (prev > exp->size) {
2552 LOGINT(ctx);
2553 return LY_EINT;
2554 }
2555
2556 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2557 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2558 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2559 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2560 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2561 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2562 }
2563
2564 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002565 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002566 exp->tok_len[exp->used] = tok_len;
2567 ++exp->used;
2568 return LY_SUCCESS;
2569}
2570
2571void
Michal Vasko14676352020-05-29 11:35:55 +02002572lyxp_expr_free(const struct ly_ctx *ctx, struct lyxp_expr *expr)
Radek Krejcib1646a92018-11-02 16:08:26 +01002573{
2574 uint16_t i;
2575
2576 if (!expr) {
2577 return;
2578 }
2579
2580 lydict_remove(ctx, expr->expr);
2581 free(expr->tokens);
2582 free(expr->tok_pos);
2583 free(expr->tok_len);
2584 if (expr->repeat) {
2585 for (i = 0; i < expr->used; ++i) {
2586 free(expr->repeat[i]);
2587 }
2588 }
2589 free(expr->repeat);
2590 free(expr);
2591}
2592
2593struct lyxp_expr *
Michal Vasko14676352020-05-29 11:35:55 +02002594lyxp_expr_parse(const struct ly_ctx *ctx, const char *expr)
Radek Krejcib1646a92018-11-02 16:08:26 +01002595{
2596 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002597 size_t parsed = 0, tok_len;
2598 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002599 enum lyxp_token tok_type;
2600 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002601 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002602
2603 if (strlen(expr) > UINT16_MAX) {
2604 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2605 return NULL;
2606 }
2607
2608 /* init lyxp_expr structure */
2609 ret = calloc(1, sizeof *ret);
2610 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2611 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2612 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2613 ret->used = 0;
2614 ret->size = LYXP_EXPR_SIZE_START;
2615 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2616 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2617
2618 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2619 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2620
2621 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2622 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2623
2624 while (is_xmlws(expr[parsed])) {
2625 ++parsed;
2626 }
2627
2628 do {
2629 if (expr[parsed] == '(') {
2630
2631 /* '(' */
2632 tok_len = 1;
2633 tok_type = LYXP_TOKEN_PAR1;
2634
2635 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2636 /* it is a NodeType/FunctionName after all */
2637 if (((ret->tok_len[ret->used - 1] == 4)
2638 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2639 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2640 ((ret->tok_len[ret->used - 1] == 7)
2641 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2642 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2643 } else {
2644 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2645 }
2646 prev_function_check = 0;
2647 }
2648
2649 } else if (expr[parsed] == ')') {
2650
2651 /* ')' */
2652 tok_len = 1;
2653 tok_type = LYXP_TOKEN_PAR2;
2654
2655 } else if (expr[parsed] == '[') {
2656
2657 /* '[' */
2658 tok_len = 1;
2659 tok_type = LYXP_TOKEN_BRACK1;
2660
2661 } else if (expr[parsed] == ']') {
2662
2663 /* ']' */
2664 tok_len = 1;
2665 tok_type = LYXP_TOKEN_BRACK2;
2666
2667 } else if (!strncmp(&expr[parsed], "..", 2)) {
2668
2669 /* '..' */
2670 tok_len = 2;
2671 tok_type = LYXP_TOKEN_DDOT;
2672
2673 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2674
2675 /* '.' */
2676 tok_len = 1;
2677 tok_type = LYXP_TOKEN_DOT;
2678
2679 } else if (expr[parsed] == '@') {
2680
2681 /* '@' */
2682 tok_len = 1;
2683 tok_type = LYXP_TOKEN_AT;
2684
2685 } else if (expr[parsed] == ',') {
2686
2687 /* ',' */
2688 tok_len = 1;
2689 tok_type = LYXP_TOKEN_COMMA;
2690
2691 } else if (expr[parsed] == '\'') {
2692
2693 /* Literal with ' */
2694 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2695 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2696 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2697 ++tok_len;
2698 tok_type = LYXP_TOKEN_LITERAL;
2699
2700 } else if (expr[parsed] == '\"') {
2701
2702 /* Literal with " */
2703 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2704 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2705 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2706 ++tok_len;
2707 tok_type = LYXP_TOKEN_LITERAL;
2708
2709 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2710
2711 /* Number */
2712 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2713 if (expr[parsed + tok_len] == '.') {
2714 ++tok_len;
2715 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2716 }
2717 tok_type = LYXP_TOKEN_NUMBER;
2718
2719 } else if (expr[parsed] == '/') {
2720
2721 /* Operator '/', '//' */
2722 if (!strncmp(&expr[parsed], "//", 2)) {
2723 tok_len = 2;
Michal Vasko14676352020-05-29 11:35:55 +02002724 tok_type = LYXP_TOKEN_OPERATOR_RPATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002725 } else {
2726 tok_len = 1;
Michal Vasko14676352020-05-29 11:35:55 +02002727 tok_type = LYXP_TOKEN_OPERATOR_PATH;
Radek Krejcib1646a92018-11-02 16:08:26 +01002728 }
Radek Krejcib1646a92018-11-02 16:08:26 +01002729
2730 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2731 || !strncmp(&expr[parsed], ">=", 2)) {
2732
2733 /* Operator '!=', '<=', '>=' */
2734 tok_len = 2;
2735 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2736
2737 } else if (expr[parsed] == '|') {
2738
2739 /* Operator '|' */
2740 tok_len = 1;
2741 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2742
2743 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2744
2745 /* Operator '+', '-' */
2746 tok_len = 1;
2747 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2748
2749 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2750
2751 /* Operator '=', '<', '>' */
2752 tok_len = 1;
2753 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2754
2755 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2756 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2757 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2758 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2759 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2760 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2761 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2762 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
Michal Vasko14676352020-05-29 11:35:55 +02002763 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)
2764 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_RPATH)) {
Radek Krejcib1646a92018-11-02 16:08:26 +01002765
2766 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2767 if (expr[parsed] == '*') {
2768 tok_len = 1;
2769 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2770
2771 } else if (!strncmp(&expr[parsed], "or", 2)) {
2772 tok_len = 2;
2773 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2774
2775 } else if (!strncmp(&expr[parsed], "and", 3)) {
2776 tok_len = 3;
2777 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2778
2779 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2780 tok_len = 3;
2781 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2782
2783 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002784 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2785 expr[parsed], expr[parsed], ret->tok_len[ret->used - 1], &ret->expr[ret->tok_pos[ret->used - 1]]);
Radek Krejcib1646a92018-11-02 16:08:26 +01002786 goto error;
2787 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002788 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002789 goto error;
2790 }
2791 } else if (expr[parsed] == '*') {
2792
2793 /* NameTest '*' */
2794 tok_len = 1;
2795 tok_type = LYXP_TOKEN_NAMETEST;
2796
2797 } else {
2798
2799 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2800 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002801 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002802 tok_len = ncname_len;
2803
2804 if (expr[parsed + tok_len] == ':') {
2805 ++tok_len;
2806 if (expr[parsed + tok_len] == '*') {
2807 ++tok_len;
2808 } else {
2809 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002810 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002811 tok_len += ncname_len;
2812 }
2813 /* remove old flag to prevent ambiguities */
2814 prev_function_check = 0;
2815 tok_type = LYXP_TOKEN_NAMETEST;
2816 } else {
2817 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2818 prev_function_check = 1;
2819 tok_type = LYXP_TOKEN_NAMETEST;
2820 }
2821 }
2822
2823 /* store the token, move on to the next one */
2824 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2825 parsed += tok_len;
2826 while (is_xmlws(expr[parsed])) {
2827 ++parsed;
2828 }
2829
2830 } while (expr[parsed]);
2831
2832 /* prealloc repeat */
2833 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2834 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2835
Michal Vasko03ff5a72019-09-11 13:49:33 +02002836 /* fill repeat */
2837 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2838 if (ret->used > exp_idx) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002839 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2840 &ret->expr[ret->tok_pos[exp_idx]]);
2841 goto error;
2842 }
2843
2844 print_expr_struct_debug(ret);
2845
Radek Krejcib1646a92018-11-02 16:08:26 +01002846 return ret;
2847
2848error:
2849 lyxp_expr_free(ctx, ret);
2850 return NULL;
2851}
2852
Michal Vasko03ff5a72019-09-11 13:49:33 +02002853/*
2854 * warn functions
2855 *
2856 * Warn functions check specific reasonable conditions for schema XPath
2857 * and print a warning if they are not satisfied.
2858 */
2859
2860/**
2861 * @brief Get the last-added schema node that is currently in the context.
2862 *
2863 * @param[in] set Set to search in.
2864 * @return Last-added schema context node, NULL if no node is in context.
2865 */
2866static struct lysc_node *
2867warn_get_scnode_in_ctx(struct lyxp_set *set)
2868{
2869 uint32_t i;
2870
2871 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2872 return NULL;
2873 }
2874
2875 i = set->used;
2876 do {
2877 --i;
2878 if (set->val.scnodes[i].in_ctx == 1) {
2879 /* if there are more, simply return the first found (last added) */
2880 return set->val.scnodes[i].scnode;
2881 }
2882 } while (i);
2883
2884 return NULL;
2885}
2886
2887/**
2888 * @brief Test whether a type is numeric - integer type or decimal64.
2889 *
2890 * @param[in] type Type to test.
2891 * @return 1 if numeric, 0 otherwise.
2892 */
2893static int
2894warn_is_numeric_type(struct lysc_type *type)
2895{
2896 struct lysc_type_union *uni;
2897 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002898 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002899
2900 switch (type->basetype) {
2901 case LY_TYPE_DEC64:
2902 case LY_TYPE_INT8:
2903 case LY_TYPE_UINT8:
2904 case LY_TYPE_INT16:
2905 case LY_TYPE_UINT16:
2906 case LY_TYPE_INT32:
2907 case LY_TYPE_UINT32:
2908 case LY_TYPE_INT64:
2909 case LY_TYPE_UINT64:
2910 return 1;
2911 case LY_TYPE_UNION:
2912 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002913 LY_ARRAY_FOR(uni->types, u) {
2914 ret = warn_is_numeric_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002915 if (ret) {
2916 /* found a suitable type */
2917 return 1;
2918 }
2919 }
2920 /* did not find any suitable type */
2921 return 0;
2922 case LY_TYPE_LEAFREF:
2923 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2924 default:
2925 return 0;
2926 }
2927}
2928
2929/**
2930 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2931 *
2932 * @param[in] type Type to test.
2933 * @return 1 if string, 0 otherwise.
2934 */
2935static int
2936warn_is_string_type(struct lysc_type *type)
2937{
2938 struct lysc_type_union *uni;
2939 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002940 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002941
2942 switch (type->basetype) {
2943 case LY_TYPE_BITS:
2944 case LY_TYPE_ENUM:
2945 case LY_TYPE_IDENT:
2946 case LY_TYPE_INST:
2947 case LY_TYPE_STRING:
2948 return 1;
2949 case LY_TYPE_UNION:
2950 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002951 LY_ARRAY_FOR(uni->types, u) {
2952 ret = warn_is_string_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002953 if (ret) {
2954 /* found a suitable type */
2955 return 1;
2956 }
2957 }
2958 /* did not find any suitable type */
2959 return 0;
2960 case LY_TYPE_LEAFREF:
2961 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2962 default:
2963 return 0;
2964 }
2965}
2966
2967/**
2968 * @brief Test whether a type is one specific type.
2969 *
2970 * @param[in] type Type to test.
2971 * @param[in] base Expected type.
2972 * @return 1 if it is, 0 otherwise.
2973 */
2974static int
2975warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2976{
2977 struct lysc_type_union *uni;
2978 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002979 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002980
2981 if (type->basetype == base) {
2982 return 1;
2983 } else if (type->basetype == LY_TYPE_UNION) {
2984 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002985 LY_ARRAY_FOR(uni->types, u) {
2986 ret = warn_is_specific_type(uni->types[u], base);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002987 if (ret) {
2988 /* found a suitable type */
2989 return 1;
2990 }
2991 }
2992 /* did not find any suitable type */
2993 return 0;
2994 } else if (type->basetype == LY_TYPE_LEAFREF) {
2995 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2996 }
2997
2998 return 0;
2999}
3000
3001/**
3002 * @brief Get next type of a (union) type.
3003 *
3004 * @param[in] type Base type.
3005 * @param[in] prev_type Previously returned type.
3006 * @return Next type or NULL.
3007 */
3008static struct lysc_type *
3009warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3010{
3011 struct lysc_type_union *uni;
3012 int found = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003013 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003014
3015 switch (type->basetype) {
3016 case LY_TYPE_UNION:
3017 uni = (struct lysc_type_union *)type;
3018 if (!prev_type) {
3019 return uni->types[0];
3020 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003021 LY_ARRAY_FOR(uni->types, u) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003022 if (found) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003023 return uni->types[u];
Michal Vasko03ff5a72019-09-11 13:49:33 +02003024 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003025 if (prev_type == uni->types[u]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003026 found = 1;
3027 }
3028 }
3029 return NULL;
3030 default:
3031 if (prev_type) {
3032 assert(type == prev_type);
3033 return NULL;
3034 } else {
3035 return type;
3036 }
3037 }
3038}
3039
3040/**
3041 * @brief Test whether 2 types have a common type.
3042 *
3043 * @param[in] type1 First type.
3044 * @param[in] type2 Second type.
3045 * @return 1 if they do, 0 otherwise.
3046 */
3047static int
3048warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3049{
3050 struct lysc_type *t1, *rt1, *t2, *rt2;
3051
3052 t1 = NULL;
3053 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3054 if (t1->basetype == LY_TYPE_LEAFREF) {
3055 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3056 } else {
3057 rt1 = t1;
3058 }
3059
3060 t2 = NULL;
3061 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3062 if (t2->basetype == LY_TYPE_LEAFREF) {
3063 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3064 } else {
3065 rt2 = t2;
3066 }
3067
3068 if (rt2->basetype == rt1->basetype) {
3069 /* match found */
3070 return 1;
3071 }
3072 }
3073 }
3074
3075 return 0;
3076}
3077
3078/**
3079 * @brief Check both operands of comparison operators.
3080 *
3081 * @param[in] ctx Context for errors.
3082 * @param[in] set1 First operand set.
3083 * @param[in] set2 Second operand set.
3084 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3085 * @param[in] expr Start of the expression to print with the warning.
3086 * @param[in] tok_pos Token position.
3087 */
3088static void
3089warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3090{
3091 struct lysc_node_leaf *node1, *node2;
3092 int leaves = 1, warning = 0;
3093
3094 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3095 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3096
3097 if (!node1 && !node2) {
3098 /* no node-sets involved, nothing to do */
3099 return;
3100 }
3101
3102 if (node1) {
3103 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3104 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3105 warning = 1;
3106 leaves = 0;
3107 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3108 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3109 warning = 1;
3110 }
3111 }
3112
3113 if (node2) {
3114 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3115 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3116 warning = 1;
3117 leaves = 0;
3118 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3119 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3120 warning = 1;
3121 }
3122 }
3123
3124 if (node1 && node2 && leaves && !numbers_only) {
3125 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3126 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3127 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3128 && !warn_is_equal_type(node1->type, node2->type))) {
3129 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3130 warning = 1;
3131 }
3132 }
3133
3134 if (warning) {
3135 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3136 }
3137}
3138
3139/**
3140 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3141 *
3142 * @param[in] exp Parsed XPath expression.
3143 * @param[in] set Set with the leaf/leaf-list.
3144 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3145 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3146 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3147 */
3148static void
3149warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3150{
3151 struct lysc_node *scnode;
3152 struct lysc_type *type;
3153 char *value;
3154 LY_ERR rc;
3155 struct ly_err_item *err = NULL;
3156
3157 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3158 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3159 /* check that the node can have the specified value */
3160 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3161 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3162 } else {
3163 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3164 }
3165 if (!value) {
3166 LOGMEM(set->ctx);
3167 return;
3168 }
3169
3170 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3171 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3172 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3173 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3174 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3175 exp->expr + exp->tok_pos[equal_exp]);
3176 }
3177
3178 type = ((struct lysc_node_leaf *)scnode)->type;
3179 if (type->basetype != LY_TYPE_IDENT) {
3180 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3181 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3182
3183 if (err) {
3184 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3185 ly_err_free(err);
3186 } else if (rc != LY_SUCCESS) {
3187 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3188 }
3189 if (rc != LY_SUCCESS) {
3190 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3191 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3192 exp->expr + exp->tok_pos[equal_exp]);
3193 }
3194 }
3195 free(value);
3196 }
3197}
3198
3199/*
3200 * XPath functions
3201 */
3202
3203/**
3204 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3205 * depending on whether the first node bit value from the second argument is set.
3206 *
3207 * @param[in] args Array of arguments.
3208 * @param[in] arg_count Count of elements in @p args.
3209 * @param[in,out] set Context and result set at the same time.
3210 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003211 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003212 */
3213static LY_ERR
3214xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3215{
3216 struct lyd_node_term *leaf;
3217 struct lysc_node_leaf *sleaf;
3218 struct lysc_type_bits *bits;
3219 LY_ERR rc = LY_SUCCESS;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003220 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003221
3222 if (options & LYXP_SCNODE_ALL) {
3223 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3224 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003225 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3226 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 +02003227 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3228 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003229 }
3230
3231 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3232 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3233 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 +02003234 } else if (!warn_is_string_type(sleaf->type)) {
3235 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003236 }
3237 }
3238 set_scnode_clear_ctx(set);
3239 return rc;
3240 }
3241
Michal Vaskod3678892020-05-21 10:06:58 +02003242 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003243 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "bit-is-set(node-set, string)");
3244 return LY_EVALID;
3245 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003246 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003247 LY_CHECK_RET(rc);
3248
3249 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003250 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003251 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3252 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3253 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3254 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003255 LY_ARRAY_FOR(bits->bits, u) {
3256 if (!strcmp(bits->bits[u].name, args[1]->val.str)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003257 set_fill_boolean(set, 1);
3258 break;
3259 }
3260 }
3261 }
3262 }
3263
3264 return LY_SUCCESS;
3265}
3266
3267/**
3268 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3269 * with the argument converted to boolean.
3270 *
3271 * @param[in] args Array of arguments.
3272 * @param[in] arg_count Count of elements in @p args.
3273 * @param[in,out] set Context and result set at the same time.
3274 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003275 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003276 */
3277static LY_ERR
3278xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3279{
3280 LY_ERR rc;
3281
3282 if (options & LYXP_SCNODE_ALL) {
3283 set_scnode_clear_ctx(set);
3284 return LY_SUCCESS;
3285 }
3286
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003287 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003288 LY_CHECK_RET(rc);
3289 set_fill_set(set, args[0]);
3290
3291 return LY_SUCCESS;
3292}
3293
3294/**
3295 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3296 * with the first argument rounded up to the nearest integer.
3297 *
3298 * @param[in] args Array of arguments.
3299 * @param[in] arg_count Count of elements in @p args.
3300 * @param[in,out] set Context and result set at the same time.
3301 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003302 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003303 */
3304static LY_ERR
3305xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3306{
3307 struct lysc_node_leaf *sleaf;
3308 LY_ERR rc = LY_SUCCESS;
3309
3310 if (options & LYXP_SCNODE_ALL) {
3311 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3312 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003313 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3314 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 +02003315 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3316 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003317 }
3318 set_scnode_clear_ctx(set);
3319 return rc;
3320 }
3321
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003322 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003323 LY_CHECK_RET(rc);
3324 if ((long long)args[0]->val.num != args[0]->val.num) {
3325 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3326 } else {
3327 set_fill_number(set, args[0]->val.num);
3328 }
3329
3330 return LY_SUCCESS;
3331}
3332
3333/**
3334 * @brief Execute the XPath concat(string, string, string*) function.
3335 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3336 *
3337 * @param[in] args Array of arguments.
3338 * @param[in] arg_count Count of elements in @p args.
3339 * @param[in,out] set Context and result set at the same time.
3340 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003341 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003342 */
3343static LY_ERR
3344xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3345{
3346 uint16_t i;
3347 char *str = NULL;
3348 size_t used = 1;
3349 LY_ERR rc = LY_SUCCESS;
3350 struct lysc_node_leaf *sleaf;
3351
3352 if (options & LYXP_SCNODE_ALL) {
3353 for (i = 0; i < arg_count; ++i) {
3354 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3355 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3356 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3357 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003358 } else if (!warn_is_string_type(sleaf->type)) {
3359 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", __func__, i + 1, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003360 }
3361 }
3362 }
3363 set_scnode_clear_ctx(set);
3364 return rc;
3365 }
3366
3367 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003368 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003369 if (rc != LY_SUCCESS) {
3370 free(str);
3371 return rc;
3372 }
3373
3374 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3375 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3376 strcpy(str + used - 1, args[i]->val.str);
3377 used += strlen(args[i]->val.str);
3378 }
3379
3380 /* free, kind of */
Michal Vaskod3678892020-05-21 10:06:58 +02003381 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003382 set->type = LYXP_SET_STRING;
3383 set->val.str = str;
3384
3385 return LY_SUCCESS;
3386}
3387
3388/**
3389 * @brief Execute the XPath contains(string, string) function.
3390 * Returns LYXP_SET_BOOLEAN whether the second argument can
3391 * be found in the first or not.
3392 *
3393 * @param[in] args Array of arguments.
3394 * @param[in] arg_count Count of elements in @p args.
3395 * @param[in,out] set Context and result set at the same time.
3396 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003397 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003398 */
3399static LY_ERR
3400xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3401{
3402 struct lysc_node_leaf *sleaf;
3403 LY_ERR rc = LY_SUCCESS;
3404
3405 if (options & LYXP_SCNODE_ALL) {
3406 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3407 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3408 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 +02003409 } else if (!warn_is_string_type(sleaf->type)) {
3410 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003411 }
3412 }
3413
3414 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3415 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3416 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 +02003417 } else if (!warn_is_string_type(sleaf->type)) {
3418 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003419 }
3420 }
3421 set_scnode_clear_ctx(set);
3422 return rc;
3423 }
3424
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003425 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003426 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003427 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003428 LY_CHECK_RET(rc);
3429
3430 if (strstr(args[0]->val.str, args[1]->val.str)) {
3431 set_fill_boolean(set, 1);
3432 } else {
3433 set_fill_boolean(set, 0);
3434 }
3435
3436 return LY_SUCCESS;
3437}
3438
3439/**
3440 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3441 * with the size of the node-set from the argument.
3442 *
3443 * @param[in] args Array of arguments.
3444 * @param[in] arg_count Count of elements in @p args.
3445 * @param[in,out] set Context and result set at the same time.
3446 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003447 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003448 */
3449static LY_ERR
3450xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3451{
3452 struct lysc_node *scnode = NULL;
3453 LY_ERR rc = LY_SUCCESS;
3454
3455 if (options & LYXP_SCNODE_ALL) {
3456 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3457 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003458 }
3459 set_scnode_clear_ctx(set);
3460 return rc;
3461 }
3462
Michal Vasko03ff5a72019-09-11 13:49:33 +02003463 if (args[0]->type != LYXP_SET_NODE_SET) {
3464 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3465 return LY_EVALID;
3466 }
3467
3468 set_fill_number(set, args[0]->used);
3469 return LY_SUCCESS;
3470}
3471
3472/**
3473 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3474 * with the context with the intial node.
3475 *
3476 * @param[in] args Array of arguments.
3477 * @param[in] arg_count Count of elements in @p args.
3478 * @param[in,out] set Context and result set at the same time.
3479 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003480 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003481 */
3482static LY_ERR
3483xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3484{
3485 if (arg_count || args) {
3486 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3487 return LY_EVALID;
3488 }
3489
3490 if (options & LYXP_SCNODE_ALL) {
3491 set_scnode_clear_ctx(set);
3492
Michal Vaskoecd62de2019-11-13 12:35:11 +01003493 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003494 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02003495 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003496
3497 /* position is filled later */
3498 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3499 }
3500
3501 return LY_SUCCESS;
3502}
3503
3504/**
3505 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3506 * leafref or instance-identifier target node(s).
3507 *
3508 * @param[in] args Array of arguments.
3509 * @param[in] arg_count Count of elements in @p args.
3510 * @param[in,out] set Context and result set at the same time.
3511 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003512 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003513 */
3514static LY_ERR
3515xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3516{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003517 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003518 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003519 struct lysc_node_leaf *sleaf = NULL;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003520 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003521 const struct lyd_node *node;
3522 char *errmsg = NULL;
3523 const char *val;
3524 int dynamic;
3525 LY_ERR rc = LY_SUCCESS;
3526
3527 if (options & LYXP_SCNODE_ALL) {
3528 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3529 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003530 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3531 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 +02003532 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3533 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3534 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003535 }
3536 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003537 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003538 cctx.ctx = set->ctx;
3539 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3540 /* it was already validated, it must succeed */
3541 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003542 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003543 }
3544 }
3545
Michal Vasko03ff5a72019-09-11 13:49:33 +02003546 return rc;
3547 }
3548
Michal Vaskod3678892020-05-21 10:06:58 +02003549 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003550 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3551 return LY_EVALID;
3552 }
3553
Michal Vaskod3678892020-05-21 10:06:58 +02003554 lyxp_set_free_content(set);
3555 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003556 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3557 sleaf = (struct lysc_node_leaf *)leaf->schema;
3558 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3559 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3560 /* find leafref target */
3561 val = lyd_value2str(leaf, &dynamic);
3562 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
Michal Vaskof03ed032020-03-04 13:31:44 +01003563 set->tree, &leaf->value, &errmsg);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003564 if (dynamic) {
3565 free((char *)val);
3566 }
3567 if (!node) {
3568 LOGERR(set->ctx, LY_EINVAL, errmsg);
3569 free(errmsg);
3570 return LY_EINVAL;
3571 }
3572
3573 /* insert it */
3574 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3575 } else {
3576 assert(sleaf->type->basetype == LY_TYPE_INST);
Michal Vaskof03ed032020-03-04 13:31:44 +01003577 node = (struct lyd_node *)lyd_target(leaf->value.target, set->tree);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003578 if (!node) {
3579 val = lyd_value2str(leaf, &dynamic);
3580 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3581 if (dynamic) {
3582 free((char *)val);
3583 }
3584 return LY_EVALID;
3585 }
3586 }
3587 }
3588 }
3589
3590 return LY_SUCCESS;
3591}
3592
3593/**
3594 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3595 * on whether the first argument nodes contain a node of an identity derived from the second
3596 * argument identity.
3597 *
3598 * @param[in] args Array of arguments.
3599 * @param[in] arg_count Count of elements in @p args.
3600 * @param[in,out] set Context and result set at the same time.
3601 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003602 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003603 */
3604static LY_ERR
3605xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3606{
3607 uint16_t i;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003608 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003609 struct lyd_node_term *leaf;
3610 struct lysc_node_leaf *sleaf;
3611 struct lyd_value data = {0};
3612 struct ly_err_item *err = NULL;
3613 LY_ERR rc = LY_SUCCESS;
3614 int found;
3615
3616 if (options & LYXP_SCNODE_ALL) {
3617 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3618 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003619 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3620 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 +02003621 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3622 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003623 }
3624
3625 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3626 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3627 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 +02003628 } else if (!warn_is_string_type(sleaf->type)) {
3629 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003630 }
3631 }
3632 set_scnode_clear_ctx(set);
3633 return rc;
3634 }
3635
Michal Vaskod3678892020-05-21 10:06:58 +02003636 if (args[0]->type != LYXP_SET_NODE_SET) {
3637 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
3638 "derived-from(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003639 return LY_EVALID;
3640 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003641 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003642 LY_CHECK_RET(rc);
3643
3644 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003645 found = 0;
3646 for (i = 0; i < args[0]->used; ++i) {
3647 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3648 sleaf = (struct lysc_node_leaf *)leaf->schema;
3649 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3650 /* store args[1] into ident */
3651 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3652 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3653 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
3654 if (err) {
3655 ly_err_print(err);
3656 ly_err_free(err);
3657 }
3658 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003659
Michal Vaskod3678892020-05-21 10:06:58 +02003660 LY_ARRAY_FOR(data.ident->derived, u) {
3661 if (data.ident->derived[u] == leaf->value.ident) {
3662 set_fill_boolean(set, 1);
3663 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003664 break;
3665 }
3666 }
Michal Vaskod3678892020-05-21 10:06:58 +02003667 if (found) {
3668 break;
3669 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003670 }
3671 }
3672
3673 return LY_SUCCESS;
3674}
3675
3676/**
3677 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3678 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3679 * the second argument identity.
3680 *
3681 * @param[in] args Array of arguments.
3682 * @param[in] arg_count Count of elements in @p args.
3683 * @param[in,out] set Context and result set at the same time.
3684 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003685 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003686 */
3687static LY_ERR
3688xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3689{
3690 uint16_t i;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003691 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003692 struct lyd_node_term *leaf;
3693 struct lysc_node_leaf *sleaf;
3694 struct lyd_value data = {0};
3695 struct ly_err_item *err = NULL;
3696 LY_ERR rc = LY_SUCCESS;
3697 int found;
3698
3699 if (options & LYXP_SCNODE_ALL) {
3700 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3701 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003702 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3703 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 +02003704 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3705 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003706 }
3707
3708 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3709 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3710 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 +02003711 } else if (!warn_is_string_type(sleaf->type)) {
3712 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003713 }
3714 }
3715 set_scnode_clear_ctx(set);
3716 return rc;
3717 }
3718
Michal Vaskod3678892020-05-21 10:06:58 +02003719 if (args[0]->type != LYXP_SET_NODE_SET) {
3720 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
3721 "derived-from-or-self(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003722 return LY_EVALID;
3723 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003724 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003725 LY_CHECK_RET(rc);
3726
3727 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003728 found = 0;
3729 for (i = 0; i < args[0]->used; ++i) {
3730 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3731 sleaf = (struct lysc_node_leaf *)leaf->schema;
3732 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3733 /* store args[1] into ident */
3734 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3735 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3736 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
3737 if (err) {
3738 ly_err_print(err);
3739 ly_err_free(err);
3740 }
3741 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003742
Michal Vaskod3678892020-05-21 10:06:58 +02003743 if (data.ident == leaf->value.ident) {
3744 set_fill_boolean(set, 1);
3745 break;
3746 }
3747 LY_ARRAY_FOR(data.ident->derived, u) {
3748 if (data.ident->derived[u] == leaf->value.ident) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003749 set_fill_boolean(set, 1);
Michal Vaskod3678892020-05-21 10:06:58 +02003750 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003751 break;
3752 }
Michal Vaskod3678892020-05-21 10:06:58 +02003753 }
3754 if (found) {
3755 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003756 }
3757 }
3758 }
3759
3760 return LY_SUCCESS;
3761}
3762
3763/**
3764 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3765 * with the integer value of the first node's enum value, otherwise NaN.
3766 *
3767 * @param[in] args Array of arguments.
3768 * @param[in] arg_count Count of elements in @p args.
3769 * @param[in,out] set Context and result set at the same time.
3770 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003771 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003772 */
3773static LY_ERR
3774xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3775{
3776 struct lyd_node_term *leaf;
3777 struct lysc_node_leaf *sleaf;
3778 LY_ERR rc = LY_SUCCESS;
3779
3780 if (options & LYXP_SCNODE_ALL) {
3781 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3782 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003783 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3784 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 +02003785 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3786 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003787 }
3788 set_scnode_clear_ctx(set);
3789 return rc;
3790 }
3791
Michal Vaskod3678892020-05-21 10:06:58 +02003792 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003793 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3794 return LY_EVALID;
3795 }
3796
3797 set_fill_number(set, NAN);
Michal Vaskod3678892020-05-21 10:06:58 +02003798 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003799 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3800 sleaf = (struct lysc_node_leaf *)leaf->schema;
3801 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3802 set_fill_number(set, leaf->value.enum_item->value);
3803 }
3804 }
3805
3806 return LY_SUCCESS;
3807}
3808
3809/**
3810 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3811 * with false value.
3812 *
3813 * @param[in] args Array of arguments.
3814 * @param[in] arg_count Count of elements in @p args.
3815 * @param[in,out] set Context and result set at the same time.
3816 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003817 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003818 */
3819static LY_ERR
3820xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3821{
3822 if (options & LYXP_SCNODE_ALL) {
3823 set_scnode_clear_ctx(set);
3824 return LY_SUCCESS;
3825 }
3826
3827 set_fill_boolean(set, 0);
3828 return LY_SUCCESS;
3829}
3830
3831/**
3832 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3833 * with the first argument floored (truncated).
3834 *
3835 * @param[in] args Array of arguments.
3836 * @param[in] arg_count Count of elements in @p args.
3837 * @param[in,out] set Context and result set at the same time.
3838 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003839 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003840 */
3841static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003842xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003843{
3844 LY_ERR rc;
3845
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003846 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003847 LY_CHECK_RET(rc);
3848 if (isfinite(args[0]->val.num)) {
3849 set_fill_number(set, (long long)args[0]->val.num);
3850 }
3851
3852 return LY_SUCCESS;
3853}
3854
3855/**
3856 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3857 * whether the language of the text matches the one from the argument.
3858 *
3859 * @param[in] args Array of arguments.
3860 * @param[in] arg_count Count of elements in @p args.
3861 * @param[in,out] set Context and result set at the same time.
3862 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003863 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003864 */
3865static LY_ERR
3866xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3867{
3868 const struct lyd_node *node;
3869 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01003870 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003871 const char *val;
3872 int i, dynamic;
3873 LY_ERR rc = LY_SUCCESS;
3874
3875 if (options & LYXP_SCNODE_ALL) {
3876 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3877 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3878 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 +02003879 } else if (!warn_is_string_type(sleaf->type)) {
3880 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003881 }
3882 }
3883 set_scnode_clear_ctx(set);
3884 return rc;
3885 }
3886
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003887 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003888 LY_CHECK_RET(rc);
3889
Michal Vasko03ff5a72019-09-11 13:49:33 +02003890 if (set->type != LYXP_SET_NODE_SET) {
3891 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3892 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02003893 } else if (!set->used) {
3894 set_fill_boolean(set, 0);
3895 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003896 }
3897
3898 switch (set->val.nodes[0].type) {
3899 case LYXP_NODE_ELEM:
3900 case LYXP_NODE_TEXT:
3901 node = set->val.nodes[0].node;
3902 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01003903 case LYXP_NODE_META:
3904 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003905 break;
3906 default:
3907 /* nothing to do with roots */
3908 set_fill_boolean(set, 0);
3909 return LY_SUCCESS;
3910 }
3911
Michal Vasko9f96a052020-03-10 09:41:45 +01003912 /* find lang metadata */
Michal Vasko03ff5a72019-09-11 13:49:33 +02003913 for (; node; node = (struct lyd_node *)node->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01003914 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003915 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01003916 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003917 break;
3918 }
3919 }
3920
Michal Vasko9f96a052020-03-10 09:41:45 +01003921 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003922 break;
3923 }
3924 }
3925
3926 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01003927 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003928 set_fill_boolean(set, 0);
3929 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01003930 val = lyd_meta2str(meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003931 for (i = 0; args[0]->val.str[i]; ++i) {
3932 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3933 set_fill_boolean(set, 0);
3934 break;
3935 }
3936 }
3937 if (!args[0]->val.str[i]) {
3938 if (!val[i] || (val[i] == '-')) {
3939 set_fill_boolean(set, 1);
3940 } else {
3941 set_fill_boolean(set, 0);
3942 }
3943 }
3944 if (dynamic) {
3945 free((char *)val);
3946 }
3947 }
3948
3949 return LY_SUCCESS;
3950}
3951
3952/**
3953 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3954 * with the context size.
3955 *
3956 * @param[in] args Array of arguments.
3957 * @param[in] arg_count Count of elements in @p args.
3958 * @param[in,out] set Context and result set at the same time.
3959 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003960 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003961 */
3962static LY_ERR
3963xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3964{
3965 if (options & LYXP_SCNODE_ALL) {
3966 set_scnode_clear_ctx(set);
3967 return LY_SUCCESS;
3968 }
3969
Michal Vasko03ff5a72019-09-11 13:49:33 +02003970 if (set->type != LYXP_SET_NODE_SET) {
3971 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3972 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02003973 } else if (!set->used) {
3974 set_fill_number(set, 0);
3975 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003976 }
3977
3978 set_fill_number(set, set->ctx_size);
3979 return LY_SUCCESS;
3980}
3981
3982/**
3983 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3984 * with the node name without namespace from the argument or the context.
3985 *
3986 * @param[in] args Array of arguments.
3987 * @param[in] arg_count Count of elements in @p args.
3988 * @param[in,out] set Context and result set at the same time.
3989 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003990 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003991 */
3992static LY_ERR
3993xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3994{
3995 struct lyxp_set_node *item;
3996 /* suppress unused variable warning */
3997 (void)options;
3998
3999 if (options & LYXP_SCNODE_ALL) {
4000 set_scnode_clear_ctx(set);
4001 return LY_SUCCESS;
4002 }
4003
4004 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004005 if (args[0]->type != LYXP_SET_NODE_SET) {
4006 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4007 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004008 } else if (!args[0]->used) {
4009 set_fill_string(set, "", 0);
4010 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004011 }
4012
4013 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004014 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004015
4016 item = &args[0]->val.nodes[0];
4017 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004018 if (set->type != LYXP_SET_NODE_SET) {
4019 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4020 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004021 } else if (!set->used) {
4022 set_fill_string(set, "", 0);
4023 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004024 }
4025
4026 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004027 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004028
4029 item = &set->val.nodes[0];
4030 }
4031
4032 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004033 case LYXP_NODE_NONE:
4034 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004035 case LYXP_NODE_ROOT:
4036 case LYXP_NODE_ROOT_CONFIG:
4037 case LYXP_NODE_TEXT:
4038 set_fill_string(set, "", 0);
4039 break;
4040 case LYXP_NODE_ELEM:
4041 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4042 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004043 case LYXP_NODE_META:
4044 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004045 break;
4046 }
4047
4048 return LY_SUCCESS;
4049}
4050
4051/**
4052 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4053 * with the node name fully qualified (with namespace) from the argument or the context.
4054 *
4055 * @param[in] args Array of arguments.
4056 * @param[in] arg_count Count of elements in @p args.
4057 * @param[in,out] set Context and result set at the same time.
4058 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004059 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004060 */
4061static LY_ERR
4062xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4063{
4064 struct lyxp_set_node *item;
4065 struct lys_module *mod;
4066 char *str;
4067 const char *name;
4068 int rc;
4069
4070 if (options & LYXP_SCNODE_ALL) {
4071 set_scnode_clear_ctx(set);
4072 return LY_SUCCESS;
4073 }
4074
4075 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004076 if (args[0]->type != LYXP_SET_NODE_SET) {
4077 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4078 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004079 } else if (!args[0]->used) {
4080 set_fill_string(set, "", 0);
4081 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004082 }
4083
4084 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004085 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004086
4087 item = &args[0]->val.nodes[0];
4088 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004089 if (set->type != LYXP_SET_NODE_SET) {
4090 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4091 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004092 } else if (!set->used) {
4093 set_fill_string(set, "", 0);
4094 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004095 }
4096
4097 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004098 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004099
4100 item = &set->val.nodes[0];
4101 }
4102
4103 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004104 case LYXP_NODE_NONE:
4105 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004106 case LYXP_NODE_ROOT:
4107 case LYXP_NODE_ROOT_CONFIG:
4108 case LYXP_NODE_TEXT:
4109 mod = NULL;
4110 name = NULL;
4111 break;
4112 case LYXP_NODE_ELEM:
4113 mod = item->node->schema->module;
4114 name = item->node->schema->name;
4115 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004116 case LYXP_NODE_META:
4117 mod = ((struct lyd_meta *)item->node)->annotation->module;
4118 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004119 break;
4120 }
4121
4122 if (mod && name) {
4123 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01004124 case LYD_SCHEMA:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004125 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4126 break;
4127 case LYD_JSON:
4128 rc = asprintf(&str, "%s:%s", mod->name, name);
4129 break;
Michal Vasko52927e22020-03-16 17:26:14 +01004130 case LYD_XML:
Michal Vasko9409ef62019-09-12 11:47:17 +02004131 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004132 }
4133 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4134 set_fill_string(set, str, strlen(str));
4135 free(str);
4136 } else {
4137 set_fill_string(set, "", 0);
4138 }
4139
4140 return LY_SUCCESS;
4141}
4142
4143/**
4144 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4145 * with the namespace of the node from the argument or the context.
4146 *
4147 * @param[in] args Array of arguments.
4148 * @param[in] arg_count Count of elements in @p args.
4149 * @param[in,out] set Context and result set at the same time.
4150 * @param[in] options XPath options.
4151 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4152 */
4153static LY_ERR
4154xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4155{
4156 struct lyxp_set_node *item;
4157 struct lys_module *mod;
4158 /* suppress unused variable warning */
4159 (void)options;
4160
4161 if (options & LYXP_SCNODE_ALL) {
4162 set_scnode_clear_ctx(set);
4163 return LY_SUCCESS;
4164 }
4165
4166 if (arg_count) {
Michal Vaskod3678892020-05-21 10:06:58 +02004167 if (args[0]->type != LYXP_SET_NODE_SET) {
4168 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
4169 "namespace-uri(node-set?)");
4170 return LY_EVALID;
4171 } else if (!args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004172 set_fill_string(set, "", 0);
4173 return LY_SUCCESS;
4174 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004175
4176 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004177 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004178
4179 item = &args[0]->val.nodes[0];
4180 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004181 if (set->type != LYXP_SET_NODE_SET) {
4182 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4183 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004184 } else if (!set->used) {
4185 set_fill_string(set, "", 0);
4186 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004187 }
4188
4189 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004190 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004191
4192 item = &set->val.nodes[0];
4193 }
4194
4195 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004196 case LYXP_NODE_NONE:
4197 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004198 case LYXP_NODE_ROOT:
4199 case LYXP_NODE_ROOT_CONFIG:
4200 case LYXP_NODE_TEXT:
4201 set_fill_string(set, "", 0);
4202 break;
4203 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004204 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004205 if (item->type == LYXP_NODE_ELEM) {
4206 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004207 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004208 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004209 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004210 }
4211
4212 set_fill_string(set, mod->ns, strlen(mod->ns));
4213 break;
4214 }
4215
4216 return LY_SUCCESS;
4217}
4218
4219/**
4220 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4221 * with only nodes from the context. In practice it either leaves the context
4222 * as it is or returns an empty node set.
4223 *
4224 * @param[in] args Array of arguments.
4225 * @param[in] arg_count Count of elements in @p args.
4226 * @param[in,out] set Context and result set at the same time.
4227 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004228 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004229 */
4230static LY_ERR
4231xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4232{
4233 if (options & LYXP_SCNODE_ALL) {
4234 set_scnode_clear_ctx(set);
4235 return LY_SUCCESS;
4236 }
4237
4238 if (set->type != LYXP_SET_NODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02004239 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004240 }
4241 return LY_SUCCESS;
4242}
4243
4244/**
4245 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4246 * with normalized value (no leading, trailing, double white spaces) of the node
4247 * from the argument or the context.
4248 *
4249 * @param[in] args Array of arguments.
4250 * @param[in] arg_count Count of elements in @p args.
4251 * @param[in,out] set Context and result set at the same time.
4252 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004253 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004254 */
4255static LY_ERR
4256xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4257{
4258 uint16_t i, new_used;
4259 char *new;
4260 int have_spaces = 0, space_before = 0;
4261 struct lysc_node_leaf *sleaf;
4262 LY_ERR rc = LY_SUCCESS;
4263
4264 if (options & LYXP_SCNODE_ALL) {
4265 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4266 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4267 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 +02004268 } else if (!warn_is_string_type(sleaf->type)) {
4269 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004270 }
4271 }
4272 set_scnode_clear_ctx(set);
4273 return rc;
4274 }
4275
4276 if (arg_count) {
4277 set_fill_set(set, args[0]);
4278 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004279 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004280 LY_CHECK_RET(rc);
4281
4282 /* is there any normalization necessary? */
4283 for (i = 0; set->val.str[i]; ++i) {
4284 if (is_xmlws(set->val.str[i])) {
4285 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4286 have_spaces = 1;
4287 break;
4288 }
4289 space_before = 1;
4290 } else {
4291 space_before = 0;
4292 }
4293 }
4294
4295 /* yep, there is */
4296 if (have_spaces) {
4297 /* it's enough, at least one character will go, makes space for ending '\0' */
4298 new = malloc(strlen(set->val.str) * sizeof(char));
4299 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4300 new_used = 0;
4301
4302 space_before = 0;
4303 for (i = 0; set->val.str[i]; ++i) {
4304 if (is_xmlws(set->val.str[i])) {
4305 if ((i == 0) || space_before) {
4306 space_before = 1;
4307 continue;
4308 } else {
4309 space_before = 1;
4310 }
4311 } else {
4312 space_before = 0;
4313 }
4314
4315 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4316 ++new_used;
4317 }
4318
4319 /* at worst there is one trailing space now */
4320 if (new_used && is_xmlws(new[new_used - 1])) {
4321 --new_used;
4322 }
4323
4324 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4325 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4326 new[new_used] = '\0';
4327
4328 free(set->val.str);
4329 set->val.str = new;
4330 }
4331
4332 return LY_SUCCESS;
4333}
4334
4335/**
4336 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4337 * with the argument converted to boolean and logically inverted.
4338 *
4339 * @param[in] args Array of arguments.
4340 * @param[in] arg_count Count of elements in @p args.
4341 * @param[in,out] set Context and result set at the same time.
4342 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004343 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004344 */
4345static LY_ERR
4346xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4347{
4348 if (options & LYXP_SCNODE_ALL) {
4349 set_scnode_clear_ctx(set);
4350 return LY_SUCCESS;
4351 }
4352
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004353 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004354 if (args[0]->val.bool) {
4355 set_fill_boolean(set, 0);
4356 } else {
4357 set_fill_boolean(set, 1);
4358 }
4359
4360 return LY_SUCCESS;
4361}
4362
4363/**
4364 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4365 * with the number representation of either the argument or the context.
4366 *
4367 * @param[in] args Array of arguments.
4368 * @param[in] arg_count Count of elements in @p args.
4369 * @param[in,out] set Context and result set at the same time.
4370 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004371 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004372 */
4373static LY_ERR
4374xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4375{
4376 LY_ERR rc;
4377
4378 if (options & LYXP_SCNODE_ALL) {
4379 set_scnode_clear_ctx(set);
4380 return LY_SUCCESS;
4381 }
4382
4383 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004384 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004385 LY_CHECK_RET(rc);
4386 set_fill_set(set, args[0]);
4387 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004388 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004389 LY_CHECK_RET(rc);
4390 }
4391
4392 return LY_SUCCESS;
4393}
4394
4395/**
4396 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4397 * with the context position.
4398 *
4399 * @param[in] args Array of arguments.
4400 * @param[in] arg_count Count of elements in @p args.
4401 * @param[in,out] set Context and result set at the same time.
4402 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004403 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004404 */
4405static LY_ERR
4406xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4407{
4408 if (options & LYXP_SCNODE_ALL) {
4409 set_scnode_clear_ctx(set);
4410 return LY_SUCCESS;
4411 }
4412
Michal Vasko03ff5a72019-09-11 13:49:33 +02004413 if (set->type != LYXP_SET_NODE_SET) {
4414 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4415 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004416 } else if (!set->used) {
4417 set_fill_number(set, 0);
4418 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004419 }
4420
4421 set_fill_number(set, set->ctx_pos);
4422
4423 /* UNUSED in 'Release' build type */
4424 (void)options;
4425 return LY_SUCCESS;
4426}
4427
4428/**
4429 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4430 * depending on whether the second argument regex matches the first argument string. For details refer to
4431 * YANG 1.1 RFC section 10.2.1.
4432 *
4433 * @param[in] args Array of arguments.
4434 * @param[in] arg_count Count of elements in @p args.
4435 * @param[in,out] set Context and result set at the same time.
4436 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004437 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004438 */
4439static LY_ERR
4440xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4441{
4442 struct lysc_pattern **patterns = NULL, **pattern;
4443 struct lysc_node_leaf *sleaf;
4444 char *path;
4445 LY_ERR rc = LY_SUCCESS;
4446 struct ly_err_item *err;
4447
4448 if (options & LYXP_SCNODE_ALL) {
4449 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4450 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4451 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 +02004452 } else if (!warn_is_string_type(sleaf->type)) {
4453 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004454 }
4455 }
4456
4457 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4458 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4459 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 +02004460 } else if (!warn_is_string_type(sleaf->type)) {
4461 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004462 }
4463 }
4464 set_scnode_clear_ctx(set);
4465 return rc;
4466 }
4467
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004468 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004469 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004470 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004471 LY_CHECK_RET(rc);
4472
4473 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4474 *pattern = malloc(sizeof **pattern);
4475 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4476 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4477 free(path);
4478 if (rc != LY_SUCCESS) {
4479 LY_ARRAY_FREE(patterns);
4480 return rc;
4481 }
4482
4483 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4484 pcre2_code_free((*pattern)->code);
4485 free(*pattern);
4486 LY_ARRAY_FREE(patterns);
4487 if (rc && (rc != LY_EVALID)) {
4488 ly_err_print(err);
4489 ly_err_free(err);
4490 return rc;
4491 }
4492
4493 if (rc == LY_EVALID) {
4494 ly_err_free(err);
4495 set_fill_boolean(set, 0);
4496 } else {
4497 set_fill_boolean(set, 1);
4498 }
4499
4500 return LY_SUCCESS;
4501}
4502
4503/**
4504 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4505 * with the rounded first argument. For details refer to
4506 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4507 *
4508 * @param[in] args Array of arguments.
4509 * @param[in] arg_count Count of elements in @p args.
4510 * @param[in,out] set Context and result set at the same time.
4511 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004512 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004513 */
4514static LY_ERR
4515xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4516{
4517 struct lysc_node_leaf *sleaf;
4518 LY_ERR rc = LY_SUCCESS;
4519
4520 if (options & LYXP_SCNODE_ALL) {
4521 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4522 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004523 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4524 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 +02004525 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4526 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004527 }
4528 set_scnode_clear_ctx(set);
4529 return rc;
4530 }
4531
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004532 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004533 LY_CHECK_RET(rc);
4534
4535 /* cover only the cases where floor can't be used */
4536 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4537 set_fill_number(set, -0.0f);
4538 } else {
4539 args[0]->val.num += 0.5;
4540 rc = xpath_floor(args, 1, args[0], options);
4541 LY_CHECK_RET(rc);
4542 set_fill_number(set, args[0]->val.num);
4543 }
4544
4545 return LY_SUCCESS;
4546}
4547
4548/**
4549 * @brief Execute the XPath starts-with(string, string) function.
4550 * Returns LYXP_SET_BOOLEAN whether the second argument is
4551 * the prefix of the first or not.
4552 *
4553 * @param[in] args Array of arguments.
4554 * @param[in] arg_count Count of elements in @p args.
4555 * @param[in,out] set Context and result set at the same time.
4556 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004557 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004558 */
4559static LY_ERR
4560xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4561{
4562 struct lysc_node_leaf *sleaf;
4563 LY_ERR rc = LY_SUCCESS;
4564
4565 if (options & LYXP_SCNODE_ALL) {
4566 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4567 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4568 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 +02004569 } else if (!warn_is_string_type(sleaf->type)) {
4570 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004571 }
4572 }
4573
4574 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4575 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4576 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 +02004577 } else if (!warn_is_string_type(sleaf->type)) {
4578 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004579 }
4580 }
4581 set_scnode_clear_ctx(set);
4582 return rc;
4583 }
4584
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004585 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004586 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004587 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004588 LY_CHECK_RET(rc);
4589
4590 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4591 set_fill_boolean(set, 0);
4592 } else {
4593 set_fill_boolean(set, 1);
4594 }
4595
4596 return LY_SUCCESS;
4597}
4598
4599/**
4600 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4601 * with the string representation of either the argument or the context.
4602 *
4603 * @param[in] args Array of arguments.
4604 * @param[in] arg_count Count of elements in @p args.
4605 * @param[in,out] set Context and result set at the same time.
4606 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004607 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004608 */
4609static LY_ERR
4610xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4611{
4612 LY_ERR rc;
4613
4614 if (options & LYXP_SCNODE_ALL) {
4615 set_scnode_clear_ctx(set);
4616 return LY_SUCCESS;
4617 }
4618
4619 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004620 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004621 LY_CHECK_RET(rc);
4622 set_fill_set(set, args[0]);
4623 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004624 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004625 LY_CHECK_RET(rc);
4626 }
4627
4628 return LY_SUCCESS;
4629}
4630
4631/**
4632 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4633 * with the length of the string in either the argument or the context.
4634 *
4635 * @param[in] args Array of arguments.
4636 * @param[in] arg_count Count of elements in @p args.
4637 * @param[in,out] set Context and result set at the same time.
4638 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004639 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004640 */
4641static LY_ERR
4642xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4643{
4644 struct lysc_node_leaf *sleaf;
4645 LY_ERR rc = LY_SUCCESS;
4646
4647 if (options & LYXP_SCNODE_ALL) {
4648 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4649 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4650 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 +02004651 } else if (!warn_is_string_type(sleaf->type)) {
4652 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004653 }
4654 }
4655 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4656 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4657 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 +02004658 } else if (!warn_is_string_type(sleaf->type)) {
4659 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004660 }
4661 }
4662 set_scnode_clear_ctx(set);
4663 return rc;
4664 }
4665
4666 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004667 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004668 LY_CHECK_RET(rc);
4669 set_fill_number(set, strlen(args[0]->val.str));
4670 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004671 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004672 LY_CHECK_RET(rc);
4673 set_fill_number(set, strlen(set->val.str));
4674 }
4675
4676 return LY_SUCCESS;
4677}
4678
4679/**
4680 * @brief Execute the XPath substring(string, number, number?) function.
4681 * Returns LYXP_SET_STRING substring of the first argument starting
4682 * on the second argument index ending on the third argument index,
4683 * indexed from 1. For exact definition refer to
4684 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4685 *
4686 * @param[in] args Array of arguments.
4687 * @param[in] arg_count Count of elements in @p args.
4688 * @param[in,out] set Context and result set at the same time.
4689 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004690 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004691 */
4692static LY_ERR
4693xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4694{
4695 int start, len;
4696 uint16_t str_start, str_len, pos;
4697 struct lysc_node_leaf *sleaf;
4698 LY_ERR rc = LY_SUCCESS;
4699
4700 if (options & LYXP_SCNODE_ALL) {
4701 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4702 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4703 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 +02004704 } else if (!warn_is_string_type(sleaf->type)) {
4705 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004706 }
4707 }
4708
4709 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4710 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4711 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 +02004712 } else if (!warn_is_numeric_type(sleaf->type)) {
4713 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004714 }
4715 }
4716
4717 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4718 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4719 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4720 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 +02004721 } else if (!warn_is_numeric_type(sleaf->type)) {
4722 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004723 }
4724 }
4725 set_scnode_clear_ctx(set);
4726 return rc;
4727 }
4728
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004729 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004730 LY_CHECK_RET(rc);
4731
4732 /* start */
4733 if (xpath_round(&args[1], 1, args[1], options)) {
4734 return -1;
4735 }
4736 if (isfinite(args[1]->val.num)) {
4737 start = args[1]->val.num - 1;
4738 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4739 start = INT_MIN;
4740 } else {
4741 start = INT_MAX;
4742 }
4743
4744 /* len */
4745 if (arg_count == 3) {
4746 rc = xpath_round(&args[2], 1, args[2], options);
4747 LY_CHECK_RET(rc);
4748 if (isfinite(args[2]->val.num)) {
4749 len = args[2]->val.num;
4750 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4751 len = 0;
4752 } else {
4753 len = INT_MAX;
4754 }
4755 } else {
4756 len = INT_MAX;
4757 }
4758
4759 /* find matching character positions */
4760 str_start = 0;
4761 str_len = 0;
4762 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4763 if (pos < start) {
4764 ++str_start;
4765 } else if (pos < start + len) {
4766 ++str_len;
4767 } else {
4768 break;
4769 }
4770 }
4771
4772 set_fill_string(set, args[0]->val.str + str_start, str_len);
4773 return LY_SUCCESS;
4774}
4775
4776/**
4777 * @brief Execute the XPath substring-after(string, string) function.
4778 * Returns LYXP_SET_STRING with the string succeeding the occurance
4779 * of the second argument in the first or an empty string.
4780 *
4781 * @param[in] args Array of arguments.
4782 * @param[in] arg_count Count of elements in @p args.
4783 * @param[in,out] set Context and result set at the same time.
4784 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004785 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004786 */
4787static LY_ERR
4788xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4789{
4790 char *ptr;
4791 struct lysc_node_leaf *sleaf;
4792 LY_ERR rc = LY_SUCCESS;
4793
4794 if (options & LYXP_SCNODE_ALL) {
4795 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4796 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4797 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 +02004798 } else if (!warn_is_string_type(sleaf->type)) {
4799 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004800 }
4801 }
4802
4803 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4804 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4805 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 +02004806 } else if (!warn_is_string_type(sleaf->type)) {
4807 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004808 }
4809 }
4810 set_scnode_clear_ctx(set);
4811 return rc;
4812 }
4813
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004814 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004815 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004816 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004817 LY_CHECK_RET(rc);
4818
4819 ptr = strstr(args[0]->val.str, args[1]->val.str);
4820 if (ptr) {
4821 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4822 } else {
4823 set_fill_string(set, "", 0);
4824 }
4825
4826 return LY_SUCCESS;
4827}
4828
4829/**
4830 * @brief Execute the XPath substring-before(string, string) function.
4831 * Returns LYXP_SET_STRING with the string preceding the occurance
4832 * of the second argument in the first or an empty string.
4833 *
4834 * @param[in] args Array of arguments.
4835 * @param[in] arg_count Count of elements in @p args.
4836 * @param[in,out] set Context and result set at the same time.
4837 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004838 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004839 */
4840static LY_ERR
4841xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4842{
4843 char *ptr;
4844 struct lysc_node_leaf *sleaf;
4845 LY_ERR rc = LY_SUCCESS;
4846
4847 if (options & LYXP_SCNODE_ALL) {
4848 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4849 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4850 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 +02004851 } else if (!warn_is_string_type(sleaf->type)) {
4852 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004853 }
4854 }
4855
4856 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4857 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4858 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 +02004859 } else if (!warn_is_string_type(sleaf->type)) {
4860 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004861 }
4862 }
4863 set_scnode_clear_ctx(set);
4864 return rc;
4865 }
4866
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004867 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004868 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004869 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004870 LY_CHECK_RET(rc);
4871
4872 ptr = strstr(args[0]->val.str, args[1]->val.str);
4873 if (ptr) {
4874 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4875 } else {
4876 set_fill_string(set, "", 0);
4877 }
4878
4879 return LY_SUCCESS;
4880}
4881
4882/**
4883 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4884 * with the sum of all the nodes in the context.
4885 *
4886 * @param[in] args Array of arguments.
4887 * @param[in] arg_count Count of elements in @p args.
4888 * @param[in,out] set Context and result set at the same time.
4889 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004890 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004891 */
4892static LY_ERR
4893xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4894{
4895 long double num;
4896 char *str;
4897 uint16_t i;
4898 struct lyxp_set set_item;
4899 struct lysc_node_leaf *sleaf;
4900 LY_ERR rc = LY_SUCCESS;
4901
4902 if (options & LYXP_SCNODE_ALL) {
4903 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4904 for (i = 0; i < args[0]->used; ++i) {
4905 if (args[0]->val.scnodes[i].in_ctx == 1) {
4906 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4907 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4908 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4909 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004910 } else if (!warn_is_numeric_type(sleaf->type)) {
4911 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004912 }
4913 }
4914 }
4915 }
4916 set_scnode_clear_ctx(set);
4917 return rc;
4918 }
4919
4920 set_fill_number(set, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004921
4922 if (args[0]->type != LYXP_SET_NODE_SET) {
4923 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4924 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004925 } else if (!args[0]->used) {
4926 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004927 }
4928
Michal Vasko5c4e5892019-11-14 12:31:38 +01004929 set_init(&set_item, set);
4930
Michal Vasko03ff5a72019-09-11 13:49:33 +02004931 set_item.type = LYXP_SET_NODE_SET;
4932 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4933 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4934
4935 set_item.used = 1;
4936 set_item.size = 1;
4937
4938 for (i = 0; i < args[0]->used; ++i) {
4939 set_item.val.nodes[0] = args[0]->val.nodes[i];
4940
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004941 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004942 LY_CHECK_RET(rc);
4943 num = cast_string_to_number(str);
4944 free(str);
4945 set->val.num += num;
4946 }
4947
4948 free(set_item.val.nodes);
4949
4950 return LY_SUCCESS;
4951}
4952
4953/**
4954 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4955 * with the text content of the nodes in the context.
4956 *
4957 * @param[in] args Array of arguments.
4958 * @param[in] arg_count Count of elements in @p args.
4959 * @param[in,out] set Context and result set at the same time.
4960 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004961 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004962 */
4963static LY_ERR
4964xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4965{
4966 uint32_t i;
4967
4968 if (options & LYXP_SCNODE_ALL) {
4969 set_scnode_clear_ctx(set);
4970 return LY_SUCCESS;
4971 }
4972
Michal Vasko03ff5a72019-09-11 13:49:33 +02004973 if (set->type != LYXP_SET_NODE_SET) {
4974 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4975 return LY_EVALID;
4976 }
4977
4978 for (i = 0; i < set->used;) {
4979 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004980 case LYXP_NODE_NONE:
4981 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004982 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004983 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4984 set->val.nodes[i].type = LYXP_NODE_TEXT;
4985 ++i;
4986 break;
4987 }
4988 /* fall through */
4989 case LYXP_NODE_ROOT:
4990 case LYXP_NODE_ROOT_CONFIG:
4991 case LYXP_NODE_TEXT:
Michal Vasko9f96a052020-03-10 09:41:45 +01004992 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004993 set_remove_node(set, i);
4994 break;
4995 }
4996 }
4997
4998 return LY_SUCCESS;
4999}
5000
5001/**
5002 * @brief Execute the XPath translate(string, string, string) function.
5003 * Returns LYXP_SET_STRING with the first argument with the characters
5004 * from the second argument replaced by those on the corresponding
5005 * positions in the third argument.
5006 *
5007 * @param[in] args Array of arguments.
5008 * @param[in] arg_count Count of elements in @p args.
5009 * @param[in,out] set Context and result set at the same time.
5010 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005011 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005012 */
5013static LY_ERR
5014xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5015{
5016 uint16_t i, j, new_used;
5017 char *new;
5018 int found, have_removed;
5019 struct lysc_node_leaf *sleaf;
5020 LY_ERR rc = LY_SUCCESS;
5021
5022 if (options & LYXP_SCNODE_ALL) {
5023 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5024 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5025 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 +02005026 } else if (!warn_is_string_type(sleaf->type)) {
5027 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005028 }
5029 }
5030
5031 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5032 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5033 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 +02005034 } else if (!warn_is_string_type(sleaf->type)) {
5035 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005036 }
5037 }
5038
5039 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5040 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5041 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 +02005042 } else if (!warn_is_string_type(sleaf->type)) {
5043 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005044 }
5045 }
5046 set_scnode_clear_ctx(set);
5047 return rc;
5048 }
5049
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005050 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005051 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005052 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005053 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005054 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005055 LY_CHECK_RET(rc);
5056
5057 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5058 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5059 new_used = 0;
5060
5061 have_removed = 0;
5062 for (i = 0; args[0]->val.str[i]; ++i) {
5063 found = 0;
5064
5065 for (j = 0; args[1]->val.str[j]; ++j) {
5066 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5067 /* removing this char */
5068 if (j >= strlen(args[2]->val.str)) {
5069 have_removed = 1;
5070 found = 1;
5071 break;
5072 }
5073 /* replacing this char */
5074 new[new_used] = args[2]->val.str[j];
5075 ++new_used;
5076 found = 1;
5077 break;
5078 }
5079 }
5080
5081 /* copying this char */
5082 if (!found) {
5083 new[new_used] = args[0]->val.str[i];
5084 ++new_used;
5085 }
5086 }
5087
5088 if (have_removed) {
5089 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5090 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5091 }
5092 new[new_used] = '\0';
5093
Michal Vaskod3678892020-05-21 10:06:58 +02005094 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005095 set->type = LYXP_SET_STRING;
5096 set->val.str = new;
5097
5098 return LY_SUCCESS;
5099}
5100
5101/**
5102 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5103 * with true value.
5104 *
5105 * @param[in] args Array of arguments.
5106 * @param[in] arg_count Count of elements in @p args.
5107 * @param[in,out] set Context and result set at the same time.
5108 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005109 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005110 */
5111static LY_ERR
5112xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5113{
5114 if (options & LYXP_SCNODE_ALL) {
5115 set_scnode_clear_ctx(set);
5116 return LY_SUCCESS;
5117 }
5118
5119 set_fill_boolean(set, 1);
5120 return LY_SUCCESS;
5121}
5122
5123/*
5124 * moveto functions
5125 *
5126 * They and only they actually change the context (set).
5127 */
5128
5129/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005130 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005131 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005132 * XPath @p set is expected to be a (sc)node set!
5133 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005134 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5135 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5136 * @param[in] set Set with XPath context.
5137 * @param[out] moveto_mod Expected module of a matching node.
5138 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005139 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005140static LY_ERR
5141moveto_resolve_model(const char **qname, uint16_t *qname_len, struct lyxp_set *set, const struct lys_module **moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005142{
Michal Vasko6346ece2019-09-24 13:12:53 +02005143 const struct lys_module *mod;
5144 const char *ptr;
5145 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005146 char *str;
5147
Michal Vasko2104e9f2020-03-06 08:23:25 +01005148 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5149
Michal Vasko6346ece2019-09-24 13:12:53 +02005150 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5151 /* specific module */
5152 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005153
Michal Vasko6346ece2019-09-24 13:12:53 +02005154 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01005155 case LYD_SCHEMA:
Michal Vasko6346ece2019-09-24 13:12:53 +02005156 /* schema, search all local module imports */
5157 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5158 break;
5159 case LYD_JSON:
5160 /* JSON data, search in context */
5161 str = strndup(*qname, pref_len);
Michal Vasko97e76fd2020-05-27 15:22:01 +02005162 mod = ly_ctx_get_module_implemented(set->ctx, str);
Michal Vasko6346ece2019-09-24 13:12:53 +02005163 free(str);
5164 break;
Michal Vasko52927e22020-03-16 17:26:14 +01005165 case LYD_XML:
Michal Vasko6346ece2019-09-24 13:12:53 +02005166 LOGINT_RET(set->ctx);
5167 }
5168
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005169 /* Check for errors and non-implemented modules, as they are not valid */
5170 if (!mod || !mod->implemented) {
Michal Vasko2104e9f2020-03-06 08:23:25 +01005171 if (set->type == LYXP_SET_SCNODE_SET) {
5172 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INMOD, pref_len, *qname);
5173 } else {
5174 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5175 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005176 return LY_EVALID;
5177 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005178
Michal Vasko6346ece2019-09-24 13:12:53 +02005179 *qname += pref_len + 1;
5180 *qname_len -= pref_len + 1;
5181 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5182 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005183 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005184 } else {
5185 /* local module */
5186 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005187 }
5188
Michal Vasko6346ece2019-09-24 13:12:53 +02005189 *moveto_mod = mod;
5190 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005191}
5192
5193/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005194 * @brief Move context @p set to the root. Handles absolute path.
5195 * Result is LYXP_SET_NODE_SET.
5196 *
5197 * @param[in,out] set Set to use.
5198 * @param[in] options Xpath options.
5199 */
5200static void
5201moveto_root(struct lyxp_set *set, int options)
5202{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005203 if (!set) {
5204 return;
5205 }
5206
5207 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005208 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005209 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005210 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005211 set->type = LYXP_SET_NODE_SET;
5212 set->used = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005213 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005214 }
5215}
5216
5217/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005218 * @brief Check whether a node has some unresolved "when".
5219 *
5220 * @param[in] node Node to check.
5221 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5222 */
5223static LY_ERR
5224moveto_when_check(const struct lyd_node *node)
5225{
5226 const struct lysc_node *schema;
5227
5228 if (!node) {
5229 return LY_SUCCESS;
5230 }
5231
5232 schema = node->schema;
5233 do {
5234 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5235 return LY_EINCOMPLETE;
5236 }
5237 schema = schema->parent;
5238 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5239
5240 return LY_SUCCESS;
5241}
5242
5243/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005244 * @brief Check @p node as a part of NameTest processing.
5245 *
5246 * @param[in] node Node to check.
5247 * @param[in] root_type XPath root node type.
Michal Vaskod3678892020-05-21 10:06:58 +02005248 * @param[in] node_name Node name in the dictionary to move to, NULL for any node.
5249 * @param[in] moveto_mod Expected module of the node, NULL for any.
Michal Vasko6346ece2019-09-24 13:12:53 +02005250 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5251 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005252 */
5253static LY_ERR
5254moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5255 const struct lys_module *moveto_mod)
5256{
5257 /* module check */
5258 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005259 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005260 }
5261
Michal Vasko5c4e5892019-11-14 12:31:38 +01005262 /* context check */
5263 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005264 return LY_EINVAL;
5265 }
5266
5267 /* name check */
Michal Vasko61ac2f62020-05-25 12:39:51 +02005268 if (node_name && strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005269 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005270 }
5271
Michal Vaskoa1424542019-11-14 16:08:52 +01005272 /* when check */
5273 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005274 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005275 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005276
5277 /* match */
5278 return LY_SUCCESS;
5279}
5280
5281/**
5282 * @brief Check @p node as a part of schema NameTest processing.
5283 *
5284 * @param[in] node Schema node to check.
5285 * @param[in] root_type XPath root node type.
Michal Vaskod3678892020-05-21 10:06:58 +02005286 * @param[in] node_name Node name in the dictionary to move to, NULL for any nodes.
5287 * @param[in] moveto_mod Expected module of the node, NULL for any.
Michal Vasko6346ece2019-09-24 13:12:53 +02005288 * @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 +02005289 */
5290static LY_ERR
5291moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005292 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005293{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005294 /* module check */
Michal Vaskod3678892020-05-21 10:06:58 +02005295 if (moveto_mod && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005296 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005297 }
5298
5299 /* context check */
5300 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5301 return LY_EINVAL;
5302 }
5303
5304 /* name check */
Michal Vasko61ac2f62020-05-25 12:39:51 +02005305 if (node_name && strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005306 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005307 }
5308
5309 /* match */
5310 return LY_SUCCESS;
5311}
5312
5313/**
Michal Vaskod3678892020-05-21 10:06:58 +02005314 * @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 +02005315 *
5316 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005317 * @param[in] mod Matching node module, NULL for any.
5318 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005319 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5320 */
5321static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005322moveto_node(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005323{
Michal Vaskof03ed032020-03-04 13:31:44 +01005324 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005325 int replaced;
Michal Vaskod3678892020-05-21 10:06:58 +02005326 const struct lyd_node *siblings, *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005327 LY_ERR rc;
5328
Michal Vaskod3678892020-05-21 10:06:58 +02005329 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005330 return LY_SUCCESS;
5331 }
5332
5333 if (set->type != LYXP_SET_NODE_SET) {
5334 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5335 return LY_EVALID;
5336 }
5337
Michal Vasko03ff5a72019-09-11 13:49:33 +02005338 for (i = 0; i < set->used; ) {
5339 replaced = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02005340 siblings = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005341
5342 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 +01005343 assert(!set->val.nodes[i].node);
Michal Vaskod3678892020-05-21 10:06:58 +02005344
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005345 /* search in all the trees */
Michal Vaskod3678892020-05-21 10:06:58 +02005346 siblings = set->tree;
Michal Vasko5c4e5892019-11-14 12:31:38 +01005347 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskod3678892020-05-21 10:06:58 +02005348 /* search in children */
5349 siblings = lyd_node_children(set->val.nodes[i].node);
5350 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005351
Michal Vaskod3678892020-05-21 10:06:58 +02005352 for (sub = siblings; sub; sub = sub->next) {
5353 rc = moveto_node_check(sub, set->root_type, ncname, mod);
5354 if (rc == LY_SUCCESS) {
5355 if (!replaced) {
5356 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5357 replaced = 1;
5358 } else {
5359 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005360 }
Michal Vaskod3678892020-05-21 10:06:58 +02005361 ++i;
5362 } else if (rc == LY_EINCOMPLETE) {
5363 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005364 }
5365 }
5366
5367 if (!replaced) {
5368 /* no match */
5369 set_remove_node(set, i);
5370 }
5371 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005372
5373 return LY_SUCCESS;
5374}
5375
5376/**
Michal Vaskod3678892020-05-21 10:06:58 +02005377 * @brief Move context @p set to a node using hashes. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5378 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005379 *
5380 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005381 * @param[in] scnode Matching node schema.
5382 * @param[in] list_inst If @p scnode is ::LYS_LIST, the matching list instance. Ignored otherwise.
5383 * @param[in] llist_val If @p scnode is ::LYS_LEAFLIST, the matching leaf-list value. Ignored otherwise.
5384 * @param[in] llist_val_len Length of @p llist_val.
5385 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5386 */
5387static LY_ERR
5388moveto_node_hash(struct lyxp_set *set, const struct lysc_node *scnode, const struct lyd_node *list_inst,
5389 const char *llist_val, uint16_t llist_val_len)
5390{
5391 uint32_t i;
5392 int replaced;
5393 const struct lyd_node *siblings;
5394 struct lyd_node *sub;
5395
5396 assert(scnode && ((scnode->nodetype != LYS_LIST) || list_inst) && ((scnode->nodetype != LYS_LEAFLIST) || llist_val));
5397
5398 if (!set) {
5399 return LY_SUCCESS;
5400 }
5401
5402 if (set->type != LYXP_SET_NODE_SET) {
5403 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5404 return LY_EVALID;
5405 }
5406
5407 /* context check for all the nodes since we have the schema node */
5408 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
5409 lyxp_set_free_content(set);
5410 return LY_SUCCESS;
5411 }
5412
5413 for (i = 0; i < set->used; ) {
5414 replaced = 0;
5415 siblings = NULL;
5416
5417 if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
5418 assert(!set->val.nodes[i].node);
5419
5420 /* search in all the trees */
5421 siblings = set->tree;
5422 } else if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5423 /* search in children */
5424 siblings = lyd_node_children(set->val.nodes[i].node);
5425 }
5426
5427 /* find the node using hashes */
5428 if (scnode->nodetype == LYS_LIST) {
5429 lyd_find_sibling_first(siblings, list_inst, &sub);
5430 } else {
5431 lyd_find_sibling_val(siblings, scnode, llist_val, llist_val_len, &sub);
5432 }
5433
5434 /* when check */
5435 if (sub && moveto_when_check(sub)) {
5436 return LY_EINCOMPLETE;
5437 }
5438
5439 if (sub) {
5440 /* pos filled later */
5441 if (!replaced) {
5442 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5443 replaced = 1;
5444 } else {
5445 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5446 }
5447 ++i;
5448 }
5449
5450 if (!replaced) {
5451 /* no match */
5452 set_remove_node(set, i);
5453 }
5454 }
5455
5456 return LY_SUCCESS;
5457}
5458
5459/**
5460 * @brief Move context @p set to a schema node. Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5461 *
5462 * @param[in,out] set Set to use.
5463 * @param[in] mod Matching node module, NULL for any.
5464 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005465 * @param[in] options XPath options.
5466 * @return LY_ERR
5467 */
5468static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005469moveto_scnode(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005470{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005471 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005472 uint32_t mod_idx;
Michal Vasko519fd602020-05-26 12:17:39 +02005473 const struct lysc_node *iter, *start_parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005474
Michal Vaskod3678892020-05-21 10:06:58 +02005475 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005476 return LY_SUCCESS;
5477 }
5478
5479 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005480 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005481 return LY_EVALID;
5482 }
5483
Michal Vaskocafad9d2019-11-07 15:20:03 +01005484 /* getnext opts */
5485 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5486 if (options & LYXP_SCNODE_OUTPUT) {
5487 getnext_opts |= LYS_GETNEXT_OUTPUT;
5488 }
5489
Michal Vasko03ff5a72019-09-11 13:49:33 +02005490 orig_used = set->used;
5491 for (i = 0; i < orig_used; ++i) {
5492 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005493 if (set->val.scnodes[i].in_ctx != -2) {
5494 continue;
5495 }
5496
5497 /* remember context node */
5498 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005499 } else {
5500 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005501 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005502
5503 start_parent = set->val.scnodes[i].scnode;
5504
5505 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
Michal Vaskod3678892020-05-21 10:06:58 +02005506 /* it can actually be in any module, it's all <running>, but we know it's mod (if set),
Michal Vasko03ff5a72019-09-11 13:49:33 +02005507 * so use it directly (root node itself is useless in this case) */
5508 mod_idx = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02005509 while (mod || (mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
Michal Vasko519fd602020-05-26 12:17:39 +02005510 iter = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005511 /* module may not be implemented */
Michal Vasko519fd602020-05-26 12:17:39 +02005512 while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
5513 if (!moveto_scnode_check(iter, set->root_type, ncname, mod)) {
5514 idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005515 /* we need to prevent these nodes from being considered in this moveto */
5516 if ((idx < orig_used) && (idx > i)) {
5517 set->val.scnodes[idx].in_ctx = 2;
5518 temp_ctx = 1;
5519 }
5520 }
5521 }
5522
5523 if (!mod_idx) {
Michal Vaskod3678892020-05-21 10:06:58 +02005524 /* mod was specified, we are not going through the whole context */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005525 break;
5526 }
5527 /* next iteration */
Michal Vaskod3678892020-05-21 10:06:58 +02005528 mod = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005529 }
5530
Michal Vasko519fd602020-05-26 12:17:39 +02005531 } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
5532 iter = NULL;
5533 while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
5534 if (!moveto_scnode_check(iter, set->root_type, ncname, (mod ? mod : set->local_mod))) {
5535 idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005536 if ((idx < orig_used) && (idx > i)) {
5537 set->val.scnodes[idx].in_ctx = 2;
5538 temp_ctx = 1;
5539 }
5540 }
5541 }
5542 }
5543 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005544
5545 /* correct temporary in_ctx values */
5546 if (temp_ctx) {
5547 for (i = 0; i < orig_used; ++i) {
5548 if (set->val.scnodes[i].in_ctx == 2) {
5549 set->val.scnodes[i].in_ctx = 1;
5550 }
5551 }
5552 }
5553
5554 return LY_SUCCESS;
5555}
5556
5557/**
Michal Vaskod3678892020-05-21 10:06:58 +02005558 * @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 +02005559 * Context position aware.
5560 *
5561 * @param[in] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005562 * @param[in] mod Matching node module, NULL for any.
5563 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005564 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5565 */
5566static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005567moveto_node_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005568{
5569 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005570 const struct lyd_node *next, *elem, *start;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005571 struct lyxp_set ret_set;
5572 LY_ERR rc;
5573
Michal Vaskod3678892020-05-21 10:06:58 +02005574 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005575 return LY_SUCCESS;
5576 }
5577
5578 if (set->type != LYXP_SET_NODE_SET) {
5579 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5580 return LY_EVALID;
5581 }
5582
Michal Vasko9f96a052020-03-10 09:41:45 +01005583 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vaskod3678892020-05-21 10:06:58 +02005584 rc = moveto_node(set, NULL, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005585 LY_CHECK_RET(rc);
5586
Michal Vasko6346ece2019-09-24 13:12:53 +02005587 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005588 set_init(&ret_set, set);
5589 for (i = 0; i < set->used; ++i) {
5590
5591 /* TREE DFS */
5592 start = set->val.nodes[i].node;
5593 for (elem = next = start; elem; elem = next) {
Michal Vaskod3678892020-05-21 10:06:58 +02005594 rc = moveto_node_check(elem, set->root_type, ncname, mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005595 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005596 /* add matching node into result set */
5597 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5598 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5599 /* the node is a duplicate, we'll process it later in the set */
5600 goto skip_children;
5601 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005602 } else if (rc == LY_EINCOMPLETE) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005603 return rc;
5604 } else if (rc == LY_EINVAL) {
5605 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005606 }
5607
5608 /* TREE DFS NEXT ELEM */
5609 /* select element for the next run - children first */
Michal Vaskod3678892020-05-21 10:06:58 +02005610 next = lyd_node_children(elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005611 if (!next) {
5612skip_children:
5613 /* no children, so try siblings, but only if it's not the start,
5614 * that is considered to be the root and it's siblings are not traversed */
5615 if (elem != start) {
5616 next = elem->next;
5617 } else {
5618 break;
5619 }
5620 }
5621 while (!next) {
5622 /* no siblings, go back through the parents */
5623 if ((struct lyd_node *)elem->parent == start) {
5624 /* we are done, no next element to process */
5625 break;
5626 }
5627 /* parent is already processed, go to its sibling */
5628 elem = (struct lyd_node *)elem->parent;
5629 next = elem->next;
5630 }
5631 }
5632 }
5633
5634 /* make the temporary set the current one */
5635 ret_set.ctx_pos = set->ctx_pos;
5636 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02005637 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005638 memcpy(set, &ret_set, sizeof *set);
5639
5640 return LY_SUCCESS;
5641}
5642
5643/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005644 * @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 +02005645 *
5646 * @param[in] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005647 * @param[in] mod Matching node module, NULL for any.
5648 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005649 * @param[in] options XPath options.
5650 * @return LY_ERR
5651 */
5652static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005653moveto_scnode_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005654{
Michal Vasko6346ece2019-09-24 13:12:53 +02005655 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005656 const struct lysc_node *next, *elem, *start;
Michal Vasko6346ece2019-09-24 13:12:53 +02005657 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005658
Michal Vaskod3678892020-05-21 10:06:58 +02005659 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005660 return LY_SUCCESS;
5661 }
5662
5663 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005664 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005665 return LY_EVALID;
5666 }
5667
Michal Vasko03ff5a72019-09-11 13:49:33 +02005668 orig_used = set->used;
5669 for (i = 0; i < orig_used; ++i) {
5670 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005671 if (set->val.scnodes[i].in_ctx != -2) {
5672 continue;
5673 }
5674
5675 /* remember context node */
5676 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005677 } else {
5678 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005679 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005680
5681 /* TREE DFS */
5682 start = set->val.scnodes[i].scnode;
5683 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005684 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5685 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005686 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005687 }
5688
Michal Vaskod3678892020-05-21 10:06:58 +02005689 rc = moveto_scnode_check(elem, set->root_type, ncname, mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005690 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005691 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005692 set->val.scnodes[idx].in_ctx = 1;
5693 if (idx > i) {
5694 /* we will process it later in the set */
5695 goto skip_children;
5696 }
5697 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005698 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005699 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005700 } else if (rc == LY_EINVAL) {
5701 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005702 }
5703
5704next_iter:
5705 /* TREE DFS NEXT ELEM */
5706 /* select element for the next run - children first */
5707 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005708 if (!next) {
5709skip_children:
5710 /* no children, so try siblings, but only if it's not the start,
5711 * that is considered to be the root and it's siblings are not traversed */
5712 if (elem != start) {
5713 next = elem->next;
5714 } else {
5715 break;
5716 }
5717 }
5718 while (!next) {
5719 /* no siblings, go back through the parents */
5720 if (elem->parent == start) {
5721 /* we are done, no next element to process */
5722 break;
5723 }
5724 /* parent is already processed, go to its sibling */
5725 elem = elem->parent;
5726 next = elem->next;
5727 }
5728 }
5729 }
5730
5731 return LY_SUCCESS;
5732}
5733
5734/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005735 * @brief Move context @p set to an attribute. Result is LYXP_SET_NODE_SET.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005736 * Indirectly context position aware.
5737 *
5738 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005739 * @param[in] mod Matching metadata module, NULL for any.
5740 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005741 * @return LY_ERR
5742 */
5743static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005744moveto_attr(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005745{
5746 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02005747 int replaced;
Michal Vasko9f96a052020-03-10 09:41:45 +01005748 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005749
Michal Vaskod3678892020-05-21 10:06:58 +02005750 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005751 return LY_SUCCESS;
5752 }
5753
5754 if (set->type != LYXP_SET_NODE_SET) {
5755 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5756 return LY_EVALID;
5757 }
5758
Michal Vasko03ff5a72019-09-11 13:49:33 +02005759 for (i = 0; i < set->used; ) {
5760 replaced = 0;
5761
5762 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5763 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005764 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005765 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005766
5767 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02005768 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005769 continue;
5770 }
5771
Michal Vaskod3678892020-05-21 10:06:58 +02005772 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005773 /* match */
5774 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005775 set->val.meta[i].meta = sub;
5776 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005777 /* pos does not change */
5778 replaced = 1;
5779 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005780 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 +02005781 }
5782 ++i;
5783 }
5784 }
5785 }
5786
5787 if (!replaced) {
5788 /* no match */
5789 set_remove_node(set, i);
5790 }
5791 }
5792
5793 return LY_SUCCESS;
5794}
5795
5796/**
5797 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
Michal Vasko61ac2f62020-05-25 12:39:51 +02005798 * Result is LYXP_SET_NODE_SET. Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005799 *
5800 * @param[in,out] set1 Set to use for the result.
5801 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005802 * @return LY_ERR
5803 */
5804static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005805moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005806{
5807 LY_ERR rc;
5808
Michal Vaskod3678892020-05-21 10:06:58 +02005809 if ((set1->type != LYXP_SET_NODE_SET) || (set2->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005810 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5811 return LY_EVALID;
5812 }
5813
5814 /* set2 is empty or both set1 and set2 */
Michal Vaskod3678892020-05-21 10:06:58 +02005815 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005816 return LY_SUCCESS;
5817 }
5818
Michal Vaskod3678892020-05-21 10:06:58 +02005819 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005820 memcpy(set1, set2, sizeof *set1);
5821 /* dynamic memory belongs to set1 now, do not free */
Michal Vaskod3678892020-05-21 10:06:58 +02005822 memset(set2, 0, sizeof *set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005823 return LY_SUCCESS;
5824 }
5825
5826 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005827 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005828
5829 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005830 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005831 LY_CHECK_RET(rc);
5832
5833 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005834 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005835
5836 return LY_SUCCESS;
5837}
5838
5839/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005840 * @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 +02005841 * Context position aware.
5842 *
5843 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005844 * @param[in] mod Matching metadata module, NULL for any.
5845 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005846 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5847 */
5848static int
Michal Vaskod3678892020-05-21 10:06:58 +02005849moveto_attr_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005850{
5851 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02005852 int replaced;
Michal Vasko9f96a052020-03-10 09:41:45 +01005853 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005854 struct lyxp_set *set_all_desc = NULL;
5855 LY_ERR rc;
5856
Michal Vaskod3678892020-05-21 10:06:58 +02005857 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005858 return LY_SUCCESS;
5859 }
5860
5861 if (set->type != LYXP_SET_NODE_SET) {
5862 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5863 return LY_EVALID;
5864 }
5865
Michal Vasko03ff5a72019-09-11 13:49:33 +02005866 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5867 * but it likely won't be used much, so it's a waste of time */
5868 /* copy the context */
5869 set_all_desc = set_copy(set);
5870 /* get all descendant nodes (the original context nodes are removed) */
Michal Vaskod3678892020-05-21 10:06:58 +02005871 rc = moveto_node_alldesc(set_all_desc, NULL, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005872 if (rc != LY_SUCCESS) {
5873 lyxp_set_free(set_all_desc);
5874 return rc;
5875 }
5876 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005877 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005878 if (rc != LY_SUCCESS) {
5879 lyxp_set_free(set_all_desc);
5880 return rc;
5881 }
5882 lyxp_set_free(set_all_desc);
5883
Michal Vasko03ff5a72019-09-11 13:49:33 +02005884 for (i = 0; i < set->used; ) {
5885 replaced = 0;
5886
5887 /* only attributes of an elem can be in the result, skip all the rest,
5888 * we have all attributes qualified in lyd tree */
5889 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005890 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005891 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02005892 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005893 continue;
5894 }
5895
Michal Vaskod3678892020-05-21 10:06:58 +02005896 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005897 /* match */
5898 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005899 set->val.meta[i].meta = sub;
5900 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005901 /* pos does not change */
5902 replaced = 1;
5903 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005904 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 +02005905 }
5906 ++i;
5907 }
5908 }
5909 }
5910
5911 if (!replaced) {
5912 /* no match */
5913 set_remove_node(set, i);
5914 }
5915 }
5916
5917 return LY_SUCCESS;
5918}
5919
5920/**
Michal Vasko61ac2f62020-05-25 12:39:51 +02005921 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET.
5922 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005923 *
5924 * @param[in] parent Current parent.
5925 * @param[in] parent_pos Position of @p parent.
5926 * @param[in] parent_type Node type of @p parent.
5927 * @param[in,out] to_set Set to use.
5928 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005929 * @param[in] options XPath options.
5930 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5931 */
5932static LY_ERR
5933moveto_self_add_children_r(const struct lyd_node *parent, uint32_t parent_pos, enum lyxp_node_type parent_type,
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005934 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005935{
Michal Vasko61ac2f62020-05-25 12:39:51 +02005936 const struct lyd_node *iter, *first;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005937 LY_ERR rc;
5938
5939 switch (parent_type) {
5940 case LYXP_NODE_ROOT:
5941 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko61ac2f62020-05-25 12:39:51 +02005942 assert(!parent);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005943
Michal Vasko61ac2f62020-05-25 12:39:51 +02005944 /* add all top-level nodes as elements */
5945 first = to_set->tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005946 break;
5947 case LYXP_NODE_ELEM:
Michal Vasko61ac2f62020-05-25 12:39:51 +02005948 /* add just the text node of this term element node */
5949 if (parent->schema->nodetype & (LYD_NODE_TERM | LYD_NODE_ANY)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005950 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5951 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5952 }
Michal Vasko61ac2f62020-05-25 12:39:51 +02005953 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005954 }
Michal Vasko61ac2f62020-05-25 12:39:51 +02005955
5956 /* add all the children of this node */
5957 first = lyd_node_children(parent);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005958 break;
5959 default:
5960 LOGINT_RET(parent->schema->module->ctx);
5961 }
5962
Michal Vasko61ac2f62020-05-25 12:39:51 +02005963 /* add all top-level nodes as elements */
5964 LY_LIST_FOR(first, iter) {
5965 /* context check */
5966 if ((parent_type == LYXP_NODE_ROOT_CONFIG) && (iter->schema->flags & LYS_CONFIG_R)) {
5967 continue;
5968 }
5969
5970 /* when check */
5971 if (moveto_when_check(iter)) {
5972 return LY_EINCOMPLETE;
5973 }
5974
5975 if (!set_dup_node_check(dup_check_set, iter, LYXP_NODE_ELEM, -1)) {
5976 set_insert_node(to_set, iter, 0, LYXP_NODE_ELEM, to_set->used);
5977
5978 /* also add all the children of this node, recursively */
5979 rc = moveto_self_add_children_r(iter, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
5980 LY_CHECK_RET(rc);
5981 }
5982 }
5983
Michal Vasko03ff5a72019-09-11 13:49:33 +02005984 return LY_SUCCESS;
5985}
5986
5987/**
5988 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5989 * (or LYXP_SET_EMPTY). Context position aware.
5990 *
5991 * @param[in,out] set Set to use.
5992 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
5993 * @param[in] options XPath options.
5994 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5995 */
5996static LY_ERR
5997moveto_self(struct lyxp_set *set, int all_desc, int options)
5998{
5999 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006000 struct lyxp_set ret_set;
6001 LY_ERR rc;
6002
Michal Vaskod3678892020-05-21 10:06:58 +02006003 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006004 return LY_SUCCESS;
6005 }
6006
6007 if (set->type != LYXP_SET_NODE_SET) {
6008 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6009 return LY_EVALID;
6010 }
6011
6012 /* nothing to do */
6013 if (!all_desc) {
6014 return LY_SUCCESS;
6015 }
6016
Michal Vasko03ff5a72019-09-11 13:49:33 +02006017 /* add all the children, they get added recursively */
6018 set_init(&ret_set, set);
6019 for (i = 0; i < set->used; ++i) {
6020 /* copy the current node to tmp */
6021 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6022
6023 /* do not touch attributes and text nodes */
Michal Vasko9f96a052020-03-10 09:41:45 +01006024 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006025 continue;
6026 }
6027
Michal Vasko03ff5a72019-09-11 13:49:33 +02006028 /* add all the children */
6029 rc = moveto_self_add_children_r(set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, &ret_set,
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006030 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006031 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006032 lyxp_set_free_content(&ret_set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006033 return rc;
6034 }
6035 }
6036
6037 /* use the temporary set as the current one */
6038 ret_set.ctx_pos = set->ctx_pos;
6039 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02006040 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006041 memcpy(set, &ret_set, sizeof *set);
6042
6043 return LY_SUCCESS;
6044}
6045
6046/**
6047 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6048 * (or LYXP_SET_EMPTY).
6049 *
6050 * @param[in,out] set Set to use.
6051 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6052 * @param[in] options XPath options.
6053 * @return LY_ERR
6054 */
6055static LY_ERR
6056moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6057{
Michal Vasko519fd602020-05-26 12:17:39 +02006058 int getnext_opts;
6059 uint32_t i, mod_idx;
6060 const struct lysc_node *iter, *start_parent;
6061 const struct lys_module *mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006062
Michal Vaskod3678892020-05-21 10:06:58 +02006063 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006064 return LY_SUCCESS;
6065 }
6066
6067 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006068 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006069 return LY_EVALID;
6070 }
6071
6072 /* nothing to do */
6073 if (!all_desc) {
6074 return LY_SUCCESS;
6075 }
6076
Michal Vasko519fd602020-05-26 12:17:39 +02006077 /* getnext opts */
6078 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
6079 if (options & LYXP_SCNODE_OUTPUT) {
6080 getnext_opts |= LYS_GETNEXT_OUTPUT;
6081 }
6082
6083 /* add all the children, recursively as they are being added into the same set */
Michal Vasko03ff5a72019-09-11 13:49:33 +02006084 for (i = 0; i < set->used; ++i) {
6085 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006086 if (set->val.scnodes[i].in_ctx != -2) {
6087 continue;
6088 }
6089
Michal Vasko519fd602020-05-26 12:17:39 +02006090 /* remember context node */
6091 set->val.scnodes[i].in_ctx = -1;
6092 } else {
6093 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006094 }
6095
Michal Vasko519fd602020-05-26 12:17:39 +02006096 start_parent = set->val.scnodes[i].scnode;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006097
Michal Vasko519fd602020-05-26 12:17:39 +02006098 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
6099 /* it can actually be in any module, it's all <running> */
6100 mod_idx = 0;
6101 while ((mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
6102 iter = NULL;
6103 /* module may not be implemented */
6104 while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
6105 /* context check */
6106 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
6107 continue;
6108 }
6109
6110 lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
6111 /* throw away the insert index, we want to consider that node again, recursively */
6112 }
6113 }
6114
6115 } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6116 iter = NULL;
6117 while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006118 /* context check */
Michal Vasko519fd602020-05-26 12:17:39 +02006119 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006120 continue;
6121 }
6122
Michal Vasko519fd602020-05-26 12:17:39 +02006123 lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006124 }
6125 }
6126 }
6127
6128 return LY_SUCCESS;
6129}
6130
6131/**
6132 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6133 * (or LYXP_SET_EMPTY). Context position aware.
6134 *
6135 * @param[in] set Set to use.
6136 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6137 * @param[in] options XPath options.
6138 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6139 */
6140static LY_ERR
6141moveto_parent(struct lyxp_set *set, int all_desc, int options)
6142{
6143 LY_ERR rc;
6144 uint32_t i;
6145 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006146 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006147
Michal Vaskod3678892020-05-21 10:06:58 +02006148 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006149 return LY_SUCCESS;
6150 }
6151
6152 if (set->type != LYXP_SET_NODE_SET) {
6153 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6154 return LY_EVALID;
6155 }
6156
6157 if (all_desc) {
6158 /* <path>//.. == <path>//./.. */
6159 rc = moveto_self(set, 1, options);
6160 LY_CHECK_RET(rc);
6161 }
6162
Michal Vasko57eab132019-09-24 11:46:26 +02006163 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006164 node = set->val.nodes[i].node;
6165
6166 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6167 new_node = (struct lyd_node *)node->parent;
6168 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6169 new_node = node;
Michal Vasko9f96a052020-03-10 09:41:45 +01006170 } else if (set->val.nodes[i].type == LYXP_NODE_META) {
6171 new_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006172 if (!new_node) {
6173 LOGINT_RET(set->ctx);
6174 }
6175 } else {
6176 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006177 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006178 continue;
6179 }
6180
Michal Vaskoa1424542019-11-14 16:08:52 +01006181 /* when check */
6182 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006183 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006184 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006185
6186 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006187 if (!new_node) {
6188 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006189
6190 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6191 } else {
6192 new_type = LYXP_NODE_ELEM;
6193 }
6194
Michal Vasko03ff5a72019-09-11 13:49:33 +02006195 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006196 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006197 } else {
6198 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006199 }
6200 }
6201
Michal Vasko2caefc12019-11-14 16:07:56 +01006202 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006203 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006204
6205 return LY_SUCCESS;
6206}
6207
6208/**
6209 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6210 * (or LYXP_SET_EMPTY).
6211 *
6212 * @param[in] set Set to use.
6213 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6214 * @param[in] options XPath options.
6215 * @return LY_ERR
6216 */
6217static LY_ERR
6218moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6219{
6220 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006221 const struct lysc_node *node, *new_node;
6222 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006223 LY_ERR rc;
6224
Michal Vaskod3678892020-05-21 10:06:58 +02006225 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006226 return LY_SUCCESS;
6227 }
6228
6229 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006230 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006231 return LY_EVALID;
6232 }
6233
6234 if (all_desc) {
6235 /* <path>//.. == <path>//./.. */
6236 rc = moveto_scnode_self(set, 1, options);
6237 LY_CHECK_RET(rc);
6238 }
6239
Michal Vasko03ff5a72019-09-11 13:49:33 +02006240 orig_used = set->used;
6241 for (i = 0; i < orig_used; ++i) {
6242 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006243 if (set->val.scnodes[i].in_ctx != -2) {
6244 continue;
6245 }
6246
6247 /* remember context node */
6248 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006249 } else {
6250 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006251 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006252
6253 node = set->val.scnodes[i].scnode;
6254
6255 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vaskod3678892020-05-21 10:06:58 +02006256 new_node = lysc_data_parent(node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006257 } else {
6258 /* root does not have a parent */
6259 continue;
6260 }
6261
Michal Vasko03ff5a72019-09-11 13:49:33 +02006262 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006263 if (!new_node) {
6264 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006265
6266 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6267 } else {
6268 new_type = LYXP_NODE_ELEM;
6269 }
6270
Michal Vaskoecd62de2019-11-13 12:35:11 +01006271 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006272 if ((idx < orig_used) && (idx > i)) {
6273 set->val.scnodes[idx].in_ctx = 2;
6274 temp_ctx = 1;
6275 }
6276 }
6277
6278 if (temp_ctx) {
6279 for (i = 0; i < orig_used; ++i) {
6280 if (set->val.scnodes[i].in_ctx == 2) {
6281 set->val.scnodes[i].in_ctx = 1;
6282 }
6283 }
6284 }
6285
6286 return LY_SUCCESS;
6287}
6288
6289/**
6290 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6291 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6292 *
6293 * @param[in,out] set1 Set to use for the result.
6294 * @param[in] set2 Set acting as the second operand for @p op.
6295 * @param[in] op Comparison operator to process.
6296 * @param[in] options XPath options.
6297 * @return LY_ERR
6298 */
6299static LY_ERR
6300moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6301{
6302 /*
6303 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6304 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6305 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6306 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6307 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6308 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6309 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6310 *
6311 * '=' or '!='
6312 * BOOLEAN + BOOLEAN
6313 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6314 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6315 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6316 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6317 * NUMBER + NUMBER
6318 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6319 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6320 * STRING + STRING
6321 *
6322 * '<=', '<', '>=', '>'
6323 * NUMBER + NUMBER
6324 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6325 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6326 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6327 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6328 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6329 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6330 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6331 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6332 */
6333 struct lyxp_set iter1, iter2;
6334 int result;
6335 int64_t i;
6336 LY_ERR rc;
6337
Michal Vaskod3678892020-05-21 10:06:58 +02006338 iter1.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006339
6340 /* iterative evaluation with node-sets */
6341 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6342 if (set1->type == LYXP_SET_NODE_SET) {
6343 for (i = 0; i < set1->used; ++i) {
6344 switch (set2->type) {
6345 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006346 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006347 break;
6348 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006349 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006350 break;
6351 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006352 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006353 break;
6354 }
6355 LY_CHECK_RET(rc);
6356
6357 rc = moveto_op_comp(&iter1, set2, op, options);
6358 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006359 lyxp_set_free_content(&iter1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006360 return rc;
6361 }
6362
6363 /* lazy evaluation until true */
6364 if (iter1.val.bool) {
6365 set_fill_boolean(set1, 1);
6366 return LY_SUCCESS;
6367 }
6368 }
6369 } else {
6370 for (i = 0; i < set2->used; ++i) {
6371 switch (set1->type) {
6372 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006373 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006374 break;
6375 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006376 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006377 break;
6378 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006379 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006380 break;
6381 }
6382 LY_CHECK_RET(rc);
6383
6384 set_fill_set(&iter1, set1);
6385
6386 rc = moveto_op_comp(&iter1, &iter2, op, options);
6387 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006388 lyxp_set_free_content(&iter1);
6389 lyxp_set_free_content(&iter2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006390 return rc;
6391 }
Michal Vaskod3678892020-05-21 10:06:58 +02006392 lyxp_set_free_content(&iter2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006393
6394 /* lazy evaluation until true */
6395 if (iter1.val.bool) {
6396 set_fill_boolean(set1, 1);
6397 return LY_SUCCESS;
6398 }
6399 }
6400 }
6401
6402 /* false for all nodes */
6403 set_fill_boolean(set1, 0);
6404 return LY_SUCCESS;
6405 }
6406
6407 /* first convert properly */
6408 if ((op[0] == '=') || (op[0] == '!')) {
6409 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006410 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6411 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006412 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006413 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006414 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006415 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006416 LY_CHECK_RET(rc);
6417 } /* else we have 2 strings */
6418 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006419 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006420 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006421 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006422 LY_CHECK_RET(rc);
6423 }
6424
6425 assert(set1->type == set2->type);
6426
6427 /* compute result */
6428 if (op[0] == '=') {
6429 if (set1->type == LYXP_SET_BOOLEAN) {
6430 result = (set1->val.bool == set2->val.bool);
6431 } else if (set1->type == LYXP_SET_NUMBER) {
6432 result = (set1->val.num == set2->val.num);
6433 } else {
6434 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006435 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006436 }
6437 } else if (op[0] == '!') {
6438 if (set1->type == LYXP_SET_BOOLEAN) {
6439 result = (set1->val.bool != set2->val.bool);
6440 } else if (set1->type == LYXP_SET_NUMBER) {
6441 result = (set1->val.num != set2->val.num);
6442 } else {
6443 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006444 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006445 }
6446 } else {
6447 assert(set1->type == LYXP_SET_NUMBER);
6448 if (op[0] == '<') {
6449 if (op[1] == '=') {
6450 result = (set1->val.num <= set2->val.num);
6451 } else {
6452 result = (set1->val.num < set2->val.num);
6453 }
6454 } else {
6455 if (op[1] == '=') {
6456 result = (set1->val.num >= set2->val.num);
6457 } else {
6458 result = (set1->val.num > set2->val.num);
6459 }
6460 }
6461 }
6462
6463 /* assign result */
6464 if (result) {
6465 set_fill_boolean(set1, 1);
6466 } else {
6467 set_fill_boolean(set1, 0);
6468 }
6469
6470 return LY_SUCCESS;
6471}
6472
6473/**
6474 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6475 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6476 *
6477 * @param[in,out] set1 Set to use for the result.
6478 * @param[in] set2 Set acting as the second operand for @p op.
6479 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006480 * @return LY_ERR
6481 */
6482static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006483moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006484{
6485 LY_ERR rc;
6486
6487 /* unary '-' */
6488 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006489 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006490 LY_CHECK_RET(rc);
6491 set1->val.num *= -1;
6492 lyxp_set_free(set2);
6493 return LY_SUCCESS;
6494 }
6495
6496 assert(set1 && set2);
6497
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006498 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006499 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006500 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006501 LY_CHECK_RET(rc);
6502
6503 switch (op[0]) {
6504 /* '+' */
6505 case '+':
6506 set1->val.num += set2->val.num;
6507 break;
6508
6509 /* '-' */
6510 case '-':
6511 set1->val.num -= set2->val.num;
6512 break;
6513
6514 /* '*' */
6515 case '*':
6516 set1->val.num *= set2->val.num;
6517 break;
6518
6519 /* 'div' */
6520 case 'd':
6521 set1->val.num /= set2->val.num;
6522 break;
6523
6524 /* 'mod' */
6525 case 'm':
6526 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6527 break;
6528
6529 default:
6530 LOGINT_RET(set1->ctx);
6531 }
6532
6533 return LY_SUCCESS;
6534}
6535
6536/*
6537 * eval functions
6538 *
6539 * They execute a parsed XPath expression on some data subtree.
6540 */
6541
6542/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02006543 * @brief Evaluate Predicate. Logs directly on error.
6544 *
Michal Vaskod3678892020-05-21 10:06:58 +02006545 * [9] Predicate ::= '[' Expr ']'
Michal Vasko03ff5a72019-09-11 13:49:33 +02006546 *
6547 * @param[in] exp Parsed XPath expression.
6548 * @param[in] exp_idx Position in the expression @p exp.
6549 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6550 * @param[in] options XPath options.
6551 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6552 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6553 */
6554static LY_ERR
6555eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6556{
6557 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006558 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006559 uint32_t orig_pos, orig_size;
6560 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006561 struct lyxp_set set2;
6562 struct lyd_node *orig_parent;
6563
6564 /* '[' */
6565 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02006566 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006567 ++(*exp_idx);
6568
6569 if (!set) {
6570only_parse:
6571 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6572 LY_CHECK_RET(rc);
6573 } else if (set->type == LYXP_SET_NODE_SET) {
6574 /* 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 +01006575 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006576
6577 /* empty set, nothing to evaluate */
6578 if (!set->used) {
6579 goto only_parse;
6580 }
6581
6582 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006583 orig_pos = 0;
6584 orig_size = set->used;
6585 orig_parent = NULL;
Michal Vasko39dbf352020-05-21 10:08:59 +02006586 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006587 set_init(&set2, set);
6588 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6589 /* remember the node context position for position() and context size for last(),
6590 * predicates should always be evaluated with respect to the child axis (since we do
6591 * not support explicit axes) so we assign positions based on their parents */
6592 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6593 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6594 orig_pos = 1;
6595 } else {
6596 ++orig_pos;
6597 }
6598
6599 set2.ctx_pos = orig_pos;
6600 set2.ctx_size = orig_size;
6601 *exp_idx = orig_exp;
6602
6603 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6604 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006605 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006606 return rc;
6607 }
6608
6609 /* number is a position */
6610 if (set2.type == LYXP_SET_NUMBER) {
6611 if ((long long)set2.val.num == orig_pos) {
6612 set2.val.num = 1;
6613 } else {
6614 set2.val.num = 0;
6615 }
6616 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006617 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006618
6619 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006620 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006621 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006622 }
6623 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006624 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006625
6626 } else if (set->type == LYXP_SET_SCNODE_SET) {
6627 for (i = 0; i < set->used; ++i) {
6628 if (set->val.scnodes[i].in_ctx == 1) {
6629 /* there is a currently-valid node */
6630 break;
6631 }
6632 }
6633 /* empty set, nothing to evaluate */
6634 if (i == set->used) {
6635 goto only_parse;
6636 }
6637
6638 orig_exp = *exp_idx;
6639
Michal Vasko03ff5a72019-09-11 13:49:33 +02006640 /* set special in_ctx to all the valid snodes */
6641 pred_in_ctx = set_scnode_new_in_ctx(set);
6642
6643 /* use the valid snodes one-by-one */
6644 for (i = 0; i < set->used; ++i) {
6645 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6646 continue;
6647 }
6648 set->val.scnodes[i].in_ctx = 1;
6649
6650 *exp_idx = orig_exp;
6651
6652 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6653 LY_CHECK_RET(rc);
6654
6655 set->val.scnodes[i].in_ctx = pred_in_ctx;
6656 }
6657
6658 /* restore the state as it was before the predicate */
6659 for (i = 0; i < set->used; ++i) {
6660 if (set->val.scnodes[i].in_ctx == 1) {
6661 set->val.scnodes[i].in_ctx = 0;
6662 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6663 set->val.scnodes[i].in_ctx = 1;
6664 }
6665 }
6666
6667 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02006668 set2.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006669 set_fill_set(&set2, set);
6670
6671 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6672 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006673 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006674 return rc;
6675 }
6676
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006677 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006678 if (!set2.val.bool) {
Michal Vaskod3678892020-05-21 10:06:58 +02006679 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006680 }
Michal Vaskod3678892020-05-21 10:06:58 +02006681 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006682 }
6683
6684 /* ']' */
6685 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6686 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02006687 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006688 ++(*exp_idx);
6689
6690 return LY_SUCCESS;
6691}
6692
6693/**
Michal Vaskod3678892020-05-21 10:06:58 +02006694 * @brief Evaluate Literal. Logs directly on error.
6695 *
6696 * @param[in] exp Parsed XPath expression.
6697 * @param[in] exp_idx Position in the expression @p exp.
6698 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6699 */
6700static void
6701eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6702{
6703 if (set) {
6704 if (exp->tok_len[*exp_idx] == 2) {
6705 set_fill_string(set, "", 0);
6706 } else {
6707 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6708 }
6709 }
6710 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02006711 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02006712 ++(*exp_idx);
6713}
6714
6715/**
6716 * @brief Check and parse a predicate following a leaf-list to extract its value.
6717 * On success all the used tokens are skipped.
6718 *
6719 * @param[in] exp Parsed XPath expression.
6720 * @param[in] exp_idx Position in the expression @p exp.
6721 * @param[out] val Leaf-list value on success.
6722 * @param[out] val_len Length of @p val.
6723 * @return LY_ERR
6724 */
6725static LY_ERR
6726eval_name_test_parse_leaflist_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, const char **val, uint16_t *val_len)
6727{
6728 uint16_t cur_idx;
6729
6730 cur_idx = *exp_idx;
6731
6732 /* '[' */
6733 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK1)) {
6734 return LY_EINVAL;
6735 }
6736 ++cur_idx;
6737
6738 /* '.' */
6739 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_DOT)) {
6740 return LY_EINVAL;
6741 }
6742 ++cur_idx;
6743
6744 /* '=' */
6745 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_OPERATOR_COMP)
6746 || (exp->expr[exp->tok_pos[cur_idx]] != '=')) {
6747 return LY_EINVAL;
6748 }
6749 ++cur_idx;
6750
6751 /* value */
6752 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_LITERAL)) {
6753 return LY_EINVAL;
6754 }
6755 ++cur_idx;
6756
6757 /* ']' */
6758 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK2)) {
6759 return LY_EINVAL;
6760 }
6761 ++cur_idx;
6762
6763 /* success */
6764 *val = &exp->expr[exp->tok_pos[cur_idx - 2] + 1];
6765 *val_len = exp->tok_len[cur_idx - 2] - 2;
6766 *exp_idx = cur_idx;
6767 return LY_SUCCESS;
6768}
6769
6770/**
6771 * @brief Check and parse a predicate following a list to make sure all the tokens are as expected (all key values defined).
6772 * On success all the used tokens are skipped.
6773 *
6774 * @param[in] exp Parsed XPath expression.
6775 * @param[in] exp_idx Position in the expression @p exp.
6776 * @param[in] slist Schema node of the list.
6777 * @param[out] val Leaf-list value on success.
6778 * @param[out] val_len Length of @p val.
6779 * @return LY_ERR
6780 */
6781static LY_ERR
6782eval_name_test_parse_list_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, const struct lysc_node *slist,
6783 const char **keys, uint16_t *keys_len)
6784{
6785 uint16_t key_count, i, cur_idx;
6786 const struct lysc_node *key;
6787
6788 if (slist->flags & LYS_KEYLESS) {
6789 /* invalid */
6790 return LY_EINVAL;
6791 }
6792
6793 /* get key count */
6794 key_count = 0;
6795 for (key = lysc_node_children(slist, 0); key && (key->flags & LYS_KEY); key = key->next) {
6796 ++key_count;
6797 }
6798
6799 /* briefly check the predicate for each key */
6800 cur_idx = *exp_idx;
6801 for (i = 0; i < key_count; ++i) {
6802 /* '[' */
6803 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK1)) {
6804 return LY_EINVAL;
6805 }
6806 ++cur_idx;
6807
6808 /* key-name */
6809 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_NAMETEST)) {
6810 return LY_EINVAL;
6811 }
6812 ++cur_idx;
6813
6814 /* '=' */
6815 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_OPERATOR_COMP)
6816 || (exp->expr[exp->tok_pos[cur_idx]] != '=')) {
6817 return LY_EINVAL;
6818 }
6819 ++cur_idx;
6820
6821 /* key-value */
6822 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_LITERAL)) {
6823 return LY_EINVAL;
6824 }
6825 ++cur_idx;
6826
6827 /* ']' */
6828 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK2)) {
6829 return LY_EINVAL;
6830 }
6831 ++cur_idx;
6832 }
6833
6834 /* success */
6835 *keys = &exp->expr[exp->tok_pos[*exp_idx]];
6836 *keys_len = (exp->expr + exp->tok_pos[cur_idx - 1] + exp->tok_len[cur_idx - 1]) - *keys;
6837 *exp_idx = cur_idx;
6838 return LY_SUCCESS;
6839}
6840
6841/**
6842 * @brief Evaluate NameTest and any following Predicates. Logs directly on error.
6843 *
6844 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6845 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6846 * [7] NameTest ::= '*' | NCName ':' '*' | QName
6847 *
6848 * @param[in] exp Parsed XPath expression.
6849 * @param[in] exp_idx Position in the expression @p exp.
6850 * @param[in] attr_axis Whether to search attributes or standard nodes.
6851 * @param[in] all_desc Whether to search all the descendants or children only.
6852 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6853 * @param[in] options XPath options.
6854 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6855 */
6856static LY_ERR
6857eval_name_test_with_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc, struct lyxp_set *set,
6858 int options)
6859{
6860 int i;
6861 char *path;
6862 const char *ncname = NULL, *key_val = NULL;
6863 uint16_t ncname_len, key_val_len, prev_exp_idx;
6864 const struct lys_module *moveto_mod;
6865 const struct lysc_node *scnode = NULL, *tmp;
6866 struct lyd_node *list_inst = NULL;
6867 LY_ERR rc = LY_SUCCESS;
6868
6869 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02006870 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02006871 ++(*exp_idx);
6872
6873 if (!set) {
6874 goto moveto;
6875 }
6876
6877 ncname = &exp->expr[exp->tok_pos[*exp_idx - 1]];
6878 ncname_len = exp->tok_len[*exp_idx - 1];
6879
6880 /* parse (and skip) module name */
6881 rc = moveto_resolve_model(&ncname, &ncname_len, set, &moveto_mod);
6882 LY_CHECK_GOTO(rc, cleanup);
6883
6884 if (moveto_mod && !attr_axis && !all_desc && (set->type == LYXP_SET_NODE_SET)) {
6885 /* find the matching schema node in some parent in the context */
6886 for (i = 0; i < (signed)set->used; ++i) {
6887 if (set->val.nodes[i].type == set->root_type) {
6888 tmp = lys_find_child(NULL, moveto_mod, ncname, ncname_len, 0, 0);
6889 } else if ((set->val.nodes[i].type == LYXP_NODE_ELEM)
6890 && (!scnode || (lysc_data_parent(scnode) != set->val.nodes[i].node->schema))) {
6891 /* do not repeat the same search */
6892 tmp = lys_find_child(set->val.nodes[i].node->schema, moveto_mod, ncname, ncname_len, 0, 0);
6893 }
6894
6895 /* additional context check */
6896 if (tmp && (set->root_type == LYXP_NODE_ROOT_CONFIG) && (tmp->flags & LYS_CONFIG_R)) {
6897 tmp = NULL;
6898 }
6899
6900 if (tmp) {
6901 if (scnode) {
6902 /* we found a schema node with the same name but at different level, give up, too complicated */
6903 scnode = NULL;
6904 break;
6905 } else {
6906 /* remember the found schema node and continue to make sure it can be used */
6907 scnode = tmp;
6908 }
6909 tmp = NULL;
6910 }
6911 }
6912
6913 if (scnode && (scnode->nodetype == LYS_LIST)) {
6914 /* make sure all the tokens are right */
6915 prev_exp_idx = *exp_idx;
6916 if (eval_name_test_parse_list_predicate(exp, exp_idx, scnode, &key_val, &key_val_len)) {
6917 scnode = NULL;
6918 }
6919
6920 /* try to create a list instance */
6921 if (scnode && lyd_create_list(scnode, key_val, key_val_len, set->format, 0, &list_inst)) {
6922 /* for whatever reason the list failed to be created, just use standard name comparison and
6923 * parse predicate normally */
6924 *exp_idx = prev_exp_idx;
6925 scnode = NULL;
6926 }
6927 } else if (scnode && (scnode->nodetype == LYS_LEAFLIST)) {
6928 /* make sure we know the leaf-list value */
6929 if (eval_name_test_parse_leaflist_predicate(exp, exp_idx, &key_val, &key_val_len)) {
6930 /* value could not be recognized, use standard name comparison */
6931 scnode = NULL;
6932 }
6933 }
6934 }
6935
6936 if (!scnode) {
6937 /* we are not able to match based on a schema node */
6938 if (!moveto_mod) {
6939 /* '*', all nodes match */
6940 ncname = NULL;
6941 } else {
6942 /* insert name into dictionary for efficient comparison */
6943 ncname = lydict_insert(set->ctx, ncname, ncname_len);
6944 }
6945 }
6946
6947moveto:
6948 /* move to the attribute(s), data node(s), or schema node(s) */
6949 if (attr_axis) {
6950 if (set && (options & LYXP_SCNODE_ALL)) {
6951 set_scnode_clear_ctx(set);
6952 } else {
6953 if (all_desc) {
6954 rc = moveto_attr_alldesc(set, moveto_mod, ncname);
6955 } else {
6956 rc = moveto_attr(set, moveto_mod, ncname);
6957 }
6958 LY_CHECK_GOTO(rc, cleanup);
6959 }
6960 } else {
6961 if (set && (options & LYXP_SCNODE_ALL)) {
6962 if (all_desc) {
6963 rc = moveto_scnode_alldesc(set, moveto_mod, ncname, options);
6964 } else {
6965 rc = moveto_scnode(set, moveto_mod, ncname, options);
6966 }
6967 LY_CHECK_GOTO(rc, cleanup);
6968
6969 for (i = set->used - 1; i > -1; --i) {
6970 if (set->val.scnodes[i].in_ctx > 0) {
6971 break;
6972 }
6973 }
6974 if (i == -1) {
6975 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6976 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6977 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6978 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6979 free(path);
6980 }
6981 } else {
6982 if (all_desc) {
6983 rc = moveto_node_alldesc(set, moveto_mod, ncname);
6984 } else {
6985 if (scnode) {
6986 /* we can find the nodes using hashes */
6987 rc = moveto_node_hash(set, scnode, list_inst, key_val, key_val_len);
6988 } else {
6989 rc = moveto_node(set, moveto_mod, ncname);
6990 }
6991 }
6992 LY_CHECK_GOTO(rc, cleanup);
6993 }
6994 }
6995
6996 /* Predicate* */
Michal Vasko14676352020-05-29 11:35:55 +02006997 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_BRACK1)) {
Michal Vaskod3678892020-05-21 10:06:58 +02006998 rc = eval_predicate(exp, exp_idx, set, options, 1);
6999 LY_CHECK_RET(rc);
7000 }
7001
7002cleanup:
Michal Vaskodb51a8d2020-05-27 15:22:29 +02007003 if (set) {
7004 lydict_remove(set->ctx, ncname);
7005 }
Michal Vaskod3678892020-05-21 10:06:58 +02007006 lyd_free_tree(list_inst);
7007 return rc;
7008}
7009
7010/**
7011 * @brief Evaluate NodeType and any following Predicates. Logs directly on error.
7012 *
7013 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
7014 * [6] NodeTest ::= NameTest | NodeType '(' ')'
7015 * [8] NodeType ::= 'text' | 'node'
7016 *
7017 * @param[in] exp Parsed XPath expression.
7018 * @param[in] exp_idx Position in the expression @p exp.
7019 * @param[in] attr_axis Whether to search attributes or standard nodes.
7020 * @param[in] all_desc Whether to search all the descendants or children only.
7021 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7022 * @param[in] options XPath options.
7023 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7024 */
7025static LY_ERR
7026eval_node_type_with_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
7027 struct lyxp_set *set, int options)
7028{
7029 LY_ERR rc;
7030
7031 /* TODO */
7032 (void)attr_axis;
7033 (void)all_desc;
7034
7035 if (set) {
7036 assert(exp->tok_len[*exp_idx] == 4);
7037 if (set->type == LYXP_SET_SCNODE_SET) {
7038 set_scnode_clear_ctx(set);
7039 /* just for the debug message below */
7040 set = NULL;
7041 } else {
7042 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
7043 rc = xpath_node(NULL, 0, set, options);
7044 } else {
7045 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
7046 rc = xpath_text(NULL, 0, set, options);
7047 }
7048 LY_CHECK_RET(rc);
7049 }
7050 }
7051 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007052 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02007053 ++(*exp_idx);
7054
7055 /* '(' */
7056 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7057 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007058 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02007059 ++(*exp_idx);
7060
7061 /* ')' */
7062 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7063 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007064 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02007065 ++(*exp_idx);
7066
7067 /* Predicate* */
Michal Vasko14676352020-05-29 11:35:55 +02007068 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_BRACK1)) {
Michal Vaskod3678892020-05-21 10:06:58 +02007069 rc = eval_predicate(exp, exp_idx, set, options, 1);
7070 LY_CHECK_RET(rc);
7071 }
7072
7073 return LY_SUCCESS;
7074}
7075
7076/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02007077 * @brief Evaluate RelativeLocationPath. Logs directly on error.
7078 *
7079 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
7080 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
Michal Vaskod3678892020-05-21 10:06:58 +02007081 * [6] NodeTest ::= NameTest | NodeType '(' ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007082 *
7083 * @param[in] exp Parsed XPath expression.
7084 * @param[in] exp_idx Position in the expression @p exp.
7085 * @param[in] all_desc Whether to search all the descendants or children only.
7086 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7087 * @param[in] options XPath options.
7088 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
7089 */
7090static LY_ERR
7091eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
7092{
7093 int attr_axis;
7094 LY_ERR rc;
7095
7096 goto step;
7097 do {
7098 /* evaluate '/' or '//' */
7099 if (exp->tok_len[*exp_idx] == 1) {
7100 all_desc = 0;
7101 } else {
7102 assert(exp->tok_len[*exp_idx] == 2);
7103 all_desc = 1;
7104 }
7105 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007106 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007107 ++(*exp_idx);
7108
7109step:
Michal Vaskod3678892020-05-21 10:06:58 +02007110 /* evaluate abbreviated axis '@'? if any */
7111 if (exp->tokens[*exp_idx] == LYXP_TOKEN_AT) {
7112 attr_axis = 1;
7113
7114 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007115 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vaskod3678892020-05-21 10:06:58 +02007116 ++(*exp_idx);
7117 } else {
7118 attr_axis = 0;
7119 }
7120
Michal Vasko03ff5a72019-09-11 13:49:33 +02007121 /* Step */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007122 switch (exp->tokens[*exp_idx]) {
7123 case LYXP_TOKEN_DOT:
7124 /* evaluate '.' */
7125 if (set && (options & LYXP_SCNODE_ALL)) {
7126 rc = moveto_scnode_self(set, all_desc, options);
7127 } else {
7128 rc = moveto_self(set, all_desc, options);
7129 }
7130 LY_CHECK_RET(rc);
7131 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007132 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007133 ++(*exp_idx);
7134 break;
7135
7136 case LYXP_TOKEN_DDOT:
7137 /* evaluate '..' */
7138 if (set && (options & LYXP_SCNODE_ALL)) {
7139 rc = moveto_scnode_parent(set, all_desc, options);
7140 } else {
7141 rc = moveto_parent(set, all_desc, options);
7142 }
7143 LY_CHECK_RET(rc);
7144 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007145 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007146 ++(*exp_idx);
7147 break;
7148
Michal Vasko03ff5a72019-09-11 13:49:33 +02007149 case LYXP_TOKEN_NAMETEST:
Michal Vaskod3678892020-05-21 10:06:58 +02007150 /* evaluate NameTest Predicate* */
7151 rc = eval_name_test_with_predicate(exp, exp_idx, attr_axis, all_desc, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007152 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02007153 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007154
Michal Vaskod3678892020-05-21 10:06:58 +02007155 case LYXP_TOKEN_NODETYPE:
7156 /* evaluate NodeType Predicate* */
7157 rc = eval_node_type_with_predicate(exp, exp_idx, attr_axis, all_desc, set, options);
7158 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007159 break;
7160
7161 default:
Michal Vasko02a77382019-09-12 11:47:35 +02007162 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007163 }
Michal Vasko14676352020-05-29 11:35:55 +02007164 } while (!exp_check_token2(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, LYXP_TOKEN_OPERATOR_RPATH));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007165
7166 return LY_SUCCESS;
7167}
7168
7169/**
7170 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
7171 *
7172 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
7173 *
7174 * @param[in] exp Parsed XPath expression.
7175 * @param[in] exp_idx Position in the expression @p exp.
7176 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7177 * @param[in] options XPath options.
7178 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7179 */
7180static LY_ERR
7181eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7182{
7183 int all_desc;
7184 LY_ERR rc;
7185
7186 if (set) {
7187 /* no matter what tokens follow, we need to be at the root */
7188 moveto_root(set, options);
7189 }
7190
7191 /* '/' RelativeLocationPath? */
7192 if (exp->tok_len[*exp_idx] == 1) {
7193 /* evaluate '/' - deferred */
7194 all_desc = 0;
7195 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007196 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007197 ++(*exp_idx);
7198
Michal Vasko14676352020-05-29 11:35:55 +02007199 if (lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_NONE)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007200 return LY_SUCCESS;
7201 }
7202 switch (exp->tokens[*exp_idx]) {
7203 case LYXP_TOKEN_DOT:
7204 case LYXP_TOKEN_DDOT:
7205 case LYXP_TOKEN_AT:
7206 case LYXP_TOKEN_NAMETEST:
7207 case LYXP_TOKEN_NODETYPE:
7208 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7209 LY_CHECK_RET(rc);
7210 break;
7211 default:
7212 break;
7213 }
7214
7215 /* '//' RelativeLocationPath */
7216 } else {
7217 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
7218 all_desc = 1;
7219 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007220 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007221 ++(*exp_idx);
7222
7223 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7224 LY_CHECK_RET(rc);
7225 }
7226
7227 return LY_SUCCESS;
7228}
7229
7230/**
7231 * @brief Evaluate FunctionCall. Logs directly on error.
7232 *
Michal Vaskod3678892020-05-21 10:06:58 +02007233 * [11] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007234 *
7235 * @param[in] exp Parsed XPath expression.
7236 * @param[in] exp_idx Position in the expression @p exp.
7237 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7238 * @param[in] options XPath options.
7239 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7240 */
7241static LY_ERR
7242eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7243{
7244 LY_ERR rc;
7245 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007246 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007247 struct lyxp_set **args = NULL, **args_aux;
7248
7249 if (set) {
7250 /* FunctionName */
7251 switch (exp->tok_len[*exp_idx]) {
7252 case 3:
7253 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7254 xpath_func = &xpath_not;
7255 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7256 xpath_func = &xpath_sum;
7257 }
7258 break;
7259 case 4:
7260 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7261 xpath_func = &xpath_lang;
7262 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7263 xpath_func = &xpath_last;
7264 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7265 xpath_func = &xpath_name;
7266 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7267 xpath_func = &xpath_true;
7268 }
7269 break;
7270 case 5:
7271 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7272 xpath_func = &xpath_count;
7273 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7274 xpath_func = &xpath_false;
7275 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7276 xpath_func = &xpath_floor;
7277 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7278 xpath_func = &xpath_round;
7279 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7280 xpath_func = &xpath_deref;
7281 }
7282 break;
7283 case 6:
7284 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7285 xpath_func = &xpath_concat;
7286 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7287 xpath_func = &xpath_number;
7288 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7289 xpath_func = &xpath_string;
7290 }
7291 break;
7292 case 7:
7293 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7294 xpath_func = &xpath_boolean;
7295 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7296 xpath_func = &xpath_ceiling;
7297 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7298 xpath_func = &xpath_current;
7299 }
7300 break;
7301 case 8:
7302 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7303 xpath_func = &xpath_contains;
7304 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7305 xpath_func = &xpath_position;
7306 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7307 xpath_func = &xpath_re_match;
7308 }
7309 break;
7310 case 9:
7311 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7312 xpath_func = &xpath_substring;
7313 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7314 xpath_func = &xpath_translate;
7315 }
7316 break;
7317 case 10:
7318 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7319 xpath_func = &xpath_local_name;
7320 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7321 xpath_func = &xpath_enum_value;
7322 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7323 xpath_func = &xpath_bit_is_set;
7324 }
7325 break;
7326 case 11:
7327 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7328 xpath_func = &xpath_starts_with;
7329 }
7330 break;
7331 case 12:
7332 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7333 xpath_func = &xpath_derived_from;
7334 }
7335 break;
7336 case 13:
7337 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7338 xpath_func = &xpath_namespace_uri;
7339 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7340 xpath_func = &xpath_string_length;
7341 }
7342 break;
7343 case 15:
7344 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7345 xpath_func = &xpath_normalize_space;
7346 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7347 xpath_func = &xpath_substring_after;
7348 }
7349 break;
7350 case 16:
7351 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7352 xpath_func = &xpath_substring_before;
7353 }
7354 break;
7355 case 20:
7356 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7357 xpath_func = &xpath_derived_from_or_self;
7358 }
7359 break;
7360 }
7361
7362 if (!xpath_func) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007363 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7364 return LY_EVALID;
7365 }
7366 }
7367
7368 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007369 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007370 ++(*exp_idx);
7371
7372 /* '(' */
7373 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7374 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007375 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007376 ++(*exp_idx);
7377
7378 /* ( Expr ( ',' Expr )* )? */
7379 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7380 if (set) {
7381 args = malloc(sizeof *args);
7382 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7383 arg_count = 1;
7384 args[0] = set_copy(set);
7385 if (!args[0]) {
7386 rc = LY_EMEM;
7387 goto cleanup;
7388 }
7389
7390 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7391 LY_CHECK_GOTO(rc, cleanup);
7392 } else {
7393 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7394 LY_CHECK_GOTO(rc, cleanup);
7395 }
7396 }
Michal Vasko14676352020-05-29 11:35:55 +02007397 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_COMMA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007398 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007399 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007400 ++(*exp_idx);
7401
7402 if (set) {
7403 ++arg_count;
7404 args_aux = realloc(args, arg_count * sizeof *args);
7405 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7406 args = args_aux;
7407 args[arg_count - 1] = set_copy(set);
7408 if (!args[arg_count - 1]) {
7409 rc = LY_EMEM;
7410 goto cleanup;
7411 }
7412
7413 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7414 LY_CHECK_GOTO(rc, cleanup);
7415 } else {
7416 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7417 LY_CHECK_GOTO(rc, cleanup);
7418 }
7419 }
7420
7421 /* ')' */
7422 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7423 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007424 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007425 ++(*exp_idx);
7426
7427 if (set) {
7428 /* evaluate function */
7429 rc = xpath_func(args, arg_count, set, options);
7430
7431 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007432 /* merge all nodes from arg evaluations */
7433 for (i = 0; i < arg_count; ++i) {
7434 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007435 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007436 }
7437 }
7438 } else {
7439 rc = LY_SUCCESS;
7440 }
7441
7442cleanup:
7443 for (i = 0; i < arg_count; ++i) {
7444 lyxp_set_free(args[i]);
7445 }
7446 free(args);
7447
7448 return rc;
7449}
7450
7451/**
7452 * @brief Evaluate Number. Logs directly on error.
7453 *
7454 * @param[in] ctx Context for errors.
7455 * @param[in] exp Parsed XPath expression.
7456 * @param[in] exp_idx Position in the expression @p exp.
7457 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7458 * @return LY_ERR
7459 */
7460static LY_ERR
7461eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7462{
7463 long double num;
7464 char *endptr;
7465
7466 if (set) {
7467 errno = 0;
7468 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7469 if (errno) {
7470 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7471 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7472 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7473 return LY_EVALID;
7474 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7475 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7476 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7477 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7478 return LY_EVALID;
7479 }
7480
7481 set_fill_number(set, num);
7482 }
7483
7484 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007485 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007486 ++(*exp_idx);
7487 return LY_SUCCESS;
7488}
7489
7490/**
7491 * @brief Evaluate PathExpr. Logs directly on error.
7492 *
Michal Vaskod3678892020-05-21 10:06:58 +02007493 * [12] PathExpr ::= LocationPath | PrimaryExpr Predicate*
Michal Vasko03ff5a72019-09-11 13:49:33 +02007494 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7495 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7496 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
Michal Vaskod3678892020-05-21 10:06:58 +02007497 * [10] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
Michal Vasko03ff5a72019-09-11 13:49:33 +02007498 *
7499 * @param[in] exp Parsed XPath expression.
7500 * @param[in] exp_idx Position in the expression @p exp.
7501 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7502 * @param[in] options XPath options.
7503 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7504 */
7505static LY_ERR
7506eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7507{
7508 int all_desc, parent_pos_pred;
7509 LY_ERR rc;
7510
7511 switch (exp->tokens[*exp_idx]) {
7512 case LYXP_TOKEN_PAR1:
7513 /* '(' Expr ')' */
7514
7515 /* '(' */
7516 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007517 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007518 ++(*exp_idx);
7519
7520 /* Expr */
7521 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7522 LY_CHECK_RET(rc);
7523
7524 /* ')' */
7525 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7526 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007527 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007528 ++(*exp_idx);
7529
7530 parent_pos_pred = 0;
7531 goto predicate;
7532
7533 case LYXP_TOKEN_DOT:
7534 case LYXP_TOKEN_DDOT:
7535 case LYXP_TOKEN_AT:
7536 case LYXP_TOKEN_NAMETEST:
7537 case LYXP_TOKEN_NODETYPE:
7538 /* RelativeLocationPath */
7539 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7540 LY_CHECK_RET(rc);
7541 break;
7542
7543 case LYXP_TOKEN_FUNCNAME:
7544 /* FunctionCall */
7545 if (!set) {
7546 rc = eval_function_call(exp, exp_idx, NULL, options);
7547 } else {
7548 rc = eval_function_call(exp, exp_idx, set, options);
7549 }
7550 LY_CHECK_RET(rc);
7551
7552 parent_pos_pred = 1;
7553 goto predicate;
7554
7555 case LYXP_TOKEN_OPERATOR_PATH:
Michal Vasko14676352020-05-29 11:35:55 +02007556 case LYXP_TOKEN_OPERATOR_RPATH:
Michal Vasko03ff5a72019-09-11 13:49:33 +02007557 /* AbsoluteLocationPath */
7558 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7559 LY_CHECK_RET(rc);
7560 break;
7561
7562 case LYXP_TOKEN_LITERAL:
7563 /* Literal */
7564 if (!set || (options & LYXP_SCNODE_ALL)) {
7565 if (set) {
7566 set_scnode_clear_ctx(set);
7567 }
7568 eval_literal(exp, exp_idx, NULL);
7569 } else {
7570 eval_literal(exp, exp_idx, set);
7571 }
7572
7573 parent_pos_pred = 1;
7574 goto predicate;
7575
7576 case LYXP_TOKEN_NUMBER:
7577 /* Number */
7578 if (!set || (options & LYXP_SCNODE_ALL)) {
7579 if (set) {
7580 set_scnode_clear_ctx(set);
7581 }
Michal Vasko02a77382019-09-12 11:47:35 +02007582 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007583 } else {
7584 rc = eval_number(set->ctx, exp, exp_idx, set);
7585 }
7586 LY_CHECK_RET(rc);
7587
7588 parent_pos_pred = 1;
7589 goto predicate;
7590
7591 default:
Michal Vasko24cddf82020-06-01 08:17:01 +02007592 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*exp_idx]),
Michal Vasko03ff5a72019-09-11 13:49:33 +02007593 &exp->expr[exp->tok_pos[*exp_idx]]);
7594 return LY_EVALID;
7595 }
7596
7597 return LY_SUCCESS;
7598
7599predicate:
7600 /* Predicate* */
Michal Vasko14676352020-05-29 11:35:55 +02007601 while (!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_BRACK1)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007602 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7603 LY_CHECK_RET(rc);
7604 }
7605
7606 /* ('/' or '//') RelativeLocationPath */
Michal Vasko14676352020-05-29 11:35:55 +02007607 if (!exp_check_token2(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, LYXP_TOKEN_OPERATOR_RPATH)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007608
7609 /* evaluate '/' or '//' */
Michal Vasko14676352020-05-29 11:35:55 +02007610 if (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007611 all_desc = 0;
7612 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007613 all_desc = 1;
7614 }
7615
7616 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007617 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007618 ++(*exp_idx);
7619
7620 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7621 LY_CHECK_RET(rc);
7622 }
7623
7624 return LY_SUCCESS;
7625}
7626
7627/**
7628 * @brief Evaluate UnionExpr. Logs directly on error.
7629 *
Michal Vaskod3678892020-05-21 10:06:58 +02007630 * [20] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007631 *
7632 * @param[in] exp Parsed XPath expression.
7633 * @param[in] exp_idx Position in the expression @p exp.
7634 * @param[in] repeat How many times this expression is repeated.
7635 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7636 * @param[in] options XPath options.
7637 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7638 */
7639static LY_ERR
7640eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7641{
7642 LY_ERR rc = LY_SUCCESS;
7643 struct lyxp_set orig_set, set2;
7644 uint16_t i;
7645
7646 assert(repeat);
7647
7648 set_init(&orig_set, set);
7649 set_init(&set2, set);
7650
7651 set_fill_set(&orig_set, set);
7652
7653 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7654 LY_CHECK_GOTO(rc, cleanup);
7655
7656 /* ('|' PathExpr)* */
7657 for (i = 0; i < repeat; ++i) {
7658 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7659 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007660 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007661 ++(*exp_idx);
7662
7663 if (!set) {
7664 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7665 LY_CHECK_GOTO(rc, cleanup);
7666 continue;
7667 }
7668
7669 set_fill_set(&set2, &orig_set);
7670 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7671 LY_CHECK_GOTO(rc, cleanup);
7672
7673 /* eval */
7674 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007675 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007676 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007677 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007678 LY_CHECK_GOTO(rc, cleanup);
7679 }
7680 }
7681
7682cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007683 lyxp_set_free_content(&orig_set);
7684 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007685 return rc;
7686}
7687
7688/**
7689 * @brief Evaluate UnaryExpr. Logs directly on error.
7690 *
Michal Vaskod3678892020-05-21 10:06:58 +02007691 * [19] UnaryExpr ::= UnionExpr | '-' UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007692 *
7693 * @param[in] exp Parsed XPath expression.
7694 * @param[in] exp_idx Position in the expression @p exp.
7695 * @param[in] repeat How many times this expression is repeated.
7696 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7697 * @param[in] options XPath options.
7698 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7699 */
7700static LY_ERR
7701eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7702{
7703 LY_ERR rc;
7704 uint16_t this_op, i;
7705
7706 assert(repeat);
7707
7708 /* ('-')+ */
7709 this_op = *exp_idx;
7710 for (i = 0; i < repeat; ++i) {
Michal Vasko14676352020-05-29 11:35:55 +02007711 assert(!lyxp_check_token(NULL, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
Michal Vasko03ff5a72019-09-11 13:49:33 +02007712
7713 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007714 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007715 ++(*exp_idx);
7716 }
7717
7718 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7719 LY_CHECK_RET(rc);
7720
7721 if (set && (repeat % 2)) {
7722 if (options & LYXP_SCNODE_ALL) {
7723 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7724 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007725 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007726 LY_CHECK_RET(rc);
7727 }
7728 }
7729
7730 return LY_SUCCESS;
7731}
7732
7733/**
7734 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7735 *
Michal Vaskod3678892020-05-21 10:06:58 +02007736 * [18] MultiplicativeExpr ::= UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007737 * | MultiplicativeExpr '*' UnaryExpr
7738 * | MultiplicativeExpr 'div' UnaryExpr
7739 * | MultiplicativeExpr 'mod' UnaryExpr
7740 *
7741 * @param[in] exp Parsed XPath expression.
7742 * @param[in] exp_idx Position in the expression @p exp.
7743 * @param[in] repeat How many times this expression is repeated.
7744 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7745 * @param[in] options XPath options.
7746 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7747 */
7748static LY_ERR
7749eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7750{
7751 LY_ERR rc;
7752 uint16_t this_op;
7753 struct lyxp_set orig_set, set2;
7754 uint16_t i;
7755
7756 assert(repeat);
7757
7758 set_init(&orig_set, set);
7759 set_init(&set2, set);
7760
7761 set_fill_set(&orig_set, set);
7762
7763 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7764 LY_CHECK_GOTO(rc, cleanup);
7765
7766 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7767 for (i = 0; i < repeat; ++i) {
7768 this_op = *exp_idx;
7769
7770 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7771 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007772 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007773 ++(*exp_idx);
7774
7775 if (!set) {
7776 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7777 LY_CHECK_GOTO(rc, cleanup);
7778 continue;
7779 }
7780
7781 set_fill_set(&set2, &orig_set);
7782 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7783 LY_CHECK_GOTO(rc, cleanup);
7784
7785 /* eval */
7786 if (options & LYXP_SCNODE_ALL) {
7787 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007788 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007789 set_scnode_clear_ctx(set);
7790 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007791 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007792 LY_CHECK_GOTO(rc, cleanup);
7793 }
7794 }
7795
7796cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007797 lyxp_set_free_content(&orig_set);
7798 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007799 return rc;
7800}
7801
7802/**
7803 * @brief Evaluate AdditiveExpr. Logs directly on error.
7804 *
Michal Vaskod3678892020-05-21 10:06:58 +02007805 * [17] AdditiveExpr ::= MultiplicativeExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007806 * | AdditiveExpr '+' MultiplicativeExpr
7807 * | AdditiveExpr '-' MultiplicativeExpr
7808 *
7809 * @param[in] exp Parsed XPath expression.
7810 * @param[in] exp_idx Position in the expression @p exp.
7811 * @param[in] repeat How many times this expression is repeated.
7812 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7813 * @param[in] options XPath options.
7814 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7815 */
7816static LY_ERR
7817eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7818{
7819 LY_ERR rc;
7820 uint16_t this_op;
7821 struct lyxp_set orig_set, set2;
7822 uint16_t i;
7823
7824 assert(repeat);
7825
7826 set_init(&orig_set, set);
7827 set_init(&set2, set);
7828
7829 set_fill_set(&orig_set, set);
7830
7831 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7832 LY_CHECK_GOTO(rc, cleanup);
7833
7834 /* ('+' / '-' MultiplicativeExpr)* */
7835 for (i = 0; i < repeat; ++i) {
7836 this_op = *exp_idx;
7837
7838 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7839 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007840 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007841 ++(*exp_idx);
7842
7843 if (!set) {
7844 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7845 LY_CHECK_GOTO(rc, cleanup);
7846 continue;
7847 }
7848
7849 set_fill_set(&set2, &orig_set);
7850 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7851 LY_CHECK_GOTO(rc, cleanup);
7852
7853 /* eval */
7854 if (options & LYXP_SCNODE_ALL) {
7855 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007856 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007857 set_scnode_clear_ctx(set);
7858 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007859 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007860 LY_CHECK_GOTO(rc, cleanup);
7861 }
7862 }
7863
7864cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007865 lyxp_set_free_content(&orig_set);
7866 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007867 return rc;
7868}
7869
7870/**
7871 * @brief Evaluate RelationalExpr. Logs directly on error.
7872 *
Michal Vaskod3678892020-05-21 10:06:58 +02007873 * [16] RelationalExpr ::= AdditiveExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007874 * | RelationalExpr '<' AdditiveExpr
7875 * | RelationalExpr '>' AdditiveExpr
7876 * | RelationalExpr '<=' AdditiveExpr
7877 * | RelationalExpr '>=' AdditiveExpr
7878 *
7879 * @param[in] exp Parsed XPath expression.
7880 * @param[in] exp_idx Position in the expression @p exp.
7881 * @param[in] repeat How many times this expression is repeated.
7882 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7883 * @param[in] options XPath options.
7884 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7885 */
7886static LY_ERR
7887eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7888{
7889 LY_ERR rc;
7890 uint16_t this_op;
7891 struct lyxp_set orig_set, set2;
7892 uint16_t i;
7893
7894 assert(repeat);
7895
7896 set_init(&orig_set, set);
7897 set_init(&set2, set);
7898
7899 set_fill_set(&orig_set, set);
7900
7901 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7902 LY_CHECK_GOTO(rc, cleanup);
7903
7904 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7905 for (i = 0; i < repeat; ++i) {
7906 this_op = *exp_idx;
7907
7908 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7909 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007910 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007911 ++(*exp_idx);
7912
7913 if (!set) {
7914 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7915 LY_CHECK_GOTO(rc, cleanup);
7916 continue;
7917 }
7918
7919 set_fill_set(&set2, &orig_set);
7920 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7921 LY_CHECK_GOTO(rc, cleanup);
7922
7923 /* eval */
7924 if (options & LYXP_SCNODE_ALL) {
7925 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007926 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007927 set_scnode_clear_ctx(set);
7928 } else {
7929 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7930 LY_CHECK_GOTO(rc, cleanup);
7931 }
7932 }
7933
7934cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007935 lyxp_set_free_content(&orig_set);
7936 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007937 return rc;
7938}
7939
7940/**
7941 * @brief Evaluate EqualityExpr. Logs directly on error.
7942 *
Michal Vaskod3678892020-05-21 10:06:58 +02007943 * [15] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007944 * | EqualityExpr '!=' RelationalExpr
7945 *
7946 * @param[in] exp Parsed XPath expression.
7947 * @param[in] exp_idx Position in the expression @p exp.
7948 * @param[in] repeat How many times this expression is repeated.
7949 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7950 * @param[in] options XPath options.
7951 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7952 */
7953static LY_ERR
7954eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7955{
7956 LY_ERR rc;
7957 uint16_t this_op;
7958 struct lyxp_set orig_set, set2;
7959 uint16_t i;
7960
7961 assert(repeat);
7962
7963 set_init(&orig_set, set);
7964 set_init(&set2, set);
7965
7966 set_fill_set(&orig_set, set);
7967
7968 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7969 LY_CHECK_GOTO(rc, cleanup);
7970
7971 /* ('=' / '!=' RelationalExpr)* */
7972 for (i = 0; i < repeat; ++i) {
7973 this_op = *exp_idx;
7974
7975 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7976 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
Michal Vasko24cddf82020-06-01 08:17:01 +02007977 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007978 ++(*exp_idx);
7979
7980 if (!set) {
7981 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7982 LY_CHECK_GOTO(rc, cleanup);
7983 continue;
7984 }
7985
7986 set_fill_set(&set2, &orig_set);
7987 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7988 LY_CHECK_GOTO(rc, cleanup);
7989
7990 /* eval */
7991 if (options & LYXP_SCNODE_ALL) {
7992 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7993 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7994 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007995 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007996 set_scnode_clear_ctx(set);
7997 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007998 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7999 LY_CHECK_GOTO(rc, cleanup);
8000 }
8001 }
8002
8003cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008004 lyxp_set_free_content(&orig_set);
8005 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008006 return rc;
8007}
8008
8009/**
8010 * @brief Evaluate AndExpr. Logs directly on error.
8011 *
Michal Vaskod3678892020-05-21 10:06:58 +02008012 * [14] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008013 *
8014 * @param[in] exp Parsed XPath expression.
8015 * @param[in] exp_idx Position in the expression @p exp.
8016 * @param[in] repeat How many times this expression is repeated.
8017 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8018 * @param[in] options XPath options.
8019 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8020 */
8021static LY_ERR
8022eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
8023{
8024 LY_ERR rc;
8025 struct lyxp_set orig_set, set2;
8026 uint16_t i;
8027
8028 assert(repeat);
8029
8030 set_init(&orig_set, set);
8031 set_init(&set2, set);
8032
8033 set_fill_set(&orig_set, set);
8034
8035 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
8036 LY_CHECK_GOTO(rc, cleanup);
8037
8038 /* cast to boolean, we know that will be the final result */
8039 if (set && (options & LYXP_SCNODE_ALL)) {
8040 set_scnode_clear_ctx(set);
8041 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008042 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008043 }
8044
8045 /* ('and' EqualityExpr)* */
8046 for (i = 0; i < repeat; ++i) {
8047 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
8048 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
Michal Vasko24cddf82020-06-01 08:17:01 +02008049 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008050 ++(*exp_idx);
8051
8052 /* lazy evaluation */
8053 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
8054 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
8055 LY_CHECK_GOTO(rc, cleanup);
8056 continue;
8057 }
8058
8059 set_fill_set(&set2, &orig_set);
8060 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
8061 LY_CHECK_GOTO(rc, cleanup);
8062
8063 /* eval - just get boolean value actually */
8064 if (set->type == LYXP_SET_SCNODE_SET) {
8065 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008066 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008067 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008068 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008069 set_fill_set(set, &set2);
8070 }
8071 }
8072
8073cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008074 lyxp_set_free_content(&orig_set);
8075 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008076 return rc;
8077}
8078
8079/**
8080 * @brief Evaluate OrExpr. Logs directly on error.
8081 *
Michal Vaskod3678892020-05-21 10:06:58 +02008082 * [13] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008083 *
8084 * @param[in] exp Parsed XPath expression.
8085 * @param[in] exp_idx Position in the expression @p exp.
8086 * @param[in] repeat How many times this expression is repeated.
8087 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8088 * @param[in] options XPath options.
8089 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8090 */
8091static LY_ERR
8092eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
8093{
8094 LY_ERR rc;
8095 struct lyxp_set orig_set, set2;
8096 uint16_t i;
8097
8098 assert(repeat);
8099
8100 set_init(&orig_set, set);
8101 set_init(&set2, set);
8102
8103 set_fill_set(&orig_set, set);
8104
8105 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
8106 LY_CHECK_GOTO(rc, cleanup);
8107
8108 /* cast to boolean, we know that will be the final result */
8109 if (set && (options & LYXP_SCNODE_ALL)) {
8110 set_scnode_clear_ctx(set);
8111 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008112 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008113 }
8114
8115 /* ('or' AndExpr)* */
8116 for (i = 0; i < repeat; ++i) {
8117 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
8118 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
Michal Vasko24cddf82020-06-01 08:17:01 +02008119 lyxp_print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008120 ++(*exp_idx);
8121
8122 /* lazy evaluation */
8123 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
8124 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
8125 LY_CHECK_GOTO(rc, cleanup);
8126 continue;
8127 }
8128
8129 set_fill_set(&set2, &orig_set);
8130 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
8131 * but it does not matter */
8132 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
8133 LY_CHECK_GOTO(rc, cleanup);
8134
8135 /* eval - just get boolean value actually */
8136 if (set->type == LYXP_SET_SCNODE_SET) {
8137 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008138 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008139 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008140 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008141 set_fill_set(set, &set2);
8142 }
8143 }
8144
8145cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008146 lyxp_set_free_content(&orig_set);
8147 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008148 return rc;
8149}
8150
8151/**
8152 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
8153 *
8154 * @param[in] exp Parsed XPath expression.
8155 * @param[in] exp_idx Position in the expression @p exp.
8156 * @param[in] etype Expression type to evaluate.
8157 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8158 * @param[in] options XPath options.
8159 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8160 */
8161static LY_ERR
8162eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
8163{
8164 uint16_t i, count;
8165 enum lyxp_expr_type next_etype;
8166 LY_ERR rc;
8167
8168 /* process operator repeats */
8169 if (!exp->repeat[*exp_idx]) {
8170 next_etype = LYXP_EXPR_NONE;
8171 } else {
8172 /* find etype repeat */
8173 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
8174
8175 /* select one-priority lower because etype expression called us */
8176 if (i) {
8177 next_etype = exp->repeat[*exp_idx][i - 1];
8178 /* count repeats for that expression */
8179 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
8180 } else {
8181 next_etype = LYXP_EXPR_NONE;
8182 }
8183 }
8184
8185 /* decide what expression are we parsing based on the repeat */
8186 switch (next_etype) {
8187 case LYXP_EXPR_OR:
8188 rc = eval_or_expr(exp, exp_idx, count, set, options);
8189 break;
8190 case LYXP_EXPR_AND:
8191 rc = eval_and_expr(exp, exp_idx, count, set, options);
8192 break;
8193 case LYXP_EXPR_EQUALITY:
8194 rc = eval_equality_expr(exp, exp_idx, count, set, options);
8195 break;
8196 case LYXP_EXPR_RELATIONAL:
8197 rc = eval_relational_expr(exp, exp_idx, count, set, options);
8198 break;
8199 case LYXP_EXPR_ADDITIVE:
8200 rc = eval_additive_expr(exp, exp_idx, count, set, options);
8201 break;
8202 case LYXP_EXPR_MULTIPLICATIVE:
8203 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
8204 break;
8205 case LYXP_EXPR_UNARY:
8206 rc = eval_unary_expr(exp, exp_idx, count, set, options);
8207 break;
8208 case LYXP_EXPR_UNION:
8209 rc = eval_union_expr(exp, exp_idx, count, set, options);
8210 break;
8211 case LYXP_EXPR_NONE:
8212 rc = eval_path_expr(exp, exp_idx, set, options);
8213 break;
8214 default:
8215 LOGINT_RET(set->ctx);
8216 }
8217
8218 return rc;
8219}
8220
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008221/**
8222 * @brief Get root type.
8223 *
8224 * @param[in] ctx_node Context node.
8225 * @param[in] ctx_scnode Schema context node.
8226 * @param[in] options XPath options.
8227 * @return Root type.
8228 */
8229static enum lyxp_node_type
8230lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8231{
8232 if (options & LYXP_SCNODE_ALL) {
8233 if (options & LYXP_SCNODE) {
8234 /* general root that can access everything */
8235 return LYXP_NODE_ROOT;
8236 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8237 /* root context node can access only config data (because we said so, it is unspecified) */
8238 return LYXP_NODE_ROOT_CONFIG;
8239 } else {
8240 return LYXP_NODE_ROOT;
8241 }
8242 }
8243
8244 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8245 /* root context node can access only config data (because we said so, it is unspecified) */
8246 return LYXP_NODE_ROOT_CONFIG;
8247 }
8248
8249 return LYXP_NODE_ROOT;
8250}
8251
Michal Vasko03ff5a72019-09-11 13:49:33 +02008252LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008253lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
Michal Vaskof03ed032020-03-04 13:31:44 +01008254 enum lyxp_node_type ctx_node_type, const struct lyd_node *tree, struct lyxp_set *set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008255{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008256 uint16_t exp_idx = 0;
8257 LY_ERR rc;
8258
Michal Vaskoecd62de2019-11-13 12:35:11 +01008259 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008260
8261 /* prepare set for evaluation */
8262 exp_idx = 0;
8263 memset(set, 0, sizeof *set);
Michal Vaskod3678892020-05-21 10:06:58 +02008264 set->type = LYXP_SET_NODE_SET;
Michal Vasko9b368d32020-02-14 13:53:31 +01008265 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, 0);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008266 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008267 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008268 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008269 set->local_mod = local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +01008270 set->tree = tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008271 set->format = format;
8272
8273 /* evaluate */
8274 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8275 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02008276 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008277 }
8278
Michal Vasko03ff5a72019-09-11 13:49:33 +02008279 return rc;
8280}
8281
8282#if 0
8283
8284/* full xml printing of set elements, not used currently */
8285
8286void
8287lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8288{
8289 uint32_t i;
8290 char *str_num;
8291 struct lyout out;
8292
8293 memset(&out, 0, sizeof out);
8294
8295 out.type = LYOUT_STREAM;
8296 out.method.f = f;
8297
8298 switch (set->type) {
8299 case LYXP_SET_EMPTY:
8300 ly_print(&out, "Empty XPath set\n\n");
8301 break;
8302 case LYXP_SET_BOOLEAN:
8303 ly_print(&out, "Boolean XPath set:\n");
8304 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8305 break;
8306 case LYXP_SET_STRING:
8307 ly_print(&out, "String XPath set:\n");
8308 ly_print(&out, "\"%s\"\n\n", set->value.str);
8309 break;
8310 case LYXP_SET_NUMBER:
8311 ly_print(&out, "Number XPath set:\n");
8312
8313 if (isnan(set->value.num)) {
8314 str_num = strdup("NaN");
8315 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8316 str_num = strdup("0");
8317 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8318 str_num = strdup("Infinity");
8319 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8320 str_num = strdup("-Infinity");
8321 } else if ((long long)set->value.num == set->value.num) {
8322 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8323 str_num = NULL;
8324 }
8325 } else {
8326 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8327 str_num = NULL;
8328 }
8329 }
8330 if (!str_num) {
8331 LOGMEM;
8332 return;
8333 }
8334 ly_print(&out, "%s\n\n", str_num);
8335 free(str_num);
8336 break;
8337 case LYXP_SET_NODE_SET:
8338 ly_print(&out, "Node XPath set:\n");
8339
8340 for (i = 0; i < set->used; ++i) {
8341 ly_print(&out, "%d. ", i + 1);
8342 switch (set->node_type[i]) {
8343 case LYXP_NODE_ROOT_ALL:
8344 ly_print(&out, "ROOT all\n\n");
8345 break;
8346 case LYXP_NODE_ROOT_CONFIG:
8347 ly_print(&out, "ROOT config\n\n");
8348 break;
8349 case LYXP_NODE_ROOT_STATE:
8350 ly_print(&out, "ROOT state\n\n");
8351 break;
8352 case LYXP_NODE_ROOT_NOTIF:
8353 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8354 break;
8355 case LYXP_NODE_ROOT_RPC:
8356 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8357 break;
8358 case LYXP_NODE_ROOT_OUTPUT:
8359 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8360 break;
8361 case LYXP_NODE_ELEM:
8362 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8363 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8364 ly_print(&out, "\n");
8365 break;
8366 case LYXP_NODE_TEXT:
8367 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8368 break;
8369 case LYXP_NODE_ATTR:
8370 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8371 break;
8372 }
8373 }
8374 break;
8375 }
8376}
8377
8378#endif
8379
8380LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008381lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008382{
8383 long double num;
8384 char *str;
8385 LY_ERR rc;
8386
8387 if (!set || (set->type == target)) {
8388 return LY_SUCCESS;
8389 }
8390
8391 /* it's not possible to convert anything into a node set */
Michal Vaskod3678892020-05-21 10:06:58 +02008392 assert(target != LYXP_SET_NODE_SET);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008393
8394 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02008395 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008396 return LY_EINVAL;
8397 }
8398
8399 /* to STRING */
Michal Vaskod3678892020-05-21 10:06:58 +02008400 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER) && (set->type == LYXP_SET_NODE_SET))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008401 switch (set->type) {
8402 case LYXP_SET_NUMBER:
8403 if (isnan(set->val.num)) {
8404 set->val.str = strdup("NaN");
8405 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8406 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8407 set->val.str = strdup("0");
8408 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8409 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8410 set->val.str = strdup("Infinity");
8411 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8412 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8413 set->val.str = strdup("-Infinity");
8414 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8415 } else if ((long long)set->val.num == set->val.num) {
8416 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8417 LOGMEM_RET(set->ctx);
8418 }
8419 set->val.str = str;
8420 } else {
8421 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8422 LOGMEM_RET(set->ctx);
8423 }
8424 set->val.str = str;
8425 }
8426 break;
8427 case LYXP_SET_BOOLEAN:
8428 if (set->val.bool) {
8429 set->val.str = strdup("true");
8430 } else {
8431 set->val.str = strdup("false");
8432 }
8433 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8434 break;
8435 case LYXP_SET_NODE_SET:
8436 assert(set->used);
8437
8438 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008439 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008440
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008441 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008442 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02008443 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008444 set->val.str = str;
8445 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008446 default:
8447 LOGINT_RET(set->ctx);
8448 }
8449 set->type = LYXP_SET_STRING;
8450 }
8451
8452 /* to NUMBER */
8453 if (target == LYXP_SET_NUMBER) {
8454 switch (set->type) {
8455 case LYXP_SET_STRING:
8456 num = cast_string_to_number(set->val.str);
Michal Vaskod3678892020-05-21 10:06:58 +02008457 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008458 set->val.num = num;
8459 break;
8460 case LYXP_SET_BOOLEAN:
8461 if (set->val.bool) {
8462 set->val.num = 1;
8463 } else {
8464 set->val.num = 0;
8465 }
8466 break;
8467 default:
8468 LOGINT_RET(set->ctx);
8469 }
8470 set->type = LYXP_SET_NUMBER;
8471 }
8472
8473 /* to BOOLEAN */
8474 if (target == LYXP_SET_BOOLEAN) {
8475 switch (set->type) {
8476 case LYXP_SET_NUMBER:
8477 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8478 set->val.bool = 0;
8479 } else {
8480 set->val.bool = 1;
8481 }
8482 break;
8483 case LYXP_SET_STRING:
8484 if (set->val.str[0]) {
Michal Vaskod3678892020-05-21 10:06:58 +02008485 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008486 set->val.bool = 1;
8487 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02008488 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008489 set->val.bool = 0;
8490 }
8491 break;
8492 case LYXP_SET_NODE_SET:
Michal Vaskod3678892020-05-21 10:06:58 +02008493 if (set->used) {
8494 lyxp_set_free_content(set);
8495 set->val.bool = 1;
8496 } else {
8497 lyxp_set_free_content(set);
8498 set->val.bool = 0;
8499 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008500 break;
8501 default:
8502 LOGINT_RET(set->ctx);
8503 }
8504 set->type = LYXP_SET_BOOLEAN;
8505 }
8506
Michal Vasko03ff5a72019-09-11 13:49:33 +02008507 return LY_SUCCESS;
8508}
8509
8510LY_ERR
8511lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8512 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8513{
8514 struct ly_ctx *ctx;
8515 uint16_t exp_idx = 0;
8516
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008517 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008518
8519 ctx = local_mod->ctx;
8520
8521 /* prepare set for evaluation */
8522 exp_idx = 0;
8523 memset(set, 0, sizeof *set);
8524 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008525 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008526 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008527 set->ctx = ctx;
8528 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008529 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008530 set->local_mod = local_mod;
8531 set->format = format;
8532
8533 /* evaluate */
8534 return eval_expr_select(exp, &exp_idx, 0, set, options);
8535}