blob: bd57bd4fdf917a67888f0ece3738d0425480bf49 [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 Vasko03ff5a72019-09-11 13:49:33 +02006 * Copyright (c) 2015 - 2019 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
19#include "common.h"
20
Michal Vasko03ff5a72019-09-11 13:49:33 +020021#include <math.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010022#include <ctype.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdint.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010024#include <stdio.h>
25#include <stdlib.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010026#include <string.h>
Michal Vasko03ff5a72019-09-11 13:49:33 +020027#include <errno.h>
28#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010029
30#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "dict.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010032#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020033#include "printer_data.h"
34#include "tree_schema_internal.h"
35#include "plugins_types.h"
36
Michal Vasko03ff5a72019-09-11 13:49:33 +020037static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +020038static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
39
40/**
41 * @brief Print the type of an XPath \p set.
42 *
43 * @param[in] set Set to use.
44 * @return Set type string.
45 */
46static const char *
47print_set_type(struct lyxp_set *set)
48{
49 switch (set->type) {
50 case LYXP_SET_EMPTY:
51 return "empty";
52 case LYXP_SET_NODE_SET:
53 return "node set";
54 case LYXP_SET_SCNODE_SET:
55 return "schema node set";
56 case LYXP_SET_BOOLEAN:
57 return "boolean";
58 case LYXP_SET_NUMBER:
59 return "number";
60 case LYXP_SET_STRING:
61 return "string";
62 }
63
64 return NULL;
65}
66
67/**
68 * @brief Print an XPath token \p tok type.
69 *
70 * @param[in] tok Token to use.
71 * @return Token type string.
72 */
73static const char *
74print_token(enum lyxp_token tok)
75{
76 switch (tok) {
77 case LYXP_TOKEN_PAR1:
78 return "(";
79 case LYXP_TOKEN_PAR2:
80 return ")";
81 case LYXP_TOKEN_BRACK1:
82 return "[";
83 case LYXP_TOKEN_BRACK2:
84 return "]";
85 case LYXP_TOKEN_DOT:
86 return ".";
87 case LYXP_TOKEN_DDOT:
88 return "..";
89 case LYXP_TOKEN_AT:
90 return "@";
91 case LYXP_TOKEN_COMMA:
92 return ",";
93 case LYXP_TOKEN_NAMETEST:
94 return "NameTest";
95 case LYXP_TOKEN_NODETYPE:
96 return "NodeType";
97 case LYXP_TOKEN_FUNCNAME:
98 return "FunctionName";
99 case LYXP_TOKEN_OPERATOR_LOG:
100 return "Operator(Logic)";
101 case LYXP_TOKEN_OPERATOR_COMP:
102 return "Operator(Comparison)";
103 case LYXP_TOKEN_OPERATOR_MATH:
104 return "Operator(Math)";
105 case LYXP_TOKEN_OPERATOR_UNI:
106 return "Operator(Union)";
107 case LYXP_TOKEN_OPERATOR_PATH:
108 return "Operator(Path)";
109 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) {
136 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", print_token(exp->tokens[i]), exp->tok_len[i],
137 &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
247 case LYXP_SET_EMPTY:
248 LOGDBG(LY_LDGXPATH, "set EMPTY");
249 break;
250
251 case LYXP_SET_BOOLEAN:
252 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
253 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
254 break;
255
256 case LYXP_SET_STRING:
257 LOGDBG(LY_LDGXPATH, "set STRING");
258 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
259 break;
260
261 case LYXP_SET_NUMBER:
262 LOGDBG(LY_LDGXPATH, "set NUMBER");
263
264 if (isnan(set->val.num)) {
265 str = strdup("NaN");
266 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
267 str = strdup("0");
268 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
269 str = strdup("Infinity");
270 } else if (isinf(set->val.num) && signbit(set->val.num)) {
271 str = strdup("-Infinity");
272 } else if ((long long)set->val.num == set->val.num) {
273 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
274 str = NULL;
275 }
276 } else {
277 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
278 str = NULL;
279 }
280 }
281 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
282
283 LOGDBG(LY_LDGXPATH, "\t%s", str);
284 free(str);
285 }
286}
287
288#endif
289
290/**
291 * @brief Realloc the string \p str.
292 *
293 * @param[in] ctx libyang context for logging.
294 * @param[in] needed How much free space is required.
295 * @param[in,out] str Pointer to the string to use.
296 * @param[in,out] used Used bytes in \p str.
297 * @param[in,out] size Allocated bytes in \p str.
298 * @return LY_ERR
299 */
300static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100301cast_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 +0200302{
303 if (*size - *used < needed) {
304 do {
305 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
306 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
307 return LY_EINVAL;
308 }
309 *size += LYXP_STRING_CAST_SIZE_STEP;
310 } while (*size - *used < needed);
311 *str = ly_realloc(*str, *size * sizeof(char));
312 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
313 }
314
315 return LY_SUCCESS;
316}
317
318/**
319 * @brief Cast nodes recursively to one string @p str.
320 *
321 * @param[in] node Node to cast.
322 * @param[in] fake_cont Whether to put the data into a "fake" container.
323 * @param[in] root_type Type of the XPath root.
324 * @param[in] indent Current indent.
325 * @param[in,out] str Resulting string.
326 * @param[in,out] used Used bytes in @p str.
327 * @param[in,out] size Allocated bytes in @p str.
328 * @return LY_ERR
329 */
330static LY_ERR
331cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
332 uint16_t *used, uint16_t *size)
333{
334 char *buf, *line, *ptr;
335 const char *value_str;
336 int dynamic;
337 const struct lyd_node *child;
338 struct lyd_node_any *any;
339 LY_ERR rc;
340
341 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
342 return LY_SUCCESS;
343 }
344
345 if (fake_cont) {
346 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
347 LY_CHECK_RET(rc);
348 strcpy(*str + (*used - 1), "\n");
349 ++(*used);
350
351 ++indent;
352 }
353
354 switch (node->schema->nodetype) {
355 case LYS_CONTAINER:
356 case LYS_LIST:
357 case LYS_RPC:
358 case LYS_NOTIF:
359 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
360 LY_CHECK_RET(rc);
361 strcpy(*str + (*used - 1), "\n");
362 ++(*used);
363
364 for (child = lyd_node_children(node); child; child = child->next) {
365 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
366 LY_CHECK_RET(rc);
367 }
368
369 break;
370
371 case LYS_LEAF:
372 case LYS_LEAFLIST:
373 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
374
375 /* print indent */
376 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
377 if (rc != LY_SUCCESS) {
378 if (dynamic) {
379 free((char *)value_str);
380 }
381 return rc;
382 }
383 memset(*str + (*used - 1), ' ', indent * 2);
384 *used += indent * 2;
385
386 /* print value */
387 if (*used == 1) {
388 sprintf(*str + (*used - 1), "%s", value_str);
389 *used += strlen(value_str);
390 } else {
391 sprintf(*str + (*used - 1), "%s\n", value_str);
392 *used += strlen(value_str) + 1;
393 }
394 if (dynamic) {
395 free((char *)value_str);
396 }
397
398 break;
399
400 case LYS_ANYXML:
401 case LYS_ANYDATA:
402 any = (struct lyd_node_any *)node;
403 if (!(void *)any->value.tree) {
404 /* no content */
405 buf = strdup("");
406 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
407 } else {
408 switch (any->value_type) {
409 case LYD_ANYDATA_STRING:
410 case LYD_ANYDATA_XML:
411 case LYD_ANYDATA_JSON:
412 buf = strdup(any->value.json);
413 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
414 break;
415 case LYD_ANYDATA_DATATREE:
416 rc = lyd_print_mem(&buf, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
417 LY_CHECK_RET(rc);
418 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
699/**
700 * @brief Free dynamic content of a set.
701 *
702 * @param[in] set Set to modify.
703 */
704static void
705set_free_content(struct lyxp_set *set)
706{
707 if (!set) {
708 return;
709 }
710
711 if (set->type == LYXP_SET_NODE_SET) {
712 free(set->val.nodes);
713 lyht_free(set->ht);
714 set->ht = NULL;
715 } else if (set->type == LYXP_SET_SCNODE_SET) {
716 free(set->val.scnodes);
717 } else if (set->type == LYXP_SET_STRING) {
718 free(set->val.str);
719 }
720 set->type = LYXP_SET_EMPTY;
721}
722
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100723/**
724 * @brief Free dynamically-allocated set.
725 *
726 * @param[in] set Set to free.
727 */
728static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200729lyxp_set_free(struct lyxp_set *set)
730{
731 if (!set) {
732 return;
733 }
734
735 set_free_content(set);
736 free(set);
737}
738
739/**
740 * @brief Initialize set context.
741 *
742 * @param[in] new Set to initialize.
743 * @param[in] set Arbitrary initialized set.
744 */
745static void
746set_init(struct lyxp_set *new, struct lyxp_set *set)
747{
748 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200749 if (set) {
750 new->ctx = set->ctx;
751 new->ctx_node = set->ctx_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100752 new->root_type = set->root_type;
Michal Vasko02a77382019-09-12 11:47:35 +0200753 new->local_mod = set->local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +0100754 new->tree = set->tree;
Michal Vasko02a77382019-09-12 11:47:35 +0200755 new->format = set->format;
756 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200757}
758
759/**
760 * @brief Create a deep copy of a set.
761 *
762 * @param[in] set Set to copy.
763 * @return Copy of @p set.
764 */
765static struct lyxp_set *
766set_copy(struct lyxp_set *set)
767{
768 struct lyxp_set *ret;
769 uint16_t i;
Michal Vaskoba716542019-12-16 10:01:58 +0100770 int idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200771
772 if (!set) {
773 return NULL;
774 }
775
776 ret = malloc(sizeof *ret);
777 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
778 set_init(ret, set);
779
780 if (set->type == LYXP_SET_SCNODE_SET) {
781 ret->type = set->type;
782
783 for (i = 0; i < set->used; ++i) {
Michal Vaskoba716542019-12-16 10:01:58 +0100784 if ((set->val.scnodes[i].in_ctx == 1) || (set->val.scnodes[i].in_ctx == -2)) {
785 idx = lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type);
Michal Vasko3f27c522020-01-06 08:37:49 +0100786 /* coverity seems to think scnodes can be NULL */
787 if ((idx == -1) || !ret->val.scnodes) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200788 lyxp_set_free(ret);
789 return NULL;
790 }
Michal Vaskoba716542019-12-16 10:01:58 +0100791 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200792 }
793 }
794 } else if (set->type == LYXP_SET_NODE_SET) {
795 ret->type = set->type;
796 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
797 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
798 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
799
800 ret->used = ret->size = set->used;
801 ret->ctx_pos = set->ctx_pos;
802 ret->ctx_size = set->ctx_size;
803 ret->ht = lyht_dup(set->ht);
804 } else {
805 memcpy(ret, set, sizeof *ret);
806 if (set->type == LYXP_SET_STRING) {
807 ret->val.str = strdup(set->val.str);
808 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
809 }
810 }
811
812 return ret;
813}
814
815/**
816 * @brief Fill XPath set with a string. Any current data are disposed of.
817 *
818 * @param[in] set Set to fill.
819 * @param[in] string String to fill into \p set.
820 * @param[in] str_len Length of \p string. 0 is a valid value!
821 */
822static void
823set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
824{
825 set_free_content(set);
826
827 set->type = LYXP_SET_STRING;
828 if ((str_len == 0) && (string[0] != '\0')) {
829 string = "";
830 }
831 set->val.str = strndup(string, str_len);
832}
833
834/**
835 * @brief Fill XPath set with a number. Any current data are disposed of.
836 *
837 * @param[in] set Set to fill.
838 * @param[in] number Number to fill into \p set.
839 */
840static void
841set_fill_number(struct lyxp_set *set, long double number)
842{
843 set_free_content(set);
844
845 set->type = LYXP_SET_NUMBER;
846 set->val.num = number;
847}
848
849/**
850 * @brief Fill XPath set with a boolean. Any current data are disposed of.
851 *
852 * @param[in] set Set to fill.
853 * @param[in] boolean Boolean to fill into \p set.
854 */
855static void
856set_fill_boolean(struct lyxp_set *set, int boolean)
857{
858 set_free_content(set);
859
860 set->type = LYXP_SET_BOOLEAN;
861 set->val.bool = boolean;
862}
863
864/**
865 * @brief Fill XPath set with the value from another set (deep assign).
866 * Any current data are disposed of.
867 *
868 * @param[in] trg Set to fill.
869 * @param[in] src Source set to copy into \p trg.
870 */
871static void
872set_fill_set(struct lyxp_set *trg, struct lyxp_set *src)
873{
874 if (!trg || !src) {
875 return;
876 }
877
878 if (trg->type == LYXP_SET_NODE_SET) {
879 free(trg->val.nodes);
880 } else if (trg->type == LYXP_SET_STRING) {
881 free(trg->val.str);
882 }
883 set_init(trg, src);
884
885 if (src->type == LYXP_SET_SCNODE_SET) {
886 trg->type = LYXP_SET_SCNODE_SET;
887 trg->used = src->used;
888 trg->size = src->used;
889
890 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
891 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
892 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
893 } else if (src->type == LYXP_SET_BOOLEAN) {
894 set_fill_boolean(trg, src->val.bool);
895 } else if (src->type == LYXP_SET_NUMBER) {
896 set_fill_number(trg, src->val.num);
897 } else if (src->type == LYXP_SET_STRING) {
898 set_fill_string(trg, src->val.str, strlen(src->val.str));
899 } else {
900 if (trg->type == LYXP_SET_NODE_SET) {
901 free(trg->val.nodes);
902 } else if (trg->type == LYXP_SET_STRING) {
903 free(trg->val.str);
904 }
905
906 if (src->type == LYXP_SET_EMPTY) {
907 trg->type = LYXP_SET_EMPTY;
908 } else {
909 assert(src->type == LYXP_SET_NODE_SET);
910
911 trg->type = LYXP_SET_NODE_SET;
912 trg->used = src->used;
913 trg->size = src->used;
914 trg->ctx_pos = src->ctx_pos;
915 trg->ctx_size = src->ctx_size;
916
917 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
918 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
919 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
Michal Vasko9b368d32020-02-14 13:53:31 +0100920 if (src->ht) {
921 trg->ht = lyht_dup(src->ht);
922 } else {
923 trg->ht = NULL;
924 }
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 {
968 set_free_content(set);
969 set->type = LYXP_SET_EMPTY;
970 }
971}
972
973/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100974 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200975 *
976 * @param[in] set Set to use.
977 * @param[in] idx Index from @p set of the node to be removed.
978 */
979static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100980set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200981{
982 assert(set && (set->type == LYXP_SET_NODE_SET));
983 assert(idx < set->used);
984
Michal Vasko2caefc12019-11-14 16:07:56 +0100985 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
986 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
987 }
988 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200989}
990
991/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100992 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200993 * set into LYXP_SET_EMPTY. Context position aware.
994 *
995 * @param[in] set Set to consolidate.
996 */
997static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100998set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200999{
1000 uint16_t i, orig_used, end;
1001 int32_t start;
1002
Michal Vasko2caefc12019-11-14 16:07:56 +01001003 assert(set && (set->type != LYXP_SET_EMPTY));
Michal Vasko57eab132019-09-24 11:46:26 +02001004
1005 orig_used = set->used;
1006 set->used = 0;
1007 for (i = 0; i < orig_used;) {
1008 start = -1;
1009 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001010 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001011 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001012 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001013 end = i;
1014 ++i;
1015 break;
1016 }
1017
1018 ++i;
1019 if (i == orig_used) {
1020 end = i;
1021 }
1022 } while (i < orig_used);
1023
1024 if (start > -1) {
1025 /* move the whole chunk of valid nodes together */
1026 if (set->used != (unsigned)start) {
1027 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1028 }
1029 set->used += end - start;
1030 }
1031 }
1032
1033 if (!set->used) {
1034 set_free_content(set);
1035 /* this changes it to LYXP_SET_EMPTY */
1036 memset(set, 0, sizeof *set);
1037 }
1038}
1039
1040/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001041 * @brief Check for duplicates in a node set.
1042 *
1043 * @param[in] set Set to check.
1044 * @param[in] node Node to look for in @p set.
1045 * @param[in] node_type Type of @p node.
1046 * @param[in] skip_idx Index from @p set to skip.
1047 * @return LY_ERR
1048 */
1049static LY_ERR
1050set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1051{
1052 uint32_t i;
1053
Michal Vasko2caefc12019-11-14 16:07:56 +01001054 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001055 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1056 }
1057
1058 for (i = 0; i < set->used; ++i) {
1059 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1060 continue;
1061 }
1062
1063 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1064 return LY_EEXIST;
1065 }
1066 }
1067
1068 return LY_SUCCESS;
1069}
1070
Michal Vaskoecd62de2019-11-13 12:35:11 +01001071int
1072lyxp_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 +02001073{
1074 uint32_t i;
1075
1076 for (i = 0; i < set->used; ++i) {
1077 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1078 continue;
1079 }
1080
1081 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1082 return i;
1083 }
1084 }
1085
1086 return -1;
1087}
1088
Michal Vaskoecd62de2019-11-13 12:35:11 +01001089void
1090lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001091{
1092 uint32_t orig_used, i, j;
1093
1094 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1095 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1096
1097 if (set2->type == LYXP_SET_EMPTY) {
1098 return;
1099 }
1100
1101 if (set1->type == LYXP_SET_EMPTY) {
1102 memcpy(set1, set2, sizeof *set1);
1103 return;
1104 }
1105
1106 if (set1->used + set2->used > set1->size) {
1107 set1->size = set1->used + set2->used;
1108 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1109 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1110 }
1111
1112 orig_used = set1->used;
1113
1114 for (i = 0; i < set2->used; ++i) {
1115 for (j = 0; j < orig_used; ++j) {
1116 /* detect duplicities */
1117 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1118 break;
1119 }
1120 }
1121
1122 if (j == orig_used) {
1123 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1124 ++set1->used;
1125 }
1126 }
1127
1128 set_free_content(set2);
1129 set2->type = LYXP_SET_EMPTY;
1130}
1131
1132/**
1133 * @brief Insert a node into a set. Context position aware.
1134 *
1135 * @param[in] set Set to use.
1136 * @param[in] node Node to insert to @p set.
1137 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1138 * @param[in] node_type Node type of @p node.
1139 * @param[in] idx Index in @p set to insert into.
1140 */
1141static void
1142set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1143{
1144 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1145
1146 if (set->type == LYXP_SET_EMPTY) {
1147 /* first item */
1148 if (idx) {
1149 /* no real harm done, but it is a bug */
1150 LOGINT(set->ctx);
1151 idx = 0;
1152 }
1153 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1154 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1155 set->type = LYXP_SET_NODE_SET;
1156 set->used = 0;
1157 set->size = LYXP_SET_SIZE_START;
1158 set->ctx_pos = 1;
1159 set->ctx_size = 1;
1160 set->ht = NULL;
1161 } else {
1162 /* not an empty set */
1163 if (set->used == set->size) {
1164
1165 /* set is full */
1166 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1167 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1168 set->size += LYXP_SET_SIZE_STEP;
1169 }
1170
1171 if (idx > set->used) {
1172 LOGINT(set->ctx);
1173 idx = set->used;
1174 }
1175
1176 /* make space for the new node */
1177 if (idx < set->used) {
1178 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1179 }
1180 }
1181
1182 /* finally assign the value */
1183 set->val.nodes[idx].node = (struct lyd_node *)node;
1184 set->val.nodes[idx].type = node_type;
1185 set->val.nodes[idx].pos = pos;
1186 ++set->used;
1187
Michal Vasko2caefc12019-11-14 16:07:56 +01001188 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1189 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1190 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001191}
1192
Michal Vaskoecd62de2019-11-13 12:35:11 +01001193int
1194lyxp_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 +02001195{
1196 int ret;
1197
1198 assert(set->type == LYXP_SET_SCNODE_SET);
1199
Michal Vaskoecd62de2019-11-13 12:35:11 +01001200 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001201 if (ret > -1) {
1202 set->val.scnodes[ret].in_ctx = 1;
1203 } else {
1204 if (set->used == set->size) {
1205 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1206 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1207 set->size += LYXP_SET_SIZE_STEP;
1208 }
1209
1210 ret = set->used;
1211 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1212 set->val.scnodes[ret].type = node_type;
1213 set->val.scnodes[ret].in_ctx = 1;
1214 ++set->used;
1215 }
1216
1217 return ret;
1218}
1219
1220/**
1221 * @brief Replace a node in a set with another. Context position aware.
1222 *
1223 * @param[in] set Set to use.
1224 * @param[in] node Node to insert to @p set.
1225 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1226 * @param[in] node_type Node type of @p node.
1227 * @param[in] idx Index in @p set of the node to replace.
1228 */
1229static void
1230set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1231{
1232 assert(set && (idx < set->used));
1233
Michal Vasko2caefc12019-11-14 16:07:56 +01001234 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1235 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1236 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001237 set->val.nodes[idx].node = (struct lyd_node *)node;
1238 set->val.nodes[idx].type = node_type;
1239 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001240 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1241 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1242 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001243}
1244
1245/**
1246 * @brief Set all nodes with ctx 1 to a new unique context value.
1247 *
1248 * @param[in] set Set to modify.
1249 * @return New context value.
1250 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001251static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001252set_scnode_new_in_ctx(struct lyxp_set *set)
1253{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001254 uint32_t i;
1255 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001256
1257 assert(set->type == LYXP_SET_SCNODE_SET);
1258
1259 ret_ctx = 3;
1260retry:
1261 for (i = 0; i < set->used; ++i) {
1262 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1263 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1264 goto retry;
1265 }
1266 }
1267 for (i = 0; i < set->used; ++i) {
1268 if (set->val.scnodes[i].in_ctx == 1) {
1269 set->val.scnodes[i].in_ctx = ret_ctx;
1270 }
1271 }
1272
1273 return ret_ctx;
1274}
1275
1276/**
1277 * @brief Get unique @p node position in the data.
1278 *
1279 * @param[in] node Node to find.
1280 * @param[in] node_type Node type of @p node.
1281 * @param[in] root Root node.
1282 * @param[in] root_type Type of the XPath @p root node.
1283 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1284 * be used to increase efficiency and start the DFS from this node.
1285 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1286 * @return Node position.
1287 */
1288static uint32_t
1289get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1290 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1291{
1292 const struct lyd_node *next, *elem, *top_sibling;
1293 uint32_t pos = 1;
1294
1295 assert(prev && prev_pos && !root->prev->next);
1296
1297 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1298 return 0;
1299 }
1300
1301 if (*prev) {
1302 /* start from the previous element instead from the root */
1303 elem = next = *prev;
1304 pos = *prev_pos;
1305 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1306 goto dfs_search;
1307 }
1308
1309 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1310 /* TREE DFS */
1311 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1312dfs_search:
1313 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1314 goto skip_children;
1315 }
1316
1317 if (elem == node) {
1318 break;
1319 }
1320 ++pos;
1321
1322 /* TREE DFS END */
1323 /* select element for the next run - children first,
1324 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1325 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1326 next = NULL;
1327 } else {
1328 next = lyd_node_children(elem);
1329 }
1330 if (!next) {
1331skip_children:
1332 /* no children */
1333 if (elem == top_sibling) {
1334 /* we are done, root has no children */
1335 elem = NULL;
1336 break;
1337 }
1338 /* try siblings */
1339 next = elem->next;
1340 }
1341 while (!next) {
1342 /* no siblings, go back through parents */
1343 if (elem->parent == top_sibling->parent) {
1344 /* we are done, no next element to process */
1345 elem = NULL;
1346 break;
1347 }
1348 /* parent is already processed, go to its sibling */
1349 elem = (struct lyd_node *)elem->parent;
1350 next = elem->next;
1351 }
1352 }
1353
1354 /* node found */
1355 if (elem) {
1356 break;
1357 }
1358 }
1359
1360 if (!elem) {
1361 if (!(*prev)) {
1362 /* we went from root and failed to find it, cannot be */
1363 LOGINT(node->schema->module->ctx);
1364 return 0;
1365 } else {
1366 *prev = NULL;
1367 *prev_pos = 0;
1368
1369 elem = next = top_sibling = root;
1370 pos = 1;
1371 goto dfs_search;
1372 }
1373 }
1374
1375 /* remember the last found node for next time */
1376 *prev = node;
1377 *prev_pos = pos;
1378
1379 return pos;
1380}
1381
1382/**
1383 * @brief Assign (fill) missing node positions.
1384 *
1385 * @param[in] set Set to fill positions in.
1386 * @param[in] root Context root node.
1387 * @param[in] root_type Context root type.
1388 * @return LY_ERR
1389 */
1390static LY_ERR
1391set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1392{
1393 const struct lyd_node *prev = NULL, *tmp_node;
1394 uint32_t i, tmp_pos = 0;
1395
1396 for (i = 0; i < set->used; ++i) {
1397 if (!set->val.nodes[i].pos) {
1398 tmp_node = NULL;
1399 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001400 case LYXP_NODE_META:
1401 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001402 if (!tmp_node) {
1403 LOGINT_RET(root->schema->module->ctx);
1404 }
1405 /* fallthrough */
1406 case LYXP_NODE_ELEM:
1407 case LYXP_NODE_TEXT:
1408 if (!tmp_node) {
1409 tmp_node = set->val.nodes[i].node;
1410 }
1411 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1412 break;
1413 default:
1414 /* all roots have position 0 */
1415 break;
1416 }
1417 }
1418 }
1419
1420 return LY_SUCCESS;
1421}
1422
1423/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001424 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001425 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001426 * @param[in] meta Metadata to use.
1427 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001428 */
1429static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001430get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001431{
1432 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001433 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001434
Michal Vasko9f96a052020-03-10 09:41:45 +01001435 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001436 ++pos;
1437 }
1438
Michal Vasko9f96a052020-03-10 09:41:45 +01001439 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001440 return pos;
1441}
1442
1443/**
1444 * @brief Compare 2 nodes in respect to XPath document order.
1445 *
1446 * @param[in] item1 1st node.
1447 * @param[in] item2 2nd node.
1448 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1449 */
1450static int
1451set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1452{
Michal Vasko9f96a052020-03-10 09:41:45 +01001453 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001454
1455 if (item1->pos < item2->pos) {
1456 return -1;
1457 }
1458
1459 if (item1->pos > item2->pos) {
1460 return 1;
1461 }
1462
1463 /* node positions are equal, the fun case */
1464
1465 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1466 /* special case since text nodes are actually saved as their parents */
1467 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1468 if (item1->type == LYXP_NODE_ELEM) {
1469 assert(item2->type == LYXP_NODE_TEXT);
1470 return -1;
1471 } else {
1472 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1473 return 1;
1474 }
1475 }
1476
Michal Vasko9f96a052020-03-10 09:41:45 +01001477 /* we need meta positions now */
1478 if (item1->type == LYXP_NODE_META) {
1479 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001480 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001481 if (item2->type == LYXP_NODE_META) {
1482 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001483 }
1484
Michal Vasko9f96a052020-03-10 09:41:45 +01001485 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001486 /* check for duplicates */
1487 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001488 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001489 return 0;
1490 }
1491
Michal Vasko9f96a052020-03-10 09:41:45 +01001492 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001493 /* elem is always first, 2nd node is after it */
1494 if (item1->type == LYXP_NODE_ELEM) {
1495 assert(item2->type != LYXP_NODE_ELEM);
1496 return -1;
1497 }
1498
Michal Vasko9f96a052020-03-10 09:41:45 +01001499 /* 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 +02001500 /* 2nd is before 1st */
1501 if (((item1->type == LYXP_NODE_TEXT)
Michal Vasko9f96a052020-03-10 09:41:45 +01001502 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META)))
1503 || ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM))
1504 || (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META))
1505 && (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001506 return 1;
1507 }
1508
Michal Vasko9f96a052020-03-10 09:41:45 +01001509 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001510 /* 2nd is after 1st */
1511 return -1;
1512}
1513
1514/**
1515 * @brief Set cast for comparisons.
1516 *
1517 * @param[in] trg Target set to cast source into.
1518 * @param[in] src Source set.
1519 * @param[in] type Target set type.
1520 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001521 * @return LY_ERR
1522 */
1523static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001524set_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 +02001525{
1526 assert(src->type == LYXP_SET_NODE_SET);
1527
1528 set_init(trg, src);
1529
1530 /* insert node into target set */
1531 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1532
1533 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001534 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001535}
1536
1537#ifndef NDEBUG
1538
1539/**
1540 * @brief Bubble sort @p set into XPath document order.
1541 * Context position aware. Unused in the 'Release' build target.
1542 *
1543 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001544 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1545 */
1546static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001547set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001548{
1549 uint32_t i, j;
1550 int ret = 0, cmp, inverted, change;
1551 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001552 struct lyxp_set_node item;
1553 struct lyxp_set_hash_node hnode;
1554 uint64_t hash;
1555
1556 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1557 return 0;
1558 }
1559
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001560 /* find first top-level node to be used as anchor for positions */
1561 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1562 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001563
1564 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001565 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001566 return -1;
1567 }
1568
1569 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1570 print_set_debug(set);
1571
1572 for (i = 0; i < set->used; ++i) {
1573 inverted = 0;
1574 change = 0;
1575
1576 for (j = 1; j < set->used - i; ++j) {
1577 /* compare node positions */
1578 if (inverted) {
1579 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1580 } else {
1581 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1582 }
1583
1584 /* swap if needed */
1585 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1586 change = 1;
1587
1588 item = set->val.nodes[j - 1];
1589 set->val.nodes[j - 1] = set->val.nodes[j];
1590 set->val.nodes[j] = item;
1591 } else {
1592 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1593 inverted = !inverted;
1594 }
1595 }
1596
1597 ++ret;
1598
1599 if (!change) {
1600 break;
1601 }
1602 }
1603
1604 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1605 print_set_debug(set);
1606
1607 /* check node hashes */
1608 if (set->used >= LYD_HT_MIN_ITEMS) {
1609 assert(set->ht);
1610 for (i = 0; i < set->used; ++i) {
1611 hnode.node = set->val.nodes[i].node;
1612 hnode.type = set->val.nodes[i].type;
1613
1614 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1615 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1616 hash = dict_hash_multi(hash, NULL, 0);
1617
1618 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1619 }
1620 }
1621
1622 return ret - 1;
1623}
1624
1625/**
1626 * @brief Remove duplicate entries in a sorted node set.
1627 *
1628 * @param[in] set Sorted set to check.
1629 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1630 */
1631static LY_ERR
1632set_sorted_dup_node_clean(struct lyxp_set *set)
1633{
1634 uint32_t i = 0;
1635 LY_ERR ret = LY_SUCCESS;
1636
1637 if (set->used > 1) {
1638 while (i < set->used - 1) {
1639 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1640 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001641 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001642 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001643 }
Michal Vasko57eab132019-09-24 11:46:26 +02001644 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001645 }
1646 }
1647
Michal Vasko2caefc12019-11-14 16:07:56 +01001648 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001649 return ret;
1650}
1651
1652#endif
1653
1654/**
1655 * @brief Merge 2 sorted sets into one.
1656 *
1657 * @param[in,out] trg Set to merge into. Duplicates are removed.
1658 * @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 +02001659 * @return LY_ERR
1660 */
1661static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001662set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001663{
1664 uint32_t i, j, k, count, dup_count;
1665 int cmp;
1666 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001667
1668 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1669 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1670 return LY_EINVAL;
1671 }
1672
1673 if (src->type == LYXP_SET_EMPTY) {
1674 return LY_SUCCESS;
1675 } else if (trg->type == LYXP_SET_EMPTY) {
1676 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001677 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001678 return LY_SUCCESS;
1679 }
1680
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001681 /* find first top-level node to be used as anchor for positions */
1682 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1683 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001684
1685 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001686 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001687 return LY_EINT;
1688 }
1689
1690#ifndef NDEBUG
1691 LOGDBG(LY_LDGXPATH, "MERGE target");
1692 print_set_debug(trg);
1693 LOGDBG(LY_LDGXPATH, "MERGE source");
1694 print_set_debug(src);
1695#endif
1696
1697 /* make memory for the merge (duplicates are not detected yet, so space
1698 * will likely be wasted on them, too bad) */
1699 if (trg->size - trg->used < src->used) {
1700 trg->size = trg->used + src->used;
1701
1702 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1703 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1704 }
1705
1706 i = 0;
1707 j = 0;
1708 count = 0;
1709 dup_count = 0;
1710 do {
1711 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1712 if (!cmp) {
1713 if (!count) {
1714 /* duplicate, just skip it */
1715 ++i;
1716 ++j;
1717 } else {
1718 /* we are copying something already, so let's copy the duplicate too,
1719 * we are hoping that afterwards there are some more nodes to
1720 * copy and this way we can copy them all together */
1721 ++count;
1722 ++dup_count;
1723 ++i;
1724 ++j;
1725 }
1726 } else if (cmp < 0) {
1727 /* inserting src node into trg, just remember it for now */
1728 ++count;
1729 ++i;
1730
1731 /* insert the hash now */
1732 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1733 } else if (count) {
1734copy_nodes:
1735 /* time to actually copy the nodes, we have found the largest block of nodes */
1736 memmove(&trg->val.nodes[j + (count - dup_count)],
1737 &trg->val.nodes[j],
1738 (trg->used - j) * sizeof *trg->val.nodes);
1739 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1740
1741 trg->used += count - dup_count;
1742 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1743 j += count - dup_count;
1744
1745 count = 0;
1746 dup_count = 0;
1747 } else {
1748 ++j;
1749 }
1750 } while ((i < src->used) && (j < trg->used));
1751
1752 if ((i < src->used) || count) {
1753 /* insert all the hashes first */
1754 for (k = i; k < src->used; ++k) {
1755 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1756 }
1757
1758 /* loop ended, but we need to copy something at trg end */
1759 count += src->used - i;
1760 i = src->used;
1761 goto copy_nodes;
1762 }
1763
1764 /* we are inserting hashes before the actual node insert, which causes
1765 * situations when there were initially not enough items for a hash table,
1766 * but even after some were inserted, hash table was not created (during
1767 * insertion the number of items is not updated yet) */
1768 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1769 set_insert_node_hash(trg, NULL, 0);
1770 }
1771
1772#ifndef NDEBUG
1773 LOGDBG(LY_LDGXPATH, "MERGE result");
1774 print_set_debug(trg);
1775#endif
1776
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001777 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001778 return LY_SUCCESS;
1779}
1780
1781/*
1782 * (re)parse functions
1783 *
1784 * Parse functions parse the expression into
1785 * tokens (syntactic analysis).
1786 *
1787 * Reparse functions perform semantic analysis
1788 * (do not save the result, just a check) of
1789 * the expression and fill repeat indices.
1790 */
1791
1792/**
1793 * @brief Look at the next token and check its kind.
1794 *
1795 * @param[in] ctx Context for logging.
1796 * @param[in] exp Expression to use.
1797 * @param[in] exp_idx Position in the expression \p exp.
1798 * @param[in] want_tok Expected token.
1799 * @param[in] strict Whether the token is strictly required (print error if
1800 * not the next one) or we simply want to check whether it is the next or not.
1801 * @return LY_ERR
1802 */
1803static LY_ERR
1804exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1805{
1806 if (exp->used == exp_idx) {
1807 if (strict) {
1808 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1809 }
1810 return LY_EINVAL;
1811 }
1812
1813 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1814 if (strict) {
1815 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1816 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1817 }
1818 return LY_EINVAL;
1819 }
1820
1821 return LY_SUCCESS;
1822}
1823
1824/**
1825 * @brief Stack operation push on the repeat array.
1826 *
1827 * @param[in] exp Expression to use.
1828 * @param[in] exp_idx Position in the expresion \p exp.
1829 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1830 */
1831static void
1832exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1833{
1834 uint16_t i;
1835
1836 if (exp->repeat[exp_idx]) {
1837 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1838 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1839 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1840 exp->repeat[exp_idx][i] = repeat_op_idx;
1841 exp->repeat[exp_idx][i + 1] = 0;
1842 } else {
1843 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1844 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1845 exp->repeat[exp_idx][0] = repeat_op_idx;
1846 }
1847}
1848
1849/**
1850 * @brief Reparse Predicate. Logs directly on error.
1851 *
1852 * [7] Predicate ::= '[' Expr ']'
1853 *
1854 * @param[in] ctx Context for logging.
1855 * @param[in] exp Parsed XPath expression.
1856 * @param[in] exp_idx Position in the expression @p exp.
1857 * @return LY_ERR
1858 */
1859static LY_ERR
1860reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1861{
1862 LY_ERR rc;
1863
1864 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1865 LY_CHECK_RET(rc);
1866 ++(*exp_idx);
1867
1868 rc = reparse_or_expr(ctx, exp, exp_idx);
1869 LY_CHECK_RET(rc);
1870
1871 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1872 LY_CHECK_RET(rc);
1873 ++(*exp_idx);
1874
1875 return LY_SUCCESS;
1876}
1877
1878/**
1879 * @brief Reparse RelativeLocationPath. Logs directly on error.
1880 *
1881 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1882 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1883 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1884 *
1885 * @param[in] ctx Context for logging.
1886 * @param[in] exp Parsed XPath expression.
1887 * @param[in] exp_idx Position in the expression \p exp.
1888 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1889 */
1890static LY_ERR
1891reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1892{
1893 LY_ERR rc;
1894
1895 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1896 LY_CHECK_RET(rc);
1897
1898 goto step;
1899 do {
1900 /* '/' or '//' */
1901 ++(*exp_idx);
1902
1903 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1904 LY_CHECK_RET(rc);
1905step:
1906 /* Step */
1907 switch (exp->tokens[*exp_idx]) {
1908 case LYXP_TOKEN_DOT:
1909 ++(*exp_idx);
1910 break;
1911
1912 case LYXP_TOKEN_DDOT:
1913 ++(*exp_idx);
1914 break;
1915
1916 case LYXP_TOKEN_AT:
1917 ++(*exp_idx);
1918
1919 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1920 LY_CHECK_RET(rc);
1921 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1922 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1923 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1924 return LY_EVALID;
1925 }
1926 /* fall through */
1927 case LYXP_TOKEN_NAMETEST:
1928 ++(*exp_idx);
1929 goto reparse_predicate;
1930 break;
1931
1932 case LYXP_TOKEN_NODETYPE:
1933 ++(*exp_idx);
1934
1935 /* '(' */
1936 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1937 LY_CHECK_RET(rc);
1938 ++(*exp_idx);
1939
1940 /* ')' */
1941 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1942 LY_CHECK_RET(rc);
1943 ++(*exp_idx);
1944
1945reparse_predicate:
1946 /* Predicate* */
1947 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1948 rc = reparse_predicate(ctx, exp, exp_idx);
1949 LY_CHECK_RET(rc);
1950 }
1951 break;
1952 default:
1953 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1954 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1955 return LY_EVALID;
1956 }
1957 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1958
1959 return LY_SUCCESS;
1960}
1961
1962/**
1963 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1964 *
1965 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1966 *
1967 * @param[in] ctx Context for logging.
1968 * @param[in] exp Parsed XPath expression.
1969 * @param[in] exp_idx Position in the expression \p exp.
1970 * @return LY_ERR
1971 */
1972static LY_ERR
1973reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1974{
1975 LY_ERR rc;
1976
1977 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1978 LY_CHECK_RET(rc);
1979
1980 /* '/' RelativeLocationPath? */
1981 if (exp->tok_len[*exp_idx] == 1) {
1982 /* '/' */
1983 ++(*exp_idx);
1984
1985 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1986 return LY_SUCCESS;
1987 }
1988 switch (exp->tokens[*exp_idx]) {
1989 case LYXP_TOKEN_DOT:
1990 case LYXP_TOKEN_DDOT:
1991 case LYXP_TOKEN_AT:
1992 case LYXP_TOKEN_NAMETEST:
1993 case LYXP_TOKEN_NODETYPE:
1994 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1995 LY_CHECK_RET(rc);
1996 /* fall through */
1997 default:
1998 break;
1999 }
2000
2001 /* '//' RelativeLocationPath */
2002 } else {
2003 /* '//' */
2004 ++(*exp_idx);
2005
2006 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2007 LY_CHECK_RET(rc);
2008 }
2009
2010 return LY_SUCCESS;
2011}
2012
2013/**
2014 * @brief Reparse FunctionCall. Logs directly on error.
2015 *
2016 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2017 *
2018 * @param[in] ctx Context for logging.
2019 * @param[in] exp Parsed XPath expression.
2020 * @param[in] exp_idx Position in the expression @p exp.
2021 * @return LY_ERR
2022 */
2023static LY_ERR
2024reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2025{
2026 int min_arg_count = -1, max_arg_count, arg_count;
2027 uint16_t func_exp_idx;
2028 LY_ERR rc;
2029
2030 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2031 LY_CHECK_RET(rc);
2032 func_exp_idx = *exp_idx;
2033 switch (exp->tok_len[*exp_idx]) {
2034 case 3:
2035 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2036 min_arg_count = 1;
2037 max_arg_count = 1;
2038 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2039 min_arg_count = 1;
2040 max_arg_count = 1;
2041 }
2042 break;
2043 case 4:
2044 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2045 min_arg_count = 1;
2046 max_arg_count = 1;
2047 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2048 min_arg_count = 0;
2049 max_arg_count = 0;
2050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2051 min_arg_count = 0;
2052 max_arg_count = 1;
2053 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2054 min_arg_count = 0;
2055 max_arg_count = 0;
2056 }
2057 break;
2058 case 5:
2059 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2060 min_arg_count = 1;
2061 max_arg_count = 1;
2062 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2063 min_arg_count = 0;
2064 max_arg_count = 0;
2065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2066 min_arg_count = 1;
2067 max_arg_count = 1;
2068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2069 min_arg_count = 1;
2070 max_arg_count = 1;
2071 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2072 min_arg_count = 1;
2073 max_arg_count = 1;
2074 }
2075 break;
2076 case 6:
2077 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2078 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002079 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002080 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2081 min_arg_count = 0;
2082 max_arg_count = 1;
2083 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2084 min_arg_count = 0;
2085 max_arg_count = 1;
2086 }
2087 break;
2088 case 7:
2089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2090 min_arg_count = 1;
2091 max_arg_count = 1;
2092 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2093 min_arg_count = 1;
2094 max_arg_count = 1;
2095 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2096 min_arg_count = 0;
2097 max_arg_count = 0;
2098 }
2099 break;
2100 case 8:
2101 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2102 min_arg_count = 2;
2103 max_arg_count = 2;
2104 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2105 min_arg_count = 0;
2106 max_arg_count = 0;
2107 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2108 min_arg_count = 2;
2109 max_arg_count = 2;
2110 }
2111 break;
2112 case 9:
2113 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2114 min_arg_count = 2;
2115 max_arg_count = 3;
2116 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2117 min_arg_count = 3;
2118 max_arg_count = 3;
2119 }
2120 break;
2121 case 10:
2122 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2123 min_arg_count = 0;
2124 max_arg_count = 1;
2125 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2126 min_arg_count = 1;
2127 max_arg_count = 1;
2128 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2129 min_arg_count = 2;
2130 max_arg_count = 2;
2131 }
2132 break;
2133 case 11:
2134 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2135 min_arg_count = 2;
2136 max_arg_count = 2;
2137 }
2138 break;
2139 case 12:
2140 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2141 min_arg_count = 2;
2142 max_arg_count = 2;
2143 }
2144 break;
2145 case 13:
2146 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2147 min_arg_count = 0;
2148 max_arg_count = 1;
2149 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2150 min_arg_count = 0;
2151 max_arg_count = 1;
2152 }
2153 break;
2154 case 15:
2155 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2156 min_arg_count = 0;
2157 max_arg_count = 1;
2158 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2159 min_arg_count = 2;
2160 max_arg_count = 2;
2161 }
2162 break;
2163 case 16:
2164 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2165 min_arg_count = 2;
2166 max_arg_count = 2;
2167 }
2168 break;
2169 case 20:
2170 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2171 min_arg_count = 2;
2172 max_arg_count = 2;
2173 }
2174 break;
2175 }
2176 if (min_arg_count == -1) {
2177 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2178 return LY_EINVAL;
2179 }
2180 ++(*exp_idx);
2181
2182 /* '(' */
2183 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2184 LY_CHECK_RET(rc);
2185 ++(*exp_idx);
2186
2187 /* ( Expr ( ',' Expr )* )? */
2188 arg_count = 0;
2189 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2190 LY_CHECK_RET(rc);
2191 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2192 ++arg_count;
2193 rc = reparse_or_expr(ctx, exp, exp_idx);
2194 LY_CHECK_RET(rc);
2195 }
2196 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2197 ++(*exp_idx);
2198
2199 ++arg_count;
2200 rc = reparse_or_expr(ctx, exp, exp_idx);
2201 LY_CHECK_RET(rc);
2202 }
2203
2204 /* ')' */
2205 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2206 LY_CHECK_RET(rc);
2207 ++(*exp_idx);
2208
2209 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2210 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2211 &exp->expr[exp->tok_pos[func_exp_idx]]);
2212 return LY_EVALID;
2213 }
2214
2215 return LY_SUCCESS;
2216}
2217
2218/**
2219 * @brief Reparse PathExpr. Logs directly on error.
2220 *
2221 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2222 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2223 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2224 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2225 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2226 *
2227 * @param[in] ctx Context for logging.
2228 * @param[in] exp Parsed XPath expression.
2229 * @param[in] exp_idx Position in the expression @p exp.
2230 * @return LY_ERR
2231 */
2232static LY_ERR
2233reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2234{
2235 LY_ERR rc;
2236
2237 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2238 return -1;
2239 }
2240
2241 switch (exp->tokens[*exp_idx]) {
2242 case LYXP_TOKEN_PAR1:
2243 /* '(' Expr ')' Predicate* */
2244 ++(*exp_idx);
2245
2246 rc = reparse_or_expr(ctx, exp, exp_idx);
2247 LY_CHECK_RET(rc);
2248
2249 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2250 LY_CHECK_RET(rc);
2251 ++(*exp_idx);
2252 goto predicate;
2253 break;
2254 case LYXP_TOKEN_DOT:
2255 case LYXP_TOKEN_DDOT:
2256 case LYXP_TOKEN_AT:
2257 case LYXP_TOKEN_NAMETEST:
2258 case LYXP_TOKEN_NODETYPE:
2259 /* RelativeLocationPath */
2260 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2261 LY_CHECK_RET(rc);
2262 break;
2263 case LYXP_TOKEN_FUNCNAME:
2264 /* FunctionCall */
2265 rc = reparse_function_call(ctx, exp, exp_idx);
2266 LY_CHECK_RET(rc);
2267 goto predicate;
2268 break;
2269 case LYXP_TOKEN_OPERATOR_PATH:
2270 /* AbsoluteLocationPath */
2271 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2272 LY_CHECK_RET(rc);
2273 break;
2274 case LYXP_TOKEN_LITERAL:
2275 /* Literal */
2276 ++(*exp_idx);
2277 goto predicate;
2278 break;
2279 case LYXP_TOKEN_NUMBER:
2280 /* Number */
2281 ++(*exp_idx);
2282 goto predicate;
2283 break;
2284 default:
2285 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2286 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2287 return LY_EVALID;
2288 }
2289
2290 return LY_SUCCESS;
2291
2292predicate:
2293 /* Predicate* */
2294 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2295 rc = reparse_predicate(ctx, exp, exp_idx);
2296 LY_CHECK_RET(rc);
2297 }
2298
2299 /* ('/' or '//') RelativeLocationPath */
2300 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2301
2302 /* '/' or '//' */
2303 ++(*exp_idx);
2304
2305 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2306 LY_CHECK_RET(rc);
2307 }
2308
2309 return LY_SUCCESS;
2310}
2311
2312/**
2313 * @brief Reparse UnaryExpr. Logs directly on error.
2314 *
2315 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2316 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2317 *
2318 * @param[in] ctx Context for logging.
2319 * @param[in] exp Parsed XPath expression.
2320 * @param[in] exp_idx Position in the expression @p exp.
2321 * @return LY_ERR
2322 */
2323static LY_ERR
2324reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2325{
2326 uint16_t prev_exp;
2327 LY_ERR rc;
2328
2329 /* ('-')* */
2330 prev_exp = *exp_idx;
2331 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2332 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2333 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2334 ++(*exp_idx);
2335 }
2336
2337 /* PathExpr */
2338 prev_exp = *exp_idx;
2339 rc = reparse_path_expr(ctx, exp, exp_idx);
2340 LY_CHECK_RET(rc);
2341
2342 /* ('|' PathExpr)* */
2343 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2344 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2345 ++(*exp_idx);
2346
2347 rc = reparse_path_expr(ctx, exp, exp_idx);
2348 LY_CHECK_RET(rc);
2349 }
2350
2351 return LY_SUCCESS;
2352}
2353
2354/**
2355 * @brief Reparse AdditiveExpr. Logs directly on error.
2356 *
2357 * [15] AdditiveExpr ::= MultiplicativeExpr
2358 * | AdditiveExpr '+' MultiplicativeExpr
2359 * | AdditiveExpr '-' MultiplicativeExpr
2360 * [16] MultiplicativeExpr ::= UnaryExpr
2361 * | MultiplicativeExpr '*' UnaryExpr
2362 * | MultiplicativeExpr 'div' UnaryExpr
2363 * | MultiplicativeExpr 'mod' UnaryExpr
2364 *
2365 * @param[in] ctx Context for logging.
2366 * @param[in] exp Parsed XPath expression.
2367 * @param[in] exp_idx Position in the expression @p exp.
2368 * @return LY_ERR
2369 */
2370static LY_ERR
2371reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2372{
2373 uint16_t prev_add_exp, prev_mul_exp;
2374 LY_ERR rc;
2375
2376 prev_add_exp = *exp_idx;
2377 goto reparse_multiplicative_expr;
2378
2379 /* ('+' / '-' MultiplicativeExpr)* */
2380 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2381 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2382 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2383 ++(*exp_idx);
2384
2385reparse_multiplicative_expr:
2386 /* UnaryExpr */
2387 prev_mul_exp = *exp_idx;
2388 rc = reparse_unary_expr(ctx, exp, exp_idx);
2389 LY_CHECK_RET(rc);
2390
2391 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2392 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2393 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2394 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2395 ++(*exp_idx);
2396
2397 rc = reparse_unary_expr(ctx, exp, exp_idx);
2398 LY_CHECK_RET(rc);
2399 }
2400 }
2401
2402 return LY_SUCCESS;
2403}
2404
2405/**
2406 * @brief Reparse EqualityExpr. Logs directly on error.
2407 *
2408 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2409 * | EqualityExpr '!=' RelationalExpr
2410 * [14] RelationalExpr ::= AdditiveExpr
2411 * | RelationalExpr '<' AdditiveExpr
2412 * | RelationalExpr '>' AdditiveExpr
2413 * | RelationalExpr '<=' AdditiveExpr
2414 * | RelationalExpr '>=' AdditiveExpr
2415 *
2416 * @param[in] ctx Context for logging.
2417 * @param[in] exp Parsed XPath expression.
2418 * @param[in] exp_idx Position in the expression @p exp.
2419 * @return LY_ERR
2420 */
2421static LY_ERR
2422reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2423{
2424 uint16_t prev_eq_exp, prev_rel_exp;
2425 LY_ERR rc;
2426
2427 prev_eq_exp = *exp_idx;
2428 goto reparse_additive_expr;
2429
2430 /* ('=' / '!=' RelationalExpr)* */
2431 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2432 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2433 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2434 ++(*exp_idx);
2435
2436reparse_additive_expr:
2437 /* AdditiveExpr */
2438 prev_rel_exp = *exp_idx;
2439 rc = reparse_additive_expr(ctx, exp, exp_idx);
2440 LY_CHECK_RET(rc);
2441
2442 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2443 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2444 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2445 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2446 ++(*exp_idx);
2447
2448 rc = reparse_additive_expr(ctx, exp, exp_idx);
2449 LY_CHECK_RET(rc);
2450 }
2451 }
2452
2453 return LY_SUCCESS;
2454}
2455
2456/**
2457 * @brief Reparse OrExpr. Logs directly on error.
2458 *
2459 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2460 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2461 *
2462 * @param[in] ctx Context for logging.
2463 * @param[in] exp Parsed XPath expression.
2464 * @param[in] exp_idx Position in the expression @p exp.
2465 * @return LY_ERR
2466 */
2467static LY_ERR
2468reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2469{
2470 uint16_t prev_or_exp, prev_and_exp;
2471 LY_ERR rc;
2472
2473 prev_or_exp = *exp_idx;
2474 goto reparse_equality_expr;
2475
2476 /* ('or' AndExpr)* */
2477 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2478 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2479 ++(*exp_idx);
2480
2481reparse_equality_expr:
2482 /* EqualityExpr */
2483 prev_and_exp = *exp_idx;
2484 rc = reparse_equality_expr(ctx, exp, exp_idx);
2485 LY_CHECK_RET(rc);
2486
2487 /* ('and' EqualityExpr)* */
2488 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2489 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2490 ++(*exp_idx);
2491
2492 rc = reparse_equality_expr(ctx, exp, exp_idx);
2493 LY_CHECK_RET(rc);
2494 }
2495 }
2496
2497 return LY_SUCCESS;
2498}
Radek Krejcib1646a92018-11-02 16:08:26 +01002499
2500/**
2501 * @brief Parse NCName.
2502 *
2503 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002504 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002505 */
Radek Krejcid4270262019-01-07 15:07:25 +01002506static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002507parse_ncname(const char *ncname)
2508{
2509 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002510 size_t size;
2511 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002512
2513 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2514 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2515 return len;
2516 }
2517
2518 do {
2519 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002520 if (!*ncname) {
2521 break;
2522 }
Radek Krejcid4270262019-01-07 15:07:25 +01002523 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002524 } while (is_xmlqnamechar(uc) && (uc != ':'));
2525
2526 return len;
2527}
2528
2529/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002530 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002531 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002532 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002533 * @param[in] exp Expression to use.
2534 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002535 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002536 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002537 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002538 */
2539static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002540exp_add_token(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 +01002541{
2542 uint32_t prev;
2543
2544 if (exp->used == exp->size) {
2545 prev = exp->size;
2546 exp->size += LYXP_EXPR_SIZE_STEP;
2547 if (prev > exp->size) {
2548 LOGINT(ctx);
2549 return LY_EINT;
2550 }
2551
2552 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2553 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2554 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2555 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2556 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2557 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2558 }
2559
2560 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002561 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002562 exp->tok_len[exp->used] = tok_len;
2563 ++exp->used;
2564 return LY_SUCCESS;
2565}
2566
2567void
2568lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2569{
2570 uint16_t i;
2571
2572 if (!expr) {
2573 return;
2574 }
2575
2576 lydict_remove(ctx, expr->expr);
2577 free(expr->tokens);
2578 free(expr->tok_pos);
2579 free(expr->tok_len);
2580 if (expr->repeat) {
2581 for (i = 0; i < expr->used; ++i) {
2582 free(expr->repeat[i]);
2583 }
2584 }
2585 free(expr->repeat);
2586 free(expr);
2587}
2588
2589struct lyxp_expr *
2590lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2591{
2592 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002593 size_t parsed = 0, tok_len;
2594 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002595 enum lyxp_token tok_type;
2596 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002597 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002598
2599 if (strlen(expr) > UINT16_MAX) {
2600 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2601 return NULL;
2602 }
2603
2604 /* init lyxp_expr structure */
2605 ret = calloc(1, sizeof *ret);
2606 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2607 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2608 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2609 ret->used = 0;
2610 ret->size = LYXP_EXPR_SIZE_START;
2611 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2612 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2613
2614 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2615 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2616
2617 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2618 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2619
2620 while (is_xmlws(expr[parsed])) {
2621 ++parsed;
2622 }
2623
2624 do {
2625 if (expr[parsed] == '(') {
2626
2627 /* '(' */
2628 tok_len = 1;
2629 tok_type = LYXP_TOKEN_PAR1;
2630
2631 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2632 /* it is a NodeType/FunctionName after all */
2633 if (((ret->tok_len[ret->used - 1] == 4)
2634 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2635 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2636 ((ret->tok_len[ret->used - 1] == 7)
2637 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2638 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2639 } else {
2640 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2641 }
2642 prev_function_check = 0;
2643 }
2644
2645 } else if (expr[parsed] == ')') {
2646
2647 /* ')' */
2648 tok_len = 1;
2649 tok_type = LYXP_TOKEN_PAR2;
2650
2651 } else if (expr[parsed] == '[') {
2652
2653 /* '[' */
2654 tok_len = 1;
2655 tok_type = LYXP_TOKEN_BRACK1;
2656
2657 } else if (expr[parsed] == ']') {
2658
2659 /* ']' */
2660 tok_len = 1;
2661 tok_type = LYXP_TOKEN_BRACK2;
2662
2663 } else if (!strncmp(&expr[parsed], "..", 2)) {
2664
2665 /* '..' */
2666 tok_len = 2;
2667 tok_type = LYXP_TOKEN_DDOT;
2668
2669 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2670
2671 /* '.' */
2672 tok_len = 1;
2673 tok_type = LYXP_TOKEN_DOT;
2674
2675 } else if (expr[parsed] == '@') {
2676
2677 /* '@' */
2678 tok_len = 1;
2679 tok_type = LYXP_TOKEN_AT;
2680
2681 } else if (expr[parsed] == ',') {
2682
2683 /* ',' */
2684 tok_len = 1;
2685 tok_type = LYXP_TOKEN_COMMA;
2686
2687 } else if (expr[parsed] == '\'') {
2688
2689 /* Literal with ' */
2690 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2691 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2692 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2693 ++tok_len;
2694 tok_type = LYXP_TOKEN_LITERAL;
2695
2696 } else if (expr[parsed] == '\"') {
2697
2698 /* Literal with " */
2699 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2700 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2701 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2702 ++tok_len;
2703 tok_type = LYXP_TOKEN_LITERAL;
2704
2705 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2706
2707 /* Number */
2708 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2709 if (expr[parsed + tok_len] == '.') {
2710 ++tok_len;
2711 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2712 }
2713 tok_type = LYXP_TOKEN_NUMBER;
2714
2715 } else if (expr[parsed] == '/') {
2716
2717 /* Operator '/', '//' */
2718 if (!strncmp(&expr[parsed], "//", 2)) {
2719 tok_len = 2;
2720 } else {
2721 tok_len = 1;
2722 }
2723 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2724
2725 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2726 || !strncmp(&expr[parsed], ">=", 2)) {
2727
2728 /* Operator '!=', '<=', '>=' */
2729 tok_len = 2;
2730 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2731
2732 } else if (expr[parsed] == '|') {
2733
2734 /* Operator '|' */
2735 tok_len = 1;
2736 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2737
2738 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2739
2740 /* Operator '+', '-' */
2741 tok_len = 1;
2742 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2743
2744 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2745
2746 /* Operator '=', '<', '>' */
2747 tok_len = 1;
2748 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2749
2750 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2751 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2752 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2753 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2754 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2755 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2756 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2757 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2758 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2759
2760 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2761 if (expr[parsed] == '*') {
2762 tok_len = 1;
2763 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2764
2765 } else if (!strncmp(&expr[parsed], "or", 2)) {
2766 tok_len = 2;
2767 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2768
2769 } else if (!strncmp(&expr[parsed], "and", 3)) {
2770 tok_len = 3;
2771 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2772
2773 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2774 tok_len = 3;
2775 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2776
2777 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002778 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2779 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 +01002780 goto error;
2781 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002782 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002783 goto error;
2784 }
2785 } else if (expr[parsed] == '*') {
2786
2787 /* NameTest '*' */
2788 tok_len = 1;
2789 tok_type = LYXP_TOKEN_NAMETEST;
2790
2791 } else {
2792
2793 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2794 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002795 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 +01002796 tok_len = ncname_len;
2797
2798 if (expr[parsed + tok_len] == ':') {
2799 ++tok_len;
2800 if (expr[parsed + tok_len] == '*') {
2801 ++tok_len;
2802 } else {
2803 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002804 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 +01002805 tok_len += ncname_len;
2806 }
2807 /* remove old flag to prevent ambiguities */
2808 prev_function_check = 0;
2809 tok_type = LYXP_TOKEN_NAMETEST;
2810 } else {
2811 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2812 prev_function_check = 1;
2813 tok_type = LYXP_TOKEN_NAMETEST;
2814 }
2815 }
2816
2817 /* store the token, move on to the next one */
2818 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2819 parsed += tok_len;
2820 while (is_xmlws(expr[parsed])) {
2821 ++parsed;
2822 }
2823
2824 } while (expr[parsed]);
2825
2826 /* prealloc repeat */
2827 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2828 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2829
Michal Vasko03ff5a72019-09-11 13:49:33 +02002830 /* fill repeat */
2831 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2832 if (ret->used > exp_idx) {
2833 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2834 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2835 &ret->expr[ret->tok_pos[exp_idx]]);
2836 goto error;
2837 }
2838
2839 print_expr_struct_debug(ret);
2840
Radek Krejcib1646a92018-11-02 16:08:26 +01002841 return ret;
2842
2843error:
2844 lyxp_expr_free(ctx, ret);
2845 return NULL;
2846}
2847
Michal Vasko03ff5a72019-09-11 13:49:33 +02002848/*
2849 * warn functions
2850 *
2851 * Warn functions check specific reasonable conditions for schema XPath
2852 * and print a warning if they are not satisfied.
2853 */
2854
2855/**
2856 * @brief Get the last-added schema node that is currently in the context.
2857 *
2858 * @param[in] set Set to search in.
2859 * @return Last-added schema context node, NULL if no node is in context.
2860 */
2861static struct lysc_node *
2862warn_get_scnode_in_ctx(struct lyxp_set *set)
2863{
2864 uint32_t i;
2865
2866 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2867 return NULL;
2868 }
2869
2870 i = set->used;
2871 do {
2872 --i;
2873 if (set->val.scnodes[i].in_ctx == 1) {
2874 /* if there are more, simply return the first found (last added) */
2875 return set->val.scnodes[i].scnode;
2876 }
2877 } while (i);
2878
2879 return NULL;
2880}
2881
2882/**
2883 * @brief Test whether a type is numeric - integer type or decimal64.
2884 *
2885 * @param[in] type Type to test.
2886 * @return 1 if numeric, 0 otherwise.
2887 */
2888static int
2889warn_is_numeric_type(struct lysc_type *type)
2890{
2891 struct lysc_type_union *uni;
2892 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002893 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002894
2895 switch (type->basetype) {
2896 case LY_TYPE_DEC64:
2897 case LY_TYPE_INT8:
2898 case LY_TYPE_UINT8:
2899 case LY_TYPE_INT16:
2900 case LY_TYPE_UINT16:
2901 case LY_TYPE_INT32:
2902 case LY_TYPE_UINT32:
2903 case LY_TYPE_INT64:
2904 case LY_TYPE_UINT64:
2905 return 1;
2906 case LY_TYPE_UNION:
2907 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002908 LY_ARRAY_FOR(uni->types, u) {
2909 ret = warn_is_numeric_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002910 if (ret) {
2911 /* found a suitable type */
2912 return 1;
2913 }
2914 }
2915 /* did not find any suitable type */
2916 return 0;
2917 case LY_TYPE_LEAFREF:
2918 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2919 default:
2920 return 0;
2921 }
2922}
2923
2924/**
2925 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2926 *
2927 * @param[in] type Type to test.
2928 * @return 1 if string, 0 otherwise.
2929 */
2930static int
2931warn_is_string_type(struct lysc_type *type)
2932{
2933 struct lysc_type_union *uni;
2934 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002935 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002936
2937 switch (type->basetype) {
2938 case LY_TYPE_BITS:
2939 case LY_TYPE_ENUM:
2940 case LY_TYPE_IDENT:
2941 case LY_TYPE_INST:
2942 case LY_TYPE_STRING:
2943 return 1;
2944 case LY_TYPE_UNION:
2945 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002946 LY_ARRAY_FOR(uni->types, u) {
2947 ret = warn_is_string_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002948 if (ret) {
2949 /* found a suitable type */
2950 return 1;
2951 }
2952 }
2953 /* did not find any suitable type */
2954 return 0;
2955 case LY_TYPE_LEAFREF:
2956 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2957 default:
2958 return 0;
2959 }
2960}
2961
2962/**
2963 * @brief Test whether a type is one specific type.
2964 *
2965 * @param[in] type Type to test.
2966 * @param[in] base Expected type.
2967 * @return 1 if it is, 0 otherwise.
2968 */
2969static int
2970warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2971{
2972 struct lysc_type_union *uni;
2973 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002974 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002975
2976 if (type->basetype == base) {
2977 return 1;
2978 } else if (type->basetype == LY_TYPE_UNION) {
2979 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002980 LY_ARRAY_FOR(uni->types, u) {
2981 ret = warn_is_specific_type(uni->types[u], base);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002982 if (ret) {
2983 /* found a suitable type */
2984 return 1;
2985 }
2986 }
2987 /* did not find any suitable type */
2988 return 0;
2989 } else if (type->basetype == LY_TYPE_LEAFREF) {
2990 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2991 }
2992
2993 return 0;
2994}
2995
2996/**
2997 * @brief Get next type of a (union) type.
2998 *
2999 * @param[in] type Base type.
3000 * @param[in] prev_type Previously returned type.
3001 * @return Next type or NULL.
3002 */
3003static struct lysc_type *
3004warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3005{
3006 struct lysc_type_union *uni;
3007 int found = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003008 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003009
3010 switch (type->basetype) {
3011 case LY_TYPE_UNION:
3012 uni = (struct lysc_type_union *)type;
3013 if (!prev_type) {
3014 return uni->types[0];
3015 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003016 LY_ARRAY_FOR(uni->types, u) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003017 if (found) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003018 return uni->types[u];
Michal Vasko03ff5a72019-09-11 13:49:33 +02003019 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003020 if (prev_type == uni->types[u]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003021 found = 1;
3022 }
3023 }
3024 return NULL;
3025 default:
3026 if (prev_type) {
3027 assert(type == prev_type);
3028 return NULL;
3029 } else {
3030 return type;
3031 }
3032 }
3033}
3034
3035/**
3036 * @brief Test whether 2 types have a common type.
3037 *
3038 * @param[in] type1 First type.
3039 * @param[in] type2 Second type.
3040 * @return 1 if they do, 0 otherwise.
3041 */
3042static int
3043warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3044{
3045 struct lysc_type *t1, *rt1, *t2, *rt2;
3046
3047 t1 = NULL;
3048 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3049 if (t1->basetype == LY_TYPE_LEAFREF) {
3050 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3051 } else {
3052 rt1 = t1;
3053 }
3054
3055 t2 = NULL;
3056 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3057 if (t2->basetype == LY_TYPE_LEAFREF) {
3058 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3059 } else {
3060 rt2 = t2;
3061 }
3062
3063 if (rt2->basetype == rt1->basetype) {
3064 /* match found */
3065 return 1;
3066 }
3067 }
3068 }
3069
3070 return 0;
3071}
3072
3073/**
3074 * @brief Check both operands of comparison operators.
3075 *
3076 * @param[in] ctx Context for errors.
3077 * @param[in] set1 First operand set.
3078 * @param[in] set2 Second operand set.
3079 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3080 * @param[in] expr Start of the expression to print with the warning.
3081 * @param[in] tok_pos Token position.
3082 */
3083static void
3084warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3085{
3086 struct lysc_node_leaf *node1, *node2;
3087 int leaves = 1, warning = 0;
3088
3089 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3090 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3091
3092 if (!node1 && !node2) {
3093 /* no node-sets involved, nothing to do */
3094 return;
3095 }
3096
3097 if (node1) {
3098 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3099 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3100 warning = 1;
3101 leaves = 0;
3102 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3103 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3104 warning = 1;
3105 }
3106 }
3107
3108 if (node2) {
3109 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3110 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3111 warning = 1;
3112 leaves = 0;
3113 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3114 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3115 warning = 1;
3116 }
3117 }
3118
3119 if (node1 && node2 && leaves && !numbers_only) {
3120 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3121 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3122 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3123 && !warn_is_equal_type(node1->type, node2->type))) {
3124 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3125 warning = 1;
3126 }
3127 }
3128
3129 if (warning) {
3130 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3131 }
3132}
3133
3134/**
3135 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3136 *
3137 * @param[in] exp Parsed XPath expression.
3138 * @param[in] set Set with the leaf/leaf-list.
3139 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3140 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3141 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3142 */
3143static void
3144warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3145{
3146 struct lysc_node *scnode;
3147 struct lysc_type *type;
3148 char *value;
3149 LY_ERR rc;
3150 struct ly_err_item *err = NULL;
3151
3152 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3153 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3154 /* check that the node can have the specified value */
3155 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3156 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3157 } else {
3158 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3159 }
3160 if (!value) {
3161 LOGMEM(set->ctx);
3162 return;
3163 }
3164
3165 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3166 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3167 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3168 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3169 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3170 exp->expr + exp->tok_pos[equal_exp]);
3171 }
3172
3173 type = ((struct lysc_node_leaf *)scnode)->type;
3174 if (type->basetype != LY_TYPE_IDENT) {
3175 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3176 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3177
3178 if (err) {
3179 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3180 ly_err_free(err);
3181 } else if (rc != LY_SUCCESS) {
3182 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3183 }
3184 if (rc != LY_SUCCESS) {
3185 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3186 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3187 exp->expr + exp->tok_pos[equal_exp]);
3188 }
3189 }
3190 free(value);
3191 }
3192}
3193
3194/*
3195 * XPath functions
3196 */
3197
3198/**
3199 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3200 * depending on whether the first node bit value from the second argument is set.
3201 *
3202 * @param[in] args Array of arguments.
3203 * @param[in] arg_count Count of elements in @p args.
3204 * @param[in,out] set Context and result set at the same time.
3205 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003206 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003207 */
3208static LY_ERR
3209xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3210{
3211 struct lyd_node_term *leaf;
3212 struct lysc_node_leaf *sleaf;
3213 struct lysc_type_bits *bits;
3214 LY_ERR rc = LY_SUCCESS;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003215 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003216
3217 if (options & LYXP_SCNODE_ALL) {
3218 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3219 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003220 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3221 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 +02003222 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3223 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003224 }
3225
3226 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3227 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3228 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 +02003229 } else if (!warn_is_string_type(sleaf->type)) {
3230 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003231 }
3232 }
3233 set_scnode_clear_ctx(set);
3234 return rc;
3235 }
3236
3237 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3238 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)");
3239 return LY_EVALID;
3240 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003241 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003242 LY_CHECK_RET(rc);
3243
3244 set_fill_boolean(set, 0);
3245 if (args[0]->type == LYXP_SET_NODE_SET) {
3246 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3247 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3248 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3249 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003250 LY_ARRAY_FOR(bits->bits, u) {
3251 if (!strcmp(bits->bits[u].name, args[1]->val.str)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003252 set_fill_boolean(set, 1);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258
3259 return LY_SUCCESS;
3260}
3261
3262/**
3263 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3264 * with the argument converted to boolean.
3265 *
3266 * @param[in] args Array of arguments.
3267 * @param[in] arg_count Count of elements in @p args.
3268 * @param[in,out] set Context and result set at the same time.
3269 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003270 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003271 */
3272static LY_ERR
3273xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3274{
3275 LY_ERR rc;
3276
3277 if (options & LYXP_SCNODE_ALL) {
3278 set_scnode_clear_ctx(set);
3279 return LY_SUCCESS;
3280 }
3281
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003282 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003283 LY_CHECK_RET(rc);
3284 set_fill_set(set, args[0]);
3285
3286 return LY_SUCCESS;
3287}
3288
3289/**
3290 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3291 * with the first argument rounded up to the nearest integer.
3292 *
3293 * @param[in] args Array of arguments.
3294 * @param[in] arg_count Count of elements in @p args.
3295 * @param[in,out] set Context and result set at the same time.
3296 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003297 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003298 */
3299static LY_ERR
3300xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3301{
3302 struct lysc_node_leaf *sleaf;
3303 LY_ERR rc = LY_SUCCESS;
3304
3305 if (options & LYXP_SCNODE_ALL) {
3306 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3307 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003308 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3309 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 +02003310 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3311 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003312 }
3313 set_scnode_clear_ctx(set);
3314 return rc;
3315 }
3316
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003317 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003318 LY_CHECK_RET(rc);
3319 if ((long long)args[0]->val.num != args[0]->val.num) {
3320 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3321 } else {
3322 set_fill_number(set, args[0]->val.num);
3323 }
3324
3325 return LY_SUCCESS;
3326}
3327
3328/**
3329 * @brief Execute the XPath concat(string, string, string*) function.
3330 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3331 *
3332 * @param[in] args Array of arguments.
3333 * @param[in] arg_count Count of elements in @p args.
3334 * @param[in,out] set Context and result set at the same time.
3335 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003336 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003337 */
3338static LY_ERR
3339xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3340{
3341 uint16_t i;
3342 char *str = NULL;
3343 size_t used = 1;
3344 LY_ERR rc = LY_SUCCESS;
3345 struct lysc_node_leaf *sleaf;
3346
3347 if (options & LYXP_SCNODE_ALL) {
3348 for (i = 0; i < arg_count; ++i) {
3349 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3350 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3351 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3352 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003353 } else if (!warn_is_string_type(sleaf->type)) {
3354 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 +02003355 }
3356 }
3357 }
3358 set_scnode_clear_ctx(set);
3359 return rc;
3360 }
3361
3362 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003363 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003364 if (rc != LY_SUCCESS) {
3365 free(str);
3366 return rc;
3367 }
3368
3369 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3370 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3371 strcpy(str + used - 1, args[i]->val.str);
3372 used += strlen(args[i]->val.str);
3373 }
3374
3375 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003376 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003377 set->type = LYXP_SET_STRING;
3378 set->val.str = str;
3379
3380 return LY_SUCCESS;
3381}
3382
3383/**
3384 * @brief Execute the XPath contains(string, string) function.
3385 * Returns LYXP_SET_BOOLEAN whether the second argument can
3386 * be found in the first or not.
3387 *
3388 * @param[in] args Array of arguments.
3389 * @param[in] arg_count Count of elements in @p args.
3390 * @param[in,out] set Context and result set at the same time.
3391 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003392 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003393 */
3394static LY_ERR
3395xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3396{
3397 struct lysc_node_leaf *sleaf;
3398 LY_ERR rc = LY_SUCCESS;
3399
3400 if (options & LYXP_SCNODE_ALL) {
3401 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3402 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3403 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 +02003404 } else if (!warn_is_string_type(sleaf->type)) {
3405 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003406 }
3407 }
3408
3409 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3410 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3411 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 +02003412 } else if (!warn_is_string_type(sleaf->type)) {
3413 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003414 }
3415 }
3416 set_scnode_clear_ctx(set);
3417 return rc;
3418 }
3419
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003420 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003421 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003422 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003423 LY_CHECK_RET(rc);
3424
3425 if (strstr(args[0]->val.str, args[1]->val.str)) {
3426 set_fill_boolean(set, 1);
3427 } else {
3428 set_fill_boolean(set, 0);
3429 }
3430
3431 return LY_SUCCESS;
3432}
3433
3434/**
3435 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3436 * with the size of the node-set from the argument.
3437 *
3438 * @param[in] args Array of arguments.
3439 * @param[in] arg_count Count of elements in @p args.
3440 * @param[in,out] set Context and result set at the same time.
3441 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003442 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003443 */
3444static LY_ERR
3445xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3446{
3447 struct lysc_node *scnode = NULL;
3448 LY_ERR rc = LY_SUCCESS;
3449
3450 if (options & LYXP_SCNODE_ALL) {
3451 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3452 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003453 }
3454 set_scnode_clear_ctx(set);
3455 return rc;
3456 }
3457
3458 if (args[0]->type == LYXP_SET_EMPTY) {
3459 set_fill_number(set, 0);
3460 return LY_SUCCESS;
3461 }
3462
3463 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 Vasko5e0e6eb2019-11-06 15:47:50 +01003495 lyxp_set_cast(set, LYXP_SET_EMPTY);
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
3549 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3550 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 Vasko5e0e6eb2019-11-06 15:47:50 +01003554 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003555 if (args[0]->type != LYXP_SET_EMPTY) {
3556 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
3636 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3637 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3638 return LY_EVALID;
3639 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003640 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003641 LY_CHECK_RET(rc);
3642
3643 set_fill_boolean(set, 0);
3644 if (args[0]->type != LYXP_SET_EMPTY) {
3645 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,
Michal Vaskof03ed032020-03-04 13:31:44 +01003653 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003654 if (err) {
3655 ly_err_print(err);
3656 ly_err_free(err);
3657 }
3658 LY_CHECK_RET(rc);
3659
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003660 LY_ARRAY_FOR(data.ident->derived, u) {
3661 if (data.ident->derived[u] == leaf->value.ident) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003662 set_fill_boolean(set, 1);
3663 found = 1;
3664 break;
3665 }
3666 }
3667 if (found) {
3668 break;
3669 }
3670 }
3671 }
3672 }
3673
3674 return LY_SUCCESS;
3675}
3676
3677/**
3678 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3679 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3680 * the second argument identity.
3681 *
3682 * @param[in] args Array of arguments.
3683 * @param[in] arg_count Count of elements in @p args.
3684 * @param[in,out] set Context and result set at the same time.
3685 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003686 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003687 */
3688static LY_ERR
3689xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3690{
3691 uint16_t i;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003692 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003693 struct lyd_node_term *leaf;
3694 struct lysc_node_leaf *sleaf;
3695 struct lyd_value data = {0};
3696 struct ly_err_item *err = NULL;
3697 LY_ERR rc = LY_SUCCESS;
3698 int found;
3699
3700 if (options & LYXP_SCNODE_ALL) {
3701 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3702 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003703 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3704 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 +02003705 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3706 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003707 }
3708
3709 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3710 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3711 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 +02003712 } else if (!warn_is_string_type(sleaf->type)) {
3713 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003714 }
3715 }
3716 set_scnode_clear_ctx(set);
3717 return rc;
3718 }
3719
3720 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3721 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from-or-self(node-set, string)");
3722 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);
3728 if (args[0]->type != LYXP_SET_EMPTY) {
3729 found = 0;
3730 for (i = 0; i < args[0]->used; ++i) {
3731 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3732 sleaf = (struct lysc_node_leaf *)leaf->schema;
3733 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3734 /* store args[1] into ident */
3735 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3736 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
Michal Vaskof03ed032020-03-04 13:31:44 +01003737 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003738 if (err) {
3739 ly_err_print(err);
3740 ly_err_free(err);
3741 }
3742 LY_CHECK_RET(rc);
3743
3744 if (data.ident == leaf->value.ident) {
3745 set_fill_boolean(set, 1);
3746 break;
3747 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003748 LY_ARRAY_FOR(data.ident->derived, u) {
3749 if (data.ident->derived[u] == leaf->value.ident) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003750 set_fill_boolean(set, 1);
3751 found = 1;
3752 break;
3753 }
3754 }
3755 if (found) {
3756 break;
3757 }
3758 }
3759 }
3760 }
3761
3762 return LY_SUCCESS;
3763}
3764
3765/**
3766 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3767 * with the integer value of the first node's enum value, otherwise NaN.
3768 *
3769 * @param[in] args Array of arguments.
3770 * @param[in] arg_count Count of elements in @p args.
3771 * @param[in,out] set Context and result set at the same time.
3772 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003773 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003774 */
3775static LY_ERR
3776xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3777{
3778 struct lyd_node_term *leaf;
3779 struct lysc_node_leaf *sleaf;
3780 LY_ERR rc = LY_SUCCESS;
3781
3782 if (options & LYXP_SCNODE_ALL) {
3783 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3784 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003785 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3786 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 +02003787 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3788 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003789 }
3790 set_scnode_clear_ctx(set);
3791 return rc;
3792 }
3793
3794 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3795 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3796 return LY_EVALID;
3797 }
3798
3799 set_fill_number(set, NAN);
3800 if (args[0]->type == LYXP_SET_NODE_SET) {
3801 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3802 sleaf = (struct lysc_node_leaf *)leaf->schema;
3803 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3804 set_fill_number(set, leaf->value.enum_item->value);
3805 }
3806 }
3807
3808 return LY_SUCCESS;
3809}
3810
3811/**
3812 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3813 * with false value.
3814 *
3815 * @param[in] args Array of arguments.
3816 * @param[in] arg_count Count of elements in @p args.
3817 * @param[in,out] set Context and result set at the same time.
3818 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003819 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003820 */
3821static LY_ERR
3822xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3823{
3824 if (options & LYXP_SCNODE_ALL) {
3825 set_scnode_clear_ctx(set);
3826 return LY_SUCCESS;
3827 }
3828
3829 set_fill_boolean(set, 0);
3830 return LY_SUCCESS;
3831}
3832
3833/**
3834 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3835 * with the first argument floored (truncated).
3836 *
3837 * @param[in] args Array of arguments.
3838 * @param[in] arg_count Count of elements in @p args.
3839 * @param[in,out] set Context and result set at the same time.
3840 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003841 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003842 */
3843static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003844xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003845{
3846 LY_ERR rc;
3847
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003848 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003849 LY_CHECK_RET(rc);
3850 if (isfinite(args[0]->val.num)) {
3851 set_fill_number(set, (long long)args[0]->val.num);
3852 }
3853
3854 return LY_SUCCESS;
3855}
3856
3857/**
3858 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3859 * whether the language of the text matches the one from the argument.
3860 *
3861 * @param[in] args Array of arguments.
3862 * @param[in] arg_count Count of elements in @p args.
3863 * @param[in,out] set Context and result set at the same time.
3864 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003865 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003866 */
3867static LY_ERR
3868xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3869{
3870 const struct lyd_node *node;
3871 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01003872 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003873 const char *val;
3874 int i, dynamic;
3875 LY_ERR rc = LY_SUCCESS;
3876
3877 if (options & LYXP_SCNODE_ALL) {
3878 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3879 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3880 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 +02003881 } else if (!warn_is_string_type(sleaf->type)) {
3882 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003883 }
3884 }
3885 set_scnode_clear_ctx(set);
3886 return rc;
3887 }
3888
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003889 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003890 LY_CHECK_RET(rc);
3891
3892 if (set->type == LYXP_SET_EMPTY) {
3893 set_fill_boolean(set, 0);
3894 return LY_SUCCESS;
3895 }
3896 if (set->type != LYXP_SET_NODE_SET) {
3897 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3898 return LY_EVALID;
3899 }
3900
3901 switch (set->val.nodes[0].type) {
3902 case LYXP_NODE_ELEM:
3903 case LYXP_NODE_TEXT:
3904 node = set->val.nodes[0].node;
3905 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01003906 case LYXP_NODE_META:
3907 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003908 break;
3909 default:
3910 /* nothing to do with roots */
3911 set_fill_boolean(set, 0);
3912 return LY_SUCCESS;
3913 }
3914
Michal Vasko9f96a052020-03-10 09:41:45 +01003915 /* find lang metadata */
Michal Vasko03ff5a72019-09-11 13:49:33 +02003916 for (; node; node = (struct lyd_node *)node->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01003917 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003918 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01003919 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003920 break;
3921 }
3922 }
3923
Michal Vasko9f96a052020-03-10 09:41:45 +01003924 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003925 break;
3926 }
3927 }
3928
3929 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01003930 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003931 set_fill_boolean(set, 0);
3932 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01003933 val = lyd_meta2str(meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003934 for (i = 0; args[0]->val.str[i]; ++i) {
3935 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3936 set_fill_boolean(set, 0);
3937 break;
3938 }
3939 }
3940 if (!args[0]->val.str[i]) {
3941 if (!val[i] || (val[i] == '-')) {
3942 set_fill_boolean(set, 1);
3943 } else {
3944 set_fill_boolean(set, 0);
3945 }
3946 }
3947 if (dynamic) {
3948 free((char *)val);
3949 }
3950 }
3951
3952 return LY_SUCCESS;
3953}
3954
3955/**
3956 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3957 * with the context size.
3958 *
3959 * @param[in] args Array of arguments.
3960 * @param[in] arg_count Count of elements in @p args.
3961 * @param[in,out] set Context and result set at the same time.
3962 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003963 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003964 */
3965static LY_ERR
3966xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3967{
3968 if (options & LYXP_SCNODE_ALL) {
3969 set_scnode_clear_ctx(set);
3970 return LY_SUCCESS;
3971 }
3972
3973 if (set->type == LYXP_SET_EMPTY) {
3974 set_fill_number(set, 0);
3975 return LY_SUCCESS;
3976 }
3977 if (set->type != LYXP_SET_NODE_SET) {
3978 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3979 return LY_EVALID;
3980 }
3981
3982 set_fill_number(set, set->ctx_size);
3983 return LY_SUCCESS;
3984}
3985
3986/**
3987 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3988 * with the node name without namespace from the argument or the context.
3989 *
3990 * @param[in] args Array of arguments.
3991 * @param[in] arg_count Count of elements in @p args.
3992 * @param[in,out] set Context and result set at the same time.
3993 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003994 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003995 */
3996static LY_ERR
3997xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3998{
3999 struct lyxp_set_node *item;
4000 /* suppress unused variable warning */
4001 (void)options;
4002
4003 if (options & LYXP_SCNODE_ALL) {
4004 set_scnode_clear_ctx(set);
4005 return LY_SUCCESS;
4006 }
4007
4008 if (arg_count) {
4009 if (args[0]->type == LYXP_SET_EMPTY) {
4010 set_fill_string(set, "", 0);
4011 return LY_SUCCESS;
4012 }
4013 if (args[0]->type != LYXP_SET_NODE_SET) {
4014 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4015 return LY_EVALID;
4016 }
4017
4018 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004019 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004020
4021 item = &args[0]->val.nodes[0];
4022 } else {
4023 if (set->type == LYXP_SET_EMPTY) {
4024 set_fill_string(set, "", 0);
4025 return LY_SUCCESS;
4026 }
4027 if (set->type != LYXP_SET_NODE_SET) {
4028 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4029 return LY_EVALID;
4030 }
4031
4032 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004033 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004034
4035 item = &set->val.nodes[0];
4036 }
4037
4038 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004039 case LYXP_NODE_NONE:
4040 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004041 case LYXP_NODE_ROOT:
4042 case LYXP_NODE_ROOT_CONFIG:
4043 case LYXP_NODE_TEXT:
4044 set_fill_string(set, "", 0);
4045 break;
4046 case LYXP_NODE_ELEM:
4047 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4048 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004049 case LYXP_NODE_META:
4050 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004051 break;
4052 }
4053
4054 return LY_SUCCESS;
4055}
4056
4057/**
4058 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4059 * with the node name fully qualified (with namespace) from the argument or the context.
4060 *
4061 * @param[in] args Array of arguments.
4062 * @param[in] arg_count Count of elements in @p args.
4063 * @param[in,out] set Context and result set at the same time.
4064 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004065 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004066 */
4067static LY_ERR
4068xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4069{
4070 struct lyxp_set_node *item;
4071 struct lys_module *mod;
4072 char *str;
4073 const char *name;
4074 int rc;
4075
4076 if (options & LYXP_SCNODE_ALL) {
4077 set_scnode_clear_ctx(set);
4078 return LY_SUCCESS;
4079 }
4080
4081 if (arg_count) {
4082 if (args[0]->type == LYXP_SET_EMPTY) {
4083 set_fill_string(set, "", 0);
4084 return LY_SUCCESS;
4085 }
4086 if (args[0]->type != LYXP_SET_NODE_SET) {
4087 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4088 return LY_EVALID;
4089 }
4090
4091 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004092 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004093
4094 item = &args[0]->val.nodes[0];
4095 } else {
4096 if (set->type == LYXP_SET_EMPTY) {
4097 set_fill_string(set, "", 0);
4098 return LY_SUCCESS;
4099 }
4100 if (set->type != LYXP_SET_NODE_SET) {
4101 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4102 return LY_EVALID;
4103 }
4104
4105 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004106 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004107
4108 item = &set->val.nodes[0];
4109 }
4110
4111 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004112 case LYXP_NODE_NONE:
4113 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004114 case LYXP_NODE_ROOT:
4115 case LYXP_NODE_ROOT_CONFIG:
4116 case LYXP_NODE_TEXT:
4117 mod = NULL;
4118 name = NULL;
4119 break;
4120 case LYXP_NODE_ELEM:
4121 mod = item->node->schema->module;
4122 name = item->node->schema->name;
4123 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004124 case LYXP_NODE_META:
4125 mod = ((struct lyd_meta *)item->node)->annotation->module;
4126 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004127 break;
4128 }
4129
4130 if (mod && name) {
4131 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01004132 case LYD_SCHEMA:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004133 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4134 break;
4135 case LYD_JSON:
4136 rc = asprintf(&str, "%s:%s", mod->name, name);
4137 break;
Michal Vasko52927e22020-03-16 17:26:14 +01004138 case LYD_XML:
Michal Vasko9409ef62019-09-12 11:47:17 +02004139 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004140 }
4141 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4142 set_fill_string(set, str, strlen(str));
4143 free(str);
4144 } else {
4145 set_fill_string(set, "", 0);
4146 }
4147
4148 return LY_SUCCESS;
4149}
4150
4151/**
4152 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4153 * with the namespace of the node from the argument or the context.
4154 *
4155 * @param[in] args Array of arguments.
4156 * @param[in] arg_count Count of elements in @p args.
4157 * @param[in,out] set Context and result set at the same time.
4158 * @param[in] options XPath options.
4159 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4160 */
4161static LY_ERR
4162xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4163{
4164 struct lyxp_set_node *item;
4165 struct lys_module *mod;
4166 /* suppress unused variable warning */
4167 (void)options;
4168
4169 if (options & LYXP_SCNODE_ALL) {
4170 set_scnode_clear_ctx(set);
4171 return LY_SUCCESS;
4172 }
4173
4174 if (arg_count) {
4175 if (args[0]->type == LYXP_SET_EMPTY) {
4176 set_fill_string(set, "", 0);
4177 return LY_SUCCESS;
4178 }
4179 if (args[0]->type != LYXP_SET_NODE_SET) {
4180 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4181 return LY_EVALID;
4182 }
4183
4184 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004185 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004186
4187 item = &args[0]->val.nodes[0];
4188 } else {
4189 if (set->type == LYXP_SET_EMPTY) {
4190 set_fill_string(set, "", 0);
4191 return LY_SUCCESS;
4192 }
4193 if (set->type != LYXP_SET_NODE_SET) {
4194 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4195 return LY_EVALID;
4196 }
4197
4198 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004199 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004200
4201 item = &set->val.nodes[0];
4202 }
4203
4204 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004205 case LYXP_NODE_NONE:
4206 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004207 case LYXP_NODE_ROOT:
4208 case LYXP_NODE_ROOT_CONFIG:
4209 case LYXP_NODE_TEXT:
4210 set_fill_string(set, "", 0);
4211 break;
4212 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004213 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004214 if (item->type == LYXP_NODE_ELEM) {
4215 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004216 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004217 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004218 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004219 }
4220
4221 set_fill_string(set, mod->ns, strlen(mod->ns));
4222 break;
4223 }
4224
4225 return LY_SUCCESS;
4226}
4227
4228/**
4229 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4230 * with only nodes from the context. In practice it either leaves the context
4231 * as it is or returns an empty node set.
4232 *
4233 * @param[in] args Array of arguments.
4234 * @param[in] arg_count Count of elements in @p args.
4235 * @param[in,out] set Context and result set at the same time.
4236 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004237 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004238 */
4239static LY_ERR
4240xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4241{
4242 if (options & LYXP_SCNODE_ALL) {
4243 set_scnode_clear_ctx(set);
4244 return LY_SUCCESS;
4245 }
4246
4247 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004248 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004249 }
4250 return LY_SUCCESS;
4251}
4252
4253/**
4254 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4255 * with normalized value (no leading, trailing, double white spaces) of the node
4256 * from the argument or the context.
4257 *
4258 * @param[in] args Array of arguments.
4259 * @param[in] arg_count Count of elements in @p args.
4260 * @param[in,out] set Context and result set at the same time.
4261 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004262 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004263 */
4264static LY_ERR
4265xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4266{
4267 uint16_t i, new_used;
4268 char *new;
4269 int have_spaces = 0, space_before = 0;
4270 struct lysc_node_leaf *sleaf;
4271 LY_ERR rc = LY_SUCCESS;
4272
4273 if (options & LYXP_SCNODE_ALL) {
4274 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4275 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4276 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 +02004277 } else if (!warn_is_string_type(sleaf->type)) {
4278 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004279 }
4280 }
4281 set_scnode_clear_ctx(set);
4282 return rc;
4283 }
4284
4285 if (arg_count) {
4286 set_fill_set(set, args[0]);
4287 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004288 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004289 LY_CHECK_RET(rc);
4290
4291 /* is there any normalization necessary? */
4292 for (i = 0; set->val.str[i]; ++i) {
4293 if (is_xmlws(set->val.str[i])) {
4294 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4295 have_spaces = 1;
4296 break;
4297 }
4298 space_before = 1;
4299 } else {
4300 space_before = 0;
4301 }
4302 }
4303
4304 /* yep, there is */
4305 if (have_spaces) {
4306 /* it's enough, at least one character will go, makes space for ending '\0' */
4307 new = malloc(strlen(set->val.str) * sizeof(char));
4308 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4309 new_used = 0;
4310
4311 space_before = 0;
4312 for (i = 0; set->val.str[i]; ++i) {
4313 if (is_xmlws(set->val.str[i])) {
4314 if ((i == 0) || space_before) {
4315 space_before = 1;
4316 continue;
4317 } else {
4318 space_before = 1;
4319 }
4320 } else {
4321 space_before = 0;
4322 }
4323
4324 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4325 ++new_used;
4326 }
4327
4328 /* at worst there is one trailing space now */
4329 if (new_used && is_xmlws(new[new_used - 1])) {
4330 --new_used;
4331 }
4332
4333 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4334 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4335 new[new_used] = '\0';
4336
4337 free(set->val.str);
4338 set->val.str = new;
4339 }
4340
4341 return LY_SUCCESS;
4342}
4343
4344/**
4345 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4346 * with the argument converted to boolean and logically inverted.
4347 *
4348 * @param[in] args Array of arguments.
4349 * @param[in] arg_count Count of elements in @p args.
4350 * @param[in,out] set Context and result set at the same time.
4351 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004352 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004353 */
4354static LY_ERR
4355xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4356{
4357 if (options & LYXP_SCNODE_ALL) {
4358 set_scnode_clear_ctx(set);
4359 return LY_SUCCESS;
4360 }
4361
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004362 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004363 if (args[0]->val.bool) {
4364 set_fill_boolean(set, 0);
4365 } else {
4366 set_fill_boolean(set, 1);
4367 }
4368
4369 return LY_SUCCESS;
4370}
4371
4372/**
4373 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4374 * with the number representation of either the argument or the context.
4375 *
4376 * @param[in] args Array of arguments.
4377 * @param[in] arg_count Count of elements in @p args.
4378 * @param[in,out] set Context and result set at the same time.
4379 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004380 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004381 */
4382static LY_ERR
4383xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4384{
4385 LY_ERR rc;
4386
4387 if (options & LYXP_SCNODE_ALL) {
4388 set_scnode_clear_ctx(set);
4389 return LY_SUCCESS;
4390 }
4391
4392 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004393 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004394 LY_CHECK_RET(rc);
4395 set_fill_set(set, args[0]);
4396 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004397 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004398 LY_CHECK_RET(rc);
4399 }
4400
4401 return LY_SUCCESS;
4402}
4403
4404/**
4405 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4406 * with the context position.
4407 *
4408 * @param[in] args Array of arguments.
4409 * @param[in] arg_count Count of elements in @p args.
4410 * @param[in,out] set Context and result set at the same time.
4411 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004412 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004413 */
4414static LY_ERR
4415xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4416{
4417 if (options & LYXP_SCNODE_ALL) {
4418 set_scnode_clear_ctx(set);
4419 return LY_SUCCESS;
4420 }
4421
4422 if (set->type == LYXP_SET_EMPTY) {
4423 set_fill_number(set, 0);
4424 return LY_SUCCESS;
4425 }
4426 if (set->type != LYXP_SET_NODE_SET) {
4427 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4428 return LY_EVALID;
4429 }
4430
4431 set_fill_number(set, set->ctx_pos);
4432
4433 /* UNUSED in 'Release' build type */
4434 (void)options;
4435 return LY_SUCCESS;
4436}
4437
4438/**
4439 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4440 * depending on whether the second argument regex matches the first argument string. For details refer to
4441 * YANG 1.1 RFC section 10.2.1.
4442 *
4443 * @param[in] args Array of arguments.
4444 * @param[in] arg_count Count of elements in @p args.
4445 * @param[in,out] set Context and result set at the same time.
4446 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004447 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004448 */
4449static LY_ERR
4450xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4451{
4452 struct lysc_pattern **patterns = NULL, **pattern;
4453 struct lysc_node_leaf *sleaf;
4454 char *path;
4455 LY_ERR rc = LY_SUCCESS;
4456 struct ly_err_item *err;
4457
4458 if (options & LYXP_SCNODE_ALL) {
4459 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4460 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4461 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 +02004462 } else if (!warn_is_string_type(sleaf->type)) {
4463 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004464 }
4465 }
4466
4467 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4468 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4469 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 +02004470 } else if (!warn_is_string_type(sleaf->type)) {
4471 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004472 }
4473 }
4474 set_scnode_clear_ctx(set);
4475 return rc;
4476 }
4477
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004478 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004479 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004480 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004481 LY_CHECK_RET(rc);
4482
4483 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4484 *pattern = malloc(sizeof **pattern);
4485 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4486 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4487 free(path);
4488 if (rc != LY_SUCCESS) {
4489 LY_ARRAY_FREE(patterns);
4490 return rc;
4491 }
4492
4493 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4494 pcre2_code_free((*pattern)->code);
4495 free(*pattern);
4496 LY_ARRAY_FREE(patterns);
4497 if (rc && (rc != LY_EVALID)) {
4498 ly_err_print(err);
4499 ly_err_free(err);
4500 return rc;
4501 }
4502
4503 if (rc == LY_EVALID) {
4504 ly_err_free(err);
4505 set_fill_boolean(set, 0);
4506 } else {
4507 set_fill_boolean(set, 1);
4508 }
4509
4510 return LY_SUCCESS;
4511}
4512
4513/**
4514 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4515 * with the rounded first argument. For details refer to
4516 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4517 *
4518 * @param[in] args Array of arguments.
4519 * @param[in] arg_count Count of elements in @p args.
4520 * @param[in,out] set Context and result set at the same time.
4521 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004522 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004523 */
4524static LY_ERR
4525xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4526{
4527 struct lysc_node_leaf *sleaf;
4528 LY_ERR rc = LY_SUCCESS;
4529
4530 if (options & LYXP_SCNODE_ALL) {
4531 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4532 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004533 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4534 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 +02004535 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4536 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004537 }
4538 set_scnode_clear_ctx(set);
4539 return rc;
4540 }
4541
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004542 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004543 LY_CHECK_RET(rc);
4544
4545 /* cover only the cases where floor can't be used */
4546 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4547 set_fill_number(set, -0.0f);
4548 } else {
4549 args[0]->val.num += 0.5;
4550 rc = xpath_floor(args, 1, args[0], options);
4551 LY_CHECK_RET(rc);
4552 set_fill_number(set, args[0]->val.num);
4553 }
4554
4555 return LY_SUCCESS;
4556}
4557
4558/**
4559 * @brief Execute the XPath starts-with(string, string) function.
4560 * Returns LYXP_SET_BOOLEAN whether the second argument is
4561 * the prefix of the first or not.
4562 *
4563 * @param[in] args Array of arguments.
4564 * @param[in] arg_count Count of elements in @p args.
4565 * @param[in,out] set Context and result set at the same time.
4566 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004567 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004568 */
4569static LY_ERR
4570xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4571{
4572 struct lysc_node_leaf *sleaf;
4573 LY_ERR rc = LY_SUCCESS;
4574
4575 if (options & LYXP_SCNODE_ALL) {
4576 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4577 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4578 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 +02004579 } else if (!warn_is_string_type(sleaf->type)) {
4580 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004581 }
4582 }
4583
4584 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4585 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4586 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 +02004587 } else if (!warn_is_string_type(sleaf->type)) {
4588 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004589 }
4590 }
4591 set_scnode_clear_ctx(set);
4592 return rc;
4593 }
4594
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004595 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004596 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004597 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004598 LY_CHECK_RET(rc);
4599
4600 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4601 set_fill_boolean(set, 0);
4602 } else {
4603 set_fill_boolean(set, 1);
4604 }
4605
4606 return LY_SUCCESS;
4607}
4608
4609/**
4610 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4611 * with the string representation of either the argument or the context.
4612 *
4613 * @param[in] args Array of arguments.
4614 * @param[in] arg_count Count of elements in @p args.
4615 * @param[in,out] set Context and result set at the same time.
4616 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004617 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004618 */
4619static LY_ERR
4620xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4621{
4622 LY_ERR rc;
4623
4624 if (options & LYXP_SCNODE_ALL) {
4625 set_scnode_clear_ctx(set);
4626 return LY_SUCCESS;
4627 }
4628
4629 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004630 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004631 LY_CHECK_RET(rc);
4632 set_fill_set(set, args[0]);
4633 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004634 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004635 LY_CHECK_RET(rc);
4636 }
4637
4638 return LY_SUCCESS;
4639}
4640
4641/**
4642 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4643 * with the length of the string in either the argument or the context.
4644 *
4645 * @param[in] args Array of arguments.
4646 * @param[in] arg_count Count of elements in @p args.
4647 * @param[in,out] set Context and result set at the same time.
4648 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004649 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004650 */
4651static LY_ERR
4652xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4653{
4654 struct lysc_node_leaf *sleaf;
4655 LY_ERR rc = LY_SUCCESS;
4656
4657 if (options & LYXP_SCNODE_ALL) {
4658 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4659 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4660 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 +02004661 } else if (!warn_is_string_type(sleaf->type)) {
4662 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004663 }
4664 }
4665 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4666 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4667 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 +02004668 } else if (!warn_is_string_type(sleaf->type)) {
4669 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004670 }
4671 }
4672 set_scnode_clear_ctx(set);
4673 return rc;
4674 }
4675
4676 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004677 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004678 LY_CHECK_RET(rc);
4679 set_fill_number(set, strlen(args[0]->val.str));
4680 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004681 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004682 LY_CHECK_RET(rc);
4683 set_fill_number(set, strlen(set->val.str));
4684 }
4685
4686 return LY_SUCCESS;
4687}
4688
4689/**
4690 * @brief Execute the XPath substring(string, number, number?) function.
4691 * Returns LYXP_SET_STRING substring of the first argument starting
4692 * on the second argument index ending on the third argument index,
4693 * indexed from 1. For exact definition refer to
4694 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4695 *
4696 * @param[in] args Array of arguments.
4697 * @param[in] arg_count Count of elements in @p args.
4698 * @param[in,out] set Context and result set at the same time.
4699 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004700 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004701 */
4702static LY_ERR
4703xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4704{
4705 int start, len;
4706 uint16_t str_start, str_len, pos;
4707 struct lysc_node_leaf *sleaf;
4708 LY_ERR rc = LY_SUCCESS;
4709
4710 if (options & LYXP_SCNODE_ALL) {
4711 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4712 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4713 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 +02004714 } else if (!warn_is_string_type(sleaf->type)) {
4715 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004716 }
4717 }
4718
4719 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4720 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4721 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 +02004722 } else if (!warn_is_numeric_type(sleaf->type)) {
4723 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004724 }
4725 }
4726
4727 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4728 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4729 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4730 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 +02004731 } else if (!warn_is_numeric_type(sleaf->type)) {
4732 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004733 }
4734 }
4735 set_scnode_clear_ctx(set);
4736 return rc;
4737 }
4738
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004739 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004740 LY_CHECK_RET(rc);
4741
4742 /* start */
4743 if (xpath_round(&args[1], 1, args[1], options)) {
4744 return -1;
4745 }
4746 if (isfinite(args[1]->val.num)) {
4747 start = args[1]->val.num - 1;
4748 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4749 start = INT_MIN;
4750 } else {
4751 start = INT_MAX;
4752 }
4753
4754 /* len */
4755 if (arg_count == 3) {
4756 rc = xpath_round(&args[2], 1, args[2], options);
4757 LY_CHECK_RET(rc);
4758 if (isfinite(args[2]->val.num)) {
4759 len = args[2]->val.num;
4760 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4761 len = 0;
4762 } else {
4763 len = INT_MAX;
4764 }
4765 } else {
4766 len = INT_MAX;
4767 }
4768
4769 /* find matching character positions */
4770 str_start = 0;
4771 str_len = 0;
4772 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4773 if (pos < start) {
4774 ++str_start;
4775 } else if (pos < start + len) {
4776 ++str_len;
4777 } else {
4778 break;
4779 }
4780 }
4781
4782 set_fill_string(set, args[0]->val.str + str_start, str_len);
4783 return LY_SUCCESS;
4784}
4785
4786/**
4787 * @brief Execute the XPath substring-after(string, string) function.
4788 * Returns LYXP_SET_STRING with the string succeeding the occurance
4789 * of the second argument in the first or an empty string.
4790 *
4791 * @param[in] args Array of arguments.
4792 * @param[in] arg_count Count of elements in @p args.
4793 * @param[in,out] set Context and result set at the same time.
4794 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004795 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004796 */
4797static LY_ERR
4798xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4799{
4800 char *ptr;
4801 struct lysc_node_leaf *sleaf;
4802 LY_ERR rc = LY_SUCCESS;
4803
4804 if (options & LYXP_SCNODE_ALL) {
4805 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4806 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4807 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 +02004808 } else if (!warn_is_string_type(sleaf->type)) {
4809 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004810 }
4811 }
4812
4813 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4814 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4815 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 +02004816 } else if (!warn_is_string_type(sleaf->type)) {
4817 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004818 }
4819 }
4820 set_scnode_clear_ctx(set);
4821 return rc;
4822 }
4823
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004824 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004825 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004826 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004827 LY_CHECK_RET(rc);
4828
4829 ptr = strstr(args[0]->val.str, args[1]->val.str);
4830 if (ptr) {
4831 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4832 } else {
4833 set_fill_string(set, "", 0);
4834 }
4835
4836 return LY_SUCCESS;
4837}
4838
4839/**
4840 * @brief Execute the XPath substring-before(string, string) function.
4841 * Returns LYXP_SET_STRING with the string preceding the occurance
4842 * of the second argument in the first or an empty string.
4843 *
4844 * @param[in] args Array of arguments.
4845 * @param[in] arg_count Count of elements in @p args.
4846 * @param[in,out] set Context and result set at the same time.
4847 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004848 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004849 */
4850static LY_ERR
4851xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4852{
4853 char *ptr;
4854 struct lysc_node_leaf *sleaf;
4855 LY_ERR rc = LY_SUCCESS;
4856
4857 if (options & LYXP_SCNODE_ALL) {
4858 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4859 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4860 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 +02004861 } else if (!warn_is_string_type(sleaf->type)) {
4862 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004863 }
4864 }
4865
4866 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4867 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4868 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 +02004869 } else if (!warn_is_string_type(sleaf->type)) {
4870 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004871 }
4872 }
4873 set_scnode_clear_ctx(set);
4874 return rc;
4875 }
4876
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004877 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004878 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004879 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004880 LY_CHECK_RET(rc);
4881
4882 ptr = strstr(args[0]->val.str, args[1]->val.str);
4883 if (ptr) {
4884 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4885 } else {
4886 set_fill_string(set, "", 0);
4887 }
4888
4889 return LY_SUCCESS;
4890}
4891
4892/**
4893 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4894 * with the sum of all the nodes in the context.
4895 *
4896 * @param[in] args Array of arguments.
4897 * @param[in] arg_count Count of elements in @p args.
4898 * @param[in,out] set Context and result set at the same time.
4899 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004900 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004901 */
4902static LY_ERR
4903xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4904{
4905 long double num;
4906 char *str;
4907 uint16_t i;
4908 struct lyxp_set set_item;
4909 struct lysc_node_leaf *sleaf;
4910 LY_ERR rc = LY_SUCCESS;
4911
4912 if (options & LYXP_SCNODE_ALL) {
4913 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4914 for (i = 0; i < args[0]->used; ++i) {
4915 if (args[0]->val.scnodes[i].in_ctx == 1) {
4916 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4917 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4918 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4919 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004920 } else if (!warn_is_numeric_type(sleaf->type)) {
4921 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004922 }
4923 }
4924 }
4925 }
4926 set_scnode_clear_ctx(set);
4927 return rc;
4928 }
4929
4930 set_fill_number(set, 0);
4931 if (args[0]->type == LYXP_SET_EMPTY) {
4932 return LY_SUCCESS;
4933 }
4934
4935 if (args[0]->type != LYXP_SET_NODE_SET) {
4936 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4937 return LY_EVALID;
4938 }
4939
Michal Vasko5c4e5892019-11-14 12:31:38 +01004940 set_init(&set_item, set);
4941
Michal Vasko03ff5a72019-09-11 13:49:33 +02004942 set_item.type = LYXP_SET_NODE_SET;
4943 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4944 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4945
4946 set_item.used = 1;
4947 set_item.size = 1;
4948
4949 for (i = 0; i < args[0]->used; ++i) {
4950 set_item.val.nodes[0] = args[0]->val.nodes[i];
4951
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004952 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004953 LY_CHECK_RET(rc);
4954 num = cast_string_to_number(str);
4955 free(str);
4956 set->val.num += num;
4957 }
4958
4959 free(set_item.val.nodes);
4960
4961 return LY_SUCCESS;
4962}
4963
4964/**
4965 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4966 * with the text content of the nodes in the context.
4967 *
4968 * @param[in] args Array of arguments.
4969 * @param[in] arg_count Count of elements in @p args.
4970 * @param[in,out] set Context and result set at the same time.
4971 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004972 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004973 */
4974static LY_ERR
4975xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4976{
4977 uint32_t i;
4978
4979 if (options & LYXP_SCNODE_ALL) {
4980 set_scnode_clear_ctx(set);
4981 return LY_SUCCESS;
4982 }
4983
4984 if (set->type == LYXP_SET_EMPTY) {
4985 return LY_SUCCESS;
4986 }
4987 if (set->type != LYXP_SET_NODE_SET) {
4988 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4989 return LY_EVALID;
4990 }
4991
4992 for (i = 0; i < set->used;) {
4993 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004994 case LYXP_NODE_NONE:
4995 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004996 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004997 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4998 set->val.nodes[i].type = LYXP_NODE_TEXT;
4999 ++i;
5000 break;
5001 }
5002 /* fall through */
5003 case LYXP_NODE_ROOT:
5004 case LYXP_NODE_ROOT_CONFIG:
5005 case LYXP_NODE_TEXT:
Michal Vasko9f96a052020-03-10 09:41:45 +01005006 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02005007 set_remove_node(set, i);
5008 break;
5009 }
5010 }
5011
5012 return LY_SUCCESS;
5013}
5014
5015/**
5016 * @brief Execute the XPath translate(string, string, string) function.
5017 * Returns LYXP_SET_STRING with the first argument with the characters
5018 * from the second argument replaced by those on the corresponding
5019 * positions in the third argument.
5020 *
5021 * @param[in] args Array of arguments.
5022 * @param[in] arg_count Count of elements in @p args.
5023 * @param[in,out] set Context and result set at the same time.
5024 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005025 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005026 */
5027static LY_ERR
5028xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5029{
5030 uint16_t i, j, new_used;
5031 char *new;
5032 int found, have_removed;
5033 struct lysc_node_leaf *sleaf;
5034 LY_ERR rc = LY_SUCCESS;
5035
5036 if (options & LYXP_SCNODE_ALL) {
5037 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5038 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5039 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 +02005040 } else if (!warn_is_string_type(sleaf->type)) {
5041 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005042 }
5043 }
5044
5045 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5046 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5047 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 +02005048 } else if (!warn_is_string_type(sleaf->type)) {
5049 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005050 }
5051 }
5052
5053 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5054 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5055 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 +02005056 } else if (!warn_is_string_type(sleaf->type)) {
5057 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005058 }
5059 }
5060 set_scnode_clear_ctx(set);
5061 return rc;
5062 }
5063
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005064 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005065 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005066 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005067 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005068 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005069 LY_CHECK_RET(rc);
5070
5071 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5072 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5073 new_used = 0;
5074
5075 have_removed = 0;
5076 for (i = 0; args[0]->val.str[i]; ++i) {
5077 found = 0;
5078
5079 for (j = 0; args[1]->val.str[j]; ++j) {
5080 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5081 /* removing this char */
5082 if (j >= strlen(args[2]->val.str)) {
5083 have_removed = 1;
5084 found = 1;
5085 break;
5086 }
5087 /* replacing this char */
5088 new[new_used] = args[2]->val.str[j];
5089 ++new_used;
5090 found = 1;
5091 break;
5092 }
5093 }
5094
5095 /* copying this char */
5096 if (!found) {
5097 new[new_used] = args[0]->val.str[i];
5098 ++new_used;
5099 }
5100 }
5101
5102 if (have_removed) {
5103 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5104 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5105 }
5106 new[new_used] = '\0';
5107
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005108 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005109 set->type = LYXP_SET_STRING;
5110 set->val.str = new;
5111
5112 return LY_SUCCESS;
5113}
5114
5115/**
5116 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5117 * with true value.
5118 *
5119 * @param[in] args Array of arguments.
5120 * @param[in] arg_count Count of elements in @p args.
5121 * @param[in,out] set Context and result set at the same time.
5122 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005123 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005124 */
5125static LY_ERR
5126xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5127{
5128 if (options & LYXP_SCNODE_ALL) {
5129 set_scnode_clear_ctx(set);
5130 return LY_SUCCESS;
5131 }
5132
5133 set_fill_boolean(set, 1);
5134 return LY_SUCCESS;
5135}
5136
5137/*
5138 * moveto functions
5139 *
5140 * They and only they actually change the context (set).
5141 */
5142
5143/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005144 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005145 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005146 * XPath @p set is expected to be a (sc)node set!
5147 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005148 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5149 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5150 * @param[in] set Set with XPath context.
5151 * @param[out] moveto_mod Expected module of a matching node.
5152 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005153 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005154static LY_ERR
5155moveto_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 +02005156{
Michal Vasko6346ece2019-09-24 13:12:53 +02005157 const struct lys_module *mod;
5158 const char *ptr;
5159 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005160 char *str;
5161
Michal Vasko2104e9f2020-03-06 08:23:25 +01005162 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5163
Michal Vasko6346ece2019-09-24 13:12:53 +02005164 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5165 /* specific module */
5166 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005167
Michal Vasko6346ece2019-09-24 13:12:53 +02005168 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01005169 case LYD_SCHEMA:
Michal Vasko6346ece2019-09-24 13:12:53 +02005170 /* schema, search all local module imports */
5171 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5172 break;
5173 case LYD_JSON:
5174 /* JSON data, search in context */
5175 str = strndup(*qname, pref_len);
5176 mod = ly_ctx_get_module(set->ctx, str, NULL);
5177 free(str);
5178 break;
Michal Vasko52927e22020-03-16 17:26:14 +01005179 case LYD_XML:
Michal Vasko6346ece2019-09-24 13:12:53 +02005180 LOGINT_RET(set->ctx);
5181 }
5182
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005183 /* Check for errors and non-implemented modules, as they are not valid */
5184 if (!mod || !mod->implemented) {
Michal Vasko2104e9f2020-03-06 08:23:25 +01005185 if (set->type == LYXP_SET_SCNODE_SET) {
5186 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INMOD, pref_len, *qname);
5187 } else {
5188 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5189 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005190 return LY_EVALID;
5191 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005192
Michal Vasko6346ece2019-09-24 13:12:53 +02005193 *qname += pref_len + 1;
5194 *qname_len -= pref_len + 1;
5195 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5196 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005197 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005198 } else {
5199 /* local module */
5200 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005201 }
5202
Michal Vasko6346ece2019-09-24 13:12:53 +02005203 *moveto_mod = mod;
5204 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005205}
5206
5207/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005208 * @brief Move context @p set to the root. Handles absolute path.
5209 * Result is LYXP_SET_NODE_SET.
5210 *
5211 * @param[in,out] set Set to use.
5212 * @param[in] options Xpath options.
5213 */
5214static void
5215moveto_root(struct lyxp_set *set, int options)
5216{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005217 if (!set) {
5218 return;
5219 }
5220
5221 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005222 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005223 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005224 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005225 lyxp_set_cast(set, LYXP_SET_EMPTY);
5226 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005227 }
5228}
5229
5230/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005231 * @brief Check whether a node has some unresolved "when".
5232 *
5233 * @param[in] node Node to check.
5234 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5235 */
5236static LY_ERR
5237moveto_when_check(const struct lyd_node *node)
5238{
5239 const struct lysc_node *schema;
5240
5241 if (!node) {
5242 return LY_SUCCESS;
5243 }
5244
5245 schema = node->schema;
5246 do {
5247 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5248 return LY_EINCOMPLETE;
5249 }
5250 schema = schema->parent;
5251 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5252
5253 return LY_SUCCESS;
5254}
5255
5256/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005257 * @brief Check @p node as a part of NameTest processing.
5258 *
5259 * @param[in] node Node to check.
5260 * @param[in] root_type XPath root node type.
5261 * @param[in] node_name Node name to move to. Must be in the dictionary!
5262 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005263 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5264 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005265 */
5266static LY_ERR
5267moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5268 const struct lys_module *moveto_mod)
5269{
5270 /* module check */
5271 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005272 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005273 }
5274
Michal Vasko5c4e5892019-11-14 12:31:38 +01005275 /* context check */
5276 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005277 return LY_EINVAL;
5278 }
5279
5280 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005281 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005282 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005283 }
5284
Michal Vaskoa1424542019-11-14 16:08:52 +01005285 /* when check */
5286 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005287 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005288 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005289
5290 /* match */
5291 return LY_SUCCESS;
5292}
5293
5294/**
5295 * @brief Check @p node as a part of schema NameTest processing.
5296 *
5297 * @param[in] node Schema node to check.
5298 * @param[in] root_type XPath root node type.
5299 * @param[in] node_name Node name to move to. Must be in the dictionary!
5300 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005301 * @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 +02005302 */
5303static LY_ERR
5304moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005305 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005306{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005307 /* module check */
5308 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005309 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005310 }
5311
5312 /* context check */
5313 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5314 return LY_EINVAL;
5315 }
5316
5317 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005318 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005319 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005320 }
5321
5322 /* match */
5323 return LY_SUCCESS;
5324}
5325
5326/**
5327 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5328 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5329 *
5330 * @param[in,out] set Set to use.
5331 * @param[in] qname Qualified node name to move to.
5332 * @param[in] qname_len Length of @p qname.
5333 * @param[in] options XPath options.
5334 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5335 */
5336static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005337moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005338{
Michal Vaskof03ed032020-03-04 13:31:44 +01005339 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005340 int replaced;
5341 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005342 const struct lys_module *moveto_mod;
5343 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005344 LY_ERR rc;
5345
5346 if (!set || (set->type == LYXP_SET_EMPTY)) {
5347 return LY_SUCCESS;
5348 }
5349
5350 if (set->type != LYXP_SET_NODE_SET) {
5351 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5352 return LY_EVALID;
5353 }
5354
Michal Vasko6346ece2019-09-24 13:12:53 +02005355 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5356 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005357
5358 /* name */
5359 name_dict = lydict_insert(set->ctx, qname, qname_len);
5360
5361 for (i = 0; i < set->used; ) {
5362 replaced = 0;
5363
5364 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 +01005365 assert(!set->val.nodes[i].node);
5366 /* search in all the trees */
Michal Vaskof03ed032020-03-04 13:31:44 +01005367 for (sub = set->tree; sub; sub = sub->next) {
5368 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
5369 if (rc == LY_SUCCESS) {
5370 /* pos filled later */
5371 if (!replaced) {
5372 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5373 replaced = 1;
5374 } else {
5375 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005376 }
Michal Vaskof03ed032020-03-04 13:31:44 +01005377 ++i;
5378 } else if (rc == LY_EINCOMPLETE) {
5379 lydict_remove(set->ctx, name_dict);
5380 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005381 }
5382 }
5383
Michal Vasko5c4e5892019-11-14 12:31:38 +01005384 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5385 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005386
5387 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005388 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005389 if (rc == LY_SUCCESS) {
5390 if (!replaced) {
5391 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5392 replaced = 1;
5393 } else {
5394 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5395 }
5396 ++i;
5397 } else if (rc == LY_EINCOMPLETE) {
5398 lydict_remove(set->ctx, name_dict);
5399 return rc;
5400 }
5401 }
5402 }
5403
5404 if (!replaced) {
5405 /* no match */
5406 set_remove_node(set, i);
5407 }
5408 }
5409 lydict_remove(set->ctx, name_dict);
5410
5411 return LY_SUCCESS;
5412}
5413
5414/**
5415 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5416 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5417 *
5418 * @param[in,out] set Set to use.
5419 * @param[in] qname Qualified node name to move to.
5420 * @param[in] qname_len Length of @p qname.
5421 * @param[in] options XPath options.
5422 * @return LY_ERR
5423 */
5424static LY_ERR
5425moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5426{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005427 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005428 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005429 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005430 const struct lys_module *moveto_mod;
5431 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005432 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005433
5434 if (!set || (set->type == LYXP_SET_EMPTY)) {
5435 return LY_SUCCESS;
5436 }
5437
5438 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005439 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 +02005440 return LY_EVALID;
5441 }
5442
Michal Vasko6346ece2019-09-24 13:12:53 +02005443 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5444 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005445
5446 /* name */
5447 name_dict = lydict_insert(set->ctx, qname, qname_len);
5448
Michal Vaskocafad9d2019-11-07 15:20:03 +01005449 /* getnext opts */
5450 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5451 if (options & LYXP_SCNODE_OUTPUT) {
5452 getnext_opts |= LYS_GETNEXT_OUTPUT;
5453 }
5454
Michal Vasko03ff5a72019-09-11 13:49:33 +02005455 orig_used = set->used;
5456 for (i = 0; i < orig_used; ++i) {
5457 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005458 if (set->val.scnodes[i].in_ctx != -2) {
5459 continue;
5460 }
5461
5462 /* remember context node */
5463 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005464 } else {
5465 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005466 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005467
5468 start_parent = set->val.scnodes[i].scnode;
5469
5470 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5471 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5472 * so use it directly (root node itself is useless in this case) */
5473 mod_idx = 0;
5474 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5475 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005476 /* module may not be implemented */
5477 while (moveto_mod->implemented && (sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
Michal Vaskocafad9d2019-11-07 15:20:03 +01005478 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005479 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005480 /* we need to prevent these nodes from being considered in this moveto */
5481 if ((idx < orig_used) && (idx > i)) {
5482 set->val.scnodes[idx].in_ctx = 2;
5483 temp_ctx = 1;
5484 }
5485 }
5486 }
5487
5488 if (!mod_idx) {
5489 /* moveto_mod was specified, we are not going through the whole context */
5490 break;
5491 }
5492 /* next iteration */
5493 moveto_mod = NULL;
5494 }
5495
5496 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5497 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5498 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005499 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5500 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005501 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005502 if ((idx < orig_used) && (idx > i)) {
5503 set->val.scnodes[idx].in_ctx = 2;
5504 temp_ctx = 1;
5505 }
5506 }
5507 }
5508 }
5509 }
5510 lydict_remove(set->ctx, name_dict);
5511
5512 /* correct temporary in_ctx values */
5513 if (temp_ctx) {
5514 for (i = 0; i < orig_used; ++i) {
5515 if (set->val.scnodes[i].in_ctx == 2) {
5516 set->val.scnodes[i].in_ctx = 1;
5517 }
5518 }
5519 }
5520
5521 return LY_SUCCESS;
5522}
5523
5524/**
5525 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5526 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5527 * Context position aware.
5528 *
5529 * @param[in] set Set to use.
5530 * @param[in] qname Qualified node name to move to.
5531 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005532 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5533 */
5534static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005535moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005536{
5537 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005538 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005539 const struct lyd_node *next, *elem, *start;
5540 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005541 struct lyxp_set ret_set;
5542 LY_ERR rc;
5543
5544 if (!set || (set->type == LYXP_SET_EMPTY)) {
5545 return LY_SUCCESS;
5546 }
5547
5548 if (set->type != LYXP_SET_NODE_SET) {
5549 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5550 return LY_EVALID;
5551 }
5552
Michal Vasko6346ece2019-09-24 13:12:53 +02005553 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5554 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005555
Michal Vasko9f96a052020-03-10 09:41:45 +01005556 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005557 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005558 LY_CHECK_RET(rc);
5559
Michal Vasko6346ece2019-09-24 13:12:53 +02005560 /* name */
5561 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005562
Michal Vasko6346ece2019-09-24 13:12:53 +02005563 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005564 set_init(&ret_set, set);
5565 for (i = 0; i < set->used; ++i) {
5566
5567 /* TREE DFS */
5568 start = set->val.nodes[i].node;
5569 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005570 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005571 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005572 /* add matching node into result set */
5573 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5574 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5575 /* the node is a duplicate, we'll process it later in the set */
5576 goto skip_children;
5577 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005578 } else if (rc == LY_EINCOMPLETE) {
5579 lydict_remove(set->ctx, name_dict);
5580 return rc;
5581 } else if (rc == LY_EINVAL) {
5582 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005583 }
5584
5585 /* TREE DFS NEXT ELEM */
5586 /* select element for the next run - children first */
5587 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5588 next = NULL;
5589 } else {
5590 next = lyd_node_children(elem);
5591 }
5592 if (!next) {
5593skip_children:
5594 /* no children, so try siblings, but only if it's not the start,
5595 * that is considered to be the root and it's siblings are not traversed */
5596 if (elem != start) {
5597 next = elem->next;
5598 } else {
5599 break;
5600 }
5601 }
5602 while (!next) {
5603 /* no siblings, go back through the parents */
5604 if ((struct lyd_node *)elem->parent == start) {
5605 /* we are done, no next element to process */
5606 break;
5607 }
5608 /* parent is already processed, go to its sibling */
5609 elem = (struct lyd_node *)elem->parent;
5610 next = elem->next;
5611 }
5612 }
5613 }
5614
5615 /* make the temporary set the current one */
5616 ret_set.ctx_pos = set->ctx_pos;
5617 ret_set.ctx_size = set->ctx_size;
5618 set_free_content(set);
5619 memcpy(set, &ret_set, sizeof *set);
5620
Michal Vasko6346ece2019-09-24 13:12:53 +02005621 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005622 return LY_SUCCESS;
5623}
5624
5625/**
5626 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5627 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5628 *
5629 * @param[in] set Set to use.
5630 * @param[in] qname Qualified node name to move to.
5631 * @param[in] qname_len Length of @p qname.
5632 * @param[in] options XPath options.
5633 * @return LY_ERR
5634 */
5635static LY_ERR
5636moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5637{
Michal Vasko6346ece2019-09-24 13:12:53 +02005638 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005639 const struct lysc_node *next, *elem, *start;
5640 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005641 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005642
5643 if (!set || (set->type == LYXP_SET_EMPTY)) {
5644 return LY_SUCCESS;
5645 }
5646
5647 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005648 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 +02005649 return LY_EVALID;
5650 }
5651
Michal Vasko6346ece2019-09-24 13:12:53 +02005652 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5653 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005654
5655 orig_used = set->used;
5656 for (i = 0; i < orig_used; ++i) {
5657 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005658 if (set->val.scnodes[i].in_ctx != -2) {
5659 continue;
5660 }
5661
5662 /* remember context node */
5663 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005664 } else {
5665 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005666 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005667
5668 /* TREE DFS */
5669 start = set->val.scnodes[i].scnode;
5670 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005671 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5672 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005673 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005674 }
5675
Michal Vaskocafad9d2019-11-07 15:20:03 +01005676 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005677 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005678 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005679 set->val.scnodes[idx].in_ctx = 1;
5680 if (idx > i) {
5681 /* we will process it later in the set */
5682 goto skip_children;
5683 }
5684 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005685 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005686 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005687 } else if (rc == LY_EINVAL) {
5688 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005689 }
5690
5691next_iter:
5692 /* TREE DFS NEXT ELEM */
5693 /* select element for the next run - children first */
5694 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5695 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5696 next = NULL;
5697 }
5698 if (!next) {
5699skip_children:
5700 /* no children, so try siblings, but only if it's not the start,
5701 * that is considered to be the root and it's siblings are not traversed */
5702 if (elem != start) {
5703 next = elem->next;
5704 } else {
5705 break;
5706 }
5707 }
5708 while (!next) {
5709 /* no siblings, go back through the parents */
5710 if (elem->parent == start) {
5711 /* we are done, no next element to process */
5712 break;
5713 }
5714 /* parent is already processed, go to its sibling */
5715 elem = elem->parent;
5716 next = elem->next;
5717 }
5718 }
5719 }
5720
5721 return LY_SUCCESS;
5722}
5723
5724/**
5725 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5726 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5727 * Indirectly context position aware.
5728 *
5729 * @param[in,out] set Set to use.
5730 * @param[in] qname Qualified node name to move to.
5731 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005732 * @return LY_ERR
5733 */
5734static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005735moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005736{
5737 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005738 int replaced, all = 0;
5739 const struct lys_module *moveto_mod;
Michal Vasko9f96a052020-03-10 09:41:45 +01005740 struct lyd_meta *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005741 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005742
5743 if (!set || (set->type == LYXP_SET_EMPTY)) {
5744 return LY_SUCCESS;
5745 }
5746
5747 if (set->type != LYXP_SET_NODE_SET) {
5748 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5749 return LY_EVALID;
5750 }
5751
Michal Vasko6346ece2019-09-24 13:12:53 +02005752 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5753 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005754
5755 if ((qname_len == 1) && (qname[0] == '*')) {
5756 all = 1;
5757 }
5758
5759 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" */
5768 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5769 continue;
5770 }
5771
5772 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5773 /* 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.
5798 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5799 *
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
5809 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5810 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5811 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5812 return LY_EVALID;
5813 }
5814
5815 /* set2 is empty or both set1 and set2 */
5816 if (set2->type == LYXP_SET_EMPTY) {
5817 return LY_SUCCESS;
5818 }
5819
5820 if (set1->type == LYXP_SET_EMPTY) {
5821 memcpy(set1, set2, sizeof *set1);
5822 /* dynamic memory belongs to set1 now, do not free */
5823 set2->type = LYXP_SET_EMPTY;
5824 return LY_SUCCESS;
5825 }
5826
5827 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005828 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005829
5830 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005831 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005832 LY_CHECK_RET(rc);
5833
5834 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005835 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005836
5837 return LY_SUCCESS;
5838}
5839
5840/**
5841 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5842 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5843 * Context position aware.
5844 *
5845 * @param[in,out] set Set to use.
5846 * @param[in] qname Qualified node name to move to.
5847 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005848 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5849 */
5850static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005851moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005852{
5853 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005854 int replaced, all = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01005855 struct lyd_meta *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005856 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005857 struct lyxp_set *set_all_desc = NULL;
5858 LY_ERR rc;
5859
5860 if (!set || (set->type == LYXP_SET_EMPTY)) {
5861 return LY_SUCCESS;
5862 }
5863
5864 if (set->type != LYXP_SET_NODE_SET) {
5865 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5866 return LY_EVALID;
5867 }
5868
Michal Vasko6346ece2019-09-24 13:12:53 +02005869 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5870 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005871
5872 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5873 * but it likely won't be used much, so it's a waste of time */
5874 /* copy the context */
5875 set_all_desc = set_copy(set);
5876 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005877 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005878 if (rc != LY_SUCCESS) {
5879 lyxp_set_free(set_all_desc);
5880 return rc;
5881 }
5882 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005883 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005884 if (rc != LY_SUCCESS) {
5885 lyxp_set_free(set_all_desc);
5886 return rc;
5887 }
5888 lyxp_set_free(set_all_desc);
5889
5890 if ((qname_len == 1) && (qname[0] == '*')) {
5891 all = 1;
5892 }
5893
5894 for (i = 0; i < set->used; ) {
5895 replaced = 0;
5896
5897 /* only attributes of an elem can be in the result, skip all the rest,
5898 * we have all attributes qualified in lyd tree */
5899 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005900 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005901 /* check "namespace" */
5902 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5903 continue;
5904 }
5905
5906 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5907 /* match */
5908 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005909 set->val.meta[i].meta = sub;
5910 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005911 /* pos does not change */
5912 replaced = 1;
5913 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005914 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 +02005915 }
5916 ++i;
5917 }
5918 }
5919 }
5920
5921 if (!replaced) {
5922 /* no match */
5923 set_remove_node(set, i);
5924 }
5925 }
5926
5927 return LY_SUCCESS;
5928}
5929
5930/**
5931 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5932 * (or LYXP_SET_EMPTY). Context position aware.
5933 *
5934 * @param[in] parent Current parent.
5935 * @param[in] parent_pos Position of @p parent.
5936 * @param[in] parent_type Node type of @p parent.
5937 * @param[in,out] to_set Set to use.
5938 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005939 * @param[in] options XPath options.
5940 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5941 */
5942static LY_ERR
5943moveto_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 +01005944 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005945{
5946 const struct lyd_node *sub;
5947 LY_ERR rc;
5948
5949 switch (parent_type) {
5950 case LYXP_NODE_ROOT:
5951 case LYXP_NODE_ROOT_CONFIG:
5952 /* add the same node but as an element */
5953 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5954 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5955
5956 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005957 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005958 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005959 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005960 LY_CHECK_RET(rc);
5961 }
5962 }
5963 break;
5964 case LYXP_NODE_ELEM:
5965 /* add all the children ... */
5966 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5967 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5968 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005969 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005970 continue;
5971 }
5972
Michal Vaskoa1424542019-11-14 16:08:52 +01005973 /* when check */
5974 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005975 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005976 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005977
5978 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5979 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5980
Michal Vasko5c4e5892019-11-14 12:31:38 +01005981 /* skip anydata/anyxml nodes */
5982 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005983 continue;
5984 }
5985
5986 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005987 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005988 LY_CHECK_RET(rc);
5989 }
5990 }
5991
5992 /* ... or add their text node, ... */
5993 } else {
5994 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5995 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5996 }
5997 }
5998 break;
5999 default:
6000 LOGINT_RET(parent->schema->module->ctx);
6001 }
6002
6003 return LY_SUCCESS;
6004}
6005
6006/**
6007 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
6008 * (or LYXP_SET_EMPTY). Context position aware.
6009 *
6010 * @param[in,out] set Set to use.
6011 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6012 * @param[in] options XPath options.
6013 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6014 */
6015static LY_ERR
6016moveto_self(struct lyxp_set *set, int all_desc, int options)
6017{
6018 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006019 struct lyxp_set ret_set;
6020 LY_ERR rc;
6021
6022 if (!set || (set->type == LYXP_SET_EMPTY)) {
6023 return LY_SUCCESS;
6024 }
6025
6026 if (set->type != LYXP_SET_NODE_SET) {
6027 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6028 return LY_EVALID;
6029 }
6030
6031 /* nothing to do */
6032 if (!all_desc) {
6033 return LY_SUCCESS;
6034 }
6035
Michal Vasko03ff5a72019-09-11 13:49:33 +02006036 /* add all the children, they get added recursively */
6037 set_init(&ret_set, set);
6038 for (i = 0; i < set->used; ++i) {
6039 /* copy the current node to tmp */
6040 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6041
6042 /* do not touch attributes and text nodes */
Michal Vasko9f96a052020-03-10 09:41:45 +01006043 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006044 continue;
6045 }
6046
Michal Vasko5c4e5892019-11-14 12:31:38 +01006047 /* skip anydata/anyxml nodes */
6048 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006049 continue;
6050 }
6051
6052 /* add all the children */
6053 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 +01006054 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006055 if (rc != LY_SUCCESS) {
6056 set_free_content(&ret_set);
6057 return rc;
6058 }
6059 }
6060
6061 /* use the temporary set as the current one */
6062 ret_set.ctx_pos = set->ctx_pos;
6063 ret_set.ctx_size = set->ctx_size;
6064 set_free_content(set);
6065 memcpy(set, &ret_set, sizeof *set);
6066
6067 return LY_SUCCESS;
6068}
6069
6070/**
6071 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6072 * (or LYXP_SET_EMPTY).
6073 *
6074 * @param[in,out] set Set to use.
6075 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6076 * @param[in] options XPath options.
6077 * @return LY_ERR
6078 */
6079static LY_ERR
6080moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6081{
6082 const struct lysc_node *sub;
6083 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006084
6085 if (!set || (set->type == LYXP_SET_EMPTY)) {
6086 return LY_SUCCESS;
6087 }
6088
6089 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006090 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 +02006091 return LY_EVALID;
6092 }
6093
6094 /* nothing to do */
6095 if (!all_desc) {
6096 return LY_SUCCESS;
6097 }
6098
Michal Vasko03ff5a72019-09-11 13:49:33 +02006099 /* add all the children, they get added recursively */
6100 for (i = 0; i < set->used; ++i) {
6101 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006102 if (set->val.scnodes[i].in_ctx != -2) {
6103 continue;
6104 }
6105
6106 /* remember context node (it was traversed again so it changes to a normal node) */
6107 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006108 }
6109
6110 /* add all the children */
6111 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6112 sub = NULL;
6113 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6114 /* RPC input/output check */
6115 if (options & LYXP_SCNODE_OUTPUT) {
6116 if (sub->parent->nodetype == LYS_INPUT) {
6117 continue;
6118 }
6119 } else {
6120 if (sub->parent->nodetype == LYS_OUTPUT) {
6121 continue;
6122 }
6123 }
6124
6125 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006126 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006127 continue;
6128 }
6129
Michal Vaskoecd62de2019-11-13 12:35:11 +01006130 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006131 /* throw away the insert index, we want to consider that node again, recursively */
6132 }
6133 }
6134 }
6135
6136 return LY_SUCCESS;
6137}
6138
6139/**
6140 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6141 * (or LYXP_SET_EMPTY). Context position aware.
6142 *
6143 * @param[in] set Set to use.
6144 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6145 * @param[in] options XPath options.
6146 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6147 */
6148static LY_ERR
6149moveto_parent(struct lyxp_set *set, int all_desc, int options)
6150{
6151 LY_ERR rc;
6152 uint32_t i;
6153 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006154 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006155
6156 if (!set || (set->type == LYXP_SET_EMPTY)) {
6157 return LY_SUCCESS;
6158 }
6159
6160 if (set->type != LYXP_SET_NODE_SET) {
6161 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6162 return LY_EVALID;
6163 }
6164
6165 if (all_desc) {
6166 /* <path>//.. == <path>//./.. */
6167 rc = moveto_self(set, 1, options);
6168 LY_CHECK_RET(rc);
6169 }
6170
Michal Vasko57eab132019-09-24 11:46:26 +02006171 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006172 node = set->val.nodes[i].node;
6173
6174 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6175 new_node = (struct lyd_node *)node->parent;
6176 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6177 new_node = node;
Michal Vasko9f96a052020-03-10 09:41:45 +01006178 } else if (set->val.nodes[i].type == LYXP_NODE_META) {
6179 new_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006180 if (!new_node) {
6181 LOGINT_RET(set->ctx);
6182 }
6183 } else {
6184 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006185 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006186 continue;
6187 }
6188
Michal Vaskoa1424542019-11-14 16:08:52 +01006189 /* when check */
6190 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006191 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006192 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006193
6194 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006195 if (!new_node) {
6196 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006197
6198 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6199 } else {
6200 new_type = LYXP_NODE_ELEM;
6201 }
6202
Michal Vasko03ff5a72019-09-11 13:49:33 +02006203 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006204 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006205 } else {
6206 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006207 }
6208 }
6209
Michal Vasko2caefc12019-11-14 16:07:56 +01006210 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006211 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006212
6213 return LY_SUCCESS;
6214}
6215
6216/**
6217 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6218 * (or LYXP_SET_EMPTY).
6219 *
6220 * @param[in] set Set to use.
6221 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6222 * @param[in] options XPath options.
6223 * @return LY_ERR
6224 */
6225static LY_ERR
6226moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6227{
6228 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006229 const struct lysc_node *node, *new_node;
6230 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006231 LY_ERR rc;
6232
6233 if (!set || (set->type == LYXP_SET_EMPTY)) {
6234 return LY_SUCCESS;
6235 }
6236
6237 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006238 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 +02006239 return LY_EVALID;
6240 }
6241
6242 if (all_desc) {
6243 /* <path>//.. == <path>//./.. */
6244 rc = moveto_scnode_self(set, 1, options);
6245 LY_CHECK_RET(rc);
6246 }
6247
Michal Vasko03ff5a72019-09-11 13:49:33 +02006248 orig_used = set->used;
6249 for (i = 0; i < orig_used; ++i) {
6250 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006251 if (set->val.scnodes[i].in_ctx != -2) {
6252 continue;
6253 }
6254
6255 /* remember context node */
6256 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006257 } else {
6258 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006259 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006260
6261 node = set->val.scnodes[i].scnode;
6262
6263 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6264 for (new_node = node->parent;
6265 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6266 new_node = new_node->parent);
6267 } else {
6268 /* root does not have a parent */
6269 continue;
6270 }
6271
Michal Vasko03ff5a72019-09-11 13:49:33 +02006272 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006273 if (!new_node) {
6274 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006275
6276 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6277 } else {
6278 new_type = LYXP_NODE_ELEM;
6279 }
6280
Michal Vaskoecd62de2019-11-13 12:35:11 +01006281 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006282 if ((idx < orig_used) && (idx > i)) {
6283 set->val.scnodes[idx].in_ctx = 2;
6284 temp_ctx = 1;
6285 }
6286 }
6287
6288 if (temp_ctx) {
6289 for (i = 0; i < orig_used; ++i) {
6290 if (set->val.scnodes[i].in_ctx == 2) {
6291 set->val.scnodes[i].in_ctx = 1;
6292 }
6293 }
6294 }
6295
6296 return LY_SUCCESS;
6297}
6298
6299/**
6300 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6301 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6302 *
6303 * @param[in,out] set1 Set to use for the result.
6304 * @param[in] set2 Set acting as the second operand for @p op.
6305 * @param[in] op Comparison operator to process.
6306 * @param[in] options XPath options.
6307 * @return LY_ERR
6308 */
6309static LY_ERR
6310moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6311{
6312 /*
6313 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6314 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6315 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6316 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6317 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6318 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6319 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6320 *
6321 * '=' or '!='
6322 * BOOLEAN + BOOLEAN
6323 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6324 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6325 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6326 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6327 * NUMBER + NUMBER
6328 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6329 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6330 * STRING + STRING
6331 *
6332 * '<=', '<', '>=', '>'
6333 * NUMBER + NUMBER
6334 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6335 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6336 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6337 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6338 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6339 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6340 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6341 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6342 */
6343 struct lyxp_set iter1, iter2;
6344 int result;
6345 int64_t i;
6346 LY_ERR rc;
6347
6348 iter1.type = LYXP_SET_EMPTY;
6349
6350 /* empty node-sets are always false */
6351 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6352 set_fill_boolean(set1, 0);
6353 return LY_SUCCESS;
6354 }
6355
6356 /* iterative evaluation with node-sets */
6357 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6358 if (set1->type == LYXP_SET_NODE_SET) {
6359 for (i = 0; i < set1->used; ++i) {
6360 switch (set2->type) {
6361 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006362 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006363 break;
6364 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006365 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006366 break;
6367 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006368 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006369 break;
6370 }
6371 LY_CHECK_RET(rc);
6372
6373 rc = moveto_op_comp(&iter1, set2, op, options);
6374 if (rc != LY_SUCCESS) {
6375 set_free_content(&iter1);
6376 return rc;
6377 }
6378
6379 /* lazy evaluation until true */
6380 if (iter1.val.bool) {
6381 set_fill_boolean(set1, 1);
6382 return LY_SUCCESS;
6383 }
6384 }
6385 } else {
6386 for (i = 0; i < set2->used; ++i) {
6387 switch (set1->type) {
6388 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006389 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006390 break;
6391 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006392 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006393 break;
6394 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006395 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006396 break;
6397 }
6398 LY_CHECK_RET(rc);
6399
6400 set_fill_set(&iter1, set1);
6401
6402 rc = moveto_op_comp(&iter1, &iter2, op, options);
6403 if (rc != LY_SUCCESS) {
6404 set_free_content(&iter1);
6405 set_free_content(&iter2);
6406 return rc;
6407 }
6408 set_free_content(&iter2);
6409
6410 /* lazy evaluation until true */
6411 if (iter1.val.bool) {
6412 set_fill_boolean(set1, 1);
6413 return LY_SUCCESS;
6414 }
6415 }
6416 }
6417
6418 /* false for all nodes */
6419 set_fill_boolean(set1, 0);
6420 return LY_SUCCESS;
6421 }
6422
6423 /* first convert properly */
6424 if ((op[0] == '=') || (op[0] == '!')) {
6425 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006426 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6427 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006428 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006429 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006430 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006431 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006432 LY_CHECK_RET(rc);
6433 } /* else we have 2 strings */
6434 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006435 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006436 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006437 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006438 LY_CHECK_RET(rc);
6439 }
6440
6441 assert(set1->type == set2->type);
6442
6443 /* compute result */
6444 if (op[0] == '=') {
6445 if (set1->type == LYXP_SET_BOOLEAN) {
6446 result = (set1->val.bool == set2->val.bool);
6447 } else if (set1->type == LYXP_SET_NUMBER) {
6448 result = (set1->val.num == set2->val.num);
6449 } else {
6450 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006451 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006452 }
6453 } else if (op[0] == '!') {
6454 if (set1->type == LYXP_SET_BOOLEAN) {
6455 result = (set1->val.bool != set2->val.bool);
6456 } else if (set1->type == LYXP_SET_NUMBER) {
6457 result = (set1->val.num != set2->val.num);
6458 } else {
6459 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006460 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006461 }
6462 } else {
6463 assert(set1->type == LYXP_SET_NUMBER);
6464 if (op[0] == '<') {
6465 if (op[1] == '=') {
6466 result = (set1->val.num <= set2->val.num);
6467 } else {
6468 result = (set1->val.num < set2->val.num);
6469 }
6470 } else {
6471 if (op[1] == '=') {
6472 result = (set1->val.num >= set2->val.num);
6473 } else {
6474 result = (set1->val.num > set2->val.num);
6475 }
6476 }
6477 }
6478
6479 /* assign result */
6480 if (result) {
6481 set_fill_boolean(set1, 1);
6482 } else {
6483 set_fill_boolean(set1, 0);
6484 }
6485
6486 return LY_SUCCESS;
6487}
6488
6489/**
6490 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6491 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6492 *
6493 * @param[in,out] set1 Set to use for the result.
6494 * @param[in] set2 Set acting as the second operand for @p op.
6495 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006496 * @return LY_ERR
6497 */
6498static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006499moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006500{
6501 LY_ERR rc;
6502
6503 /* unary '-' */
6504 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006505 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006506 LY_CHECK_RET(rc);
6507 set1->val.num *= -1;
6508 lyxp_set_free(set2);
6509 return LY_SUCCESS;
6510 }
6511
6512 assert(set1 && set2);
6513
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006514 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006515 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006516 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006517 LY_CHECK_RET(rc);
6518
6519 switch (op[0]) {
6520 /* '+' */
6521 case '+':
6522 set1->val.num += set2->val.num;
6523 break;
6524
6525 /* '-' */
6526 case '-':
6527 set1->val.num -= set2->val.num;
6528 break;
6529
6530 /* '*' */
6531 case '*':
6532 set1->val.num *= set2->val.num;
6533 break;
6534
6535 /* 'div' */
6536 case 'd':
6537 set1->val.num /= set2->val.num;
6538 break;
6539
6540 /* 'mod' */
6541 case 'm':
6542 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6543 break;
6544
6545 default:
6546 LOGINT_RET(set1->ctx);
6547 }
6548
6549 return LY_SUCCESS;
6550}
6551
6552/*
6553 * eval functions
6554 *
6555 * They execute a parsed XPath expression on some data subtree.
6556 */
6557
6558/**
6559 * @brief Evaluate Literal. Logs directly on error.
6560 *
6561 * @param[in] exp Parsed XPath expression.
6562 * @param[in] exp_idx Position in the expression @p exp.
6563 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6564 */
6565static void
6566eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6567{
6568 if (set) {
6569 if (exp->tok_len[*exp_idx] == 2) {
6570 set_fill_string(set, "", 0);
6571 } else {
6572 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6573 }
6574 }
6575 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6576 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6577 ++(*exp_idx);
6578}
6579
6580/**
6581 * @brief Evaluate NodeTest. Logs directly on error.
6582 *
6583 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6584 *
6585 * @param[in] exp Parsed XPath expression.
6586 * @param[in] exp_idx Position in the expression @p exp.
6587 * @param[in] attr_axis Whether to search attributes or standard nodes.
6588 * @param[in] all_desc Whether to search all the descendants or children only.
6589 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6590 * @param[in] options XPath options.
6591 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6592 */
6593static int
6594eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6595 struct lyxp_set *set, int options)
6596{
6597 int i;
6598 char *path;
6599 LY_ERR rc;
6600
6601 switch (exp->tokens[*exp_idx]) {
6602 case LYXP_TOKEN_NAMETEST:
6603 if (attr_axis) {
6604 if (set && (options & LYXP_SCNODE_ALL)) {
6605 set_scnode_clear_ctx(set);
6606 rc = LY_SUCCESS;
6607 } else {
6608 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006609 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006610 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006611 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006612 }
6613 }
6614 } else {
6615 if (all_desc) {
6616 if (set && (options & LYXP_SCNODE_ALL)) {
6617 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6618 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006619 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006620 }
6621 } else {
6622 if (set && (options & LYXP_SCNODE_ALL)) {
6623 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6624 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006625 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006626 }
6627 }
6628
6629 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6630 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006631 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006632 break;
6633 }
6634 }
6635 if (i == -1) {
6636 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6637 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6638 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6639 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6640 free(path);
6641 }
6642 }
6643 }
6644 LY_CHECK_RET(rc);
6645
6646 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6647 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6648 ++(*exp_idx);
6649 break;
6650
6651 case LYXP_TOKEN_NODETYPE:
6652 if (set) {
6653 assert(exp->tok_len[*exp_idx] == 4);
6654 if (set->type == LYXP_SET_SCNODE_SET) {
6655 set_scnode_clear_ctx(set);
6656 /* just for the debug message underneath */
6657 set = NULL;
6658 } else {
6659 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6660 rc = xpath_node(NULL, 0, set, options);
6661 LY_CHECK_RET(rc);
6662 } else {
6663 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6664 rc = xpath_text(NULL, 0, set, options);
6665 LY_CHECK_RET(rc);
6666 }
6667 }
6668 }
6669 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6670 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6671 ++(*exp_idx);
6672
6673 /* '(' */
6674 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6675 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6676 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6677 ++(*exp_idx);
6678
6679 /* ')' */
6680 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6681 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6682 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6683 ++(*exp_idx);
6684 break;
6685
6686 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006687 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006688 }
6689
6690 return LY_SUCCESS;
6691}
6692
6693/**
6694 * @brief Evaluate Predicate. Logs directly on error.
6695 *
6696 * [7] Predicate ::= '[' Expr ']'
6697 *
6698 * @param[in] exp Parsed XPath expression.
6699 * @param[in] exp_idx Position in the expression @p exp.
6700 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6701 * @param[in] options XPath options.
6702 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6703 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6704 */
6705static LY_ERR
6706eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6707{
6708 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006709 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006710 uint32_t orig_pos, orig_size;
6711 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006712 struct lyxp_set set2;
6713 struct lyd_node *orig_parent;
6714
6715 /* '[' */
6716 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6717 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6718 ++(*exp_idx);
6719
6720 if (!set) {
6721only_parse:
6722 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6723 LY_CHECK_RET(rc);
6724 } else if (set->type == LYXP_SET_NODE_SET) {
6725 /* 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 +01006726 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006727
6728 /* empty set, nothing to evaluate */
6729 if (!set->used) {
6730 goto only_parse;
6731 }
6732
6733 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006734 orig_pos = 0;
6735 orig_size = set->used;
6736 orig_parent = NULL;
6737 for (i = 0; i < set->used; ) {
6738 set_init(&set2, set);
6739 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6740 /* remember the node context position for position() and context size for last(),
6741 * predicates should always be evaluated with respect to the child axis (since we do
6742 * not support explicit axes) so we assign positions based on their parents */
6743 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6744 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6745 orig_pos = 1;
6746 } else {
6747 ++orig_pos;
6748 }
6749
6750 set2.ctx_pos = orig_pos;
6751 set2.ctx_size = orig_size;
6752 *exp_idx = orig_exp;
6753
6754 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6755 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006756 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006757 return rc;
6758 }
6759
6760 /* number is a position */
6761 if (set2.type == LYXP_SET_NUMBER) {
6762 if ((long long)set2.val.num == orig_pos) {
6763 set2.val.num = 1;
6764 } else {
6765 set2.val.num = 0;
6766 }
6767 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006768 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006769
6770 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006771 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006772 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006773 }
6774 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006775 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006776
6777 } else if (set->type == LYXP_SET_SCNODE_SET) {
6778 for (i = 0; i < set->used; ++i) {
6779 if (set->val.scnodes[i].in_ctx == 1) {
6780 /* there is a currently-valid node */
6781 break;
6782 }
6783 }
6784 /* empty set, nothing to evaluate */
6785 if (i == set->used) {
6786 goto only_parse;
6787 }
6788
6789 orig_exp = *exp_idx;
6790
Michal Vasko03ff5a72019-09-11 13:49:33 +02006791 /* set special in_ctx to all the valid snodes */
6792 pred_in_ctx = set_scnode_new_in_ctx(set);
6793
6794 /* use the valid snodes one-by-one */
6795 for (i = 0; i < set->used; ++i) {
6796 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6797 continue;
6798 }
6799 set->val.scnodes[i].in_ctx = 1;
6800
6801 *exp_idx = orig_exp;
6802
6803 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6804 LY_CHECK_RET(rc);
6805
6806 set->val.scnodes[i].in_ctx = pred_in_ctx;
6807 }
6808
6809 /* restore the state as it was before the predicate */
6810 for (i = 0; i < set->used; ++i) {
6811 if (set->val.scnodes[i].in_ctx == 1) {
6812 set->val.scnodes[i].in_ctx = 0;
6813 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6814 set->val.scnodes[i].in_ctx = 1;
6815 }
6816 }
6817
6818 } else {
6819 set2.type = LYXP_SET_EMPTY;
6820 set_fill_set(&set2, set);
6821
6822 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6823 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006824 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006825 return rc;
6826 }
6827
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006828 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006829 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006830 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006831 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006832 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006833 }
6834
6835 /* ']' */
6836 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6837 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6838 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6839 ++(*exp_idx);
6840
6841 return LY_SUCCESS;
6842}
6843
6844/**
6845 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6846 *
6847 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6848 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6849 *
6850 * @param[in] exp Parsed XPath expression.
6851 * @param[in] exp_idx Position in the expression @p exp.
6852 * @param[in] all_desc Whether to search all the descendants or children only.
6853 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6854 * @param[in] options XPath options.
6855 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6856 */
6857static LY_ERR
6858eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6859{
6860 int attr_axis;
6861 LY_ERR rc;
6862
6863 goto step;
6864 do {
6865 /* evaluate '/' or '//' */
6866 if (exp->tok_len[*exp_idx] == 1) {
6867 all_desc = 0;
6868 } else {
6869 assert(exp->tok_len[*exp_idx] == 2);
6870 all_desc = 1;
6871 }
6872 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6873 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6874 ++(*exp_idx);
6875
6876step:
6877 /* Step */
6878 attr_axis = 0;
6879 switch (exp->tokens[*exp_idx]) {
6880 case LYXP_TOKEN_DOT:
6881 /* evaluate '.' */
6882 if (set && (options & LYXP_SCNODE_ALL)) {
6883 rc = moveto_scnode_self(set, all_desc, options);
6884 } else {
6885 rc = moveto_self(set, all_desc, options);
6886 }
6887 LY_CHECK_RET(rc);
6888 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6889 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6890 ++(*exp_idx);
6891 break;
6892
6893 case LYXP_TOKEN_DDOT:
6894 /* evaluate '..' */
6895 if (set && (options & LYXP_SCNODE_ALL)) {
6896 rc = moveto_scnode_parent(set, all_desc, options);
6897 } else {
6898 rc = moveto_parent(set, all_desc, options);
6899 }
6900 LY_CHECK_RET(rc);
6901 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6902 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6903 ++(*exp_idx);
6904 break;
6905
6906 case LYXP_TOKEN_AT:
6907 /* evaluate '@' */
6908 attr_axis = 1;
6909 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6910 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6911 ++(*exp_idx);
6912
6913 /* fall through */
6914 case LYXP_TOKEN_NAMETEST:
6915 case LYXP_TOKEN_NODETYPE:
6916 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6917 LY_CHECK_RET(rc);
6918
6919 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6920 rc = eval_predicate(exp, exp_idx, set, options, 1);
6921 LY_CHECK_RET(rc);
6922 }
6923 break;
6924
6925 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006926 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006927 }
6928 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6929
6930 return LY_SUCCESS;
6931}
6932
6933/**
6934 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6935 *
6936 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6937 *
6938 * @param[in] exp Parsed XPath expression.
6939 * @param[in] exp_idx Position in the expression @p exp.
6940 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6941 * @param[in] options XPath options.
6942 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6943 */
6944static LY_ERR
6945eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6946{
6947 int all_desc;
6948 LY_ERR rc;
6949
6950 if (set) {
6951 /* no matter what tokens follow, we need to be at the root */
6952 moveto_root(set, options);
6953 }
6954
6955 /* '/' RelativeLocationPath? */
6956 if (exp->tok_len[*exp_idx] == 1) {
6957 /* evaluate '/' - deferred */
6958 all_desc = 0;
6959 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6960 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6961 ++(*exp_idx);
6962
Michal Vasko4b9e1052019-09-13 11:25:37 +02006963 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006964 return LY_SUCCESS;
6965 }
6966 switch (exp->tokens[*exp_idx]) {
6967 case LYXP_TOKEN_DOT:
6968 case LYXP_TOKEN_DDOT:
6969 case LYXP_TOKEN_AT:
6970 case LYXP_TOKEN_NAMETEST:
6971 case LYXP_TOKEN_NODETYPE:
6972 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6973 LY_CHECK_RET(rc);
6974 break;
6975 default:
6976 break;
6977 }
6978
6979 /* '//' RelativeLocationPath */
6980 } else {
6981 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6982 all_desc = 1;
6983 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6984 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6985 ++(*exp_idx);
6986
6987 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6988 LY_CHECK_RET(rc);
6989 }
6990
6991 return LY_SUCCESS;
6992}
6993
6994/**
6995 * @brief Evaluate FunctionCall. Logs directly on error.
6996 *
6997 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6998 *
6999 * @param[in] exp Parsed XPath expression.
7000 * @param[in] exp_idx Position in the expression @p exp.
7001 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7002 * @param[in] options XPath options.
7003 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7004 */
7005static LY_ERR
7006eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7007{
7008 LY_ERR rc;
7009 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007010 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007011 struct lyxp_set **args = NULL, **args_aux;
7012
7013 if (set) {
7014 /* FunctionName */
7015 switch (exp->tok_len[*exp_idx]) {
7016 case 3:
7017 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7018 xpath_func = &xpath_not;
7019 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7020 xpath_func = &xpath_sum;
7021 }
7022 break;
7023 case 4:
7024 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7025 xpath_func = &xpath_lang;
7026 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7027 xpath_func = &xpath_last;
7028 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7029 xpath_func = &xpath_name;
7030 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7031 xpath_func = &xpath_true;
7032 }
7033 break;
7034 case 5:
7035 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7036 xpath_func = &xpath_count;
7037 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7038 xpath_func = &xpath_false;
7039 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7040 xpath_func = &xpath_floor;
7041 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7042 xpath_func = &xpath_round;
7043 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7044 xpath_func = &xpath_deref;
7045 }
7046 break;
7047 case 6:
7048 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7049 xpath_func = &xpath_concat;
7050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7051 xpath_func = &xpath_number;
7052 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7053 xpath_func = &xpath_string;
7054 }
7055 break;
7056 case 7:
7057 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7058 xpath_func = &xpath_boolean;
7059 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7060 xpath_func = &xpath_ceiling;
7061 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7062 xpath_func = &xpath_current;
7063 }
7064 break;
7065 case 8:
7066 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7067 xpath_func = &xpath_contains;
7068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7069 xpath_func = &xpath_position;
7070 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7071 xpath_func = &xpath_re_match;
7072 }
7073 break;
7074 case 9:
7075 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7076 xpath_func = &xpath_substring;
7077 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7078 xpath_func = &xpath_translate;
7079 }
7080 break;
7081 case 10:
7082 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7083 xpath_func = &xpath_local_name;
7084 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7085 xpath_func = &xpath_enum_value;
7086 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7087 xpath_func = &xpath_bit_is_set;
7088 }
7089 break;
7090 case 11:
7091 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7092 xpath_func = &xpath_starts_with;
7093 }
7094 break;
7095 case 12:
7096 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7097 xpath_func = &xpath_derived_from;
7098 }
7099 break;
7100 case 13:
7101 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7102 xpath_func = &xpath_namespace_uri;
7103 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7104 xpath_func = &xpath_string_length;
7105 }
7106 break;
7107 case 15:
7108 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7109 xpath_func = &xpath_normalize_space;
7110 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7111 xpath_func = &xpath_substring_after;
7112 }
7113 break;
7114 case 16:
7115 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7116 xpath_func = &xpath_substring_before;
7117 }
7118 break;
7119 case 20:
7120 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7121 xpath_func = &xpath_derived_from_or_self;
7122 }
7123 break;
7124 }
7125
7126 if (!xpath_func) {
7127 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7128 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]]);
7129 return LY_EVALID;
7130 }
7131 }
7132
7133 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7134 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7135 ++(*exp_idx);
7136
7137 /* '(' */
7138 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7139 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7140 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7141 ++(*exp_idx);
7142
7143 /* ( Expr ( ',' Expr )* )? */
7144 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7145 if (set) {
7146 args = malloc(sizeof *args);
7147 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7148 arg_count = 1;
7149 args[0] = set_copy(set);
7150 if (!args[0]) {
7151 rc = LY_EMEM;
7152 goto cleanup;
7153 }
7154
7155 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7156 LY_CHECK_GOTO(rc, cleanup);
7157 } else {
7158 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7159 LY_CHECK_GOTO(rc, cleanup);
7160 }
7161 }
7162 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7163 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7164 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7165 ++(*exp_idx);
7166
7167 if (set) {
7168 ++arg_count;
7169 args_aux = realloc(args, arg_count * sizeof *args);
7170 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7171 args = args_aux;
7172 args[arg_count - 1] = set_copy(set);
7173 if (!args[arg_count - 1]) {
7174 rc = LY_EMEM;
7175 goto cleanup;
7176 }
7177
7178 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7179 LY_CHECK_GOTO(rc, cleanup);
7180 } else {
7181 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7182 LY_CHECK_GOTO(rc, cleanup);
7183 }
7184 }
7185
7186 /* ')' */
7187 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7188 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7189 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7190 ++(*exp_idx);
7191
7192 if (set) {
7193 /* evaluate function */
7194 rc = xpath_func(args, arg_count, set, options);
7195
7196 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007197 /* merge all nodes from arg evaluations */
7198 for (i = 0; i < arg_count; ++i) {
7199 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007200 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007201 }
7202 }
7203 } else {
7204 rc = LY_SUCCESS;
7205 }
7206
7207cleanup:
7208 for (i = 0; i < arg_count; ++i) {
7209 lyxp_set_free(args[i]);
7210 }
7211 free(args);
7212
7213 return rc;
7214}
7215
7216/**
7217 * @brief Evaluate Number. Logs directly on error.
7218 *
7219 * @param[in] ctx Context for errors.
7220 * @param[in] exp Parsed XPath expression.
7221 * @param[in] exp_idx Position in the expression @p exp.
7222 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7223 * @return LY_ERR
7224 */
7225static LY_ERR
7226eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7227{
7228 long double num;
7229 char *endptr;
7230
7231 if (set) {
7232 errno = 0;
7233 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7234 if (errno) {
7235 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7236 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7237 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7238 return LY_EVALID;
7239 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7240 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7241 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7242 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7243 return LY_EVALID;
7244 }
7245
7246 set_fill_number(set, num);
7247 }
7248
7249 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7250 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7251 ++(*exp_idx);
7252 return LY_SUCCESS;
7253}
7254
7255/**
7256 * @brief Evaluate PathExpr. Logs directly on error.
7257 *
7258 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7259 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7260 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7261 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7262 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7263 *
7264 * @param[in] exp Parsed XPath expression.
7265 * @param[in] exp_idx Position in the expression @p exp.
7266 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7267 * @param[in] options XPath options.
7268 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7269 */
7270static LY_ERR
7271eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7272{
7273 int all_desc, parent_pos_pred;
7274 LY_ERR rc;
7275
7276 switch (exp->tokens[*exp_idx]) {
7277 case LYXP_TOKEN_PAR1:
7278 /* '(' Expr ')' */
7279
7280 /* '(' */
7281 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7282 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7283 ++(*exp_idx);
7284
7285 /* Expr */
7286 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7287 LY_CHECK_RET(rc);
7288
7289 /* ')' */
7290 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7291 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7292 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7293 ++(*exp_idx);
7294
7295 parent_pos_pred = 0;
7296 goto predicate;
7297
7298 case LYXP_TOKEN_DOT:
7299 case LYXP_TOKEN_DDOT:
7300 case LYXP_TOKEN_AT:
7301 case LYXP_TOKEN_NAMETEST:
7302 case LYXP_TOKEN_NODETYPE:
7303 /* RelativeLocationPath */
7304 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7305 LY_CHECK_RET(rc);
7306 break;
7307
7308 case LYXP_TOKEN_FUNCNAME:
7309 /* FunctionCall */
7310 if (!set) {
7311 rc = eval_function_call(exp, exp_idx, NULL, options);
7312 } else {
7313 rc = eval_function_call(exp, exp_idx, set, options);
7314 }
7315 LY_CHECK_RET(rc);
7316
7317 parent_pos_pred = 1;
7318 goto predicate;
7319
7320 case LYXP_TOKEN_OPERATOR_PATH:
7321 /* AbsoluteLocationPath */
7322 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7323 LY_CHECK_RET(rc);
7324 break;
7325
7326 case LYXP_TOKEN_LITERAL:
7327 /* Literal */
7328 if (!set || (options & LYXP_SCNODE_ALL)) {
7329 if (set) {
7330 set_scnode_clear_ctx(set);
7331 }
7332 eval_literal(exp, exp_idx, NULL);
7333 } else {
7334 eval_literal(exp, exp_idx, set);
7335 }
7336
7337 parent_pos_pred = 1;
7338 goto predicate;
7339
7340 case LYXP_TOKEN_NUMBER:
7341 /* Number */
7342 if (!set || (options & LYXP_SCNODE_ALL)) {
7343 if (set) {
7344 set_scnode_clear_ctx(set);
7345 }
Michal Vasko02a77382019-09-12 11:47:35 +02007346 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007347 } else {
7348 rc = eval_number(set->ctx, exp, exp_idx, set);
7349 }
7350 LY_CHECK_RET(rc);
7351
7352 parent_pos_pred = 1;
7353 goto predicate;
7354
7355 default:
7356 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7357 &exp->expr[exp->tok_pos[*exp_idx]]);
7358 return LY_EVALID;
7359 }
7360
7361 return LY_SUCCESS;
7362
7363predicate:
7364 /* Predicate* */
7365 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7366 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7367 LY_CHECK_RET(rc);
7368 }
7369
7370 /* ('/' or '//') RelativeLocationPath */
7371 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7372
7373 /* evaluate '/' or '//' */
7374 if (exp->tok_len[*exp_idx] == 1) {
7375 all_desc = 0;
7376 } else {
7377 assert(exp->tok_len[*exp_idx] == 2);
7378 all_desc = 1;
7379 }
7380
7381 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7382 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7383 ++(*exp_idx);
7384
7385 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7386 LY_CHECK_RET(rc);
7387 }
7388
7389 return LY_SUCCESS;
7390}
7391
7392/**
7393 * @brief Evaluate UnionExpr. Logs directly on error.
7394 *
7395 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7396 *
7397 * @param[in] exp Parsed XPath expression.
7398 * @param[in] exp_idx Position in the expression @p exp.
7399 * @param[in] repeat How many times this expression is repeated.
7400 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7401 * @param[in] options XPath options.
7402 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7403 */
7404static LY_ERR
7405eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7406{
7407 LY_ERR rc = LY_SUCCESS;
7408 struct lyxp_set orig_set, set2;
7409 uint16_t i;
7410
7411 assert(repeat);
7412
7413 set_init(&orig_set, set);
7414 set_init(&set2, set);
7415
7416 set_fill_set(&orig_set, set);
7417
7418 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7419 LY_CHECK_GOTO(rc, cleanup);
7420
7421 /* ('|' PathExpr)* */
7422 for (i = 0; i < repeat; ++i) {
7423 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7424 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7425 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7426 ++(*exp_idx);
7427
7428 if (!set) {
7429 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7430 LY_CHECK_GOTO(rc, cleanup);
7431 continue;
7432 }
7433
7434 set_fill_set(&set2, &orig_set);
7435 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7436 LY_CHECK_GOTO(rc, cleanup);
7437
7438 /* eval */
7439 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007440 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007441 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007442 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007443 LY_CHECK_GOTO(rc, cleanup);
7444 }
7445 }
7446
7447cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007448 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7449 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007450 return rc;
7451}
7452
7453/**
7454 * @brief Evaluate UnaryExpr. Logs directly on error.
7455 *
7456 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7457 *
7458 * @param[in] exp Parsed XPath expression.
7459 * @param[in] exp_idx Position in the expression @p exp.
7460 * @param[in] repeat How many times this expression is repeated.
7461 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7462 * @param[in] options XPath options.
7463 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7464 */
7465static LY_ERR
7466eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7467{
7468 LY_ERR rc;
7469 uint16_t this_op, i;
7470
7471 assert(repeat);
7472
7473 /* ('-')+ */
7474 this_op = *exp_idx;
7475 for (i = 0; i < repeat; ++i) {
7476 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7477
7478 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7479 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7480 ++(*exp_idx);
7481 }
7482
7483 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7484 LY_CHECK_RET(rc);
7485
7486 if (set && (repeat % 2)) {
7487 if (options & LYXP_SCNODE_ALL) {
7488 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7489 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007490 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007491 LY_CHECK_RET(rc);
7492 }
7493 }
7494
7495 return LY_SUCCESS;
7496}
7497
7498/**
7499 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7500 *
7501 * [16] MultiplicativeExpr ::= UnaryExpr
7502 * | MultiplicativeExpr '*' UnaryExpr
7503 * | MultiplicativeExpr 'div' UnaryExpr
7504 * | MultiplicativeExpr 'mod' UnaryExpr
7505 *
7506 * @param[in] exp Parsed XPath expression.
7507 * @param[in] exp_idx Position in the expression @p exp.
7508 * @param[in] repeat How many times this expression is repeated.
7509 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7510 * @param[in] options XPath options.
7511 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7512 */
7513static LY_ERR
7514eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7515{
7516 LY_ERR rc;
7517 uint16_t this_op;
7518 struct lyxp_set orig_set, set2;
7519 uint16_t i;
7520
7521 assert(repeat);
7522
7523 set_init(&orig_set, set);
7524 set_init(&set2, set);
7525
7526 set_fill_set(&orig_set, set);
7527
7528 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7529 LY_CHECK_GOTO(rc, cleanup);
7530
7531 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7532 for (i = 0; i < repeat; ++i) {
7533 this_op = *exp_idx;
7534
7535 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7536 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7537 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7538 ++(*exp_idx);
7539
7540 if (!set) {
7541 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7542 LY_CHECK_GOTO(rc, cleanup);
7543 continue;
7544 }
7545
7546 set_fill_set(&set2, &orig_set);
7547 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7548 LY_CHECK_GOTO(rc, cleanup);
7549
7550 /* eval */
7551 if (options & LYXP_SCNODE_ALL) {
7552 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007553 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007554 set_scnode_clear_ctx(set);
7555 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007556 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007557 LY_CHECK_GOTO(rc, cleanup);
7558 }
7559 }
7560
7561cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007562 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7563 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007564 return rc;
7565}
7566
7567/**
7568 * @brief Evaluate AdditiveExpr. Logs directly on error.
7569 *
7570 * [15] AdditiveExpr ::= MultiplicativeExpr
7571 * | AdditiveExpr '+' MultiplicativeExpr
7572 * | AdditiveExpr '-' MultiplicativeExpr
7573 *
7574 * @param[in] exp Parsed XPath expression.
7575 * @param[in] exp_idx Position in the expression @p exp.
7576 * @param[in] repeat How many times this expression is repeated.
7577 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7578 * @param[in] options XPath options.
7579 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7580 */
7581static LY_ERR
7582eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7583{
7584 LY_ERR rc;
7585 uint16_t this_op;
7586 struct lyxp_set orig_set, set2;
7587 uint16_t i;
7588
7589 assert(repeat);
7590
7591 set_init(&orig_set, set);
7592 set_init(&set2, set);
7593
7594 set_fill_set(&orig_set, set);
7595
7596 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7597 LY_CHECK_GOTO(rc, cleanup);
7598
7599 /* ('+' / '-' MultiplicativeExpr)* */
7600 for (i = 0; i < repeat; ++i) {
7601 this_op = *exp_idx;
7602
7603 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7604 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7605 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7606 ++(*exp_idx);
7607
7608 if (!set) {
7609 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7610 LY_CHECK_GOTO(rc, cleanup);
7611 continue;
7612 }
7613
7614 set_fill_set(&set2, &orig_set);
7615 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7616 LY_CHECK_GOTO(rc, cleanup);
7617
7618 /* eval */
7619 if (options & LYXP_SCNODE_ALL) {
7620 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007621 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007622 set_scnode_clear_ctx(set);
7623 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007624 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007625 LY_CHECK_GOTO(rc, cleanup);
7626 }
7627 }
7628
7629cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007630 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7631 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007632 return rc;
7633}
7634
7635/**
7636 * @brief Evaluate RelationalExpr. Logs directly on error.
7637 *
7638 * [14] RelationalExpr ::= AdditiveExpr
7639 * | RelationalExpr '<' AdditiveExpr
7640 * | RelationalExpr '>' AdditiveExpr
7641 * | RelationalExpr '<=' AdditiveExpr
7642 * | RelationalExpr '>=' AdditiveExpr
7643 *
7644 * @param[in] exp Parsed XPath expression.
7645 * @param[in] exp_idx Position in the expression @p exp.
7646 * @param[in] repeat How many times this expression is repeated.
7647 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7648 * @param[in] options XPath options.
7649 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7650 */
7651static LY_ERR
7652eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7653{
7654 LY_ERR rc;
7655 uint16_t this_op;
7656 struct lyxp_set orig_set, set2;
7657 uint16_t i;
7658
7659 assert(repeat);
7660
7661 set_init(&orig_set, set);
7662 set_init(&set2, set);
7663
7664 set_fill_set(&orig_set, set);
7665
7666 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7667 LY_CHECK_GOTO(rc, cleanup);
7668
7669 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7670 for (i = 0; i < repeat; ++i) {
7671 this_op = *exp_idx;
7672
7673 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7674 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7675 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7676 ++(*exp_idx);
7677
7678 if (!set) {
7679 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7680 LY_CHECK_GOTO(rc, cleanup);
7681 continue;
7682 }
7683
7684 set_fill_set(&set2, &orig_set);
7685 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7686 LY_CHECK_GOTO(rc, cleanup);
7687
7688 /* eval */
7689 if (options & LYXP_SCNODE_ALL) {
7690 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007691 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007692 set_scnode_clear_ctx(set);
7693 } else {
7694 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7695 LY_CHECK_GOTO(rc, cleanup);
7696 }
7697 }
7698
7699cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007700 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7701 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007702 return rc;
7703}
7704
7705/**
7706 * @brief Evaluate EqualityExpr. Logs directly on error.
7707 *
7708 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7709 * | EqualityExpr '!=' RelationalExpr
7710 *
7711 * @param[in] exp Parsed XPath expression.
7712 * @param[in] exp_idx Position in the expression @p exp.
7713 * @param[in] repeat How many times this expression is repeated.
7714 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7715 * @param[in] options XPath options.
7716 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7717 */
7718static LY_ERR
7719eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7720{
7721 LY_ERR rc;
7722 uint16_t this_op;
7723 struct lyxp_set orig_set, set2;
7724 uint16_t i;
7725
7726 assert(repeat);
7727
7728 set_init(&orig_set, set);
7729 set_init(&set2, set);
7730
7731 set_fill_set(&orig_set, set);
7732
7733 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7734 LY_CHECK_GOTO(rc, cleanup);
7735
7736 /* ('=' / '!=' RelationalExpr)* */
7737 for (i = 0; i < repeat; ++i) {
7738 this_op = *exp_idx;
7739
7740 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7741 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7742 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7743 ++(*exp_idx);
7744
7745 if (!set) {
7746 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7747 LY_CHECK_GOTO(rc, cleanup);
7748 continue;
7749 }
7750
7751 set_fill_set(&set2, &orig_set);
7752 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7753 LY_CHECK_GOTO(rc, cleanup);
7754
7755 /* eval */
7756 if (options & LYXP_SCNODE_ALL) {
7757 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7758 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7759 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007760 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007761 set_scnode_clear_ctx(set);
7762 } else {
7763 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7764 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7765 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7766 /* left operand is identityref */
7767 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7768 /* missing prefix in the right operand */
7769 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7770 if (!set2.val.str) {
7771 goto cleanup;
7772 }
7773
7774 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7775 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7776 set2.val.str[strlen(set->local_mod->name)] = ':';
7777 }
7778 }
7779
7780 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7781 LY_CHECK_GOTO(rc, cleanup);
7782 }
7783 }
7784
7785cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007786 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7787 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007788 return rc;
7789}
7790
7791/**
7792 * @brief Evaluate AndExpr. Logs directly on error.
7793 *
7794 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7795 *
7796 * @param[in] exp Parsed XPath expression.
7797 * @param[in] exp_idx Position in the expression @p exp.
7798 * @param[in] repeat How many times this expression is repeated.
7799 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7800 * @param[in] options XPath options.
7801 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7802 */
7803static LY_ERR
7804eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7805{
7806 LY_ERR rc;
7807 struct lyxp_set orig_set, set2;
7808 uint16_t i;
7809
7810 assert(repeat);
7811
7812 set_init(&orig_set, set);
7813 set_init(&set2, set);
7814
7815 set_fill_set(&orig_set, set);
7816
7817 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7818 LY_CHECK_GOTO(rc, cleanup);
7819
7820 /* cast to boolean, we know that will be the final result */
7821 if (set && (options & LYXP_SCNODE_ALL)) {
7822 set_scnode_clear_ctx(set);
7823 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007824 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007825 }
7826
7827 /* ('and' EqualityExpr)* */
7828 for (i = 0; i < repeat; ++i) {
7829 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7830 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7831 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7832 ++(*exp_idx);
7833
7834 /* lazy evaluation */
7835 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7836 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7837 LY_CHECK_GOTO(rc, cleanup);
7838 continue;
7839 }
7840
7841 set_fill_set(&set2, &orig_set);
7842 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7843 LY_CHECK_GOTO(rc, cleanup);
7844
7845 /* eval - just get boolean value actually */
7846 if (set->type == LYXP_SET_SCNODE_SET) {
7847 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007848 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007849 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007850 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007851 set_fill_set(set, &set2);
7852 }
7853 }
7854
7855cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007856 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7857 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007858 return rc;
7859}
7860
7861/**
7862 * @brief Evaluate OrExpr. Logs directly on error.
7863 *
7864 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7865 *
7866 * @param[in] exp Parsed XPath expression.
7867 * @param[in] exp_idx Position in the expression @p exp.
7868 * @param[in] repeat How many times this expression is repeated.
7869 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7870 * @param[in] options XPath options.
7871 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7872 */
7873static LY_ERR
7874eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7875{
7876 LY_ERR rc;
7877 struct lyxp_set orig_set, set2;
7878 uint16_t i;
7879
7880 assert(repeat);
7881
7882 set_init(&orig_set, set);
7883 set_init(&set2, set);
7884
7885 set_fill_set(&orig_set, set);
7886
7887 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7888 LY_CHECK_GOTO(rc, cleanup);
7889
7890 /* cast to boolean, we know that will be the final result */
7891 if (set && (options & LYXP_SCNODE_ALL)) {
7892 set_scnode_clear_ctx(set);
7893 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007894 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007895 }
7896
7897 /* ('or' AndExpr)* */
7898 for (i = 0; i < repeat; ++i) {
7899 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7900 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7901 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7902 ++(*exp_idx);
7903
7904 /* lazy evaluation */
7905 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7906 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7907 LY_CHECK_GOTO(rc, cleanup);
7908 continue;
7909 }
7910
7911 set_fill_set(&set2, &orig_set);
7912 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7913 * but it does not matter */
7914 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7915 LY_CHECK_GOTO(rc, cleanup);
7916
7917 /* eval - just get boolean value actually */
7918 if (set->type == LYXP_SET_SCNODE_SET) {
7919 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007920 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007921 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007922 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007923 set_fill_set(set, &set2);
7924 }
7925 }
7926
7927cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007928 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7929 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007930 return rc;
7931}
7932
7933/**
7934 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7935 *
7936 * @param[in] exp Parsed XPath expression.
7937 * @param[in] exp_idx Position in the expression @p exp.
7938 * @param[in] etype Expression type to evaluate.
7939 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7940 * @param[in] options XPath options.
7941 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7942 */
7943static LY_ERR
7944eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7945{
7946 uint16_t i, count;
7947 enum lyxp_expr_type next_etype;
7948 LY_ERR rc;
7949
7950 /* process operator repeats */
7951 if (!exp->repeat[*exp_idx]) {
7952 next_etype = LYXP_EXPR_NONE;
7953 } else {
7954 /* find etype repeat */
7955 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7956
7957 /* select one-priority lower because etype expression called us */
7958 if (i) {
7959 next_etype = exp->repeat[*exp_idx][i - 1];
7960 /* count repeats for that expression */
7961 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7962 } else {
7963 next_etype = LYXP_EXPR_NONE;
7964 }
7965 }
7966
7967 /* decide what expression are we parsing based on the repeat */
7968 switch (next_etype) {
7969 case LYXP_EXPR_OR:
7970 rc = eval_or_expr(exp, exp_idx, count, set, options);
7971 break;
7972 case LYXP_EXPR_AND:
7973 rc = eval_and_expr(exp, exp_idx, count, set, options);
7974 break;
7975 case LYXP_EXPR_EQUALITY:
7976 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7977 break;
7978 case LYXP_EXPR_RELATIONAL:
7979 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7980 break;
7981 case LYXP_EXPR_ADDITIVE:
7982 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7983 break;
7984 case LYXP_EXPR_MULTIPLICATIVE:
7985 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7986 break;
7987 case LYXP_EXPR_UNARY:
7988 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7989 break;
7990 case LYXP_EXPR_UNION:
7991 rc = eval_union_expr(exp, exp_idx, count, set, options);
7992 break;
7993 case LYXP_EXPR_NONE:
7994 rc = eval_path_expr(exp, exp_idx, set, options);
7995 break;
7996 default:
7997 LOGINT_RET(set->ctx);
7998 }
7999
8000 return rc;
8001}
8002
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008003/**
8004 * @brief Get root type.
8005 *
8006 * @param[in] ctx_node Context node.
8007 * @param[in] ctx_scnode Schema context node.
8008 * @param[in] options XPath options.
8009 * @return Root type.
8010 */
8011static enum lyxp_node_type
8012lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8013{
8014 if (options & LYXP_SCNODE_ALL) {
8015 if (options & LYXP_SCNODE) {
8016 /* general root that can access everything */
8017 return LYXP_NODE_ROOT;
8018 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8019 /* root context node can access only config data (because we said so, it is unspecified) */
8020 return LYXP_NODE_ROOT_CONFIG;
8021 } else {
8022 return LYXP_NODE_ROOT;
8023 }
8024 }
8025
8026 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8027 /* root context node can access only config data (because we said so, it is unspecified) */
8028 return LYXP_NODE_ROOT_CONFIG;
8029 }
8030
8031 return LYXP_NODE_ROOT;
8032}
8033
Michal Vasko03ff5a72019-09-11 13:49:33 +02008034LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008035lyxp_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 +01008036 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 +02008037{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008038 uint16_t exp_idx = 0;
8039 LY_ERR rc;
8040
Michal Vaskoecd62de2019-11-13 12:35:11 +01008041 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008042
8043 /* prepare set for evaluation */
8044 exp_idx = 0;
8045 memset(set, 0, sizeof *set);
8046 set->type = LYXP_SET_EMPTY;
Michal Vasko9b368d32020-02-14 13:53:31 +01008047 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, 0);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008048 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008049 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008050 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008051 set->local_mod = local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +01008052 set->tree = tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008053 set->format = format;
8054
8055 /* evaluate */
8056 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8057 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008058 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008059 }
8060
Michal Vasko03ff5a72019-09-11 13:49:33 +02008061 return rc;
8062}
8063
8064#if 0
8065
8066/* full xml printing of set elements, not used currently */
8067
8068void
8069lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8070{
8071 uint32_t i;
8072 char *str_num;
8073 struct lyout out;
8074
8075 memset(&out, 0, sizeof out);
8076
8077 out.type = LYOUT_STREAM;
8078 out.method.f = f;
8079
8080 switch (set->type) {
8081 case LYXP_SET_EMPTY:
8082 ly_print(&out, "Empty XPath set\n\n");
8083 break;
8084 case LYXP_SET_BOOLEAN:
8085 ly_print(&out, "Boolean XPath set:\n");
8086 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8087 break;
8088 case LYXP_SET_STRING:
8089 ly_print(&out, "String XPath set:\n");
8090 ly_print(&out, "\"%s\"\n\n", set->value.str);
8091 break;
8092 case LYXP_SET_NUMBER:
8093 ly_print(&out, "Number XPath set:\n");
8094
8095 if (isnan(set->value.num)) {
8096 str_num = strdup("NaN");
8097 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8098 str_num = strdup("0");
8099 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8100 str_num = strdup("Infinity");
8101 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8102 str_num = strdup("-Infinity");
8103 } else if ((long long)set->value.num == set->value.num) {
8104 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8105 str_num = NULL;
8106 }
8107 } else {
8108 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8109 str_num = NULL;
8110 }
8111 }
8112 if (!str_num) {
8113 LOGMEM;
8114 return;
8115 }
8116 ly_print(&out, "%s\n\n", str_num);
8117 free(str_num);
8118 break;
8119 case LYXP_SET_NODE_SET:
8120 ly_print(&out, "Node XPath set:\n");
8121
8122 for (i = 0; i < set->used; ++i) {
8123 ly_print(&out, "%d. ", i + 1);
8124 switch (set->node_type[i]) {
8125 case LYXP_NODE_ROOT_ALL:
8126 ly_print(&out, "ROOT all\n\n");
8127 break;
8128 case LYXP_NODE_ROOT_CONFIG:
8129 ly_print(&out, "ROOT config\n\n");
8130 break;
8131 case LYXP_NODE_ROOT_STATE:
8132 ly_print(&out, "ROOT state\n\n");
8133 break;
8134 case LYXP_NODE_ROOT_NOTIF:
8135 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8136 break;
8137 case LYXP_NODE_ROOT_RPC:
8138 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8139 break;
8140 case LYXP_NODE_ROOT_OUTPUT:
8141 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8142 break;
8143 case LYXP_NODE_ELEM:
8144 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8145 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8146 ly_print(&out, "\n");
8147 break;
8148 case LYXP_NODE_TEXT:
8149 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8150 break;
8151 case LYXP_NODE_ATTR:
8152 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8153 break;
8154 }
8155 }
8156 break;
8157 }
8158}
8159
8160#endif
8161
8162LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008163lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008164{
8165 long double num;
8166 char *str;
8167 LY_ERR rc;
8168
8169 if (!set || (set->type == target)) {
8170 return LY_SUCCESS;
8171 }
8172
8173 /* it's not possible to convert anything into a node set */
8174 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8175
8176 if (set->type == LYXP_SET_SCNODE_SET) {
8177 set_free_content(set);
8178 return LY_EINVAL;
8179 }
8180
8181 /* to STRING */
8182 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8183 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8184 switch (set->type) {
8185 case LYXP_SET_NUMBER:
8186 if (isnan(set->val.num)) {
8187 set->val.str = strdup("NaN");
8188 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8189 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8190 set->val.str = strdup("0");
8191 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8192 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8193 set->val.str = strdup("Infinity");
8194 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8195 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8196 set->val.str = strdup("-Infinity");
8197 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8198 } else if ((long long)set->val.num == set->val.num) {
8199 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8200 LOGMEM_RET(set->ctx);
8201 }
8202 set->val.str = str;
8203 } else {
8204 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8205 LOGMEM_RET(set->ctx);
8206 }
8207 set->val.str = str;
8208 }
8209 break;
8210 case LYXP_SET_BOOLEAN:
8211 if (set->val.bool) {
8212 set->val.str = strdup("true");
8213 } else {
8214 set->val.str = strdup("false");
8215 }
8216 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8217 break;
8218 case LYXP_SET_NODE_SET:
8219 assert(set->used);
8220
8221 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008222 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008223
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008224 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008225 LY_CHECK_RET(rc);
8226 set_free_content(set);
8227 set->val.str = str;
8228 break;
8229 case LYXP_SET_EMPTY:
8230 set->val.str = strdup("");
8231 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8232 break;
8233 default:
8234 LOGINT_RET(set->ctx);
8235 }
8236 set->type = LYXP_SET_STRING;
8237 }
8238
8239 /* to NUMBER */
8240 if (target == LYXP_SET_NUMBER) {
8241 switch (set->type) {
8242 case LYXP_SET_STRING:
8243 num = cast_string_to_number(set->val.str);
8244 set_free_content(set);
8245 set->val.num = num;
8246 break;
8247 case LYXP_SET_BOOLEAN:
8248 if (set->val.bool) {
8249 set->val.num = 1;
8250 } else {
8251 set->val.num = 0;
8252 }
8253 break;
8254 default:
8255 LOGINT_RET(set->ctx);
8256 }
8257 set->type = LYXP_SET_NUMBER;
8258 }
8259
8260 /* to BOOLEAN */
8261 if (target == LYXP_SET_BOOLEAN) {
8262 switch (set->type) {
8263 case LYXP_SET_NUMBER:
8264 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8265 set->val.bool = 0;
8266 } else {
8267 set->val.bool = 1;
8268 }
8269 break;
8270 case LYXP_SET_STRING:
8271 if (set->val.str[0]) {
8272 set_free_content(set);
8273 set->val.bool = 1;
8274 } else {
8275 set_free_content(set);
8276 set->val.bool = 0;
8277 }
8278 break;
8279 case LYXP_SET_NODE_SET:
8280 set_free_content(set);
8281
8282 assert(set->used);
8283 set->val.bool = 1;
8284 break;
8285 case LYXP_SET_EMPTY:
8286 set->val.bool = 0;
8287 break;
8288 default:
8289 LOGINT_RET(set->ctx);
8290 }
8291 set->type = LYXP_SET_BOOLEAN;
8292 }
8293
8294 /* to EMPTY */
8295 if (target == LYXP_SET_EMPTY) {
8296 set_free_content(set);
8297 set->type = LYXP_SET_EMPTY;
8298 }
8299
8300 return LY_SUCCESS;
8301}
8302
8303LY_ERR
8304lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8305 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8306{
8307 struct ly_ctx *ctx;
8308 uint16_t exp_idx = 0;
8309
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008310 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008311
8312 ctx = local_mod->ctx;
8313
8314 /* prepare set for evaluation */
8315 exp_idx = 0;
8316 memset(set, 0, sizeof *set);
8317 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008318 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008319 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008320 set->ctx = ctx;
8321 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008322 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008323 set->local_mod = local_mod;
8324 set->format = format;
8325
8326 /* evaluate */
8327 return eval_expr_select(exp, &exp_idx, 0, set, options);
8328}