blob: 93dd7f6fc6607c284330beb0c1ec76c876e0ba7e [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) {
176 case LYXP_NODE_ROOT:
177 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
178 break;
179 case LYXP_NODE_ROOT_CONFIG:
180 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
181 break;
182 case LYXP_NODE_ELEM:
183 if ((item->node->schema->nodetype == LYS_LIST)
184 && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
185 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
186 item->node->schema->name,
187 (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node), &dynamic)));
188 if (dynamic) {
189 free(str);
190 }
191 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
192 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
193 item->node->schema->name,
194 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
195 if (dynamic) {
196 free(str);
197 }
198 } else {
199 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
200 }
201 break;
202 case LYXP_NODE_TEXT:
203 if (item->node->schema->nodetype & LYS_ANYDATA) {
204 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
205 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
206 } else {
207 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
208 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
209 if (dynamic) {
210 free(str);
211 }
212 }
213 break;
214 case LYXP_NODE_ATTR:
215 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ATTR %s = %s", i + 1, item->pos, set->val.attrs[i].attr->name,
216 set->val.attrs[i].attr->value);
217 break;
218 }
219 }
220 break;
221
222 case LYXP_SET_SCNODE_SET:
223 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
224 for (i = 0; i < set->used; ++i) {
225 sitem = &set->val.scnodes[i];
226
227 switch (sitem->type) {
228 case LYXP_NODE_ROOT:
229 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
230 break;
231 case LYXP_NODE_ROOT_CONFIG:
232 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
233 break;
234 case LYXP_NODE_ELEM:
235 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
236 break;
237 default:
238 LOGINT(NULL);
239 break;
240 }
241 }
242 break;
243
244 case LYXP_SET_EMPTY:
245 LOGDBG(LY_LDGXPATH, "set EMPTY");
246 break;
247
248 case LYXP_SET_BOOLEAN:
249 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
250 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
251 break;
252
253 case LYXP_SET_STRING:
254 LOGDBG(LY_LDGXPATH, "set STRING");
255 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
256 break;
257
258 case LYXP_SET_NUMBER:
259 LOGDBG(LY_LDGXPATH, "set NUMBER");
260
261 if (isnan(set->val.num)) {
262 str = strdup("NaN");
263 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
264 str = strdup("0");
265 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
266 str = strdup("Infinity");
267 } else if (isinf(set->val.num) && signbit(set->val.num)) {
268 str = strdup("-Infinity");
269 } else if ((long long)set->val.num == set->val.num) {
270 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
271 str = NULL;
272 }
273 } else {
274 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
275 str = NULL;
276 }
277 }
278 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
279
280 LOGDBG(LY_LDGXPATH, "\t%s", str);
281 free(str);
282 }
283}
284
285#endif
286
287/**
288 * @brief Realloc the string \p str.
289 *
290 * @param[in] ctx libyang context for logging.
291 * @param[in] needed How much free space is required.
292 * @param[in,out] str Pointer to the string to use.
293 * @param[in,out] used Used bytes in \p str.
294 * @param[in,out] size Allocated bytes in \p str.
295 * @return LY_ERR
296 */
297static LY_ERR
298cast_string_realloc(struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
299{
300 if (*size - *used < needed) {
301 do {
302 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
303 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
304 return LY_EINVAL;
305 }
306 *size += LYXP_STRING_CAST_SIZE_STEP;
307 } while (*size - *used < needed);
308 *str = ly_realloc(*str, *size * sizeof(char));
309 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
310 }
311
312 return LY_SUCCESS;
313}
314
315/**
316 * @brief Cast nodes recursively to one string @p str.
317 *
318 * @param[in] node Node to cast.
319 * @param[in] fake_cont Whether to put the data into a "fake" container.
320 * @param[in] root_type Type of the XPath root.
321 * @param[in] indent Current indent.
322 * @param[in,out] str Resulting string.
323 * @param[in,out] used Used bytes in @p str.
324 * @param[in,out] size Allocated bytes in @p str.
325 * @return LY_ERR
326 */
327static LY_ERR
328cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
329 uint16_t *used, uint16_t *size)
330{
331 char *buf, *line, *ptr;
332 const char *value_str;
333 int dynamic;
334 const struct lyd_node *child;
335 struct lyd_node_any *any;
336 LY_ERR rc;
337
338 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
339 return LY_SUCCESS;
340 }
341
342 if (fake_cont) {
343 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
344 LY_CHECK_RET(rc);
345 strcpy(*str + (*used - 1), "\n");
346 ++(*used);
347
348 ++indent;
349 }
350
351 switch (node->schema->nodetype) {
352 case LYS_CONTAINER:
353 case LYS_LIST:
354 case LYS_RPC:
355 case LYS_NOTIF:
356 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
357 LY_CHECK_RET(rc);
358 strcpy(*str + (*used - 1), "\n");
359 ++(*used);
360
361 for (child = lyd_node_children(node); child; child = child->next) {
362 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
363 LY_CHECK_RET(rc);
364 }
365
366 break;
367
368 case LYS_LEAF:
369 case LYS_LEAFLIST:
370 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
371
372 /* print indent */
373 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
374 if (rc != LY_SUCCESS) {
375 if (dynamic) {
376 free((char *)value_str);
377 }
378 return rc;
379 }
380 memset(*str + (*used - 1), ' ', indent * 2);
381 *used += indent * 2;
382
383 /* print value */
384 if (*used == 1) {
385 sprintf(*str + (*used - 1), "%s", value_str);
386 *used += strlen(value_str);
387 } else {
388 sprintf(*str + (*used - 1), "%s\n", value_str);
389 *used += strlen(value_str) + 1;
390 }
391 if (dynamic) {
392 free((char *)value_str);
393 }
394
395 break;
396
397 case LYS_ANYXML:
398 case LYS_ANYDATA:
399 any = (struct lyd_node_any *)node;
400 if (!(void *)any->value.tree) {
401 /* no content */
402 buf = strdup("");
403 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
404 } else {
405 switch (any->value_type) {
406 case LYD_ANYDATA_STRING:
407 case LYD_ANYDATA_XML:
408 case LYD_ANYDATA_JSON:
409 buf = strdup(any->value.json);
410 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
411 break;
412 case LYD_ANYDATA_DATATREE:
413 rc = lyd_print_mem(&buf, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
414 LY_CHECK_RET(rc);
415 break;
416 /* TODO case LYD_ANYDATA_LYB:
417 LOGERR(LYD_NODE_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
418 return -1;*/
419 }
420 }
421
422 line = strtok_r(buf, "\n", &ptr);
423 do {
424 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
425 if (rc != LY_SUCCESS) {
426 free(buf);
427 return rc;
428 }
429 memset(*str + (*used - 1), ' ', indent * 2);
430 *used += indent * 2;
431
432 strcpy(*str + (*used - 1), line);
433 *used += strlen(line);
434
435 strcpy(*str + (*used - 1), "\n");
436 *used += 1;
437 } while ((line = strtok_r(NULL, "\n", &ptr)));
438
439 free(buf);
440 break;
441
442 default:
443 LOGINT_RET(LYD_NODE_CTX(node));
444 }
445
446 if (fake_cont) {
447 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
448 LY_CHECK_RET(rc);
449 strcpy(*str + (*used - 1), "\n");
450 ++(*used);
451
452 --indent;
453 }
454
455 return LY_SUCCESS;
456}
457
458/**
459 * @brief Cast an element into a string.
460 *
461 * @param[in] node Node to cast.
462 * @param[in] fake_cont Whether to put the data into a "fake" container.
463 * @param[in] root_type Type of the XPath root.
464 * @param[out] str Element cast to dynamically-allocated string.
465 * @return LY_ERR
466 */
467static LY_ERR
468cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, char **str)
469{
470 uint16_t used, size;
471 LY_ERR rc;
472
473 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
474 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
475 (*str)[0] = '\0';
476 used = 1;
477 size = LYXP_STRING_CAST_SIZE_START;
478
479 rc = cast_string_recursive(node, fake_cont, root_type, 0, str, &used, &size);
480 if (rc != LY_SUCCESS) {
481 free(*str);
482 return rc;
483 }
484
485 if (size > used) {
486 *str = ly_realloc(*str, used * sizeof(char));
487 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
488 }
489 return LY_SUCCESS;
490}
491
492/**
493 * @brief Cast a LYXP_SET_NODE_SET set into a string.
494 * Context position aware.
495 *
496 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200497 * @param[out] str Cast dynamically-allocated string.
498 * @return LY_ERR
499 */
500static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100501cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200502{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200503 int dynamic;
504
Michal Vasko03ff5a72019-09-11 13:49:33 +0200505 switch (set->val.nodes[0].type) {
506 case LYXP_NODE_ROOT:
507 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100508 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200509 case LYXP_NODE_ELEM:
510 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100511 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200512 case LYXP_NODE_ATTR:
513 *str = (char *)lyd_attr2str(set->val.attrs[0].attr, &dynamic);
514 if (!dynamic) {
515 *str = strdup(*str);
516 if (!*str) {
517 LOGMEM_RET(set->ctx);
518 }
519 }
520 return LY_SUCCESS;
521 }
522
523 LOGINT_RET(set->ctx);
524}
525
526/**
527 * @brief Cast a string into an XPath number.
528 *
529 * @param[in] str String to use.
530 * @return Cast number.
531 */
532static long double
533cast_string_to_number(const char *str)
534{
535 long double num;
536 char *ptr;
537
538 errno = 0;
539 num = strtold(str, &ptr);
540 if (errno || *ptr) {
541 num = NAN;
542 }
543 return num;
544}
545
546/**
547 * @brief Callback for checking value equality.
548 *
549 * @param[in] val1_p First value.
550 * @param[in] val2_p Second value.
551 * @param[in] mod Whether hash table is being modified.
552 * @param[in] cb_data Callback data.
553 * @return 0 if not equal, non-zero if equal.
554 */
555static int
556set_values_equal_cb(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
557{
558 struct lyxp_set_hash_node *val1, *val2;
559
560 val1 = (struct lyxp_set_hash_node *)val1_p;
561 val2 = (struct lyxp_set_hash_node *)val2_p;
562
563 if ((val1->node == val2->node) && (val1->type == val2->type)) {
564 return 1;
565 }
566
567 return 0;
568}
569
570/**
571 * @brief Insert node and its hash into set.
572 *
573 * @param[in] set et to insert to.
574 * @param[in] node Node with hash.
575 * @param[in] type Node type.
576 */
577static void
578set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
579{
580 int r;
581 uint32_t i, hash;
582 struct lyxp_set_hash_node hnode;
583
584 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
585 /* create hash table and add all the nodes */
586 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
587 for (i = 0; i < set->used; ++i) {
588 hnode.node = set->val.nodes[i].node;
589 hnode.type = set->val.nodes[i].type;
590
591 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
592 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
593 hash = dict_hash_multi(hash, NULL, 0);
594
595 r = lyht_insert(set->ht, &hnode, hash, NULL);
596 assert(!r);
597 (void)r;
598 }
599 } else if (set->ht) {
600 assert(node);
601
602 /* add the new node into hash table */
603 hnode.node = node;
604 hnode.type = type;
605
606 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
607 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
608 hash = dict_hash_multi(hash, NULL, 0);
609
610 r = lyht_insert(set->ht, &hnode, hash, NULL);
611 assert(!r);
612 (void)r;
613 }
614}
615
616/**
617 * @brief Remove node and its hash from set.
618 *
619 * @param[in] set Set to remove from.
620 * @param[in] node Node to remove.
621 * @param[in] type Node type.
622 */
623static void
624set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
625{
626 int r;
627 struct lyxp_set_hash_node hnode;
628 uint32_t hash;
629
630 if (set->ht) {
631 hnode.node = node;
632 hnode.type = type;
633
634 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
635 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
636 hash = dict_hash_multi(hash, NULL, 0);
637
638 r = lyht_remove(set->ht, &hnode, hash);
639 assert(!r);
640 (void)r;
641
642 if (!set->ht->used) {
643 lyht_free(set->ht);
644 set->ht = NULL;
645 }
646 }
647}
648
649/**
650 * @brief Check whether node is in set based on its hash.
651 *
652 * @param[in] set Set to search in.
653 * @param[in] node Node to search for.
654 * @param[in] type Node type.
655 * @param[in] skip_idx Index in @p set to skip.
656 * @return LY_ERR
657 */
658static LY_ERR
659set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
660{
661 struct lyxp_set_hash_node hnode, *match_p;
662 uint32_t hash;
663
664 hnode.node = node;
665 hnode.type = type;
666
667 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
668 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
669 hash = dict_hash_multi(hash, NULL, 0);
670
671 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
672 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
673 /* we found it on the index that should be skipped, find another */
674 hnode = *match_p;
675 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
676 /* none other found */
677 return LY_SUCCESS;
678 }
679 }
680
681 return LY_EEXIST;
682 }
683
684 /* not found */
685 return LY_SUCCESS;
686}
687
688/**
689 * @brief Free dynamic content of a set.
690 *
691 * @param[in] set Set to modify.
692 */
693static void
694set_free_content(struct lyxp_set *set)
695{
696 if (!set) {
697 return;
698 }
699
700 if (set->type == LYXP_SET_NODE_SET) {
701 free(set->val.nodes);
702 lyht_free(set->ht);
703 set->ht = NULL;
704 } else if (set->type == LYXP_SET_SCNODE_SET) {
705 free(set->val.scnodes);
706 } else if (set->type == LYXP_SET_STRING) {
707 free(set->val.str);
708 }
709 set->type = LYXP_SET_EMPTY;
710}
711
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100712/**
713 * @brief Free dynamically-allocated set.
714 *
715 * @param[in] set Set to free.
716 */
717static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200718lyxp_set_free(struct lyxp_set *set)
719{
720 if (!set) {
721 return;
722 }
723
724 set_free_content(set);
725 free(set);
726}
727
728/**
729 * @brief Initialize set context.
730 *
731 * @param[in] new Set to initialize.
732 * @param[in] set Arbitrary initialized set.
733 */
734static void
735set_init(struct lyxp_set *new, struct lyxp_set *set)
736{
737 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200738 if (set) {
739 new->ctx = set->ctx;
740 new->ctx_node = set->ctx_node;
741 new->local_mod = set->local_mod;
742 new->trees = set->trees;
743 new->format = set->format;
744 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200745}
746
747/**
748 * @brief Create a deep copy of a set.
749 *
750 * @param[in] set Set to copy.
751 * @return Copy of @p set.
752 */
753static struct lyxp_set *
754set_copy(struct lyxp_set *set)
755{
756 struct lyxp_set *ret;
757 uint16_t i;
758
759 if (!set) {
760 return NULL;
761 }
762
763 ret = malloc(sizeof *ret);
764 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
765 set_init(ret, set);
766
767 if (set->type == LYXP_SET_SCNODE_SET) {
768 ret->type = set->type;
769
770 for (i = 0; i < set->used; ++i) {
771 if (set->val.scnodes[i].in_ctx == 1) {
Michal Vaskoecd62de2019-11-13 12:35:11 +0100772 if (lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200773 lyxp_set_free(ret);
774 return NULL;
775 }
776 }
777 }
778 } else if (set->type == LYXP_SET_NODE_SET) {
779 ret->type = set->type;
780 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
781 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
782 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
783
784 ret->used = ret->size = set->used;
785 ret->ctx_pos = set->ctx_pos;
786 ret->ctx_size = set->ctx_size;
787 ret->ht = lyht_dup(set->ht);
788 } else {
789 memcpy(ret, set, sizeof *ret);
790 if (set->type == LYXP_SET_STRING) {
791 ret->val.str = strdup(set->val.str);
792 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
793 }
794 }
795
796 return ret;
797}
798
799/**
800 * @brief Fill XPath set with a string. Any current data are disposed of.
801 *
802 * @param[in] set Set to fill.
803 * @param[in] string String to fill into \p set.
804 * @param[in] str_len Length of \p string. 0 is a valid value!
805 */
806static void
807set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
808{
809 set_free_content(set);
810
811 set->type = LYXP_SET_STRING;
812 if ((str_len == 0) && (string[0] != '\0')) {
813 string = "";
814 }
815 set->val.str = strndup(string, str_len);
816}
817
818/**
819 * @brief Fill XPath set with a number. Any current data are disposed of.
820 *
821 * @param[in] set Set to fill.
822 * @param[in] number Number to fill into \p set.
823 */
824static void
825set_fill_number(struct lyxp_set *set, long double number)
826{
827 set_free_content(set);
828
829 set->type = LYXP_SET_NUMBER;
830 set->val.num = number;
831}
832
833/**
834 * @brief Fill XPath set with a boolean. Any current data are disposed of.
835 *
836 * @param[in] set Set to fill.
837 * @param[in] boolean Boolean to fill into \p set.
838 */
839static void
840set_fill_boolean(struct lyxp_set *set, int boolean)
841{
842 set_free_content(set);
843
844 set->type = LYXP_SET_BOOLEAN;
845 set->val.bool = boolean;
846}
847
848/**
849 * @brief Fill XPath set with the value from another set (deep assign).
850 * Any current data are disposed of.
851 *
852 * @param[in] trg Set to fill.
853 * @param[in] src Source set to copy into \p trg.
854 */
855static void
856set_fill_set(struct lyxp_set *trg, struct lyxp_set *src)
857{
858 if (!trg || !src) {
859 return;
860 }
861
862 if (trg->type == LYXP_SET_NODE_SET) {
863 free(trg->val.nodes);
864 } else if (trg->type == LYXP_SET_STRING) {
865 free(trg->val.str);
866 }
867 set_init(trg, src);
868
869 if (src->type == LYXP_SET_SCNODE_SET) {
870 trg->type = LYXP_SET_SCNODE_SET;
871 trg->used = src->used;
872 trg->size = src->used;
873
874 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
875 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
876 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
877 } else if (src->type == LYXP_SET_BOOLEAN) {
878 set_fill_boolean(trg, src->val.bool);
879 } else if (src->type == LYXP_SET_NUMBER) {
880 set_fill_number(trg, src->val.num);
881 } else if (src->type == LYXP_SET_STRING) {
882 set_fill_string(trg, src->val.str, strlen(src->val.str));
883 } else {
884 if (trg->type == LYXP_SET_NODE_SET) {
885 free(trg->val.nodes);
886 } else if (trg->type == LYXP_SET_STRING) {
887 free(trg->val.str);
888 }
889
890 if (src->type == LYXP_SET_EMPTY) {
891 trg->type = LYXP_SET_EMPTY;
892 } else {
893 assert(src->type == LYXP_SET_NODE_SET);
894
895 trg->type = LYXP_SET_NODE_SET;
896 trg->used = src->used;
897 trg->size = src->used;
898 trg->ctx_pos = src->ctx_pos;
899 trg->ctx_size = src->ctx_size;
900
901 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
902 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
903 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
904 trg->ht = lyht_dup(src->ht);
905 }
906 }
907}
908
909/**
910 * @brief Clear context of all schema nodes.
911 *
912 * @param[in] set Set to clear.
913 */
914static void
915set_scnode_clear_ctx(struct lyxp_set *set)
916{
917 uint32_t i;
918
919 for (i = 0; i < set->used; ++i) {
920 if (set->val.scnodes[i].in_ctx == 1) {
921 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100922 } else if (set->val.scnodes[i].in_ctx == -2) {
923 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200924 }
925 }
926}
927
928/**
929 * @brief Remove a node from a set. Removing last node changes
930 * set into LYXP_SET_EMPTY. Context position aware.
931 *
932 * @param[in] set Set to use.
933 * @param[in] idx Index from @p set of the node to be removed.
934 */
935static void
936set_remove_node(struct lyxp_set *set, uint32_t idx)
937{
938 assert(set && (set->type == LYXP_SET_NODE_SET));
939 assert(idx < set->used);
940
941 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
942
943 --set->used;
944 if (set->used) {
945 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
946 (set->used - idx) * sizeof *set->val.nodes);
947 } else {
948 set_free_content(set);
949 set->type = LYXP_SET_EMPTY;
950 }
951}
952
953/**
Michal Vasko57eab132019-09-24 11:46:26 +0200954 * @brief Remove a node from a set by setting the node value to NULL.
955 *
956 * @param[in] set Set to use.
957 * @param[in] idx Index from @p set of the node to be removed.
958 */
959static void
960set_remove_node_null(struct lyxp_set *set, uint32_t idx)
961{
962 assert(set && (set->type == LYXP_SET_NODE_SET));
963 assert(idx < set->used);
964
965 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
966 set->val.nodes[idx].node = NULL;
967}
968
969/**
970 * @brief Remove all NULL nodes from a set. Removing last node changes
971 * set into LYXP_SET_EMPTY. Context position aware.
972 *
973 * @param[in] set Set to consolidate.
974 */
975static void
976set_remove_nodes_null(struct lyxp_set *set)
977{
978 uint16_t i, orig_used, end;
979 int32_t start;
980
981 assert(set && (set->type == LYXP_SET_NODE_SET));
982
983 orig_used = set->used;
984 set->used = 0;
985 for (i = 0; i < orig_used;) {
986 start = -1;
987 do {
988 if (set->val.nodes[i].node && (start == -1)) {
989 start = i;
990 } else if ((start > -1) && !set->val.nodes[i].node) {
991 end = i;
992 ++i;
993 break;
994 }
995
996 ++i;
997 if (i == orig_used) {
998 end = i;
999 }
1000 } while (i < orig_used);
1001
1002 if (start > -1) {
1003 /* move the whole chunk of valid nodes together */
1004 if (set->used != (unsigned)start) {
1005 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1006 }
1007 set->used += end - start;
1008 }
1009 }
1010
1011 if (!set->used) {
1012 set_free_content(set);
1013 /* this changes it to LYXP_SET_EMPTY */
1014 memset(set, 0, sizeof *set);
1015 }
1016}
1017
1018/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001019 * @brief Check for duplicates in a node set.
1020 *
1021 * @param[in] set Set to check.
1022 * @param[in] node Node to look for in @p set.
1023 * @param[in] node_type Type of @p node.
1024 * @param[in] skip_idx Index from @p set to skip.
1025 * @return LY_ERR
1026 */
1027static LY_ERR
1028set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1029{
1030 uint32_t i;
1031
1032 if (set->ht) {
1033 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1034 }
1035
1036 for (i = 0; i < set->used; ++i) {
1037 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1038 continue;
1039 }
1040
1041 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1042 return LY_EEXIST;
1043 }
1044 }
1045
1046 return LY_SUCCESS;
1047}
1048
Michal Vaskoecd62de2019-11-13 12:35:11 +01001049int
1050lyxp_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 +02001051{
1052 uint32_t i;
1053
1054 for (i = 0; i < set->used; ++i) {
1055 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1056 continue;
1057 }
1058
1059 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1060 return i;
1061 }
1062 }
1063
1064 return -1;
1065}
1066
Michal Vaskoecd62de2019-11-13 12:35:11 +01001067void
1068lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001069{
1070 uint32_t orig_used, i, j;
1071
1072 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1073 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1074
1075 if (set2->type == LYXP_SET_EMPTY) {
1076 return;
1077 }
1078
1079 if (set1->type == LYXP_SET_EMPTY) {
1080 memcpy(set1, set2, sizeof *set1);
1081 return;
1082 }
1083
1084 if (set1->used + set2->used > set1->size) {
1085 set1->size = set1->used + set2->used;
1086 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1087 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1088 }
1089
1090 orig_used = set1->used;
1091
1092 for (i = 0; i < set2->used; ++i) {
1093 for (j = 0; j < orig_used; ++j) {
1094 /* detect duplicities */
1095 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1096 break;
1097 }
1098 }
1099
1100 if (j == orig_used) {
1101 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1102 ++set1->used;
1103 }
1104 }
1105
1106 set_free_content(set2);
1107 set2->type = LYXP_SET_EMPTY;
1108}
1109
1110/**
1111 * @brief Insert a node into a set. Context position aware.
1112 *
1113 * @param[in] set Set to use.
1114 * @param[in] node Node to insert to @p set.
1115 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1116 * @param[in] node_type Node type of @p node.
1117 * @param[in] idx Index in @p set to insert into.
1118 */
1119static void
1120set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1121{
1122 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1123
1124 if (set->type == LYXP_SET_EMPTY) {
1125 /* first item */
1126 if (idx) {
1127 /* no real harm done, but it is a bug */
1128 LOGINT(set->ctx);
1129 idx = 0;
1130 }
1131 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1132 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1133 set->type = LYXP_SET_NODE_SET;
1134 set->used = 0;
1135 set->size = LYXP_SET_SIZE_START;
1136 set->ctx_pos = 1;
1137 set->ctx_size = 1;
1138 set->ht = NULL;
1139 } else {
1140 /* not an empty set */
1141 if (set->used == set->size) {
1142
1143 /* set is full */
1144 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1145 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1146 set->size += LYXP_SET_SIZE_STEP;
1147 }
1148
1149 if (idx > set->used) {
1150 LOGINT(set->ctx);
1151 idx = set->used;
1152 }
1153
1154 /* make space for the new node */
1155 if (idx < set->used) {
1156 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1157 }
1158 }
1159
1160 /* finally assign the value */
1161 set->val.nodes[idx].node = (struct lyd_node *)node;
1162 set->val.nodes[idx].type = node_type;
1163 set->val.nodes[idx].pos = pos;
1164 ++set->used;
1165
1166 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1167}
1168
Michal Vaskoecd62de2019-11-13 12:35:11 +01001169int
1170lyxp_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 +02001171{
1172 int ret;
1173
1174 assert(set->type == LYXP_SET_SCNODE_SET);
1175
Michal Vaskoecd62de2019-11-13 12:35:11 +01001176 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001177 if (ret > -1) {
1178 set->val.scnodes[ret].in_ctx = 1;
1179 } else {
1180 if (set->used == set->size) {
1181 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1182 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1183 set->size += LYXP_SET_SIZE_STEP;
1184 }
1185
1186 ret = set->used;
1187 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1188 set->val.scnodes[ret].type = node_type;
1189 set->val.scnodes[ret].in_ctx = 1;
1190 ++set->used;
1191 }
1192
1193 return ret;
1194}
1195
1196/**
1197 * @brief Replace a node in a set with another. Context position aware.
1198 *
1199 * @param[in] set Set to use.
1200 * @param[in] node Node to insert to @p set.
1201 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1202 * @param[in] node_type Node type of @p node.
1203 * @param[in] idx Index in @p set of the node to replace.
1204 */
1205static void
1206set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1207{
1208 assert(set && (idx < set->used));
1209
1210 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1211 set->val.nodes[idx].node = (struct lyd_node *)node;
1212 set->val.nodes[idx].type = node_type;
1213 set->val.nodes[idx].pos = pos;
1214 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1215}
1216
1217/**
1218 * @brief Set all nodes with ctx 1 to a new unique context value.
1219 *
1220 * @param[in] set Set to modify.
1221 * @return New context value.
1222 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001223static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001224set_scnode_new_in_ctx(struct lyxp_set *set)
1225{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001226 uint32_t i;
1227 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001228
1229 assert(set->type == LYXP_SET_SCNODE_SET);
1230
1231 ret_ctx = 3;
1232retry:
1233 for (i = 0; i < set->used; ++i) {
1234 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1235 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1236 goto retry;
1237 }
1238 }
1239 for (i = 0; i < set->used; ++i) {
1240 if (set->val.scnodes[i].in_ctx == 1) {
1241 set->val.scnodes[i].in_ctx = ret_ctx;
1242 }
1243 }
1244
1245 return ret_ctx;
1246}
1247
1248/**
1249 * @brief Get unique @p node position in the data.
1250 *
1251 * @param[in] node Node to find.
1252 * @param[in] node_type Node type of @p node.
1253 * @param[in] root Root node.
1254 * @param[in] root_type Type of the XPath @p root node.
1255 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1256 * be used to increase efficiency and start the DFS from this node.
1257 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1258 * @return Node position.
1259 */
1260static uint32_t
1261get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1262 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1263{
1264 const struct lyd_node *next, *elem, *top_sibling;
1265 uint32_t pos = 1;
1266
1267 assert(prev && prev_pos && !root->prev->next);
1268
1269 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1270 return 0;
1271 }
1272
1273 if (*prev) {
1274 /* start from the previous element instead from the root */
1275 elem = next = *prev;
1276 pos = *prev_pos;
1277 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1278 goto dfs_search;
1279 }
1280
1281 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1282 /* TREE DFS */
1283 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1284dfs_search:
1285 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1286 goto skip_children;
1287 }
1288
1289 if (elem == node) {
1290 break;
1291 }
1292 ++pos;
1293
1294 /* TREE DFS END */
1295 /* select element for the next run - children first,
1296 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1297 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1298 next = NULL;
1299 } else {
1300 next = lyd_node_children(elem);
1301 }
1302 if (!next) {
1303skip_children:
1304 /* no children */
1305 if (elem == top_sibling) {
1306 /* we are done, root has no children */
1307 elem = NULL;
1308 break;
1309 }
1310 /* try siblings */
1311 next = elem->next;
1312 }
1313 while (!next) {
1314 /* no siblings, go back through parents */
1315 if (elem->parent == top_sibling->parent) {
1316 /* we are done, no next element to process */
1317 elem = NULL;
1318 break;
1319 }
1320 /* parent is already processed, go to its sibling */
1321 elem = (struct lyd_node *)elem->parent;
1322 next = elem->next;
1323 }
1324 }
1325
1326 /* node found */
1327 if (elem) {
1328 break;
1329 }
1330 }
1331
1332 if (!elem) {
1333 if (!(*prev)) {
1334 /* we went from root and failed to find it, cannot be */
1335 LOGINT(node->schema->module->ctx);
1336 return 0;
1337 } else {
1338 *prev = NULL;
1339 *prev_pos = 0;
1340
1341 elem = next = top_sibling = root;
1342 pos = 1;
1343 goto dfs_search;
1344 }
1345 }
1346
1347 /* remember the last found node for next time */
1348 *prev = node;
1349 *prev_pos = pos;
1350
1351 return pos;
1352}
1353
1354/**
1355 * @brief Assign (fill) missing node positions.
1356 *
1357 * @param[in] set Set to fill positions in.
1358 * @param[in] root Context root node.
1359 * @param[in] root_type Context root type.
1360 * @return LY_ERR
1361 */
1362static LY_ERR
1363set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1364{
1365 const struct lyd_node *prev = NULL, *tmp_node;
1366 uint32_t i, tmp_pos = 0;
1367
1368 for (i = 0; i < set->used; ++i) {
1369 if (!set->val.nodes[i].pos) {
1370 tmp_node = NULL;
1371 switch (set->val.nodes[i].type) {
1372 case LYXP_NODE_ATTR:
1373 tmp_node = set->val.attrs[i].attr->parent;
1374 if (!tmp_node) {
1375 LOGINT_RET(root->schema->module->ctx);
1376 }
1377 /* fallthrough */
1378 case LYXP_NODE_ELEM:
1379 case LYXP_NODE_TEXT:
1380 if (!tmp_node) {
1381 tmp_node = set->val.nodes[i].node;
1382 }
1383 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1384 break;
1385 default:
1386 /* all roots have position 0 */
1387 break;
1388 }
1389 }
1390 }
1391
1392 return LY_SUCCESS;
1393}
1394
1395/**
1396 * @brief Get unique @p attr position in the parent attributes.
1397 *
1398 * @param[in] attr Attr to use.
1399 * @return Attribute position.
1400 */
1401static uint16_t
1402get_attr_pos(struct lyd_attr *attr)
1403{
1404 uint16_t pos = 0;
1405 struct lyd_attr *attr2;
1406
1407 for (attr2 = attr->parent->attr; attr2 && (attr2 != attr); attr2 = attr2->next) {
1408 ++pos;
1409 }
1410
1411 assert(attr2);
1412 return pos;
1413}
1414
1415/**
1416 * @brief Compare 2 nodes in respect to XPath document order.
1417 *
1418 * @param[in] item1 1st node.
1419 * @param[in] item2 2nd node.
1420 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1421 */
1422static int
1423set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1424{
1425 uint32_t attr_pos1 = 0, attr_pos2 = 0;
1426
1427 if (item1->pos < item2->pos) {
1428 return -1;
1429 }
1430
1431 if (item1->pos > item2->pos) {
1432 return 1;
1433 }
1434
1435 /* node positions are equal, the fun case */
1436
1437 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1438 /* special case since text nodes are actually saved as their parents */
1439 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1440 if (item1->type == LYXP_NODE_ELEM) {
1441 assert(item2->type == LYXP_NODE_TEXT);
1442 return -1;
1443 } else {
1444 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1445 return 1;
1446 }
1447 }
1448
1449 /* we need attr positions now */
1450 if (item1->type == LYXP_NODE_ATTR) {
1451 attr_pos1 = get_attr_pos((struct lyd_attr *)item1->node);
1452 }
1453 if (item2->type == LYXP_NODE_ATTR) {
1454 attr_pos2 = get_attr_pos((struct lyd_attr *)item2->node);
1455 }
1456
1457 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st ATTR - =pos= - 2nd ATTR */
1458 /* check for duplicates */
1459 if (item1->node == item2->node) {
1460 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_ATTR) || (attr_pos1 == attr_pos2)));
1461 return 0;
1462 }
1463
1464 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd ATTR */
1465 /* elem is always first, 2nd node is after it */
1466 if (item1->type == LYXP_NODE_ELEM) {
1467 assert(item2->type != LYXP_NODE_ELEM);
1468 return -1;
1469 }
1470
1471 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd ATTR, 1st ATTR - any pos - 2nd ELEM, 1st ATTR - >pos> - 2nd ATTR */
1472 /* 2nd is before 1st */
1473 if (((item1->type == LYXP_NODE_TEXT)
1474 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_ATTR)))
1475 || ((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ELEM))
1476 || (((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ATTR))
1477 && (attr_pos1 > attr_pos2))) {
1478 return 1;
1479 }
1480
1481 /* 1st ATTR - any pos - 2nd TEXT, 1st ATTR <pos< - 2nd ATTR */
1482 /* 2nd is after 1st */
1483 return -1;
1484}
1485
1486/**
1487 * @brief Set cast for comparisons.
1488 *
1489 * @param[in] trg Target set to cast source into.
1490 * @param[in] src Source set.
1491 * @param[in] type Target set type.
1492 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001493 * @return LY_ERR
1494 */
1495static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001496set_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 +02001497{
1498 assert(src->type == LYXP_SET_NODE_SET);
1499
1500 set_init(trg, src);
1501
1502 /* insert node into target set */
1503 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1504
1505 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001506 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001507}
1508
1509#ifndef NDEBUG
1510
1511/**
1512 * @brief Bubble sort @p set into XPath document order.
1513 * Context position aware. Unused in the 'Release' build target.
1514 *
1515 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001516 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1517 */
1518static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001519set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001520{
1521 uint32_t i, j;
1522 int ret = 0, cmp, inverted, change;
1523 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001524 struct lyxp_set_node item;
1525 struct lyxp_set_hash_node hnode;
1526 uint64_t hash;
1527
1528 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1529 return 0;
1530 }
1531
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001532 /* find first top-level node to be used as anchor for positions */
1533 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1534 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001535
1536 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001537 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001538 return -1;
1539 }
1540
1541 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1542 print_set_debug(set);
1543
1544 for (i = 0; i < set->used; ++i) {
1545 inverted = 0;
1546 change = 0;
1547
1548 for (j = 1; j < set->used - i; ++j) {
1549 /* compare node positions */
1550 if (inverted) {
1551 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1552 } else {
1553 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1554 }
1555
1556 /* swap if needed */
1557 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1558 change = 1;
1559
1560 item = set->val.nodes[j - 1];
1561 set->val.nodes[j - 1] = set->val.nodes[j];
1562 set->val.nodes[j] = item;
1563 } else {
1564 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1565 inverted = !inverted;
1566 }
1567 }
1568
1569 ++ret;
1570
1571 if (!change) {
1572 break;
1573 }
1574 }
1575
1576 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1577 print_set_debug(set);
1578
1579 /* check node hashes */
1580 if (set->used >= LYD_HT_MIN_ITEMS) {
1581 assert(set->ht);
1582 for (i = 0; i < set->used; ++i) {
1583 hnode.node = set->val.nodes[i].node;
1584 hnode.type = set->val.nodes[i].type;
1585
1586 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1587 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1588 hash = dict_hash_multi(hash, NULL, 0);
1589
1590 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1591 }
1592 }
1593
1594 return ret - 1;
1595}
1596
1597/**
1598 * @brief Remove duplicate entries in a sorted node set.
1599 *
1600 * @param[in] set Sorted set to check.
1601 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1602 */
1603static LY_ERR
1604set_sorted_dup_node_clean(struct lyxp_set *set)
1605{
1606 uint32_t i = 0;
1607 LY_ERR ret = LY_SUCCESS;
1608
1609 if (set->used > 1) {
1610 while (i < set->used - 1) {
1611 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1612 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001613 set_remove_node_null(set, i + 1);
1614 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001615 }
Michal Vasko57eab132019-09-24 11:46:26 +02001616 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001617 }
1618 }
1619
Michal Vasko57eab132019-09-24 11:46:26 +02001620 set_remove_nodes_null(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001621 return ret;
1622}
1623
1624#endif
1625
1626/**
1627 * @brief Merge 2 sorted sets into one.
1628 *
1629 * @param[in,out] trg Set to merge into. Duplicates are removed.
1630 * @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 +02001631 * @return LY_ERR
1632 */
1633static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001634set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001635{
1636 uint32_t i, j, k, count, dup_count;
1637 int cmp;
1638 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001639
1640 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1641 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1642 return LY_EINVAL;
1643 }
1644
1645 if (src->type == LYXP_SET_EMPTY) {
1646 return LY_SUCCESS;
1647 } else if (trg->type == LYXP_SET_EMPTY) {
1648 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001649 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001650 return LY_SUCCESS;
1651 }
1652
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001653 /* find first top-level node to be used as anchor for positions */
1654 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1655 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001656
1657 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001658 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001659 return LY_EINT;
1660 }
1661
1662#ifndef NDEBUG
1663 LOGDBG(LY_LDGXPATH, "MERGE target");
1664 print_set_debug(trg);
1665 LOGDBG(LY_LDGXPATH, "MERGE source");
1666 print_set_debug(src);
1667#endif
1668
1669 /* make memory for the merge (duplicates are not detected yet, so space
1670 * will likely be wasted on them, too bad) */
1671 if (trg->size - trg->used < src->used) {
1672 trg->size = trg->used + src->used;
1673
1674 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1675 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1676 }
1677
1678 i = 0;
1679 j = 0;
1680 count = 0;
1681 dup_count = 0;
1682 do {
1683 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1684 if (!cmp) {
1685 if (!count) {
1686 /* duplicate, just skip it */
1687 ++i;
1688 ++j;
1689 } else {
1690 /* we are copying something already, so let's copy the duplicate too,
1691 * we are hoping that afterwards there are some more nodes to
1692 * copy and this way we can copy them all together */
1693 ++count;
1694 ++dup_count;
1695 ++i;
1696 ++j;
1697 }
1698 } else if (cmp < 0) {
1699 /* inserting src node into trg, just remember it for now */
1700 ++count;
1701 ++i;
1702
1703 /* insert the hash now */
1704 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1705 } else if (count) {
1706copy_nodes:
1707 /* time to actually copy the nodes, we have found the largest block of nodes */
1708 memmove(&trg->val.nodes[j + (count - dup_count)],
1709 &trg->val.nodes[j],
1710 (trg->used - j) * sizeof *trg->val.nodes);
1711 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1712
1713 trg->used += count - dup_count;
1714 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1715 j += count - dup_count;
1716
1717 count = 0;
1718 dup_count = 0;
1719 } else {
1720 ++j;
1721 }
1722 } while ((i < src->used) && (j < trg->used));
1723
1724 if ((i < src->used) || count) {
1725 /* insert all the hashes first */
1726 for (k = i; k < src->used; ++k) {
1727 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1728 }
1729
1730 /* loop ended, but we need to copy something at trg end */
1731 count += src->used - i;
1732 i = src->used;
1733 goto copy_nodes;
1734 }
1735
1736 /* we are inserting hashes before the actual node insert, which causes
1737 * situations when there were initially not enough items for a hash table,
1738 * but even after some were inserted, hash table was not created (during
1739 * insertion the number of items is not updated yet) */
1740 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1741 set_insert_node_hash(trg, NULL, 0);
1742 }
1743
1744#ifndef NDEBUG
1745 LOGDBG(LY_LDGXPATH, "MERGE result");
1746 print_set_debug(trg);
1747#endif
1748
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001749 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001750 return LY_SUCCESS;
1751}
1752
1753/*
1754 * (re)parse functions
1755 *
1756 * Parse functions parse the expression into
1757 * tokens (syntactic analysis).
1758 *
1759 * Reparse functions perform semantic analysis
1760 * (do not save the result, just a check) of
1761 * the expression and fill repeat indices.
1762 */
1763
1764/**
1765 * @brief Look at the next token and check its kind.
1766 *
1767 * @param[in] ctx Context for logging.
1768 * @param[in] exp Expression to use.
1769 * @param[in] exp_idx Position in the expression \p exp.
1770 * @param[in] want_tok Expected token.
1771 * @param[in] strict Whether the token is strictly required (print error if
1772 * not the next one) or we simply want to check whether it is the next or not.
1773 * @return LY_ERR
1774 */
1775static LY_ERR
1776exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1777{
1778 if (exp->used == exp_idx) {
1779 if (strict) {
1780 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1781 }
1782 return LY_EINVAL;
1783 }
1784
1785 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1786 if (strict) {
1787 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1788 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1789 }
1790 return LY_EINVAL;
1791 }
1792
1793 return LY_SUCCESS;
1794}
1795
1796/**
1797 * @brief Stack operation push on the repeat array.
1798 *
1799 * @param[in] exp Expression to use.
1800 * @param[in] exp_idx Position in the expresion \p exp.
1801 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1802 */
1803static void
1804exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1805{
1806 uint16_t i;
1807
1808 if (exp->repeat[exp_idx]) {
1809 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1810 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1811 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1812 exp->repeat[exp_idx][i] = repeat_op_idx;
1813 exp->repeat[exp_idx][i + 1] = 0;
1814 } else {
1815 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1816 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1817 exp->repeat[exp_idx][0] = repeat_op_idx;
1818 }
1819}
1820
1821/**
1822 * @brief Reparse Predicate. Logs directly on error.
1823 *
1824 * [7] Predicate ::= '[' Expr ']'
1825 *
1826 * @param[in] ctx Context for logging.
1827 * @param[in] exp Parsed XPath expression.
1828 * @param[in] exp_idx Position in the expression @p exp.
1829 * @return LY_ERR
1830 */
1831static LY_ERR
1832reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1833{
1834 LY_ERR rc;
1835
1836 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1837 LY_CHECK_RET(rc);
1838 ++(*exp_idx);
1839
1840 rc = reparse_or_expr(ctx, exp, exp_idx);
1841 LY_CHECK_RET(rc);
1842
1843 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1844 LY_CHECK_RET(rc);
1845 ++(*exp_idx);
1846
1847 return LY_SUCCESS;
1848}
1849
1850/**
1851 * @brief Reparse RelativeLocationPath. Logs directly on error.
1852 *
1853 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1854 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1855 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1856 *
1857 * @param[in] ctx Context for logging.
1858 * @param[in] exp Parsed XPath expression.
1859 * @param[in] exp_idx Position in the expression \p exp.
1860 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1861 */
1862static LY_ERR
1863reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1864{
1865 LY_ERR rc;
1866
1867 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1868 LY_CHECK_RET(rc);
1869
1870 goto step;
1871 do {
1872 /* '/' or '//' */
1873 ++(*exp_idx);
1874
1875 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1876 LY_CHECK_RET(rc);
1877step:
1878 /* Step */
1879 switch (exp->tokens[*exp_idx]) {
1880 case LYXP_TOKEN_DOT:
1881 ++(*exp_idx);
1882 break;
1883
1884 case LYXP_TOKEN_DDOT:
1885 ++(*exp_idx);
1886 break;
1887
1888 case LYXP_TOKEN_AT:
1889 ++(*exp_idx);
1890
1891 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1892 LY_CHECK_RET(rc);
1893 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1894 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1895 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1896 return LY_EVALID;
1897 }
1898 /* fall through */
1899 case LYXP_TOKEN_NAMETEST:
1900 ++(*exp_idx);
1901 goto reparse_predicate;
1902 break;
1903
1904 case LYXP_TOKEN_NODETYPE:
1905 ++(*exp_idx);
1906
1907 /* '(' */
1908 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1909 LY_CHECK_RET(rc);
1910 ++(*exp_idx);
1911
1912 /* ')' */
1913 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1914 LY_CHECK_RET(rc);
1915 ++(*exp_idx);
1916
1917reparse_predicate:
1918 /* Predicate* */
1919 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1920 rc = reparse_predicate(ctx, exp, exp_idx);
1921 LY_CHECK_RET(rc);
1922 }
1923 break;
1924 default:
1925 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1926 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1927 return LY_EVALID;
1928 }
1929 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1930
1931 return LY_SUCCESS;
1932}
1933
1934/**
1935 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1936 *
1937 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1938 *
1939 * @param[in] ctx Context for logging.
1940 * @param[in] exp Parsed XPath expression.
1941 * @param[in] exp_idx Position in the expression \p exp.
1942 * @return LY_ERR
1943 */
1944static LY_ERR
1945reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1946{
1947 LY_ERR rc;
1948
1949 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1950 LY_CHECK_RET(rc);
1951
1952 /* '/' RelativeLocationPath? */
1953 if (exp->tok_len[*exp_idx] == 1) {
1954 /* '/' */
1955 ++(*exp_idx);
1956
1957 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1958 return LY_SUCCESS;
1959 }
1960 switch (exp->tokens[*exp_idx]) {
1961 case LYXP_TOKEN_DOT:
1962 case LYXP_TOKEN_DDOT:
1963 case LYXP_TOKEN_AT:
1964 case LYXP_TOKEN_NAMETEST:
1965 case LYXP_TOKEN_NODETYPE:
1966 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1967 LY_CHECK_RET(rc);
1968 /* fall through */
1969 default:
1970 break;
1971 }
1972
1973 /* '//' RelativeLocationPath */
1974 } else {
1975 /* '//' */
1976 ++(*exp_idx);
1977
1978 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1979 LY_CHECK_RET(rc);
1980 }
1981
1982 return LY_SUCCESS;
1983}
1984
1985/**
1986 * @brief Reparse FunctionCall. Logs directly on error.
1987 *
1988 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
1989 *
1990 * @param[in] ctx Context for logging.
1991 * @param[in] exp Parsed XPath expression.
1992 * @param[in] exp_idx Position in the expression @p exp.
1993 * @return LY_ERR
1994 */
1995static LY_ERR
1996reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1997{
1998 int min_arg_count = -1, max_arg_count, arg_count;
1999 uint16_t func_exp_idx;
2000 LY_ERR rc;
2001
2002 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2003 LY_CHECK_RET(rc);
2004 func_exp_idx = *exp_idx;
2005 switch (exp->tok_len[*exp_idx]) {
2006 case 3:
2007 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2008 min_arg_count = 1;
2009 max_arg_count = 1;
2010 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2011 min_arg_count = 1;
2012 max_arg_count = 1;
2013 }
2014 break;
2015 case 4:
2016 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2017 min_arg_count = 1;
2018 max_arg_count = 1;
2019 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2020 min_arg_count = 0;
2021 max_arg_count = 0;
2022 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2023 min_arg_count = 0;
2024 max_arg_count = 1;
2025 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2026 min_arg_count = 0;
2027 max_arg_count = 0;
2028 }
2029 break;
2030 case 5:
2031 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2032 min_arg_count = 1;
2033 max_arg_count = 1;
2034 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2035 min_arg_count = 0;
2036 max_arg_count = 0;
2037 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2038 min_arg_count = 1;
2039 max_arg_count = 1;
2040 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2041 min_arg_count = 1;
2042 max_arg_count = 1;
2043 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2044 min_arg_count = 1;
2045 max_arg_count = 1;
2046 }
2047 break;
2048 case 6:
2049 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2050 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002051 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002052 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2053 min_arg_count = 0;
2054 max_arg_count = 1;
2055 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2056 min_arg_count = 0;
2057 max_arg_count = 1;
2058 }
2059 break;
2060 case 7:
2061 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2062 min_arg_count = 1;
2063 max_arg_count = 1;
2064 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2065 min_arg_count = 1;
2066 max_arg_count = 1;
2067 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2068 min_arg_count = 0;
2069 max_arg_count = 0;
2070 }
2071 break;
2072 case 8:
2073 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2074 min_arg_count = 2;
2075 max_arg_count = 2;
2076 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2077 min_arg_count = 0;
2078 max_arg_count = 0;
2079 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2080 min_arg_count = 2;
2081 max_arg_count = 2;
2082 }
2083 break;
2084 case 9:
2085 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2086 min_arg_count = 2;
2087 max_arg_count = 3;
2088 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2089 min_arg_count = 3;
2090 max_arg_count = 3;
2091 }
2092 break;
2093 case 10:
2094 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2095 min_arg_count = 0;
2096 max_arg_count = 1;
2097 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2098 min_arg_count = 1;
2099 max_arg_count = 1;
2100 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2101 min_arg_count = 2;
2102 max_arg_count = 2;
2103 }
2104 break;
2105 case 11:
2106 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2107 min_arg_count = 2;
2108 max_arg_count = 2;
2109 }
2110 break;
2111 case 12:
2112 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2113 min_arg_count = 2;
2114 max_arg_count = 2;
2115 }
2116 break;
2117 case 13:
2118 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2119 min_arg_count = 0;
2120 max_arg_count = 1;
2121 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2122 min_arg_count = 0;
2123 max_arg_count = 1;
2124 }
2125 break;
2126 case 15:
2127 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2128 min_arg_count = 0;
2129 max_arg_count = 1;
2130 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2131 min_arg_count = 2;
2132 max_arg_count = 2;
2133 }
2134 break;
2135 case 16:
2136 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2137 min_arg_count = 2;
2138 max_arg_count = 2;
2139 }
2140 break;
2141 case 20:
2142 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2143 min_arg_count = 2;
2144 max_arg_count = 2;
2145 }
2146 break;
2147 }
2148 if (min_arg_count == -1) {
2149 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2150 return LY_EINVAL;
2151 }
2152 ++(*exp_idx);
2153
2154 /* '(' */
2155 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2156 LY_CHECK_RET(rc);
2157 ++(*exp_idx);
2158
2159 /* ( Expr ( ',' Expr )* )? */
2160 arg_count = 0;
2161 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2162 LY_CHECK_RET(rc);
2163 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2164 ++arg_count;
2165 rc = reparse_or_expr(ctx, exp, exp_idx);
2166 LY_CHECK_RET(rc);
2167 }
2168 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2169 ++(*exp_idx);
2170
2171 ++arg_count;
2172 rc = reparse_or_expr(ctx, exp, exp_idx);
2173 LY_CHECK_RET(rc);
2174 }
2175
2176 /* ')' */
2177 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2178 LY_CHECK_RET(rc);
2179 ++(*exp_idx);
2180
2181 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2182 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2183 &exp->expr[exp->tok_pos[func_exp_idx]]);
2184 return LY_EVALID;
2185 }
2186
2187 return LY_SUCCESS;
2188}
2189
2190/**
2191 * @brief Reparse PathExpr. Logs directly on error.
2192 *
2193 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2194 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2195 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2196 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2197 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2198 *
2199 * @param[in] ctx Context for logging.
2200 * @param[in] exp Parsed XPath expression.
2201 * @param[in] exp_idx Position in the expression @p exp.
2202 * @return LY_ERR
2203 */
2204static LY_ERR
2205reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2206{
2207 LY_ERR rc;
2208
2209 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2210 return -1;
2211 }
2212
2213 switch (exp->tokens[*exp_idx]) {
2214 case LYXP_TOKEN_PAR1:
2215 /* '(' Expr ')' Predicate* */
2216 ++(*exp_idx);
2217
2218 rc = reparse_or_expr(ctx, exp, exp_idx);
2219 LY_CHECK_RET(rc);
2220
2221 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2222 LY_CHECK_RET(rc);
2223 ++(*exp_idx);
2224 goto predicate;
2225 break;
2226 case LYXP_TOKEN_DOT:
2227 case LYXP_TOKEN_DDOT:
2228 case LYXP_TOKEN_AT:
2229 case LYXP_TOKEN_NAMETEST:
2230 case LYXP_TOKEN_NODETYPE:
2231 /* RelativeLocationPath */
2232 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2233 LY_CHECK_RET(rc);
2234 break;
2235 case LYXP_TOKEN_FUNCNAME:
2236 /* FunctionCall */
2237 rc = reparse_function_call(ctx, exp, exp_idx);
2238 LY_CHECK_RET(rc);
2239 goto predicate;
2240 break;
2241 case LYXP_TOKEN_OPERATOR_PATH:
2242 /* AbsoluteLocationPath */
2243 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2244 LY_CHECK_RET(rc);
2245 break;
2246 case LYXP_TOKEN_LITERAL:
2247 /* Literal */
2248 ++(*exp_idx);
2249 goto predicate;
2250 break;
2251 case LYXP_TOKEN_NUMBER:
2252 /* Number */
2253 ++(*exp_idx);
2254 goto predicate;
2255 break;
2256 default:
2257 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2258 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2259 return LY_EVALID;
2260 }
2261
2262 return LY_SUCCESS;
2263
2264predicate:
2265 /* Predicate* */
2266 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2267 rc = reparse_predicate(ctx, exp, exp_idx);
2268 LY_CHECK_RET(rc);
2269 }
2270
2271 /* ('/' or '//') RelativeLocationPath */
2272 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2273
2274 /* '/' or '//' */
2275 ++(*exp_idx);
2276
2277 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2278 LY_CHECK_RET(rc);
2279 }
2280
2281 return LY_SUCCESS;
2282}
2283
2284/**
2285 * @brief Reparse UnaryExpr. Logs directly on error.
2286 *
2287 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2288 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2289 *
2290 * @param[in] ctx Context for logging.
2291 * @param[in] exp Parsed XPath expression.
2292 * @param[in] exp_idx Position in the expression @p exp.
2293 * @return LY_ERR
2294 */
2295static LY_ERR
2296reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2297{
2298 uint16_t prev_exp;
2299 LY_ERR rc;
2300
2301 /* ('-')* */
2302 prev_exp = *exp_idx;
2303 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2304 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2305 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2306 ++(*exp_idx);
2307 }
2308
2309 /* PathExpr */
2310 prev_exp = *exp_idx;
2311 rc = reparse_path_expr(ctx, exp, exp_idx);
2312 LY_CHECK_RET(rc);
2313
2314 /* ('|' PathExpr)* */
2315 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2316 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2317 ++(*exp_idx);
2318
2319 rc = reparse_path_expr(ctx, exp, exp_idx);
2320 LY_CHECK_RET(rc);
2321 }
2322
2323 return LY_SUCCESS;
2324}
2325
2326/**
2327 * @brief Reparse AdditiveExpr. Logs directly on error.
2328 *
2329 * [15] AdditiveExpr ::= MultiplicativeExpr
2330 * | AdditiveExpr '+' MultiplicativeExpr
2331 * | AdditiveExpr '-' MultiplicativeExpr
2332 * [16] MultiplicativeExpr ::= UnaryExpr
2333 * | MultiplicativeExpr '*' UnaryExpr
2334 * | MultiplicativeExpr 'div' UnaryExpr
2335 * | MultiplicativeExpr 'mod' UnaryExpr
2336 *
2337 * @param[in] ctx Context for logging.
2338 * @param[in] exp Parsed XPath expression.
2339 * @param[in] exp_idx Position in the expression @p exp.
2340 * @return LY_ERR
2341 */
2342static LY_ERR
2343reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2344{
2345 uint16_t prev_add_exp, prev_mul_exp;
2346 LY_ERR rc;
2347
2348 prev_add_exp = *exp_idx;
2349 goto reparse_multiplicative_expr;
2350
2351 /* ('+' / '-' MultiplicativeExpr)* */
2352 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2353 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2354 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2355 ++(*exp_idx);
2356
2357reparse_multiplicative_expr:
2358 /* UnaryExpr */
2359 prev_mul_exp = *exp_idx;
2360 rc = reparse_unary_expr(ctx, exp, exp_idx);
2361 LY_CHECK_RET(rc);
2362
2363 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2364 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2365 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2366 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2367 ++(*exp_idx);
2368
2369 rc = reparse_unary_expr(ctx, exp, exp_idx);
2370 LY_CHECK_RET(rc);
2371 }
2372 }
2373
2374 return LY_SUCCESS;
2375}
2376
2377/**
2378 * @brief Reparse EqualityExpr. Logs directly on error.
2379 *
2380 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2381 * | EqualityExpr '!=' RelationalExpr
2382 * [14] RelationalExpr ::= AdditiveExpr
2383 * | RelationalExpr '<' AdditiveExpr
2384 * | RelationalExpr '>' AdditiveExpr
2385 * | RelationalExpr '<=' AdditiveExpr
2386 * | RelationalExpr '>=' AdditiveExpr
2387 *
2388 * @param[in] ctx Context for logging.
2389 * @param[in] exp Parsed XPath expression.
2390 * @param[in] exp_idx Position in the expression @p exp.
2391 * @return LY_ERR
2392 */
2393static LY_ERR
2394reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2395{
2396 uint16_t prev_eq_exp, prev_rel_exp;
2397 LY_ERR rc;
2398
2399 prev_eq_exp = *exp_idx;
2400 goto reparse_additive_expr;
2401
2402 /* ('=' / '!=' RelationalExpr)* */
2403 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2404 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2405 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2406 ++(*exp_idx);
2407
2408reparse_additive_expr:
2409 /* AdditiveExpr */
2410 prev_rel_exp = *exp_idx;
2411 rc = reparse_additive_expr(ctx, exp, exp_idx);
2412 LY_CHECK_RET(rc);
2413
2414 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2415 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2416 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2417 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2418 ++(*exp_idx);
2419
2420 rc = reparse_additive_expr(ctx, exp, exp_idx);
2421 LY_CHECK_RET(rc);
2422 }
2423 }
2424
2425 return LY_SUCCESS;
2426}
2427
2428/**
2429 * @brief Reparse OrExpr. Logs directly on error.
2430 *
2431 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2432 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2433 *
2434 * @param[in] ctx Context for logging.
2435 * @param[in] exp Parsed XPath expression.
2436 * @param[in] exp_idx Position in the expression @p exp.
2437 * @return LY_ERR
2438 */
2439static LY_ERR
2440reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2441{
2442 uint16_t prev_or_exp, prev_and_exp;
2443 LY_ERR rc;
2444
2445 prev_or_exp = *exp_idx;
2446 goto reparse_equality_expr;
2447
2448 /* ('or' AndExpr)* */
2449 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2450 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2451 ++(*exp_idx);
2452
2453reparse_equality_expr:
2454 /* EqualityExpr */
2455 prev_and_exp = *exp_idx;
2456 rc = reparse_equality_expr(ctx, exp, exp_idx);
2457 LY_CHECK_RET(rc);
2458
2459 /* ('and' EqualityExpr)* */
2460 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2461 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2462 ++(*exp_idx);
2463
2464 rc = reparse_equality_expr(ctx, exp, exp_idx);
2465 LY_CHECK_RET(rc);
2466 }
2467 }
2468
2469 return LY_SUCCESS;
2470}
Radek Krejcib1646a92018-11-02 16:08:26 +01002471
2472/**
2473 * @brief Parse NCName.
2474 *
2475 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002476 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002477 */
Radek Krejcid4270262019-01-07 15:07:25 +01002478static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002479parse_ncname(const char *ncname)
2480{
2481 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002482 size_t size;
2483 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002484
2485 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2486 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2487 return len;
2488 }
2489
2490 do {
2491 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002492 if (!*ncname) {
2493 break;
2494 }
Radek Krejcid4270262019-01-07 15:07:25 +01002495 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002496 } while (is_xmlqnamechar(uc) && (uc != ':'));
2497
2498 return len;
2499}
2500
2501/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002502 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002503 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002504 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002505 * @param[in] exp Expression to use.
2506 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002507 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002508 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002509 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002510 */
2511static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002512exp_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 +01002513{
2514 uint32_t prev;
2515
2516 if (exp->used == exp->size) {
2517 prev = exp->size;
2518 exp->size += LYXP_EXPR_SIZE_STEP;
2519 if (prev > exp->size) {
2520 LOGINT(ctx);
2521 return LY_EINT;
2522 }
2523
2524 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2525 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2526 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2527 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2528 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2529 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2530 }
2531
2532 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002533 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002534 exp->tok_len[exp->used] = tok_len;
2535 ++exp->used;
2536 return LY_SUCCESS;
2537}
2538
2539void
2540lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2541{
2542 uint16_t i;
2543
2544 if (!expr) {
2545 return;
2546 }
2547
2548 lydict_remove(ctx, expr->expr);
2549 free(expr->tokens);
2550 free(expr->tok_pos);
2551 free(expr->tok_len);
2552 if (expr->repeat) {
2553 for (i = 0; i < expr->used; ++i) {
2554 free(expr->repeat[i]);
2555 }
2556 }
2557 free(expr->repeat);
2558 free(expr);
2559}
2560
2561struct lyxp_expr *
2562lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2563{
2564 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002565 size_t parsed = 0, tok_len;
2566 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002567 enum lyxp_token tok_type;
2568 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002569 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002570
2571 if (strlen(expr) > UINT16_MAX) {
2572 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2573 return NULL;
2574 }
2575
2576 /* init lyxp_expr structure */
2577 ret = calloc(1, sizeof *ret);
2578 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2579 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2580 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2581 ret->used = 0;
2582 ret->size = LYXP_EXPR_SIZE_START;
2583 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2584 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2585
2586 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2587 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2588
2589 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2590 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2591
2592 while (is_xmlws(expr[parsed])) {
2593 ++parsed;
2594 }
2595
2596 do {
2597 if (expr[parsed] == '(') {
2598
2599 /* '(' */
2600 tok_len = 1;
2601 tok_type = LYXP_TOKEN_PAR1;
2602
2603 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2604 /* it is a NodeType/FunctionName after all */
2605 if (((ret->tok_len[ret->used - 1] == 4)
2606 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2607 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2608 ((ret->tok_len[ret->used - 1] == 7)
2609 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2610 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2611 } else {
2612 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2613 }
2614 prev_function_check = 0;
2615 }
2616
2617 } else if (expr[parsed] == ')') {
2618
2619 /* ')' */
2620 tok_len = 1;
2621 tok_type = LYXP_TOKEN_PAR2;
2622
2623 } else if (expr[parsed] == '[') {
2624
2625 /* '[' */
2626 tok_len = 1;
2627 tok_type = LYXP_TOKEN_BRACK1;
2628
2629 } else if (expr[parsed] == ']') {
2630
2631 /* ']' */
2632 tok_len = 1;
2633 tok_type = LYXP_TOKEN_BRACK2;
2634
2635 } else if (!strncmp(&expr[parsed], "..", 2)) {
2636
2637 /* '..' */
2638 tok_len = 2;
2639 tok_type = LYXP_TOKEN_DDOT;
2640
2641 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2642
2643 /* '.' */
2644 tok_len = 1;
2645 tok_type = LYXP_TOKEN_DOT;
2646
2647 } else if (expr[parsed] == '@') {
2648
2649 /* '@' */
2650 tok_len = 1;
2651 tok_type = LYXP_TOKEN_AT;
2652
2653 } else if (expr[parsed] == ',') {
2654
2655 /* ',' */
2656 tok_len = 1;
2657 tok_type = LYXP_TOKEN_COMMA;
2658
2659 } else if (expr[parsed] == '\'') {
2660
2661 /* Literal with ' */
2662 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2663 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2664 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2665 ++tok_len;
2666 tok_type = LYXP_TOKEN_LITERAL;
2667
2668 } else if (expr[parsed] == '\"') {
2669
2670 /* Literal with " */
2671 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2672 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2673 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2674 ++tok_len;
2675 tok_type = LYXP_TOKEN_LITERAL;
2676
2677 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2678
2679 /* Number */
2680 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2681 if (expr[parsed + tok_len] == '.') {
2682 ++tok_len;
2683 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2684 }
2685 tok_type = LYXP_TOKEN_NUMBER;
2686
2687 } else if (expr[parsed] == '/') {
2688
2689 /* Operator '/', '//' */
2690 if (!strncmp(&expr[parsed], "//", 2)) {
2691 tok_len = 2;
2692 } else {
2693 tok_len = 1;
2694 }
2695 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2696
2697 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2698 || !strncmp(&expr[parsed], ">=", 2)) {
2699
2700 /* Operator '!=', '<=', '>=' */
2701 tok_len = 2;
2702 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2703
2704 } else if (expr[parsed] == '|') {
2705
2706 /* Operator '|' */
2707 tok_len = 1;
2708 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2709
2710 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2711
2712 /* Operator '+', '-' */
2713 tok_len = 1;
2714 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2715
2716 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2717
2718 /* Operator '=', '<', '>' */
2719 tok_len = 1;
2720 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2721
2722 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2723 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2724 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2725 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2726 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2727 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2728 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2729 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2730 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2731
2732 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2733 if (expr[parsed] == '*') {
2734 tok_len = 1;
2735 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2736
2737 } else if (!strncmp(&expr[parsed], "or", 2)) {
2738 tok_len = 2;
2739 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2740
2741 } else if (!strncmp(&expr[parsed], "and", 3)) {
2742 tok_len = 3;
2743 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2744
2745 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2746 tok_len = 3;
2747 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2748
2749 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002750 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2751 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 +01002752 goto error;
2753 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002754 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002755 goto error;
2756 }
2757 } else if (expr[parsed] == '*') {
2758
2759 /* NameTest '*' */
2760 tok_len = 1;
2761 tok_type = LYXP_TOKEN_NAMETEST;
2762
2763 } else {
2764
2765 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2766 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002767 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 +01002768 tok_len = ncname_len;
2769
2770 if (expr[parsed + tok_len] == ':') {
2771 ++tok_len;
2772 if (expr[parsed + tok_len] == '*') {
2773 ++tok_len;
2774 } else {
2775 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002776 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 +01002777 tok_len += ncname_len;
2778 }
2779 /* remove old flag to prevent ambiguities */
2780 prev_function_check = 0;
2781 tok_type = LYXP_TOKEN_NAMETEST;
2782 } else {
2783 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2784 prev_function_check = 1;
2785 tok_type = LYXP_TOKEN_NAMETEST;
2786 }
2787 }
2788
2789 /* store the token, move on to the next one */
2790 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2791 parsed += tok_len;
2792 while (is_xmlws(expr[parsed])) {
2793 ++parsed;
2794 }
2795
2796 } while (expr[parsed]);
2797
2798 /* prealloc repeat */
2799 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2800 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2801
Michal Vasko03ff5a72019-09-11 13:49:33 +02002802 /* fill repeat */
2803 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2804 if (ret->used > exp_idx) {
2805 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2806 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2807 &ret->expr[ret->tok_pos[exp_idx]]);
2808 goto error;
2809 }
2810
2811 print_expr_struct_debug(ret);
2812
Radek Krejcib1646a92018-11-02 16:08:26 +01002813 return ret;
2814
2815error:
2816 lyxp_expr_free(ctx, ret);
2817 return NULL;
2818}
2819
Michal Vasko03ff5a72019-09-11 13:49:33 +02002820/*
2821 * warn functions
2822 *
2823 * Warn functions check specific reasonable conditions for schema XPath
2824 * and print a warning if they are not satisfied.
2825 */
2826
2827/**
2828 * @brief Get the last-added schema node that is currently in the context.
2829 *
2830 * @param[in] set Set to search in.
2831 * @return Last-added schema context node, NULL if no node is in context.
2832 */
2833static struct lysc_node *
2834warn_get_scnode_in_ctx(struct lyxp_set *set)
2835{
2836 uint32_t i;
2837
2838 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2839 return NULL;
2840 }
2841
2842 i = set->used;
2843 do {
2844 --i;
2845 if (set->val.scnodes[i].in_ctx == 1) {
2846 /* if there are more, simply return the first found (last added) */
2847 return set->val.scnodes[i].scnode;
2848 }
2849 } while (i);
2850
2851 return NULL;
2852}
2853
2854/**
2855 * @brief Test whether a type is numeric - integer type or decimal64.
2856 *
2857 * @param[in] type Type to test.
2858 * @return 1 if numeric, 0 otherwise.
2859 */
2860static int
2861warn_is_numeric_type(struct lysc_type *type)
2862{
2863 struct lysc_type_union *uni;
2864 int ret;
2865 uint32_t i;
2866
2867 switch (type->basetype) {
2868 case LY_TYPE_DEC64:
2869 case LY_TYPE_INT8:
2870 case LY_TYPE_UINT8:
2871 case LY_TYPE_INT16:
2872 case LY_TYPE_UINT16:
2873 case LY_TYPE_INT32:
2874 case LY_TYPE_UINT32:
2875 case LY_TYPE_INT64:
2876 case LY_TYPE_UINT64:
2877 return 1;
2878 case LY_TYPE_UNION:
2879 uni = (struct lysc_type_union *)type;
2880 LY_ARRAY_FOR(uni->types, i) {
2881 ret = warn_is_numeric_type(uni->types[i]);
2882 if (ret) {
2883 /* found a suitable type */
2884 return 1;
2885 }
2886 }
2887 /* did not find any suitable type */
2888 return 0;
2889 case LY_TYPE_LEAFREF:
2890 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2891 default:
2892 return 0;
2893 }
2894}
2895
2896/**
2897 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2898 *
2899 * @param[in] type Type to test.
2900 * @return 1 if string, 0 otherwise.
2901 */
2902static int
2903warn_is_string_type(struct lysc_type *type)
2904{
2905 struct lysc_type_union *uni;
2906 int ret;
2907 uint32_t i;
2908
2909 switch (type->basetype) {
2910 case LY_TYPE_BITS:
2911 case LY_TYPE_ENUM:
2912 case LY_TYPE_IDENT:
2913 case LY_TYPE_INST:
2914 case LY_TYPE_STRING:
2915 return 1;
2916 case LY_TYPE_UNION:
2917 uni = (struct lysc_type_union *)type;
2918 LY_ARRAY_FOR(uni->types, i) {
2919 ret = warn_is_string_type(uni->types[i]);
2920 if (ret) {
2921 /* found a suitable type */
2922 return 1;
2923 }
2924 }
2925 /* did not find any suitable type */
2926 return 0;
2927 case LY_TYPE_LEAFREF:
2928 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2929 default:
2930 return 0;
2931 }
2932}
2933
2934/**
2935 * @brief Test whether a type is one specific type.
2936 *
2937 * @param[in] type Type to test.
2938 * @param[in] base Expected type.
2939 * @return 1 if it is, 0 otherwise.
2940 */
2941static int
2942warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2943{
2944 struct lysc_type_union *uni;
2945 int ret;
2946 uint32_t i;
2947
2948 if (type->basetype == base) {
2949 return 1;
2950 } else if (type->basetype == LY_TYPE_UNION) {
2951 uni = (struct lysc_type_union *)type;
2952 LY_ARRAY_FOR(uni->types, i) {
2953 ret = warn_is_specific_type(uni->types[i], base);
2954 if (ret) {
2955 /* found a suitable type */
2956 return 1;
2957 }
2958 }
2959 /* did not find any suitable type */
2960 return 0;
2961 } else if (type->basetype == LY_TYPE_LEAFREF) {
2962 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2963 }
2964
2965 return 0;
2966}
2967
2968/**
2969 * @brief Get next type of a (union) type.
2970 *
2971 * @param[in] type Base type.
2972 * @param[in] prev_type Previously returned type.
2973 * @return Next type or NULL.
2974 */
2975static struct lysc_type *
2976warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
2977{
2978 struct lysc_type_union *uni;
2979 int found = 0;
2980 uint32_t i;
2981
2982 switch (type->basetype) {
2983 case LY_TYPE_UNION:
2984 uni = (struct lysc_type_union *)type;
2985 if (!prev_type) {
2986 return uni->types[0];
2987 }
2988 LY_ARRAY_FOR(uni->types, i) {
2989 if (found) {
2990 return uni->types[i];
2991 }
2992 if (prev_type == uni->types[i]) {
2993 found = 1;
2994 }
2995 }
2996 return NULL;
2997 default:
2998 if (prev_type) {
2999 assert(type == prev_type);
3000 return NULL;
3001 } else {
3002 return type;
3003 }
3004 }
3005}
3006
3007/**
3008 * @brief Test whether 2 types have a common type.
3009 *
3010 * @param[in] type1 First type.
3011 * @param[in] type2 Second type.
3012 * @return 1 if they do, 0 otherwise.
3013 */
3014static int
3015warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3016{
3017 struct lysc_type *t1, *rt1, *t2, *rt2;
3018
3019 t1 = NULL;
3020 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3021 if (t1->basetype == LY_TYPE_LEAFREF) {
3022 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3023 } else {
3024 rt1 = t1;
3025 }
3026
3027 t2 = NULL;
3028 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3029 if (t2->basetype == LY_TYPE_LEAFREF) {
3030 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3031 } else {
3032 rt2 = t2;
3033 }
3034
3035 if (rt2->basetype == rt1->basetype) {
3036 /* match found */
3037 return 1;
3038 }
3039 }
3040 }
3041
3042 return 0;
3043}
3044
3045/**
3046 * @brief Check both operands of comparison operators.
3047 *
3048 * @param[in] ctx Context for errors.
3049 * @param[in] set1 First operand set.
3050 * @param[in] set2 Second operand set.
3051 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3052 * @param[in] expr Start of the expression to print with the warning.
3053 * @param[in] tok_pos Token position.
3054 */
3055static void
3056warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3057{
3058 struct lysc_node_leaf *node1, *node2;
3059 int leaves = 1, warning = 0;
3060
3061 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3062 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3063
3064 if (!node1 && !node2) {
3065 /* no node-sets involved, nothing to do */
3066 return;
3067 }
3068
3069 if (node1) {
3070 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3071 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3072 warning = 1;
3073 leaves = 0;
3074 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3075 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3076 warning = 1;
3077 }
3078 }
3079
3080 if (node2) {
3081 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3082 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3083 warning = 1;
3084 leaves = 0;
3085 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3086 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3087 warning = 1;
3088 }
3089 }
3090
3091 if (node1 && node2 && leaves && !numbers_only) {
3092 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3093 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3094 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3095 && !warn_is_equal_type(node1->type, node2->type))) {
3096 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3097 warning = 1;
3098 }
3099 }
3100
3101 if (warning) {
3102 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3103 }
3104}
3105
3106/**
3107 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3108 *
3109 * @param[in] exp Parsed XPath expression.
3110 * @param[in] set Set with the leaf/leaf-list.
3111 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3112 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3113 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3114 */
3115static void
3116warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3117{
3118 struct lysc_node *scnode;
3119 struct lysc_type *type;
3120 char *value;
3121 LY_ERR rc;
3122 struct ly_err_item *err = NULL;
3123
3124 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3125 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3126 /* check that the node can have the specified value */
3127 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3128 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3129 } else {
3130 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3131 }
3132 if (!value) {
3133 LOGMEM(set->ctx);
3134 return;
3135 }
3136
3137 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3138 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3139 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3140 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3141 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3142 exp->expr + exp->tok_pos[equal_exp]);
3143 }
3144
3145 type = ((struct lysc_node_leaf *)scnode)->type;
3146 if (type->basetype != LY_TYPE_IDENT) {
3147 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3148 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3149
3150 if (err) {
3151 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3152 ly_err_free(err);
3153 } else if (rc != LY_SUCCESS) {
3154 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3155 }
3156 if (rc != LY_SUCCESS) {
3157 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3158 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3159 exp->expr + exp->tok_pos[equal_exp]);
3160 }
3161 }
3162 free(value);
3163 }
3164}
3165
3166/*
3167 * XPath functions
3168 */
3169
3170/**
3171 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3172 * depending on whether the first node bit value from the second argument is set.
3173 *
3174 * @param[in] args Array of arguments.
3175 * @param[in] arg_count Count of elements in @p args.
3176 * @param[in,out] set Context and result set at the same time.
3177 * @param[in] options XPath options.
3178 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3179 */
3180static LY_ERR
3181xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3182{
3183 struct lyd_node_term *leaf;
3184 struct lysc_node_leaf *sleaf;
3185 struct lysc_type_bits *bits;
3186 LY_ERR rc = LY_SUCCESS;
3187 uint32_t i;
3188
3189 if (options & LYXP_SCNODE_ALL) {
3190 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3191 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3192 rc = LY_EINVAL;
3193 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3194 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3195 rc = LY_EINVAL;
3196 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3197 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
3198 rc = LY_EINVAL;
3199 }
3200
3201 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3202 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3203 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3204 rc = LY_EINVAL;
3205 } else if (!warn_is_string_type(sleaf->type)) {
3206 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3207 rc = LY_EINVAL;
3208 }
3209 }
3210 set_scnode_clear_ctx(set);
3211 return rc;
3212 }
3213
3214 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3215 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)");
3216 return LY_EVALID;
3217 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003218 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003219 LY_CHECK_RET(rc);
3220
3221 set_fill_boolean(set, 0);
3222 if (args[0]->type == LYXP_SET_NODE_SET) {
3223 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3224 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3225 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3226 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
3227 LY_ARRAY_FOR(bits->bits, i) {
3228 if (!strcmp(bits->bits[i].name, args[1]->val.str)) {
3229 set_fill_boolean(set, 1);
3230 break;
3231 }
3232 }
3233 }
3234 }
3235
3236 return LY_SUCCESS;
3237}
3238
3239/**
3240 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3241 * with the argument converted to boolean.
3242 *
3243 * @param[in] args Array of arguments.
3244 * @param[in] arg_count Count of elements in @p args.
3245 * @param[in,out] set Context and result set at the same time.
3246 * @param[in] options XPath options.
3247 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3248 */
3249static LY_ERR
3250xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3251{
3252 LY_ERR rc;
3253
3254 if (options & LYXP_SCNODE_ALL) {
3255 set_scnode_clear_ctx(set);
3256 return LY_SUCCESS;
3257 }
3258
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003259 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003260 LY_CHECK_RET(rc);
3261 set_fill_set(set, args[0]);
3262
3263 return LY_SUCCESS;
3264}
3265
3266/**
3267 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3268 * with the first argument rounded up to the nearest integer.
3269 *
3270 * @param[in] args Array of arguments.
3271 * @param[in] arg_count Count of elements in @p args.
3272 * @param[in,out] set Context and result set at the same time.
3273 * @param[in] options XPath options.
3274 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3275 */
3276static LY_ERR
3277xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3278{
3279 struct lysc_node_leaf *sleaf;
3280 LY_ERR rc = LY_SUCCESS;
3281
3282 if (options & LYXP_SCNODE_ALL) {
3283 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3284 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3285 rc = LY_EINVAL;
3286 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3287 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3288 rc = LY_EINVAL;
3289 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3290 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
3291 rc = LY_EINVAL;
3292 }
3293 set_scnode_clear_ctx(set);
3294 return rc;
3295 }
3296
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003297 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003298 LY_CHECK_RET(rc);
3299 if ((long long)args[0]->val.num != args[0]->val.num) {
3300 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3301 } else {
3302 set_fill_number(set, args[0]->val.num);
3303 }
3304
3305 return LY_SUCCESS;
3306}
3307
3308/**
3309 * @brief Execute the XPath concat(string, string, string*) function.
3310 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3311 *
3312 * @param[in] args Array of arguments.
3313 * @param[in] arg_count Count of elements in @p args.
3314 * @param[in,out] set Context and result set at the same time.
3315 * @param[in] options XPath options.
3316 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3317 */
3318static LY_ERR
3319xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3320{
3321 uint16_t i;
3322 char *str = NULL;
3323 size_t used = 1;
3324 LY_ERR rc = LY_SUCCESS;
3325 struct lysc_node_leaf *sleaf;
3326
3327 if (options & LYXP_SCNODE_ALL) {
3328 for (i = 0; i < arg_count; ++i) {
3329 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3330 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3331 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3332 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3333 rc = LY_EINVAL;
3334 } else if (!warn_is_string_type(sleaf->type)) {
3335 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", __func__, i + 1, sleaf->name);
3336 rc = LY_EINVAL;
3337 }
3338 }
3339 }
3340 set_scnode_clear_ctx(set);
3341 return rc;
3342 }
3343
3344 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003345 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003346 if (rc != LY_SUCCESS) {
3347 free(str);
3348 return rc;
3349 }
3350
3351 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3352 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3353 strcpy(str + used - 1, args[i]->val.str);
3354 used += strlen(args[i]->val.str);
3355 }
3356
3357 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003358 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003359 set->type = LYXP_SET_STRING;
3360 set->val.str = str;
3361
3362 return LY_SUCCESS;
3363}
3364
3365/**
3366 * @brief Execute the XPath contains(string, string) function.
3367 * Returns LYXP_SET_BOOLEAN whether the second argument can
3368 * be found in the first or not.
3369 *
3370 * @param[in] args Array of arguments.
3371 * @param[in] arg_count Count of elements in @p args.
3372 * @param[in,out] set Context and result set at the same time.
3373 * @param[in] options XPath options.
3374 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3375 */
3376static LY_ERR
3377xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3378{
3379 struct lysc_node_leaf *sleaf;
3380 LY_ERR rc = LY_SUCCESS;
3381
3382 if (options & LYXP_SCNODE_ALL) {
3383 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3384 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3385 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3386 rc = LY_EINVAL;
3387 } else if (!warn_is_string_type(sleaf->type)) {
3388 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3389 rc = LY_EINVAL;
3390 }
3391 }
3392
3393 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3394 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3395 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3396 rc = LY_EINVAL;
3397 } else if (!warn_is_string_type(sleaf->type)) {
3398 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3399 rc = LY_EINVAL;
3400 }
3401 }
3402 set_scnode_clear_ctx(set);
3403 return rc;
3404 }
3405
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003406 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003407 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003408 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003409 LY_CHECK_RET(rc);
3410
3411 if (strstr(args[0]->val.str, args[1]->val.str)) {
3412 set_fill_boolean(set, 1);
3413 } else {
3414 set_fill_boolean(set, 0);
3415 }
3416
3417 return LY_SUCCESS;
3418}
3419
3420/**
3421 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3422 * with the size of the node-set from the argument.
3423 *
3424 * @param[in] args Array of arguments.
3425 * @param[in] arg_count Count of elements in @p args.
3426 * @param[in,out] set Context and result set at the same time.
3427 * @param[in] options XPath options.
3428 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3429 */
3430static LY_ERR
3431xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3432{
3433 struct lysc_node *scnode = NULL;
3434 LY_ERR rc = LY_SUCCESS;
3435
3436 if (options & LYXP_SCNODE_ALL) {
3437 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3438 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3439 rc = LY_EINVAL;
3440 }
3441 set_scnode_clear_ctx(set);
3442 return rc;
3443 }
3444
3445 if (args[0]->type == LYXP_SET_EMPTY) {
3446 set_fill_number(set, 0);
3447 return LY_SUCCESS;
3448 }
3449
3450 if (args[0]->type != LYXP_SET_NODE_SET) {
3451 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3452 return LY_EVALID;
3453 }
3454
3455 set_fill_number(set, args[0]->used);
3456 return LY_SUCCESS;
3457}
3458
3459/**
3460 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3461 * with the context with the intial node.
3462 *
3463 * @param[in] args Array of arguments.
3464 * @param[in] arg_count Count of elements in @p args.
3465 * @param[in,out] set Context and result set at the same time.
3466 * @param[in] options XPath options.
3467 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3468 */
3469static LY_ERR
3470xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3471{
3472 if (arg_count || args) {
3473 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3474 return LY_EVALID;
3475 }
3476
3477 if (options & LYXP_SCNODE_ALL) {
3478 set_scnode_clear_ctx(set);
3479
Michal Vaskoecd62de2019-11-13 12:35:11 +01003480 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003481 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003482 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003483
3484 /* position is filled later */
3485 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3486 }
3487
3488 return LY_SUCCESS;
3489}
3490
3491/**
3492 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3493 * leafref or instance-identifier target node(s).
3494 *
3495 * @param[in] args Array of arguments.
3496 * @param[in] arg_count Count of elements in @p args.
3497 * @param[in,out] set Context and result set at the same time.
3498 * @param[in] options XPath options.
3499 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3500 */
3501static LY_ERR
3502xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3503{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003504 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003505 struct lyd_node_term *leaf;
3506 struct lysc_node_leaf *sleaf;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003507 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003508 const struct lyd_node *node;
3509 char *errmsg = NULL;
3510 const char *val;
3511 int dynamic;
3512 LY_ERR rc = LY_SUCCESS;
3513
3514 if (options & LYXP_SCNODE_ALL) {
3515 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3516 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3517 rc = LY_EINVAL;
3518 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3519 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3520 rc = LY_EINVAL;
3521 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3522 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3523 __func__, sleaf->name);
3524 rc = LY_EINVAL;
3525 }
3526 set_scnode_clear_ctx(set);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003527 if ((rc == LY_SUCCESS) && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
3528 cctx.ctx = set->ctx;
3529 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3530 /* it was already validated, it must succeed */
3531 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003532 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003533 }
3534 }
3535
Michal Vasko03ff5a72019-09-11 13:49:33 +02003536 return rc;
3537 }
3538
3539 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3540 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3541 return LY_EVALID;
3542 }
3543
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003544 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003545 if (args[0]->type != LYXP_SET_EMPTY) {
3546 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3547 sleaf = (struct lysc_node_leaf *)leaf->schema;
3548 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3549 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3550 /* find leafref target */
3551 val = lyd_value2str(leaf, &dynamic);
3552 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
3553 set->trees, &leaf->value, &errmsg);
3554 if (dynamic) {
3555 free((char *)val);
3556 }
3557 if (!node) {
3558 LOGERR(set->ctx, LY_EINVAL, errmsg);
3559 free(errmsg);
3560 return LY_EINVAL;
3561 }
3562
3563 /* insert it */
3564 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3565 } else {
3566 assert(sleaf->type->basetype == LY_TYPE_INST);
3567 node = (struct lyd_node *)lyd_target(leaf->value.target, set->trees);
3568 if (!node) {
3569 val = lyd_value2str(leaf, &dynamic);
3570 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3571 if (dynamic) {
3572 free((char *)val);
3573 }
3574 return LY_EVALID;
3575 }
3576 }
3577 }
3578 }
3579
3580 return LY_SUCCESS;
3581}
3582
3583/**
3584 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3585 * on whether the first argument nodes contain a node of an identity derived from the second
3586 * argument identity.
3587 *
3588 * @param[in] args Array of arguments.
3589 * @param[in] arg_count Count of elements in @p args.
3590 * @param[in,out] set Context and result set at the same time.
3591 * @param[in] options XPath options.
3592 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3593 */
3594static LY_ERR
3595xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3596{
3597 uint16_t i;
3598 struct lyd_node_term *leaf;
3599 struct lysc_node_leaf *sleaf;
3600 struct lyd_value data = {0};
3601 struct ly_err_item *err = NULL;
3602 LY_ERR rc = LY_SUCCESS;
3603 int found;
3604
3605 if (options & LYXP_SCNODE_ALL) {
3606 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3607 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3608 rc = LY_EINVAL;
3609 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3610 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3611 rc = LY_EINVAL;
3612 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3613 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
3614 rc = LY_EINVAL;
3615 }
3616
3617 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3618 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3619 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3620 rc = LY_EINVAL;
3621 } else if (!warn_is_string_type(sleaf->type)) {
3622 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3623 rc = LY_EINVAL;
3624 }
3625 }
3626 set_scnode_clear_ctx(set);
3627 return rc;
3628 }
3629
3630 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3631 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3632 return LY_EVALID;
3633 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003634 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003635 LY_CHECK_RET(rc);
3636
3637 set_fill_boolean(set, 0);
3638 if (args[0]->type != LYXP_SET_EMPTY) {
3639 found = 0;
3640 for (i = 0; i < args[0]->used; ++i) {
3641 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3642 sleaf = (struct lysc_node_leaf *)leaf->schema;
3643 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3644 /* store args[1] into ident */
3645 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3646 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3647 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3648 if (err) {
3649 ly_err_print(err);
3650 ly_err_free(err);
3651 }
3652 LY_CHECK_RET(rc);
3653
3654 LY_ARRAY_FOR(data.ident->derived, i) {
3655 if (data.ident->derived[i] == leaf->value.ident) {
3656 set_fill_boolean(set, 1);
3657 found = 1;
3658 break;
3659 }
3660 }
3661 if (found) {
3662 break;
3663 }
3664 }
3665 }
3666 }
3667
3668 return LY_SUCCESS;
3669}
3670
3671/**
3672 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3673 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3674 * the second argument identity.
3675 *
3676 * @param[in] args Array of arguments.
3677 * @param[in] arg_count Count of elements in @p args.
3678 * @param[in,out] set Context and result set at the same time.
3679 * @param[in] options XPath options.
3680 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3681 */
3682static LY_ERR
3683xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3684{
3685 uint16_t i;
3686 struct lyd_node_term *leaf;
3687 struct lysc_node_leaf *sleaf;
3688 struct lyd_value data = {0};
3689 struct ly_err_item *err = NULL;
3690 LY_ERR rc = LY_SUCCESS;
3691 int found;
3692
3693 if (options & LYXP_SCNODE_ALL) {
3694 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3695 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3696 rc = LY_EINVAL;
3697 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3698 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3699 rc = LY_EINVAL;
3700 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3701 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
3702 rc = LY_EINVAL;
3703 }
3704
3705 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3706 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3707 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3708 rc = LY_EINVAL;
3709 } else if (!warn_is_string_type(sleaf->type)) {
3710 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3711 rc = LY_EINVAL;
3712 }
3713 }
3714 set_scnode_clear_ctx(set);
3715 return rc;
3716 }
3717
3718 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3719 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)");
3720 return LY_EVALID;
3721 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003722 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003723 LY_CHECK_RET(rc);
3724
3725 set_fill_boolean(set, 0);
3726 if (args[0]->type != LYXP_SET_EMPTY) {
3727 found = 0;
3728 for (i = 0; i < args[0]->used; ++i) {
3729 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3730 sleaf = (struct lysc_node_leaf *)leaf->schema;
3731 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3732 /* store args[1] into ident */
3733 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3734 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3735 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3736 if (err) {
3737 ly_err_print(err);
3738 ly_err_free(err);
3739 }
3740 LY_CHECK_RET(rc);
3741
3742 if (data.ident == leaf->value.ident) {
3743 set_fill_boolean(set, 1);
3744 break;
3745 }
3746 LY_ARRAY_FOR(data.ident->derived, i) {
3747 if (data.ident->derived[i] == leaf->value.ident) {
3748 set_fill_boolean(set, 1);
3749 found = 1;
3750 break;
3751 }
3752 }
3753 if (found) {
3754 break;
3755 }
3756 }
3757 }
3758 }
3759
3760 return LY_SUCCESS;
3761}
3762
3763/**
3764 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3765 * with the integer value of the first node's enum value, otherwise NaN.
3766 *
3767 * @param[in] args Array of arguments.
3768 * @param[in] arg_count Count of elements in @p args.
3769 * @param[in,out] set Context and result set at the same time.
3770 * @param[in] options XPath options.
3771 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3772 */
3773static LY_ERR
3774xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3775{
3776 struct lyd_node_term *leaf;
3777 struct lysc_node_leaf *sleaf;
3778 LY_ERR rc = LY_SUCCESS;
3779
3780 if (options & LYXP_SCNODE_ALL) {
3781 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3782 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
3783 rc = LY_EINVAL;
3784 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3785 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3786 rc = LY_EINVAL;
3787 } 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);
3789 rc = LY_EINVAL;
3790 }
3791 set_scnode_clear_ctx(set);
3792 return rc;
3793 }
3794
3795 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3796 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3797 return LY_EVALID;
3798 }
3799
3800 set_fill_number(set, NAN);
3801 if (args[0]->type == LYXP_SET_NODE_SET) {
3802 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3803 sleaf = (struct lysc_node_leaf *)leaf->schema;
3804 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3805 set_fill_number(set, leaf->value.enum_item->value);
3806 }
3807 }
3808
3809 return LY_SUCCESS;
3810}
3811
3812/**
3813 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3814 * with false value.
3815 *
3816 * @param[in] args Array of arguments.
3817 * @param[in] arg_count Count of elements in @p args.
3818 * @param[in,out] set Context and result set at the same time.
3819 * @param[in] options XPath options.
3820 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3821 */
3822static LY_ERR
3823xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3824{
3825 if (options & LYXP_SCNODE_ALL) {
3826 set_scnode_clear_ctx(set);
3827 return LY_SUCCESS;
3828 }
3829
3830 set_fill_boolean(set, 0);
3831 return LY_SUCCESS;
3832}
3833
3834/**
3835 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3836 * with the first argument floored (truncated).
3837 *
3838 * @param[in] args Array of arguments.
3839 * @param[in] arg_count Count of elements in @p args.
3840 * @param[in,out] set Context and result set at the same time.
3841 * @param[in] options XPath options.
3842 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3843 */
3844static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003845xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003846{
3847 LY_ERR rc;
3848
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003849 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003850 LY_CHECK_RET(rc);
3851 if (isfinite(args[0]->val.num)) {
3852 set_fill_number(set, (long long)args[0]->val.num);
3853 }
3854
3855 return LY_SUCCESS;
3856}
3857
3858/**
3859 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3860 * whether the language of the text matches the one from the argument.
3861 *
3862 * @param[in] args Array of arguments.
3863 * @param[in] arg_count Count of elements in @p args.
3864 * @param[in,out] set Context and result set at the same time.
3865 * @param[in] options XPath options.
3866 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3867 */
3868static LY_ERR
3869xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3870{
3871 const struct lyd_node *node;
3872 struct lysc_node_leaf *sleaf;
3873 struct lyd_attr *attr = NULL;
3874 const char *val;
3875 int i, dynamic;
3876 LY_ERR rc = LY_SUCCESS;
3877
3878 if (options & LYXP_SCNODE_ALL) {
3879 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3880 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3881 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
3882 rc = LY_EINVAL;
3883 } else if (!warn_is_string_type(sleaf->type)) {
3884 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
3885 rc = LY_EINVAL;
3886 }
3887 }
3888 set_scnode_clear_ctx(set);
3889 return rc;
3890 }
3891
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003892 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003893 LY_CHECK_RET(rc);
3894
3895 if (set->type == LYXP_SET_EMPTY) {
3896 set_fill_boolean(set, 0);
3897 return LY_SUCCESS;
3898 }
3899 if (set->type != LYXP_SET_NODE_SET) {
3900 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3901 return LY_EVALID;
3902 }
3903
3904 switch (set->val.nodes[0].type) {
3905 case LYXP_NODE_ELEM:
3906 case LYXP_NODE_TEXT:
3907 node = set->val.nodes[0].node;
3908 break;
3909 case LYXP_NODE_ATTR:
3910 node = set->val.attrs[0].attr->parent;
3911 break;
3912 default:
3913 /* nothing to do with roots */
3914 set_fill_boolean(set, 0);
3915 return LY_SUCCESS;
3916 }
3917
3918 /* find lang attribute */
3919 for (; node; node = (struct lyd_node *)node->parent) {
3920 for (attr = node->attr; attr; attr = attr->next) {
3921 /* annotations */
3922 if (attr->name && !strcmp(attr->name, "lang") && !strcmp(attr->annotation->module->name, "xml")) {
3923 break;
3924 }
3925 }
3926
3927 if (attr) {
3928 break;
3929 }
3930 }
3931
3932 /* compare languages */
3933 if (!attr) {
3934 set_fill_boolean(set, 0);
3935 } else {
3936 val = lyd_attr2str(attr, &dynamic);
3937 for (i = 0; args[0]->val.str[i]; ++i) {
3938 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3939 set_fill_boolean(set, 0);
3940 break;
3941 }
3942 }
3943 if (!args[0]->val.str[i]) {
3944 if (!val[i] || (val[i] == '-')) {
3945 set_fill_boolean(set, 1);
3946 } else {
3947 set_fill_boolean(set, 0);
3948 }
3949 }
3950 if (dynamic) {
3951 free((char *)val);
3952 }
3953 }
3954
3955 return LY_SUCCESS;
3956}
3957
3958/**
3959 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3960 * with the context size.
3961 *
3962 * @param[in] args Array of arguments.
3963 * @param[in] arg_count Count of elements in @p args.
3964 * @param[in,out] set Context and result set at the same time.
3965 * @param[in] options XPath options.
3966 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3967 */
3968static LY_ERR
3969xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3970{
3971 if (options & LYXP_SCNODE_ALL) {
3972 set_scnode_clear_ctx(set);
3973 return LY_SUCCESS;
3974 }
3975
3976 if (set->type == LYXP_SET_EMPTY) {
3977 set_fill_number(set, 0);
3978 return LY_SUCCESS;
3979 }
3980 if (set->type != LYXP_SET_NODE_SET) {
3981 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3982 return LY_EVALID;
3983 }
3984
3985 set_fill_number(set, set->ctx_size);
3986 return LY_SUCCESS;
3987}
3988
3989/**
3990 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3991 * with the node name without namespace from the argument or the context.
3992 *
3993 * @param[in] args Array of arguments.
3994 * @param[in] arg_count Count of elements in @p args.
3995 * @param[in,out] set Context and result set at the same time.
3996 * @param[in] options XPath options.
3997 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
3998 */
3999static LY_ERR
4000xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4001{
4002 struct lyxp_set_node *item;
4003 /* suppress unused variable warning */
4004 (void)options;
4005
4006 if (options & LYXP_SCNODE_ALL) {
4007 set_scnode_clear_ctx(set);
4008 return LY_SUCCESS;
4009 }
4010
4011 if (arg_count) {
4012 if (args[0]->type == LYXP_SET_EMPTY) {
4013 set_fill_string(set, "", 0);
4014 return LY_SUCCESS;
4015 }
4016 if (args[0]->type != LYXP_SET_NODE_SET) {
4017 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4018 return LY_EVALID;
4019 }
4020
4021 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004022 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004023
4024 item = &args[0]->val.nodes[0];
4025 } else {
4026 if (set->type == LYXP_SET_EMPTY) {
4027 set_fill_string(set, "", 0);
4028 return LY_SUCCESS;
4029 }
4030 if (set->type != LYXP_SET_NODE_SET) {
4031 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4032 return LY_EVALID;
4033 }
4034
4035 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004036 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004037
4038 item = &set->val.nodes[0];
4039 }
4040
4041 switch (item->type) {
4042 case LYXP_NODE_ROOT:
4043 case LYXP_NODE_ROOT_CONFIG:
4044 case LYXP_NODE_TEXT:
4045 set_fill_string(set, "", 0);
4046 break;
4047 case LYXP_NODE_ELEM:
4048 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4049 break;
4050 case LYXP_NODE_ATTR:
4051 set_fill_string(set, ((struct lyd_attr *)item->node)->name, strlen(((struct lyd_attr *)item->node)->name));
4052 break;
4053 }
4054
4055 return LY_SUCCESS;
4056}
4057
4058/**
4059 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4060 * with the node name fully qualified (with namespace) from the argument or the context.
4061 *
4062 * @param[in] args Array of arguments.
4063 * @param[in] arg_count Count of elements in @p args.
4064 * @param[in,out] set Context and result set at the same time.
4065 * @param[in] options XPath options.
4066 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4067 */
4068static LY_ERR
4069xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4070{
4071 struct lyxp_set_node *item;
4072 struct lys_module *mod;
4073 char *str;
4074 const char *name;
4075 int rc;
4076
4077 if (options & LYXP_SCNODE_ALL) {
4078 set_scnode_clear_ctx(set);
4079 return LY_SUCCESS;
4080 }
4081
4082 if (arg_count) {
4083 if (args[0]->type == LYXP_SET_EMPTY) {
4084 set_fill_string(set, "", 0);
4085 return LY_SUCCESS;
4086 }
4087 if (args[0]->type != LYXP_SET_NODE_SET) {
4088 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4089 return LY_EVALID;
4090 }
4091
4092 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004093 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004094
4095 item = &args[0]->val.nodes[0];
4096 } else {
4097 if (set->type == LYXP_SET_EMPTY) {
4098 set_fill_string(set, "", 0);
4099 return LY_SUCCESS;
4100 }
4101 if (set->type != LYXP_SET_NODE_SET) {
4102 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4103 return LY_EVALID;
4104 }
4105
4106 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004107 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004108
4109 item = &set->val.nodes[0];
4110 }
4111
4112 switch (item->type) {
4113 case LYXP_NODE_ROOT:
4114 case LYXP_NODE_ROOT_CONFIG:
4115 case LYXP_NODE_TEXT:
4116 mod = NULL;
4117 name = NULL;
4118 break;
4119 case LYXP_NODE_ELEM:
4120 mod = item->node->schema->module;
4121 name = item->node->schema->name;
4122 break;
4123 case LYXP_NODE_ATTR:
4124 mod = ((struct lyd_attr *)item->node)->annotation->module;
4125 name = ((struct lyd_attr *)item->node)->name;
4126 break;
4127 }
4128
4129 if (mod && name) {
4130 switch (set->format) {
4131 case LYD_UNKNOWN:
4132 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4133 break;
4134 case LYD_JSON:
4135 rc = asprintf(&str, "%s:%s", mod->name, name);
4136 break;
Michal Vasko9409ef62019-09-12 11:47:17 +02004137 default:
4138 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004139 }
4140 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4141 set_fill_string(set, str, strlen(str));
4142 free(str);
4143 } else {
4144 set_fill_string(set, "", 0);
4145 }
4146
4147 return LY_SUCCESS;
4148}
4149
4150/**
4151 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4152 * with the namespace of the node from the argument or the context.
4153 *
4154 * @param[in] args Array of arguments.
4155 * @param[in] arg_count Count of elements in @p args.
4156 * @param[in,out] set Context and result set at the same time.
4157 * @param[in] options XPath options.
4158 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4159 */
4160static LY_ERR
4161xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4162{
4163 struct lyxp_set_node *item;
4164 struct lys_module *mod;
4165 /* suppress unused variable warning */
4166 (void)options;
4167
4168 if (options & LYXP_SCNODE_ALL) {
4169 set_scnode_clear_ctx(set);
4170 return LY_SUCCESS;
4171 }
4172
4173 if (arg_count) {
4174 if (args[0]->type == LYXP_SET_EMPTY) {
4175 set_fill_string(set, "", 0);
4176 return LY_SUCCESS;
4177 }
4178 if (args[0]->type != LYXP_SET_NODE_SET) {
4179 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4180 return LY_EVALID;
4181 }
4182
4183 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004184 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004185
4186 item = &args[0]->val.nodes[0];
4187 } else {
4188 if (set->type == LYXP_SET_EMPTY) {
4189 set_fill_string(set, "", 0);
4190 return LY_SUCCESS;
4191 }
4192 if (set->type != LYXP_SET_NODE_SET) {
4193 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4194 return LY_EVALID;
4195 }
4196
4197 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004198 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004199
4200 item = &set->val.nodes[0];
4201 }
4202
4203 switch (item->type) {
4204 case LYXP_NODE_ROOT:
4205 case LYXP_NODE_ROOT_CONFIG:
4206 case LYXP_NODE_TEXT:
4207 set_fill_string(set, "", 0);
4208 break;
4209 case LYXP_NODE_ELEM:
4210 case LYXP_NODE_ATTR:
4211 if (item->type == LYXP_NODE_ELEM) {
4212 mod = item->node->schema->module;
4213 } else { /* LYXP_NODE_ATTR */
4214 /* annotations */
4215 mod = ((struct lyd_attr *)item->node)->annotation->module;
4216 }
4217
4218 set_fill_string(set, mod->ns, strlen(mod->ns));
4219 break;
4220 }
4221
4222 return LY_SUCCESS;
4223}
4224
4225/**
4226 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4227 * with only nodes from the context. In practice it either leaves the context
4228 * as it is or returns an empty node set.
4229 *
4230 * @param[in] args Array of arguments.
4231 * @param[in] arg_count Count of elements in @p args.
4232 * @param[in,out] set Context and result set at the same time.
4233 * @param[in] options XPath options.
4234 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4235 */
4236static LY_ERR
4237xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4238{
4239 if (options & LYXP_SCNODE_ALL) {
4240 set_scnode_clear_ctx(set);
4241 return LY_SUCCESS;
4242 }
4243
4244 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004245 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004246 }
4247 return LY_SUCCESS;
4248}
4249
4250/**
4251 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4252 * with normalized value (no leading, trailing, double white spaces) of the node
4253 * from the argument or the context.
4254 *
4255 * @param[in] args Array of arguments.
4256 * @param[in] arg_count Count of elements in @p args.
4257 * @param[in,out] set Context and result set at the same time.
4258 * @param[in] options XPath options.
4259 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4260 */
4261static LY_ERR
4262xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4263{
4264 uint16_t i, new_used;
4265 char *new;
4266 int have_spaces = 0, space_before = 0;
4267 struct lysc_node_leaf *sleaf;
4268 LY_ERR rc = LY_SUCCESS;
4269
4270 if (options & LYXP_SCNODE_ALL) {
4271 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4272 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4273 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4274 rc = LY_EINVAL;
4275 } else if (!warn_is_string_type(sleaf->type)) {
4276 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4277 rc = LY_EINVAL;
4278 }
4279 }
4280 set_scnode_clear_ctx(set);
4281 return rc;
4282 }
4283
4284 if (arg_count) {
4285 set_fill_set(set, args[0]);
4286 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004287 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004288 LY_CHECK_RET(rc);
4289
4290 /* is there any normalization necessary? */
4291 for (i = 0; set->val.str[i]; ++i) {
4292 if (is_xmlws(set->val.str[i])) {
4293 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4294 have_spaces = 1;
4295 break;
4296 }
4297 space_before = 1;
4298 } else {
4299 space_before = 0;
4300 }
4301 }
4302
4303 /* yep, there is */
4304 if (have_spaces) {
4305 /* it's enough, at least one character will go, makes space for ending '\0' */
4306 new = malloc(strlen(set->val.str) * sizeof(char));
4307 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4308 new_used = 0;
4309
4310 space_before = 0;
4311 for (i = 0; set->val.str[i]; ++i) {
4312 if (is_xmlws(set->val.str[i])) {
4313 if ((i == 0) || space_before) {
4314 space_before = 1;
4315 continue;
4316 } else {
4317 space_before = 1;
4318 }
4319 } else {
4320 space_before = 0;
4321 }
4322
4323 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4324 ++new_used;
4325 }
4326
4327 /* at worst there is one trailing space now */
4328 if (new_used && is_xmlws(new[new_used - 1])) {
4329 --new_used;
4330 }
4331
4332 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4333 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4334 new[new_used] = '\0';
4335
4336 free(set->val.str);
4337 set->val.str = new;
4338 }
4339
4340 return LY_SUCCESS;
4341}
4342
4343/**
4344 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4345 * with the argument converted to boolean and logically inverted.
4346 *
4347 * @param[in] args Array of arguments.
4348 * @param[in] arg_count Count of elements in @p args.
4349 * @param[in,out] set Context and result set at the same time.
4350 * @param[in] options XPath options.
4351 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4352 */
4353static LY_ERR
4354xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4355{
4356 if (options & LYXP_SCNODE_ALL) {
4357 set_scnode_clear_ctx(set);
4358 return LY_SUCCESS;
4359 }
4360
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004361 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004362 if (args[0]->val.bool) {
4363 set_fill_boolean(set, 0);
4364 } else {
4365 set_fill_boolean(set, 1);
4366 }
4367
4368 return LY_SUCCESS;
4369}
4370
4371/**
4372 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4373 * with the number representation of either the argument or the context.
4374 *
4375 * @param[in] args Array of arguments.
4376 * @param[in] arg_count Count of elements in @p args.
4377 * @param[in,out] set Context and result set at the same time.
4378 * @param[in] options XPath options.
4379 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4380 */
4381static LY_ERR
4382xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4383{
4384 LY_ERR rc;
4385
4386 if (options & LYXP_SCNODE_ALL) {
4387 set_scnode_clear_ctx(set);
4388 return LY_SUCCESS;
4389 }
4390
4391 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004392 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004393 LY_CHECK_RET(rc);
4394 set_fill_set(set, args[0]);
4395 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004396 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004397 LY_CHECK_RET(rc);
4398 }
4399
4400 return LY_SUCCESS;
4401}
4402
4403/**
4404 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4405 * with the context position.
4406 *
4407 * @param[in] args Array of arguments.
4408 * @param[in] arg_count Count of elements in @p args.
4409 * @param[in,out] set Context and result set at the same time.
4410 * @param[in] options XPath options.
4411 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4412 */
4413static LY_ERR
4414xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4415{
4416 if (options & LYXP_SCNODE_ALL) {
4417 set_scnode_clear_ctx(set);
4418 return LY_SUCCESS;
4419 }
4420
4421 if (set->type == LYXP_SET_EMPTY) {
4422 set_fill_number(set, 0);
4423 return LY_SUCCESS;
4424 }
4425 if (set->type != LYXP_SET_NODE_SET) {
4426 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4427 return LY_EVALID;
4428 }
4429
4430 set_fill_number(set, set->ctx_pos);
4431
4432 /* UNUSED in 'Release' build type */
4433 (void)options;
4434 return LY_SUCCESS;
4435}
4436
4437/**
4438 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4439 * depending on whether the second argument regex matches the first argument string. For details refer to
4440 * YANG 1.1 RFC section 10.2.1.
4441 *
4442 * @param[in] args Array of arguments.
4443 * @param[in] arg_count Count of elements in @p args.
4444 * @param[in,out] set Context and result set at the same time.
4445 * @param[in] options XPath options.
4446 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4447 */
4448static LY_ERR
4449xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4450{
4451 struct lysc_pattern **patterns = NULL, **pattern;
4452 struct lysc_node_leaf *sleaf;
4453 char *path;
4454 LY_ERR rc = LY_SUCCESS;
4455 struct ly_err_item *err;
4456
4457 if (options & LYXP_SCNODE_ALL) {
4458 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4459 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4460 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4461 rc = LY_EINVAL;
4462 } 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);
4464 rc = LY_EINVAL;
4465 }
4466 }
4467
4468 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4469 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4470 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4471 rc = LY_EINVAL;
4472 } else if (!warn_is_string_type(sleaf->type)) {
4473 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4474 rc = LY_EINVAL;
4475 }
4476 }
4477 set_scnode_clear_ctx(set);
4478 return rc;
4479 }
4480
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004481 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004482 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004483 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004484 LY_CHECK_RET(rc);
4485
4486 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4487 *pattern = malloc(sizeof **pattern);
4488 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4489 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4490 free(path);
4491 if (rc != LY_SUCCESS) {
4492 LY_ARRAY_FREE(patterns);
4493 return rc;
4494 }
4495
4496 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4497 pcre2_code_free((*pattern)->code);
4498 free(*pattern);
4499 LY_ARRAY_FREE(patterns);
4500 if (rc && (rc != LY_EVALID)) {
4501 ly_err_print(err);
4502 ly_err_free(err);
4503 return rc;
4504 }
4505
4506 if (rc == LY_EVALID) {
4507 ly_err_free(err);
4508 set_fill_boolean(set, 0);
4509 } else {
4510 set_fill_boolean(set, 1);
4511 }
4512
4513 return LY_SUCCESS;
4514}
4515
4516/**
4517 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4518 * with the rounded first argument. For details refer to
4519 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4520 *
4521 * @param[in] args Array of arguments.
4522 * @param[in] arg_count Count of elements in @p args.
4523 * @param[in,out] set Context and result set at the same time.
4524 * @param[in] options XPath options.
4525 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4526 */
4527static LY_ERR
4528xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4529{
4530 struct lysc_node_leaf *sleaf;
4531 LY_ERR rc = LY_SUCCESS;
4532
4533 if (options & LYXP_SCNODE_ALL) {
4534 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4535 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
4536 rc = LY_EINVAL;
4537 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4538 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4539 rc = LY_EINVAL;
4540 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4541 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
4542 rc = LY_EINVAL;
4543 }
4544 set_scnode_clear_ctx(set);
4545 return rc;
4546 }
4547
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004548 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004549 LY_CHECK_RET(rc);
4550
4551 /* cover only the cases where floor can't be used */
4552 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4553 set_fill_number(set, -0.0f);
4554 } else {
4555 args[0]->val.num += 0.5;
4556 rc = xpath_floor(args, 1, args[0], options);
4557 LY_CHECK_RET(rc);
4558 set_fill_number(set, args[0]->val.num);
4559 }
4560
4561 return LY_SUCCESS;
4562}
4563
4564/**
4565 * @brief Execute the XPath starts-with(string, string) function.
4566 * Returns LYXP_SET_BOOLEAN whether the second argument is
4567 * the prefix of the first or not.
4568 *
4569 * @param[in] args Array of arguments.
4570 * @param[in] arg_count Count of elements in @p args.
4571 * @param[in,out] set Context and result set at the same time.
4572 * @param[in] options XPath options.
4573 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4574 */
4575static LY_ERR
4576xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4577{
4578 struct lysc_node_leaf *sleaf;
4579 LY_ERR rc = LY_SUCCESS;
4580
4581 if (options & LYXP_SCNODE_ALL) {
4582 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4583 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4584 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4585 rc = LY_EINVAL;
4586 } else if (!warn_is_string_type(sleaf->type)) {
4587 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4588 rc = LY_EINVAL;
4589 }
4590 }
4591
4592 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4593 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4594 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4595 rc = LY_EINVAL;
4596 } else if (!warn_is_string_type(sleaf->type)) {
4597 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4598 rc = LY_EINVAL;
4599 }
4600 }
4601 set_scnode_clear_ctx(set);
4602 return rc;
4603 }
4604
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004605 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004606 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004607 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004608 LY_CHECK_RET(rc);
4609
4610 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4611 set_fill_boolean(set, 0);
4612 } else {
4613 set_fill_boolean(set, 1);
4614 }
4615
4616 return LY_SUCCESS;
4617}
4618
4619/**
4620 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4621 * with the string representation of either the argument or the context.
4622 *
4623 * @param[in] args Array of arguments.
4624 * @param[in] arg_count Count of elements in @p args.
4625 * @param[in,out] set Context and result set at the same time.
4626 * @param[in] options XPath options.
4627 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4628 */
4629static LY_ERR
4630xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4631{
4632 LY_ERR rc;
4633
4634 if (options & LYXP_SCNODE_ALL) {
4635 set_scnode_clear_ctx(set);
4636 return LY_SUCCESS;
4637 }
4638
4639 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004640 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004641 LY_CHECK_RET(rc);
4642 set_fill_set(set, args[0]);
4643 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004644 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004645 LY_CHECK_RET(rc);
4646 }
4647
4648 return LY_SUCCESS;
4649}
4650
4651/**
4652 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4653 * with the length of the string in either the argument or the context.
4654 *
4655 * @param[in] args Array of arguments.
4656 * @param[in] arg_count Count of elements in @p args.
4657 * @param[in,out] set Context and result set at the same time.
4658 * @param[in] options XPath options.
4659 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4660 */
4661static LY_ERR
4662xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4663{
4664 struct lysc_node_leaf *sleaf;
4665 LY_ERR rc = LY_SUCCESS;
4666
4667 if (options & LYXP_SCNODE_ALL) {
4668 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4669 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4670 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4671 rc = LY_EINVAL;
4672 } else if (!warn_is_string_type(sleaf->type)) {
4673 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4674 rc = LY_EINVAL;
4675 }
4676 }
4677 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4678 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4679 LOGWRN(set->ctx, "Argument #0 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4680 rc = LY_EINVAL;
4681 } else if (!warn_is_string_type(sleaf->type)) {
4682 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4683 rc = LY_EINVAL;
4684 }
4685 }
4686 set_scnode_clear_ctx(set);
4687 return rc;
4688 }
4689
4690 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004691 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004692 LY_CHECK_RET(rc);
4693 set_fill_number(set, strlen(args[0]->val.str));
4694 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004695 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004696 LY_CHECK_RET(rc);
4697 set_fill_number(set, strlen(set->val.str));
4698 }
4699
4700 return LY_SUCCESS;
4701}
4702
4703/**
4704 * @brief Execute the XPath substring(string, number, number?) function.
4705 * Returns LYXP_SET_STRING substring of the first argument starting
4706 * on the second argument index ending on the third argument index,
4707 * indexed from 1. For exact definition refer to
4708 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4709 *
4710 * @param[in] args Array of arguments.
4711 * @param[in] arg_count Count of elements in @p args.
4712 * @param[in,out] set Context and result set at the same time.
4713 * @param[in] options XPath options.
4714 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4715 */
4716static LY_ERR
4717xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4718{
4719 int start, len;
4720 uint16_t str_start, str_len, pos;
4721 struct lysc_node_leaf *sleaf;
4722 LY_ERR rc = LY_SUCCESS;
4723
4724 if (options & LYXP_SCNODE_ALL) {
4725 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4726 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4727 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4728 rc = LY_EINVAL;
4729 } else if (!warn_is_string_type(sleaf->type)) {
4730 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4731 rc = LY_EINVAL;
4732 }
4733 }
4734
4735 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4736 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4737 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4738 rc = LY_EINVAL;
4739 } else if (!warn_is_numeric_type(sleaf->type)) {
4740 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
4741 rc = LY_EINVAL;
4742 }
4743 }
4744
4745 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4746 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4747 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4748 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4749 rc = LY_EINVAL;
4750 } else if (!warn_is_numeric_type(sleaf->type)) {
4751 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
4752 rc = LY_EINVAL;
4753 }
4754 }
4755 set_scnode_clear_ctx(set);
4756 return rc;
4757 }
4758
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004759 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004760 LY_CHECK_RET(rc);
4761
4762 /* start */
4763 if (xpath_round(&args[1], 1, args[1], options)) {
4764 return -1;
4765 }
4766 if (isfinite(args[1]->val.num)) {
4767 start = args[1]->val.num - 1;
4768 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4769 start = INT_MIN;
4770 } else {
4771 start = INT_MAX;
4772 }
4773
4774 /* len */
4775 if (arg_count == 3) {
4776 rc = xpath_round(&args[2], 1, args[2], options);
4777 LY_CHECK_RET(rc);
4778 if (isfinite(args[2]->val.num)) {
4779 len = args[2]->val.num;
4780 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4781 len = 0;
4782 } else {
4783 len = INT_MAX;
4784 }
4785 } else {
4786 len = INT_MAX;
4787 }
4788
4789 /* find matching character positions */
4790 str_start = 0;
4791 str_len = 0;
4792 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4793 if (pos < start) {
4794 ++str_start;
4795 } else if (pos < start + len) {
4796 ++str_len;
4797 } else {
4798 break;
4799 }
4800 }
4801
4802 set_fill_string(set, args[0]->val.str + str_start, str_len);
4803 return LY_SUCCESS;
4804}
4805
4806/**
4807 * @brief Execute the XPath substring-after(string, string) function.
4808 * Returns LYXP_SET_STRING with the string succeeding the occurance
4809 * of the second argument in the first or an empty string.
4810 *
4811 * @param[in] args Array of arguments.
4812 * @param[in] arg_count Count of elements in @p args.
4813 * @param[in,out] set Context and result set at the same time.
4814 * @param[in] options XPath options.
4815 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4816 */
4817static LY_ERR
4818xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4819{
4820 char *ptr;
4821 struct lysc_node_leaf *sleaf;
4822 LY_ERR rc = LY_SUCCESS;
4823
4824 if (options & LYXP_SCNODE_ALL) {
4825 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4826 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4827 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4828 rc = LY_EINVAL;
4829 } else if (!warn_is_string_type(sleaf->type)) {
4830 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4831 rc = LY_EINVAL;
4832 }
4833 }
4834
4835 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4836 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4837 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4838 rc = LY_EINVAL;
4839 } else if (!warn_is_string_type(sleaf->type)) {
4840 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4841 rc = LY_EINVAL;
4842 }
4843 }
4844 set_scnode_clear_ctx(set);
4845 return rc;
4846 }
4847
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004848 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004849 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004850 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004851 LY_CHECK_RET(rc);
4852
4853 ptr = strstr(args[0]->val.str, args[1]->val.str);
4854 if (ptr) {
4855 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4856 } else {
4857 set_fill_string(set, "", 0);
4858 }
4859
4860 return LY_SUCCESS;
4861}
4862
4863/**
4864 * @brief Execute the XPath substring-before(string, string) function.
4865 * Returns LYXP_SET_STRING with the string preceding the occurance
4866 * of the second argument in the first or an empty string.
4867 *
4868 * @param[in] args Array of arguments.
4869 * @param[in] arg_count Count of elements in @p args.
4870 * @param[in,out] set Context and result set at the same time.
4871 * @param[in] options XPath options.
4872 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4873 */
4874static LY_ERR
4875xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4876{
4877 char *ptr;
4878 struct lysc_node_leaf *sleaf;
4879 LY_ERR rc = LY_SUCCESS;
4880
4881 if (options & LYXP_SCNODE_ALL) {
4882 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4883 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4884 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4885 rc = LY_EINVAL;
4886 } else if (!warn_is_string_type(sleaf->type)) {
4887 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4888 rc = LY_EINVAL;
4889 }
4890 }
4891
4892 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4893 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4894 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
4895 rc = LY_EINVAL;
4896 } else if (!warn_is_string_type(sleaf->type)) {
4897 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
4898 rc = LY_EINVAL;
4899 }
4900 }
4901 set_scnode_clear_ctx(set);
4902 return rc;
4903 }
4904
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004905 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004906 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004907 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004908 LY_CHECK_RET(rc);
4909
4910 ptr = strstr(args[0]->val.str, args[1]->val.str);
4911 if (ptr) {
4912 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4913 } else {
4914 set_fill_string(set, "", 0);
4915 }
4916
4917 return LY_SUCCESS;
4918}
4919
4920/**
4921 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4922 * with the sum of all the nodes in the context.
4923 *
4924 * @param[in] args Array of arguments.
4925 * @param[in] arg_count Count of elements in @p args.
4926 * @param[in,out] set Context and result set at the same time.
4927 * @param[in] options XPath options.
4928 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4929 */
4930static LY_ERR
4931xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4932{
4933 long double num;
4934 char *str;
4935 uint16_t i;
4936 struct lyxp_set set_item;
4937 struct lysc_node_leaf *sleaf;
4938 LY_ERR rc = LY_SUCCESS;
4939
4940 if (options & LYXP_SCNODE_ALL) {
4941 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4942 for (i = 0; i < args[0]->used; ++i) {
4943 if (args[0]->val.scnodes[i].in_ctx == 1) {
4944 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4945 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4946 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4947 lys_nodetype2str(sleaf->nodetype), sleaf->name);
4948 rc = LY_EINVAL;
4949 } else if (!warn_is_numeric_type(sleaf->type)) {
4950 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
4951 rc = LY_EINVAL;
4952 }
4953 }
4954 }
4955 }
4956 set_scnode_clear_ctx(set);
4957 return rc;
4958 }
4959
4960 set_fill_number(set, 0);
4961 if (args[0]->type == LYXP_SET_EMPTY) {
4962 return LY_SUCCESS;
4963 }
4964
4965 if (args[0]->type != LYXP_SET_NODE_SET) {
4966 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4967 return LY_EVALID;
4968 }
4969
Michal Vasko5c4e5892019-11-14 12:31:38 +01004970 set_init(&set_item, set);
4971
Michal Vasko03ff5a72019-09-11 13:49:33 +02004972 set_item.type = LYXP_SET_NODE_SET;
4973 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4974 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4975
4976 set_item.used = 1;
4977 set_item.size = 1;
4978
4979 for (i = 0; i < args[0]->used; ++i) {
4980 set_item.val.nodes[0] = args[0]->val.nodes[i];
4981
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004982 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004983 LY_CHECK_RET(rc);
4984 num = cast_string_to_number(str);
4985 free(str);
4986 set->val.num += num;
4987 }
4988
4989 free(set_item.val.nodes);
4990
4991 return LY_SUCCESS;
4992}
4993
4994/**
4995 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4996 * with the text content of the nodes in the context.
4997 *
4998 * @param[in] args Array of arguments.
4999 * @param[in] arg_count Count of elements in @p args.
5000 * @param[in,out] set Context and result set at the same time.
5001 * @param[in] options XPath options.
5002 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
5003 */
5004static LY_ERR
5005xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5006{
5007 uint32_t i;
5008
5009 if (options & LYXP_SCNODE_ALL) {
5010 set_scnode_clear_ctx(set);
5011 return LY_SUCCESS;
5012 }
5013
5014 if (set->type == LYXP_SET_EMPTY) {
5015 return LY_SUCCESS;
5016 }
5017 if (set->type != LYXP_SET_NODE_SET) {
5018 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
5019 return LY_EVALID;
5020 }
5021
5022 for (i = 0; i < set->used;) {
5023 switch (set->val.nodes[i].type) {
5024 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02005025 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
5026 set->val.nodes[i].type = LYXP_NODE_TEXT;
5027 ++i;
5028 break;
5029 }
5030 /* fall through */
5031 case LYXP_NODE_ROOT:
5032 case LYXP_NODE_ROOT_CONFIG:
5033 case LYXP_NODE_TEXT:
5034 case LYXP_NODE_ATTR:
5035 set_remove_node(set, i);
5036 break;
5037 }
5038 }
5039
5040 return LY_SUCCESS;
5041}
5042
5043/**
5044 * @brief Execute the XPath translate(string, string, string) function.
5045 * Returns LYXP_SET_STRING with the first argument with the characters
5046 * from the second argument replaced by those on the corresponding
5047 * positions in the third argument.
5048 *
5049 * @param[in] args Array of arguments.
5050 * @param[in] arg_count Count of elements in @p args.
5051 * @param[in,out] set Context and result set at the same time.
5052 * @param[in] options XPath options.
5053 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
5054 */
5055static LY_ERR
5056xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5057{
5058 uint16_t i, j, new_used;
5059 char *new;
5060 int found, have_removed;
5061 struct lysc_node_leaf *sleaf;
5062 LY_ERR rc = LY_SUCCESS;
5063
5064 if (options & LYXP_SCNODE_ALL) {
5065 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5066 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5067 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
5068 rc = LY_EINVAL;
5069 } else if (!warn_is_string_type(sleaf->type)) {
5070 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
5071 rc = LY_EINVAL;
5072 }
5073 }
5074
5075 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5076 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5077 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
5078 rc = LY_EINVAL;
5079 } else if (!warn_is_string_type(sleaf->type)) {
5080 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
5081 rc = LY_EINVAL;
5082 }
5083 }
5084
5085 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5086 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5087 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
5088 rc = LY_EINVAL;
5089 } else if (!warn_is_string_type(sleaf->type)) {
5090 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
5091 rc = LY_EINVAL;
5092 }
5093 }
5094 set_scnode_clear_ctx(set);
5095 return rc;
5096 }
5097
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005098 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005099 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005100 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005101 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005102 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005103 LY_CHECK_RET(rc);
5104
5105 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5106 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5107 new_used = 0;
5108
5109 have_removed = 0;
5110 for (i = 0; args[0]->val.str[i]; ++i) {
5111 found = 0;
5112
5113 for (j = 0; args[1]->val.str[j]; ++j) {
5114 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5115 /* removing this char */
5116 if (j >= strlen(args[2]->val.str)) {
5117 have_removed = 1;
5118 found = 1;
5119 break;
5120 }
5121 /* replacing this char */
5122 new[new_used] = args[2]->val.str[j];
5123 ++new_used;
5124 found = 1;
5125 break;
5126 }
5127 }
5128
5129 /* copying this char */
5130 if (!found) {
5131 new[new_used] = args[0]->val.str[i];
5132 ++new_used;
5133 }
5134 }
5135
5136 if (have_removed) {
5137 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5138 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5139 }
5140 new[new_used] = '\0';
5141
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005142 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005143 set->type = LYXP_SET_STRING;
5144 set->val.str = new;
5145
5146 return LY_SUCCESS;
5147}
5148
5149/**
5150 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5151 * with true value.
5152 *
5153 * @param[in] args Array of arguments.
5154 * @param[in] arg_count Count of elements in @p args.
5155 * @param[in,out] set Context and result set at the same time.
5156 * @param[in] options XPath options.
5157 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
5158 */
5159static LY_ERR
5160xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5161{
5162 if (options & LYXP_SCNODE_ALL) {
5163 set_scnode_clear_ctx(set);
5164 return LY_SUCCESS;
5165 }
5166
5167 set_fill_boolean(set, 1);
5168 return LY_SUCCESS;
5169}
5170
5171/*
5172 * moveto functions
5173 *
5174 * They and only they actually change the context (set).
5175 */
5176
5177/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005178 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005179 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005180 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5181 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5182 * @param[in] set Set with XPath context.
5183 * @param[out] moveto_mod Expected module of a matching node.
5184 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005185 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005186static LY_ERR
5187moveto_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 +02005188{
Michal Vasko6346ece2019-09-24 13:12:53 +02005189 const struct lys_module *mod;
5190 const char *ptr;
5191 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005192 char *str;
5193
Michal Vasko6346ece2019-09-24 13:12:53 +02005194 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5195 /* specific module */
5196 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005197
Michal Vasko6346ece2019-09-24 13:12:53 +02005198 switch (set->format) {
5199 case LYD_UNKNOWN:
5200 /* schema, search all local module imports */
5201 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5202 break;
5203 case LYD_JSON:
5204 /* JSON data, search in context */
5205 str = strndup(*qname, pref_len);
5206 mod = ly_ctx_get_module(set->ctx, str, NULL);
5207 free(str);
5208 break;
5209 default:
5210 LOGINT_RET(set->ctx);
5211 }
5212
5213 if (!mod->implemented) {
5214 /* non-implemented module is not valid */
5215 mod = NULL;
5216 }
5217 if (!mod) {
5218 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5219 return LY_EVALID;
5220 }
5221 *qname += pref_len + 1;
5222 *qname_len -= pref_len + 1;
5223 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5224 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005225 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005226 } else {
5227 /* local module */
5228 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005229 }
5230
Michal Vasko6346ece2019-09-24 13:12:53 +02005231 *moveto_mod = mod;
5232 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005233}
5234
5235/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005236 * @brief Move context @p set to the root. Handles absolute path.
5237 * Result is LYXP_SET_NODE_SET.
5238 *
5239 * @param[in,out] set Set to use.
5240 * @param[in] options Xpath options.
5241 */
5242static void
5243moveto_root(struct lyxp_set *set, int options)
5244{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005245 if (!set) {
5246 return;
5247 }
5248
5249 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005250 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005251 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005252 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005253 lyxp_set_cast(set, LYXP_SET_EMPTY);
5254 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005255 }
5256}
5257
5258/**
5259 * @brief Check @p node as a part of NameTest processing.
5260 *
5261 * @param[in] node Node to check.
5262 * @param[in] root_type XPath root node type.
5263 * @param[in] node_name Node name to move to. Must be in the dictionary!
5264 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005265 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5266 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005267 */
5268static LY_ERR
5269moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5270 const struct lys_module *moveto_mod)
5271{
5272 /* module check */
5273 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005274 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005275 }
5276
Michal Vasko5c4e5892019-11-14 12:31:38 +01005277 /* context check */
5278 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005279 return LY_EINVAL;
5280 }
5281
5282 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005283 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005284 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005285 }
5286
5287 /* TODO when check */
5288 /*if (!LYD_WHEN_DONE(node->when_status)) {
5289 return LY_EINCOMPLETE;
5290 }*/
5291
5292 /* match */
5293 return LY_SUCCESS;
5294}
5295
5296/**
5297 * @brief Check @p node as a part of schema NameTest processing.
5298 *
5299 * @param[in] node Schema node to check.
5300 * @param[in] root_type XPath root node type.
5301 * @param[in] node_name Node name to move to. Must be in the dictionary!
5302 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005303 * @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 +02005304 */
5305static LY_ERR
5306moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005307 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005308{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005309 /* module check */
5310 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005311 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005312 }
5313
5314 /* context check */
5315 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5316 return LY_EINVAL;
5317 }
5318
5319 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005320 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005321 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005322 }
5323
5324 /* match */
5325 return LY_SUCCESS;
5326}
5327
5328/**
5329 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5330 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5331 *
5332 * @param[in,out] set Set to use.
5333 * @param[in] qname Qualified node name to move to.
5334 * @param[in] qname_len Length of @p qname.
5335 * @param[in] options XPath options.
5336 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5337 */
5338static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005339moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005340{
5341 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005342 int replaced;
5343 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005344 const struct lys_module *moveto_mod;
5345 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005346 LY_ERR rc;
5347
5348 if (!set || (set->type == LYXP_SET_EMPTY)) {
5349 return LY_SUCCESS;
5350 }
5351
5352 if (set->type != LYXP_SET_NODE_SET) {
5353 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5354 return LY_EVALID;
5355 }
5356
Michal Vasko6346ece2019-09-24 13:12:53 +02005357 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5358 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005359
5360 /* name */
5361 name_dict = lydict_insert(set->ctx, qname, qname_len);
5362
5363 for (i = 0; i < set->used; ) {
5364 replaced = 0;
5365
5366 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 +01005367 assert(!set->val.nodes[i].node);
5368 /* search in all the trees */
5369 LY_ARRAY_FOR(set->trees, i) {
5370 for (sub = set->trees[i]; sub; sub = sub->next) {
5371 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005372 if (rc == LY_SUCCESS) {
5373 /* pos filled later */
5374 if (!replaced) {
5375 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5376 replaced = 1;
5377 } else {
5378 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5379 }
5380 ++i;
5381 } else if (rc == LY_EINCOMPLETE) {
5382 lydict_remove(set->ctx, name_dict);
5383 return rc;
5384 }
5385 }
5386 }
5387
Michal Vasko5c4e5892019-11-14 12:31:38 +01005388 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5389 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005390
5391 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005392 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005393 if (rc == LY_SUCCESS) {
5394 if (!replaced) {
5395 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5396 replaced = 1;
5397 } else {
5398 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5399 }
5400 ++i;
5401 } else if (rc == LY_EINCOMPLETE) {
5402 lydict_remove(set->ctx, name_dict);
5403 return rc;
5404 }
5405 }
5406 }
5407
5408 if (!replaced) {
5409 /* no match */
5410 set_remove_node(set, i);
5411 }
5412 }
5413 lydict_remove(set->ctx, name_dict);
5414
5415 return LY_SUCCESS;
5416}
5417
5418/**
5419 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5420 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5421 *
5422 * @param[in,out] set Set to use.
5423 * @param[in] qname Qualified node name to move to.
5424 * @param[in] qname_len Length of @p qname.
5425 * @param[in] options XPath options.
5426 * @return LY_ERR
5427 */
5428static LY_ERR
5429moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5430{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005431 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005432 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005433 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005434 const struct lys_module *moveto_mod;
5435 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005436 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005437
5438 if (!set || (set->type == LYXP_SET_EMPTY)) {
5439 return LY_SUCCESS;
5440 }
5441
5442 if (set->type != LYXP_SET_SCNODE_SET) {
5443 LOGVAL(set->ctx, LY_VLOG_LYS, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5444 return LY_EVALID;
5445 }
5446
Michal Vasko6346ece2019-09-24 13:12:53 +02005447 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5448 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005449
5450 /* name */
5451 name_dict = lydict_insert(set->ctx, qname, qname_len);
5452
Michal Vaskocafad9d2019-11-07 15:20:03 +01005453 /* getnext opts */
5454 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5455 if (options & LYXP_SCNODE_OUTPUT) {
5456 getnext_opts |= LYS_GETNEXT_OUTPUT;
5457 }
5458
Michal Vasko03ff5a72019-09-11 13:49:33 +02005459 orig_used = set->used;
5460 for (i = 0; i < orig_used; ++i) {
5461 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005462 if (set->val.scnodes[i].in_ctx != -2) {
5463 continue;
5464 }
5465
5466 /* remember context node */
5467 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005468 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005469
5470 start_parent = set->val.scnodes[i].scnode;
5471
5472 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5473 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5474 * so use it directly (root node itself is useless in this case) */
5475 mod_idx = 0;
5476 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5477 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005478 while ((sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
5479 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005480 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005481 /* we need to prevent these nodes from being considered in this moveto */
5482 if ((idx < orig_used) && (idx > i)) {
5483 set->val.scnodes[idx].in_ctx = 2;
5484 temp_ctx = 1;
5485 }
5486 }
5487 }
5488
5489 if (!mod_idx) {
5490 /* moveto_mod was specified, we are not going through the whole context */
5491 break;
5492 }
5493 /* next iteration */
5494 moveto_mod = NULL;
5495 }
5496
5497 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5498 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5499 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005500 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5501 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005502 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005503 if ((idx < orig_used) && (idx > i)) {
5504 set->val.scnodes[idx].in_ctx = 2;
5505 temp_ctx = 1;
5506 }
5507 }
5508 }
5509 }
5510 }
5511 lydict_remove(set->ctx, name_dict);
5512
5513 /* correct temporary in_ctx values */
5514 if (temp_ctx) {
5515 for (i = 0; i < orig_used; ++i) {
5516 if (set->val.scnodes[i].in_ctx == 2) {
5517 set->val.scnodes[i].in_ctx = 1;
5518 }
5519 }
5520 }
5521
5522 return LY_SUCCESS;
5523}
5524
5525/**
5526 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5527 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5528 * Context position aware.
5529 *
5530 * @param[in] set Set to use.
5531 * @param[in] qname Qualified node name to move to.
5532 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005533 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5534 */
5535static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005536moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005537{
5538 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005539 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005540 const struct lyd_node *next, *elem, *start;
5541 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005542 struct lyxp_set ret_set;
5543 LY_ERR rc;
5544
5545 if (!set || (set->type == LYXP_SET_EMPTY)) {
5546 return LY_SUCCESS;
5547 }
5548
5549 if (set->type != LYXP_SET_NODE_SET) {
5550 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5551 return LY_EVALID;
5552 }
5553
Michal Vasko6346ece2019-09-24 13:12:53 +02005554 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5555 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005556
5557 /* replace the original nodes (and throws away all text and attr nodes, root is replaced by a child) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005558 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005559 LY_CHECK_RET(rc);
5560
Michal Vasko6346ece2019-09-24 13:12:53 +02005561 /* name */
5562 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005563
Michal Vasko6346ece2019-09-24 13:12:53 +02005564 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005565 set_init(&ret_set, set);
5566 for (i = 0; i < set->used; ++i) {
5567
5568 /* TREE DFS */
5569 start = set->val.nodes[i].node;
5570 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005571 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005572 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005573 /* add matching node into result set */
5574 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5575 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5576 /* the node is a duplicate, we'll process it later in the set */
5577 goto skip_children;
5578 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005579 } else if (rc == LY_EINCOMPLETE) {
5580 lydict_remove(set->ctx, name_dict);
5581 return rc;
5582 } else if (rc == LY_EINVAL) {
5583 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005584 }
5585
5586 /* TREE DFS NEXT ELEM */
5587 /* select element for the next run - children first */
5588 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5589 next = NULL;
5590 } else {
5591 next = lyd_node_children(elem);
5592 }
5593 if (!next) {
5594skip_children:
5595 /* no children, so try siblings, but only if it's not the start,
5596 * that is considered to be the root and it's siblings are not traversed */
5597 if (elem != start) {
5598 next = elem->next;
5599 } else {
5600 break;
5601 }
5602 }
5603 while (!next) {
5604 /* no siblings, go back through the parents */
5605 if ((struct lyd_node *)elem->parent == start) {
5606 /* we are done, no next element to process */
5607 break;
5608 }
5609 /* parent is already processed, go to its sibling */
5610 elem = (struct lyd_node *)elem->parent;
5611 next = elem->next;
5612 }
5613 }
5614 }
5615
5616 /* make the temporary set the current one */
5617 ret_set.ctx_pos = set->ctx_pos;
5618 ret_set.ctx_size = set->ctx_size;
5619 set_free_content(set);
5620 memcpy(set, &ret_set, sizeof *set);
5621
Michal Vasko6346ece2019-09-24 13:12:53 +02005622 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005623 return LY_SUCCESS;
5624}
5625
5626/**
5627 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5628 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5629 *
5630 * @param[in] set Set to use.
5631 * @param[in] qname Qualified node name to move to.
5632 * @param[in] qname_len Length of @p qname.
5633 * @param[in] options XPath options.
5634 * @return LY_ERR
5635 */
5636static LY_ERR
5637moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5638{
Michal Vasko6346ece2019-09-24 13:12:53 +02005639 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005640 const struct lysc_node *next, *elem, *start;
5641 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005642 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005643
5644 if (!set || (set->type == LYXP_SET_EMPTY)) {
5645 return LY_SUCCESS;
5646 }
5647
5648 if (set->type != LYXP_SET_SCNODE_SET) {
5649 LOGVAL(set->ctx, LY_VLOG_LYS, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5650 return LY_EVALID;
5651 }
5652
Michal Vasko6346ece2019-09-24 13:12:53 +02005653 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5654 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005655
5656 orig_used = set->used;
5657 for (i = 0; i < orig_used; ++i) {
5658 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005659 if (set->val.scnodes[i].in_ctx != -2) {
5660 continue;
5661 }
5662
5663 /* remember context node */
5664 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005665 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005666
5667 /* TREE DFS */
5668 start = set->val.scnodes[i].scnode;
5669 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005670 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5671 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005672 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005673 }
5674
Michal Vaskocafad9d2019-11-07 15:20:03 +01005675 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005676 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005677 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005678 set->val.scnodes[idx].in_ctx = 1;
5679 if (idx > i) {
5680 /* we will process it later in the set */
5681 goto skip_children;
5682 }
5683 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005684 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005685 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005686 } else if (rc == LY_EINVAL) {
5687 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005688 }
5689
5690next_iter:
5691 /* TREE DFS NEXT ELEM */
5692 /* select element for the next run - children first */
5693 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5694 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5695 next = NULL;
5696 }
5697 if (!next) {
5698skip_children:
5699 /* no children, so try siblings, but only if it's not the start,
5700 * that is considered to be the root and it's siblings are not traversed */
5701 if (elem != start) {
5702 next = elem->next;
5703 } else {
5704 break;
5705 }
5706 }
5707 while (!next) {
5708 /* no siblings, go back through the parents */
5709 if (elem->parent == start) {
5710 /* we are done, no next element to process */
5711 break;
5712 }
5713 /* parent is already processed, go to its sibling */
5714 elem = elem->parent;
5715 next = elem->next;
5716 }
5717 }
5718 }
5719
5720 return LY_SUCCESS;
5721}
5722
5723/**
5724 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5725 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5726 * Indirectly context position aware.
5727 *
5728 * @param[in,out] set Set to use.
5729 * @param[in] qname Qualified node name to move to.
5730 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005731 * @return LY_ERR
5732 */
5733static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005734moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005735{
5736 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005737 int replaced, all = 0;
5738 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005739 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005740 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005741
5742 if (!set || (set->type == LYXP_SET_EMPTY)) {
5743 return LY_SUCCESS;
5744 }
5745
5746 if (set->type != LYXP_SET_NODE_SET) {
5747 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5748 return LY_EVALID;
5749 }
5750
Michal Vasko6346ece2019-09-24 13:12:53 +02005751 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5752 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005753
5754 if ((qname_len == 1) && (qname[0] == '*')) {
5755 all = 1;
5756 }
5757
5758 for (i = 0; i < set->used; ) {
5759 replaced = 0;
5760
5761 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5762 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005763 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005764 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5765
5766 /* check "namespace" */
5767 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5768 continue;
5769 }
5770
5771 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5772 /* match */
5773 if (!replaced) {
5774 set->val.attrs[i].attr = sub;
5775 set->val.attrs[i].type = LYXP_NODE_ATTR;
5776 /* pos does not change */
5777 replaced = 1;
5778 } else {
5779 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_ATTR, i + 1);
5780 }
5781 ++i;
5782 }
5783 }
5784 }
5785
5786 if (!replaced) {
5787 /* no match */
5788 set_remove_node(set, i);
5789 }
5790 }
5791
5792 return LY_SUCCESS;
5793}
5794
5795/**
5796 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
5797 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5798 *
5799 * @param[in,out] set1 Set to use for the result.
5800 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005801 * @return LY_ERR
5802 */
5803static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005804moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005805{
5806 LY_ERR rc;
5807
5808 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5809 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5810 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5811 return LY_EVALID;
5812 }
5813
5814 /* set2 is empty or both set1 and set2 */
5815 if (set2->type == LYXP_SET_EMPTY) {
5816 return LY_SUCCESS;
5817 }
5818
5819 if (set1->type == LYXP_SET_EMPTY) {
5820 memcpy(set1, set2, sizeof *set1);
5821 /* dynamic memory belongs to set1 now, do not free */
5822 set2->type = LYXP_SET_EMPTY;
5823 return LY_SUCCESS;
5824 }
5825
5826 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005827 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005828
5829 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005830 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005831 LY_CHECK_RET(rc);
5832
5833 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005834 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005835
5836 return LY_SUCCESS;
5837}
5838
5839/**
5840 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5841 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5842 * Context position aware.
5843 *
5844 * @param[in,out] set Set to use.
5845 * @param[in] qname Qualified node name to move to.
5846 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005847 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5848 */
5849static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005850moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005851{
5852 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005853 int replaced, all = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005854 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005855 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005856 struct lyxp_set *set_all_desc = NULL;
5857 LY_ERR rc;
5858
5859 if (!set || (set->type == LYXP_SET_EMPTY)) {
5860 return LY_SUCCESS;
5861 }
5862
5863 if (set->type != LYXP_SET_NODE_SET) {
5864 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5865 return LY_EVALID;
5866 }
5867
Michal Vasko6346ece2019-09-24 13:12:53 +02005868 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5869 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005870
5871 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5872 * but it likely won't be used much, so it's a waste of time */
5873 /* copy the context */
5874 set_all_desc = set_copy(set);
5875 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005876 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005877 if (rc != LY_SUCCESS) {
5878 lyxp_set_free(set_all_desc);
5879 return rc;
5880 }
5881 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005882 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005883 if (rc != LY_SUCCESS) {
5884 lyxp_set_free(set_all_desc);
5885 return rc;
5886 }
5887 lyxp_set_free(set_all_desc);
5888
5889 if ((qname_len == 1) && (qname[0] == '*')) {
5890 all = 1;
5891 }
5892
5893 for (i = 0; i < set->used; ) {
5894 replaced = 0;
5895
5896 /* only attributes of an elem can be in the result, skip all the rest,
5897 * we have all attributes qualified in lyd tree */
5898 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5899 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5900 /* check "namespace" */
5901 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5902 continue;
5903 }
5904
5905 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5906 /* match */
5907 if (!replaced) {
5908 set->val.attrs[i].attr = sub;
5909 set->val.attrs[i].type = LYXP_NODE_ATTR;
5910 /* pos does not change */
5911 replaced = 1;
5912 } else {
5913 set_insert_node(set, (struct lyd_node *)sub, set->val.attrs[i].pos, LYXP_NODE_ATTR, i + 1);
5914 }
5915 ++i;
5916 }
5917 }
5918 }
5919
5920 if (!replaced) {
5921 /* no match */
5922 set_remove_node(set, i);
5923 }
5924 }
5925
5926 return LY_SUCCESS;
5927}
5928
5929/**
5930 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5931 * (or LYXP_SET_EMPTY). Context position aware.
5932 *
5933 * @param[in] parent Current parent.
5934 * @param[in] parent_pos Position of @p parent.
5935 * @param[in] parent_type Node type of @p parent.
5936 * @param[in,out] to_set Set to use.
5937 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005938 * @param[in] options XPath options.
5939 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5940 */
5941static LY_ERR
5942moveto_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 +01005943 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005944{
5945 const struct lyd_node *sub;
5946 LY_ERR rc;
5947
5948 switch (parent_type) {
5949 case LYXP_NODE_ROOT:
5950 case LYXP_NODE_ROOT_CONFIG:
5951 /* add the same node but as an element */
5952 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5953 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5954
5955 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005956 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005957 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005958 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005959 LY_CHECK_RET(rc);
5960 }
5961 }
5962 break;
5963 case LYXP_NODE_ELEM:
5964 /* add all the children ... */
5965 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5966 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5967 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005968 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005969 continue;
5970 }
5971
5972 /* TODO when check */
5973 /*if (!LYD_WHEN_DONE(sub->when_status)) {
5974 return LY_EINCOMPLETE;
5975 }*/
5976
5977 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5978 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5979
Michal Vasko5c4e5892019-11-14 12:31:38 +01005980 /* skip anydata/anyxml nodes */
5981 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005982 continue;
5983 }
5984
5985 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005986 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005987 LY_CHECK_RET(rc);
5988 }
5989 }
5990
5991 /* ... or add their text node, ... */
5992 } else {
5993 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5994 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5995 }
5996 }
5997 break;
5998 default:
5999 LOGINT_RET(parent->schema->module->ctx);
6000 }
6001
6002 return LY_SUCCESS;
6003}
6004
6005/**
6006 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
6007 * (or LYXP_SET_EMPTY). Context position aware.
6008 *
6009 * @param[in,out] set Set to use.
6010 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6011 * @param[in] options XPath options.
6012 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6013 */
6014static LY_ERR
6015moveto_self(struct lyxp_set *set, int all_desc, int options)
6016{
6017 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006018 struct lyxp_set ret_set;
6019 LY_ERR rc;
6020
6021 if (!set || (set->type == LYXP_SET_EMPTY)) {
6022 return LY_SUCCESS;
6023 }
6024
6025 if (set->type != LYXP_SET_NODE_SET) {
6026 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6027 return LY_EVALID;
6028 }
6029
6030 /* nothing to do */
6031 if (!all_desc) {
6032 return LY_SUCCESS;
6033 }
6034
Michal Vasko03ff5a72019-09-11 13:49:33 +02006035 /* add all the children, they get added recursively */
6036 set_init(&ret_set, set);
6037 for (i = 0; i < set->used; ++i) {
6038 /* copy the current node to tmp */
6039 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6040
6041 /* do not touch attributes and text nodes */
6042 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_ATTR)) {
6043 continue;
6044 }
6045
Michal Vasko5c4e5892019-11-14 12:31:38 +01006046 /* skip anydata/anyxml nodes */
6047 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006048 continue;
6049 }
6050
6051 /* add all the children */
6052 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 +01006053 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006054 if (rc != LY_SUCCESS) {
6055 set_free_content(&ret_set);
6056 return rc;
6057 }
6058 }
6059
6060 /* use the temporary set as the current one */
6061 ret_set.ctx_pos = set->ctx_pos;
6062 ret_set.ctx_size = set->ctx_size;
6063 set_free_content(set);
6064 memcpy(set, &ret_set, sizeof *set);
6065
6066 return LY_SUCCESS;
6067}
6068
6069/**
6070 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6071 * (or LYXP_SET_EMPTY).
6072 *
6073 * @param[in,out] set Set to use.
6074 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6075 * @param[in] options XPath options.
6076 * @return LY_ERR
6077 */
6078static LY_ERR
6079moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6080{
6081 const struct lysc_node *sub;
6082 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006083
6084 if (!set || (set->type == LYXP_SET_EMPTY)) {
6085 return LY_SUCCESS;
6086 }
6087
6088 if (set->type != LYXP_SET_SCNODE_SET) {
6089 LOGVAL(set->ctx, LY_VLOG_LYS, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6090 return LY_EVALID;
6091 }
6092
6093 /* nothing to do */
6094 if (!all_desc) {
6095 return LY_SUCCESS;
6096 }
6097
Michal Vasko03ff5a72019-09-11 13:49:33 +02006098 /* add all the children, they get added recursively */
6099 for (i = 0; i < set->used; ++i) {
6100 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006101 if (set->val.scnodes[i].in_ctx != -2) {
6102 continue;
6103 }
6104
6105 /* remember context node (it was traversed again so it changes to a normal node) */
6106 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006107 }
6108
6109 /* add all the children */
6110 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6111 sub = NULL;
6112 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6113 /* RPC input/output check */
6114 if (options & LYXP_SCNODE_OUTPUT) {
6115 if (sub->parent->nodetype == LYS_INPUT) {
6116 continue;
6117 }
6118 } else {
6119 if (sub->parent->nodetype == LYS_OUTPUT) {
6120 continue;
6121 }
6122 }
6123
6124 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006125 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006126 continue;
6127 }
6128
Michal Vaskoecd62de2019-11-13 12:35:11 +01006129 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006130 /* throw away the insert index, we want to consider that node again, recursively */
6131 }
6132 }
6133 }
6134
6135 return LY_SUCCESS;
6136}
6137
6138/**
6139 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6140 * (or LYXP_SET_EMPTY). Context position aware.
6141 *
6142 * @param[in] set Set to use.
6143 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6144 * @param[in] options XPath options.
6145 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6146 */
6147static LY_ERR
6148moveto_parent(struct lyxp_set *set, int all_desc, int options)
6149{
6150 LY_ERR rc;
6151 uint32_t i;
6152 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006153 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006154
6155 if (!set || (set->type == LYXP_SET_EMPTY)) {
6156 return LY_SUCCESS;
6157 }
6158
6159 if (set->type != LYXP_SET_NODE_SET) {
6160 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6161 return LY_EVALID;
6162 }
6163
6164 if (all_desc) {
6165 /* <path>//.. == <path>//./.. */
6166 rc = moveto_self(set, 1, options);
6167 LY_CHECK_RET(rc);
6168 }
6169
Michal Vasko57eab132019-09-24 11:46:26 +02006170 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006171 node = set->val.nodes[i].node;
6172
6173 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6174 new_node = (struct lyd_node *)node->parent;
6175 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6176 new_node = node;
6177 } else if (set->val.nodes[i].type == LYXP_NODE_ATTR) {
6178 new_node = set->val.attrs[i].attr->parent;
6179 if (!new_node) {
6180 LOGINT_RET(set->ctx);
6181 }
6182 } else {
6183 /* root does not have a parent */
Michal Vasko57eab132019-09-24 11:46:26 +02006184 set_remove_node_null(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006185 continue;
6186 }
6187
6188 /* TODO when check */
6189 /*if (new_node && !LYD_WHEN_DONE(new_node->when_status)) {
6190 return LY_EINCOMPLETE;
6191 }*/
6192
6193 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006194 if (!new_node) {
6195 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006196
6197 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6198 } else {
6199 new_type = LYXP_NODE_ELEM;
6200 }
6201
Michal Vasko03ff5a72019-09-11 13:49:33 +02006202 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02006203 set_remove_node_null(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006204 } else {
6205 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006206 }
6207 }
6208
Michal Vasko57eab132019-09-24 11:46:26 +02006209 set_remove_nodes_null(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006210 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006211
6212 return LY_SUCCESS;
6213}
6214
6215/**
6216 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6217 * (or LYXP_SET_EMPTY).
6218 *
6219 * @param[in] set Set to use.
6220 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6221 * @param[in] options XPath options.
6222 * @return LY_ERR
6223 */
6224static LY_ERR
6225moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6226{
6227 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006228 const struct lysc_node *node, *new_node;
6229 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006230 LY_ERR rc;
6231
6232 if (!set || (set->type == LYXP_SET_EMPTY)) {
6233 return LY_SUCCESS;
6234 }
6235
6236 if (set->type != LYXP_SET_SCNODE_SET) {
6237 LOGVAL(set->ctx, LY_VLOG_LYS, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6238 return LY_EVALID;
6239 }
6240
6241 if (all_desc) {
6242 /* <path>//.. == <path>//./.. */
6243 rc = moveto_scnode_self(set, 1, options);
6244 LY_CHECK_RET(rc);
6245 }
6246
Michal Vasko03ff5a72019-09-11 13:49:33 +02006247 orig_used = set->used;
6248 for (i = 0; i < orig_used; ++i) {
6249 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006250 if (set->val.scnodes[i].in_ctx != -2) {
6251 continue;
6252 }
6253
6254 /* remember context node */
6255 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006256 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006257
6258 node = set->val.scnodes[i].scnode;
6259
6260 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6261 for (new_node = node->parent;
6262 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6263 new_node = new_node->parent);
6264 } else {
6265 /* root does not have a parent */
6266 continue;
6267 }
6268
Michal Vasko03ff5a72019-09-11 13:49:33 +02006269 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006270 if (!new_node) {
6271 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006272
6273 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6274 } else {
6275 new_type = LYXP_NODE_ELEM;
6276 }
6277
Michal Vaskoecd62de2019-11-13 12:35:11 +01006278 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006279 if ((idx < orig_used) && (idx > i)) {
6280 set->val.scnodes[idx].in_ctx = 2;
6281 temp_ctx = 1;
6282 }
6283 }
6284
6285 if (temp_ctx) {
6286 for (i = 0; i < orig_used; ++i) {
6287 if (set->val.scnodes[i].in_ctx == 2) {
6288 set->val.scnodes[i].in_ctx = 1;
6289 }
6290 }
6291 }
6292
6293 return LY_SUCCESS;
6294}
6295
6296/**
6297 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6298 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6299 *
6300 * @param[in,out] set1 Set to use for the result.
6301 * @param[in] set2 Set acting as the second operand for @p op.
6302 * @param[in] op Comparison operator to process.
6303 * @param[in] options XPath options.
6304 * @return LY_ERR
6305 */
6306static LY_ERR
6307moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6308{
6309 /*
6310 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6311 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6312 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6313 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6314 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6315 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6316 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6317 *
6318 * '=' or '!='
6319 * BOOLEAN + BOOLEAN
6320 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6321 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6322 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6323 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6324 * NUMBER + NUMBER
6325 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6326 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6327 * STRING + STRING
6328 *
6329 * '<=', '<', '>=', '>'
6330 * NUMBER + NUMBER
6331 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6332 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6333 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6334 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6335 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6336 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6337 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6338 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6339 */
6340 struct lyxp_set iter1, iter2;
6341 int result;
6342 int64_t i;
6343 LY_ERR rc;
6344
6345 iter1.type = LYXP_SET_EMPTY;
6346
6347 /* empty node-sets are always false */
6348 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6349 set_fill_boolean(set1, 0);
6350 return LY_SUCCESS;
6351 }
6352
6353 /* iterative evaluation with node-sets */
6354 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6355 if (set1->type == LYXP_SET_NODE_SET) {
6356 for (i = 0; i < set1->used; ++i) {
6357 switch (set2->type) {
6358 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006359 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006360 break;
6361 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006362 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006363 break;
6364 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006365 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006366 break;
6367 }
6368 LY_CHECK_RET(rc);
6369
6370 rc = moveto_op_comp(&iter1, set2, op, options);
6371 if (rc != LY_SUCCESS) {
6372 set_free_content(&iter1);
6373 return rc;
6374 }
6375
6376 /* lazy evaluation until true */
6377 if (iter1.val.bool) {
6378 set_fill_boolean(set1, 1);
6379 return LY_SUCCESS;
6380 }
6381 }
6382 } else {
6383 for (i = 0; i < set2->used; ++i) {
6384 switch (set1->type) {
6385 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006386 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006387 break;
6388 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006389 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006390 break;
6391 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006392 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006393 break;
6394 }
6395 LY_CHECK_RET(rc);
6396
6397 set_fill_set(&iter1, set1);
6398
6399 rc = moveto_op_comp(&iter1, &iter2, op, options);
6400 if (rc != LY_SUCCESS) {
6401 set_free_content(&iter1);
6402 set_free_content(&iter2);
6403 return rc;
6404 }
6405 set_free_content(&iter2);
6406
6407 /* lazy evaluation until true */
6408 if (iter1.val.bool) {
6409 set_fill_boolean(set1, 1);
6410 return LY_SUCCESS;
6411 }
6412 }
6413 }
6414
6415 /* false for all nodes */
6416 set_fill_boolean(set1, 0);
6417 return LY_SUCCESS;
6418 }
6419
6420 /* first convert properly */
6421 if ((op[0] == '=') || (op[0] == '!')) {
6422 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006423 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6424 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006425 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006426 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006427 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006428 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006429 LY_CHECK_RET(rc);
6430 } /* else we have 2 strings */
6431 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006432 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006433 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006434 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006435 LY_CHECK_RET(rc);
6436 }
6437
6438 assert(set1->type == set2->type);
6439
6440 /* compute result */
6441 if (op[0] == '=') {
6442 if (set1->type == LYXP_SET_BOOLEAN) {
6443 result = (set1->val.bool == set2->val.bool);
6444 } else if (set1->type == LYXP_SET_NUMBER) {
6445 result = (set1->val.num == set2->val.num);
6446 } else {
6447 assert(set1->type == LYXP_SET_STRING);
6448 result = strcmp(set1->val.str, set2->val.str);
6449 }
6450 } else if (op[0] == '!') {
6451 if (set1->type == LYXP_SET_BOOLEAN) {
6452 result = (set1->val.bool != set2->val.bool);
6453 } else if (set1->type == LYXP_SET_NUMBER) {
6454 result = (set1->val.num != set2->val.num);
6455 } else {
6456 assert(set1->type == LYXP_SET_STRING);
6457 result = strcmp(set1->val.str, set2->val.str);
6458 }
6459 } else {
6460 assert(set1->type == LYXP_SET_NUMBER);
6461 if (op[0] == '<') {
6462 if (op[1] == '=') {
6463 result = (set1->val.num <= set2->val.num);
6464 } else {
6465 result = (set1->val.num < set2->val.num);
6466 }
6467 } else {
6468 if (op[1] == '=') {
6469 result = (set1->val.num >= set2->val.num);
6470 } else {
6471 result = (set1->val.num > set2->val.num);
6472 }
6473 }
6474 }
6475
6476 /* assign result */
6477 if (result) {
6478 set_fill_boolean(set1, 1);
6479 } else {
6480 set_fill_boolean(set1, 0);
6481 }
6482
6483 return LY_SUCCESS;
6484}
6485
6486/**
6487 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6488 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6489 *
6490 * @param[in,out] set1 Set to use for the result.
6491 * @param[in] set2 Set acting as the second operand for @p op.
6492 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006493 * @return LY_ERR
6494 */
6495static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006496moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006497{
6498 LY_ERR rc;
6499
6500 /* unary '-' */
6501 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006502 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006503 LY_CHECK_RET(rc);
6504 set1->val.num *= -1;
6505 lyxp_set_free(set2);
6506 return LY_SUCCESS;
6507 }
6508
6509 assert(set1 && set2);
6510
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006511 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006512 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006513 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006514 LY_CHECK_RET(rc);
6515
6516 switch (op[0]) {
6517 /* '+' */
6518 case '+':
6519 set1->val.num += set2->val.num;
6520 break;
6521
6522 /* '-' */
6523 case '-':
6524 set1->val.num -= set2->val.num;
6525 break;
6526
6527 /* '*' */
6528 case '*':
6529 set1->val.num *= set2->val.num;
6530 break;
6531
6532 /* 'div' */
6533 case 'd':
6534 set1->val.num /= set2->val.num;
6535 break;
6536
6537 /* 'mod' */
6538 case 'm':
6539 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6540 break;
6541
6542 default:
6543 LOGINT_RET(set1->ctx);
6544 }
6545
6546 return LY_SUCCESS;
6547}
6548
6549/*
6550 * eval functions
6551 *
6552 * They execute a parsed XPath expression on some data subtree.
6553 */
6554
6555/**
6556 * @brief Evaluate Literal. Logs directly on error.
6557 *
6558 * @param[in] exp Parsed XPath expression.
6559 * @param[in] exp_idx Position in the expression @p exp.
6560 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6561 */
6562static void
6563eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6564{
6565 if (set) {
6566 if (exp->tok_len[*exp_idx] == 2) {
6567 set_fill_string(set, "", 0);
6568 } else {
6569 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6570 }
6571 }
6572 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6573 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6574 ++(*exp_idx);
6575}
6576
6577/**
6578 * @brief Evaluate NodeTest. Logs directly on error.
6579 *
6580 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6581 *
6582 * @param[in] exp Parsed XPath expression.
6583 * @param[in] exp_idx Position in the expression @p exp.
6584 * @param[in] attr_axis Whether to search attributes or standard nodes.
6585 * @param[in] all_desc Whether to search all the descendants or children only.
6586 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6587 * @param[in] options XPath options.
6588 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6589 */
6590static int
6591eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6592 struct lyxp_set *set, int options)
6593{
6594 int i;
6595 char *path;
6596 LY_ERR rc;
6597
6598 switch (exp->tokens[*exp_idx]) {
6599 case LYXP_TOKEN_NAMETEST:
6600 if (attr_axis) {
6601 if (set && (options & LYXP_SCNODE_ALL)) {
6602 set_scnode_clear_ctx(set);
6603 rc = LY_SUCCESS;
6604 } else {
6605 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006606 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006607 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006608 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006609 }
6610 }
6611 } else {
6612 if (all_desc) {
6613 if (set && (options & LYXP_SCNODE_ALL)) {
6614 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6615 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006616 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006617 }
6618 } else {
6619 if (set && (options & LYXP_SCNODE_ALL)) {
6620 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6621 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006622 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006623 }
6624 }
6625
6626 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6627 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006628 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006629 break;
6630 }
6631 }
6632 if (i == -1) {
6633 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6634 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6635 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6636 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6637 free(path);
6638 }
6639 }
6640 }
6641 LY_CHECK_RET(rc);
6642
6643 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6644 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6645 ++(*exp_idx);
6646 break;
6647
6648 case LYXP_TOKEN_NODETYPE:
6649 if (set) {
6650 assert(exp->tok_len[*exp_idx] == 4);
6651 if (set->type == LYXP_SET_SCNODE_SET) {
6652 set_scnode_clear_ctx(set);
6653 /* just for the debug message underneath */
6654 set = NULL;
6655 } else {
6656 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6657 rc = xpath_node(NULL, 0, set, options);
6658 LY_CHECK_RET(rc);
6659 } else {
6660 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6661 rc = xpath_text(NULL, 0, set, options);
6662 LY_CHECK_RET(rc);
6663 }
6664 }
6665 }
6666 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6667 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6668 ++(*exp_idx);
6669
6670 /* '(' */
6671 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6672 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6673 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6674 ++(*exp_idx);
6675
6676 /* ')' */
6677 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6678 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6679 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6680 ++(*exp_idx);
6681 break;
6682
6683 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006684 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006685 }
6686
6687 return LY_SUCCESS;
6688}
6689
6690/**
6691 * @brief Evaluate Predicate. Logs directly on error.
6692 *
6693 * [7] Predicate ::= '[' Expr ']'
6694 *
6695 * @param[in] exp Parsed XPath expression.
6696 * @param[in] exp_idx Position in the expression @p exp.
6697 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6698 * @param[in] options XPath options.
6699 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6700 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6701 */
6702static LY_ERR
6703eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6704{
6705 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006706 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006707 uint32_t orig_pos, orig_size;
6708 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006709 struct lyxp_set set2;
6710 struct lyd_node *orig_parent;
6711
6712 /* '[' */
6713 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6714 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6715 ++(*exp_idx);
6716
6717 if (!set) {
6718only_parse:
6719 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6720 LY_CHECK_RET(rc);
6721 } else if (set->type == LYXP_SET_NODE_SET) {
6722 /* 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 +01006723 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006724
6725 /* empty set, nothing to evaluate */
6726 if (!set->used) {
6727 goto only_parse;
6728 }
6729
6730 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006731 orig_pos = 0;
6732 orig_size = set->used;
6733 orig_parent = NULL;
6734 for (i = 0; i < set->used; ) {
6735 set_init(&set2, set);
6736 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6737 /* remember the node context position for position() and context size for last(),
6738 * predicates should always be evaluated with respect to the child axis (since we do
6739 * not support explicit axes) so we assign positions based on their parents */
6740 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6741 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6742 orig_pos = 1;
6743 } else {
6744 ++orig_pos;
6745 }
6746
6747 set2.ctx_pos = orig_pos;
6748 set2.ctx_size = orig_size;
6749 *exp_idx = orig_exp;
6750
6751 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6752 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006753 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006754 return rc;
6755 }
6756
6757 /* number is a position */
6758 if (set2.type == LYXP_SET_NUMBER) {
6759 if ((long long)set2.val.num == orig_pos) {
6760 set2.val.num = 1;
6761 } else {
6762 set2.val.num = 0;
6763 }
6764 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006765 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006766
6767 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006768 if (!set2.val.bool) {
6769 set_remove_node_null(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006770 }
6771 }
Michal Vasko57eab132019-09-24 11:46:26 +02006772 set_remove_nodes_null(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006773
6774 } else if (set->type == LYXP_SET_SCNODE_SET) {
6775 for (i = 0; i < set->used; ++i) {
6776 if (set->val.scnodes[i].in_ctx == 1) {
6777 /* there is a currently-valid node */
6778 break;
6779 }
6780 }
6781 /* empty set, nothing to evaluate */
6782 if (i == set->used) {
6783 goto only_parse;
6784 }
6785
6786 orig_exp = *exp_idx;
6787
Michal Vasko03ff5a72019-09-11 13:49:33 +02006788 /* set special in_ctx to all the valid snodes */
6789 pred_in_ctx = set_scnode_new_in_ctx(set);
6790
6791 /* use the valid snodes one-by-one */
6792 for (i = 0; i < set->used; ++i) {
6793 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6794 continue;
6795 }
6796 set->val.scnodes[i].in_ctx = 1;
6797
6798 *exp_idx = orig_exp;
6799
6800 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6801 LY_CHECK_RET(rc);
6802
6803 set->val.scnodes[i].in_ctx = pred_in_ctx;
6804 }
6805
6806 /* restore the state as it was before the predicate */
6807 for (i = 0; i < set->used; ++i) {
6808 if (set->val.scnodes[i].in_ctx == 1) {
6809 set->val.scnodes[i].in_ctx = 0;
6810 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6811 set->val.scnodes[i].in_ctx = 1;
6812 }
6813 }
6814
6815 } else {
6816 set2.type = LYXP_SET_EMPTY;
6817 set_fill_set(&set2, set);
6818
6819 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6820 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006821 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006822 return rc;
6823 }
6824
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006825 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006826 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006827 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006828 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006829 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006830 }
6831
6832 /* ']' */
6833 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6834 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6835 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6836 ++(*exp_idx);
6837
6838 return LY_SUCCESS;
6839}
6840
6841/**
6842 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6843 *
6844 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6845 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6846 *
6847 * @param[in] exp Parsed XPath expression.
6848 * @param[in] exp_idx Position in the expression @p exp.
6849 * @param[in] all_desc Whether to search all the descendants or children only.
6850 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6851 * @param[in] options XPath options.
6852 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6853 */
6854static LY_ERR
6855eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6856{
6857 int attr_axis;
6858 LY_ERR rc;
6859
6860 goto step;
6861 do {
6862 /* evaluate '/' or '//' */
6863 if (exp->tok_len[*exp_idx] == 1) {
6864 all_desc = 0;
6865 } else {
6866 assert(exp->tok_len[*exp_idx] == 2);
6867 all_desc = 1;
6868 }
6869 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6870 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6871 ++(*exp_idx);
6872
6873step:
6874 /* Step */
6875 attr_axis = 0;
6876 switch (exp->tokens[*exp_idx]) {
6877 case LYXP_TOKEN_DOT:
6878 /* evaluate '.' */
6879 if (set && (options & LYXP_SCNODE_ALL)) {
6880 rc = moveto_scnode_self(set, all_desc, options);
6881 } else {
6882 rc = moveto_self(set, all_desc, options);
6883 }
6884 LY_CHECK_RET(rc);
6885 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6886 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6887 ++(*exp_idx);
6888 break;
6889
6890 case LYXP_TOKEN_DDOT:
6891 /* evaluate '..' */
6892 if (set && (options & LYXP_SCNODE_ALL)) {
6893 rc = moveto_scnode_parent(set, all_desc, options);
6894 } else {
6895 rc = moveto_parent(set, all_desc, options);
6896 }
6897 LY_CHECK_RET(rc);
6898 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6899 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6900 ++(*exp_idx);
6901 break;
6902
6903 case LYXP_TOKEN_AT:
6904 /* evaluate '@' */
6905 attr_axis = 1;
6906 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6907 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6908 ++(*exp_idx);
6909
6910 /* fall through */
6911 case LYXP_TOKEN_NAMETEST:
6912 case LYXP_TOKEN_NODETYPE:
6913 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6914 LY_CHECK_RET(rc);
6915
6916 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6917 rc = eval_predicate(exp, exp_idx, set, options, 1);
6918 LY_CHECK_RET(rc);
6919 }
6920 break;
6921
6922 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006923 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006924 }
6925 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6926
6927 return LY_SUCCESS;
6928}
6929
6930/**
6931 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6932 *
6933 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6934 *
6935 * @param[in] exp Parsed XPath expression.
6936 * @param[in] exp_idx Position in the expression @p exp.
6937 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6938 * @param[in] options XPath options.
6939 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6940 */
6941static LY_ERR
6942eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6943{
6944 int all_desc;
6945 LY_ERR rc;
6946
6947 if (set) {
6948 /* no matter what tokens follow, we need to be at the root */
6949 moveto_root(set, options);
6950 }
6951
6952 /* '/' RelativeLocationPath? */
6953 if (exp->tok_len[*exp_idx] == 1) {
6954 /* evaluate '/' - deferred */
6955 all_desc = 0;
6956 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6957 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6958 ++(*exp_idx);
6959
Michal Vasko4b9e1052019-09-13 11:25:37 +02006960 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006961 return LY_SUCCESS;
6962 }
6963 switch (exp->tokens[*exp_idx]) {
6964 case LYXP_TOKEN_DOT:
6965 case LYXP_TOKEN_DDOT:
6966 case LYXP_TOKEN_AT:
6967 case LYXP_TOKEN_NAMETEST:
6968 case LYXP_TOKEN_NODETYPE:
6969 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6970 LY_CHECK_RET(rc);
6971 break;
6972 default:
6973 break;
6974 }
6975
6976 /* '//' RelativeLocationPath */
6977 } else {
6978 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6979 all_desc = 1;
6980 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6981 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6982 ++(*exp_idx);
6983
6984 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6985 LY_CHECK_RET(rc);
6986 }
6987
6988 return LY_SUCCESS;
6989}
6990
6991/**
6992 * @brief Evaluate FunctionCall. Logs directly on error.
6993 *
6994 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6995 *
6996 * @param[in] exp Parsed XPath expression.
6997 * @param[in] exp_idx Position in the expression @p exp.
6998 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6999 * @param[in] options XPath options.
7000 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7001 */
7002static LY_ERR
7003eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7004{
7005 LY_ERR rc;
7006 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
7007 uint16_t arg_count = 0, i, func_exp = *exp_idx;
7008 struct lyxp_set **args = NULL, **args_aux;
7009
7010 if (set) {
7011 /* FunctionName */
7012 switch (exp->tok_len[*exp_idx]) {
7013 case 3:
7014 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7015 xpath_func = &xpath_not;
7016 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7017 xpath_func = &xpath_sum;
7018 }
7019 break;
7020 case 4:
7021 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7022 xpath_func = &xpath_lang;
7023 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7024 xpath_func = &xpath_last;
7025 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7026 xpath_func = &xpath_name;
7027 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7028 xpath_func = &xpath_true;
7029 }
7030 break;
7031 case 5:
7032 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7033 xpath_func = &xpath_count;
7034 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7035 xpath_func = &xpath_false;
7036 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7037 xpath_func = &xpath_floor;
7038 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7039 xpath_func = &xpath_round;
7040 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7041 xpath_func = &xpath_deref;
7042 }
7043 break;
7044 case 6:
7045 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7046 xpath_func = &xpath_concat;
7047 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7048 xpath_func = &xpath_number;
7049 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7050 xpath_func = &xpath_string;
7051 }
7052 break;
7053 case 7:
7054 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7055 xpath_func = &xpath_boolean;
7056 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7057 xpath_func = &xpath_ceiling;
7058 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7059 xpath_func = &xpath_current;
7060 }
7061 break;
7062 case 8:
7063 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7064 xpath_func = &xpath_contains;
7065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7066 xpath_func = &xpath_position;
7067 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7068 xpath_func = &xpath_re_match;
7069 }
7070 break;
7071 case 9:
7072 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7073 xpath_func = &xpath_substring;
7074 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7075 xpath_func = &xpath_translate;
7076 }
7077 break;
7078 case 10:
7079 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7080 xpath_func = &xpath_local_name;
7081 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7082 xpath_func = &xpath_enum_value;
7083 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7084 xpath_func = &xpath_bit_is_set;
7085 }
7086 break;
7087 case 11:
7088 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7089 xpath_func = &xpath_starts_with;
7090 }
7091 break;
7092 case 12:
7093 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7094 xpath_func = &xpath_derived_from;
7095 }
7096 break;
7097 case 13:
7098 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7099 xpath_func = &xpath_namespace_uri;
7100 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7101 xpath_func = &xpath_string_length;
7102 }
7103 break;
7104 case 15:
7105 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7106 xpath_func = &xpath_normalize_space;
7107 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7108 xpath_func = &xpath_substring_after;
7109 }
7110 break;
7111 case 16:
7112 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7113 xpath_func = &xpath_substring_before;
7114 }
7115 break;
7116 case 20:
7117 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7118 xpath_func = &xpath_derived_from_or_self;
7119 }
7120 break;
7121 }
7122
7123 if (!xpath_func) {
7124 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7125 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]]);
7126 return LY_EVALID;
7127 }
7128 }
7129
7130 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7131 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7132 ++(*exp_idx);
7133
7134 /* '(' */
7135 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7136 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7137 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7138 ++(*exp_idx);
7139
7140 /* ( Expr ( ',' Expr )* )? */
7141 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7142 if (set) {
7143 args = malloc(sizeof *args);
7144 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7145 arg_count = 1;
7146 args[0] = set_copy(set);
7147 if (!args[0]) {
7148 rc = LY_EMEM;
7149 goto cleanup;
7150 }
7151
7152 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7153 LY_CHECK_GOTO(rc, cleanup);
7154 } else {
7155 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7156 LY_CHECK_GOTO(rc, cleanup);
7157 }
7158 }
7159 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7160 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7161 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7162 ++(*exp_idx);
7163
7164 if (set) {
7165 ++arg_count;
7166 args_aux = realloc(args, arg_count * sizeof *args);
7167 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7168 args = args_aux;
7169 args[arg_count - 1] = set_copy(set);
7170 if (!args[arg_count - 1]) {
7171 rc = LY_EMEM;
7172 goto cleanup;
7173 }
7174
7175 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7176 LY_CHECK_GOTO(rc, cleanup);
7177 } else {
7178 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7179 LY_CHECK_GOTO(rc, cleanup);
7180 }
7181 }
7182
7183 /* ')' */
7184 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7185 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7186 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7187 ++(*exp_idx);
7188
7189 if (set) {
7190 /* evaluate function */
7191 rc = xpath_func(args, arg_count, set, options);
7192
7193 if (options & LYXP_SCNODE_ALL) {
7194 if (rc == LY_EINVAL) {
7195 /* some validation warning TODO log everything immediately? */
7196 LOGWRN(set->ctx, "Previous warning generated by XPath function \"%.*s\".",
7197 (exp->tok_pos[*exp_idx - 1] - exp->tok_pos[func_exp]) + 1, &exp->expr[exp->tok_pos[func_exp]]);
7198 rc = LY_SUCCESS;
7199 }
7200
7201 /* merge all nodes from arg evaluations */
7202 for (i = 0; i < arg_count; ++i) {
7203 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007204 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007205 }
7206 }
7207 } else {
7208 rc = LY_SUCCESS;
7209 }
7210
7211cleanup:
7212 for (i = 0; i < arg_count; ++i) {
7213 lyxp_set_free(args[i]);
7214 }
7215 free(args);
7216
7217 return rc;
7218}
7219
7220/**
7221 * @brief Evaluate Number. Logs directly on error.
7222 *
7223 * @param[in] ctx Context for errors.
7224 * @param[in] exp Parsed XPath expression.
7225 * @param[in] exp_idx Position in the expression @p exp.
7226 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7227 * @return LY_ERR
7228 */
7229static LY_ERR
7230eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7231{
7232 long double num;
7233 char *endptr;
7234
7235 if (set) {
7236 errno = 0;
7237 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7238 if (errno) {
7239 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7240 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7241 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7242 return LY_EVALID;
7243 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7244 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7245 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7246 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7247 return LY_EVALID;
7248 }
7249
7250 set_fill_number(set, num);
7251 }
7252
7253 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7254 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7255 ++(*exp_idx);
7256 return LY_SUCCESS;
7257}
7258
7259/**
7260 * @brief Evaluate PathExpr. Logs directly on error.
7261 *
7262 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7263 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7264 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7265 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7266 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7267 *
7268 * @param[in] exp Parsed XPath expression.
7269 * @param[in] exp_idx Position in the expression @p exp.
7270 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7271 * @param[in] options XPath options.
7272 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7273 */
7274static LY_ERR
7275eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7276{
7277 int all_desc, parent_pos_pred;
7278 LY_ERR rc;
7279
7280 switch (exp->tokens[*exp_idx]) {
7281 case LYXP_TOKEN_PAR1:
7282 /* '(' Expr ')' */
7283
7284 /* '(' */
7285 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7286 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7287 ++(*exp_idx);
7288
7289 /* Expr */
7290 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7291 LY_CHECK_RET(rc);
7292
7293 /* ')' */
7294 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7295 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7296 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7297 ++(*exp_idx);
7298
7299 parent_pos_pred = 0;
7300 goto predicate;
7301
7302 case LYXP_TOKEN_DOT:
7303 case LYXP_TOKEN_DDOT:
7304 case LYXP_TOKEN_AT:
7305 case LYXP_TOKEN_NAMETEST:
7306 case LYXP_TOKEN_NODETYPE:
7307 /* RelativeLocationPath */
7308 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7309 LY_CHECK_RET(rc);
7310 break;
7311
7312 case LYXP_TOKEN_FUNCNAME:
7313 /* FunctionCall */
7314 if (!set) {
7315 rc = eval_function_call(exp, exp_idx, NULL, options);
7316 } else {
7317 rc = eval_function_call(exp, exp_idx, set, options);
7318 }
7319 LY_CHECK_RET(rc);
7320
7321 parent_pos_pred = 1;
7322 goto predicate;
7323
7324 case LYXP_TOKEN_OPERATOR_PATH:
7325 /* AbsoluteLocationPath */
7326 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7327 LY_CHECK_RET(rc);
7328 break;
7329
7330 case LYXP_TOKEN_LITERAL:
7331 /* Literal */
7332 if (!set || (options & LYXP_SCNODE_ALL)) {
7333 if (set) {
7334 set_scnode_clear_ctx(set);
7335 }
7336 eval_literal(exp, exp_idx, NULL);
7337 } else {
7338 eval_literal(exp, exp_idx, set);
7339 }
7340
7341 parent_pos_pred = 1;
7342 goto predicate;
7343
7344 case LYXP_TOKEN_NUMBER:
7345 /* Number */
7346 if (!set || (options & LYXP_SCNODE_ALL)) {
7347 if (set) {
7348 set_scnode_clear_ctx(set);
7349 }
Michal Vasko02a77382019-09-12 11:47:35 +02007350 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007351 } else {
7352 rc = eval_number(set->ctx, exp, exp_idx, set);
7353 }
7354 LY_CHECK_RET(rc);
7355
7356 parent_pos_pred = 1;
7357 goto predicate;
7358
7359 default:
7360 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7361 &exp->expr[exp->tok_pos[*exp_idx]]);
7362 return LY_EVALID;
7363 }
7364
7365 return LY_SUCCESS;
7366
7367predicate:
7368 /* Predicate* */
7369 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7370 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7371 LY_CHECK_RET(rc);
7372 }
7373
7374 /* ('/' or '//') RelativeLocationPath */
7375 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7376
7377 /* evaluate '/' or '//' */
7378 if (exp->tok_len[*exp_idx] == 1) {
7379 all_desc = 0;
7380 } else {
7381 assert(exp->tok_len[*exp_idx] == 2);
7382 all_desc = 1;
7383 }
7384
7385 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7386 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7387 ++(*exp_idx);
7388
7389 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7390 LY_CHECK_RET(rc);
7391 }
7392
7393 return LY_SUCCESS;
7394}
7395
7396/**
7397 * @brief Evaluate UnionExpr. Logs directly on error.
7398 *
7399 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7400 *
7401 * @param[in] exp Parsed XPath expression.
7402 * @param[in] exp_idx Position in the expression @p exp.
7403 * @param[in] repeat How many times this expression is repeated.
7404 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7405 * @param[in] options XPath options.
7406 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7407 */
7408static LY_ERR
7409eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7410{
7411 LY_ERR rc = LY_SUCCESS;
7412 struct lyxp_set orig_set, set2;
7413 uint16_t i;
7414
7415 assert(repeat);
7416
7417 set_init(&orig_set, set);
7418 set_init(&set2, set);
7419
7420 set_fill_set(&orig_set, set);
7421
7422 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7423 LY_CHECK_GOTO(rc, cleanup);
7424
7425 /* ('|' PathExpr)* */
7426 for (i = 0; i < repeat; ++i) {
7427 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7428 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7429 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7430 ++(*exp_idx);
7431
7432 if (!set) {
7433 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7434 LY_CHECK_GOTO(rc, cleanup);
7435 continue;
7436 }
7437
7438 set_fill_set(&set2, &orig_set);
7439 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7440 LY_CHECK_GOTO(rc, cleanup);
7441
7442 /* eval */
7443 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007444 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007445 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007446 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007447 LY_CHECK_GOTO(rc, cleanup);
7448 }
7449 }
7450
7451cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007452 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7453 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007454 return rc;
7455}
7456
7457/**
7458 * @brief Evaluate UnaryExpr. Logs directly on error.
7459 *
7460 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7461 *
7462 * @param[in] exp Parsed XPath expression.
7463 * @param[in] exp_idx Position in the expression @p exp.
7464 * @param[in] repeat How many times this expression is repeated.
7465 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7466 * @param[in] options XPath options.
7467 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7468 */
7469static LY_ERR
7470eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7471{
7472 LY_ERR rc;
7473 uint16_t this_op, i;
7474
7475 assert(repeat);
7476
7477 /* ('-')+ */
7478 this_op = *exp_idx;
7479 for (i = 0; i < repeat; ++i) {
7480 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7481
7482 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7483 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7484 ++(*exp_idx);
7485 }
7486
7487 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7488 LY_CHECK_RET(rc);
7489
7490 if (set && (repeat % 2)) {
7491 if (options & LYXP_SCNODE_ALL) {
7492 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7493 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007494 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007495 LY_CHECK_RET(rc);
7496 }
7497 }
7498
7499 return LY_SUCCESS;
7500}
7501
7502/**
7503 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7504 *
7505 * [16] MultiplicativeExpr ::= UnaryExpr
7506 * | MultiplicativeExpr '*' UnaryExpr
7507 * | MultiplicativeExpr 'div' UnaryExpr
7508 * | MultiplicativeExpr 'mod' UnaryExpr
7509 *
7510 * @param[in] exp Parsed XPath expression.
7511 * @param[in] exp_idx Position in the expression @p exp.
7512 * @param[in] repeat How many times this expression is repeated.
7513 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7514 * @param[in] options XPath options.
7515 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7516 */
7517static LY_ERR
7518eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7519{
7520 LY_ERR rc;
7521 uint16_t this_op;
7522 struct lyxp_set orig_set, set2;
7523 uint16_t i;
7524
7525 assert(repeat);
7526
7527 set_init(&orig_set, set);
7528 set_init(&set2, set);
7529
7530 set_fill_set(&orig_set, set);
7531
7532 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7533 LY_CHECK_GOTO(rc, cleanup);
7534
7535 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7536 for (i = 0; i < repeat; ++i) {
7537 this_op = *exp_idx;
7538
7539 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7540 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7541 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7542 ++(*exp_idx);
7543
7544 if (!set) {
7545 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7546 LY_CHECK_GOTO(rc, cleanup);
7547 continue;
7548 }
7549
7550 set_fill_set(&set2, &orig_set);
7551 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7552 LY_CHECK_GOTO(rc, cleanup);
7553
7554 /* eval */
7555 if (options & LYXP_SCNODE_ALL) {
7556 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007557 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007558 set_scnode_clear_ctx(set);
7559 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007560 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007561 LY_CHECK_GOTO(rc, cleanup);
7562 }
7563 }
7564
7565cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007566 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7567 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007568 return rc;
7569}
7570
7571/**
7572 * @brief Evaluate AdditiveExpr. Logs directly on error.
7573 *
7574 * [15] AdditiveExpr ::= MultiplicativeExpr
7575 * | AdditiveExpr '+' MultiplicativeExpr
7576 * | AdditiveExpr '-' MultiplicativeExpr
7577 *
7578 * @param[in] exp Parsed XPath expression.
7579 * @param[in] exp_idx Position in the expression @p exp.
7580 * @param[in] repeat How many times this expression is repeated.
7581 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7582 * @param[in] options XPath options.
7583 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7584 */
7585static LY_ERR
7586eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7587{
7588 LY_ERR rc;
7589 uint16_t this_op;
7590 struct lyxp_set orig_set, set2;
7591 uint16_t i;
7592
7593 assert(repeat);
7594
7595 set_init(&orig_set, set);
7596 set_init(&set2, set);
7597
7598 set_fill_set(&orig_set, set);
7599
7600 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7601 LY_CHECK_GOTO(rc, cleanup);
7602
7603 /* ('+' / '-' MultiplicativeExpr)* */
7604 for (i = 0; i < repeat; ++i) {
7605 this_op = *exp_idx;
7606
7607 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7608 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7609 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7610 ++(*exp_idx);
7611
7612 if (!set) {
7613 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7614 LY_CHECK_GOTO(rc, cleanup);
7615 continue;
7616 }
7617
7618 set_fill_set(&set2, &orig_set);
7619 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7620 LY_CHECK_GOTO(rc, cleanup);
7621
7622 /* eval */
7623 if (options & LYXP_SCNODE_ALL) {
7624 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007625 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007626 set_scnode_clear_ctx(set);
7627 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007628 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007629 LY_CHECK_GOTO(rc, cleanup);
7630 }
7631 }
7632
7633cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007634 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7635 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007636 return rc;
7637}
7638
7639/**
7640 * @brief Evaluate RelationalExpr. Logs directly on error.
7641 *
7642 * [14] RelationalExpr ::= AdditiveExpr
7643 * | RelationalExpr '<' AdditiveExpr
7644 * | RelationalExpr '>' AdditiveExpr
7645 * | RelationalExpr '<=' AdditiveExpr
7646 * | RelationalExpr '>=' AdditiveExpr
7647 *
7648 * @param[in] exp Parsed XPath expression.
7649 * @param[in] exp_idx Position in the expression @p exp.
7650 * @param[in] repeat How many times this expression is repeated.
7651 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7652 * @param[in] options XPath options.
7653 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7654 */
7655static LY_ERR
7656eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7657{
7658 LY_ERR rc;
7659 uint16_t this_op;
7660 struct lyxp_set orig_set, set2;
7661 uint16_t i;
7662
7663 assert(repeat);
7664
7665 set_init(&orig_set, set);
7666 set_init(&set2, set);
7667
7668 set_fill_set(&orig_set, set);
7669
7670 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7671 LY_CHECK_GOTO(rc, cleanup);
7672
7673 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7674 for (i = 0; i < repeat; ++i) {
7675 this_op = *exp_idx;
7676
7677 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7678 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7679 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7680 ++(*exp_idx);
7681
7682 if (!set) {
7683 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7684 LY_CHECK_GOTO(rc, cleanup);
7685 continue;
7686 }
7687
7688 set_fill_set(&set2, &orig_set);
7689 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7690 LY_CHECK_GOTO(rc, cleanup);
7691
7692 /* eval */
7693 if (options & LYXP_SCNODE_ALL) {
7694 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007695 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007696 set_scnode_clear_ctx(set);
7697 } else {
7698 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7699 LY_CHECK_GOTO(rc, cleanup);
7700 }
7701 }
7702
7703cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007704 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7705 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007706 return rc;
7707}
7708
7709/**
7710 * @brief Evaluate EqualityExpr. Logs directly on error.
7711 *
7712 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7713 * | EqualityExpr '!=' RelationalExpr
7714 *
7715 * @param[in] exp Parsed XPath expression.
7716 * @param[in] exp_idx Position in the expression @p exp.
7717 * @param[in] repeat How many times this expression is repeated.
7718 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7719 * @param[in] options XPath options.
7720 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7721 */
7722static LY_ERR
7723eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7724{
7725 LY_ERR rc;
7726 uint16_t this_op;
7727 struct lyxp_set orig_set, set2;
7728 uint16_t i;
7729
7730 assert(repeat);
7731
7732 set_init(&orig_set, set);
7733 set_init(&set2, set);
7734
7735 set_fill_set(&orig_set, set);
7736
7737 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7738 LY_CHECK_GOTO(rc, cleanup);
7739
7740 /* ('=' / '!=' RelationalExpr)* */
7741 for (i = 0; i < repeat; ++i) {
7742 this_op = *exp_idx;
7743
7744 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7745 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7746 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7747 ++(*exp_idx);
7748
7749 if (!set) {
7750 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7751 LY_CHECK_GOTO(rc, cleanup);
7752 continue;
7753 }
7754
7755 set_fill_set(&set2, &orig_set);
7756 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7757 LY_CHECK_GOTO(rc, cleanup);
7758
7759 /* eval */
7760 if (options & LYXP_SCNODE_ALL) {
7761 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7762 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7763 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007764 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007765 set_scnode_clear_ctx(set);
7766 } else {
7767 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7768 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7769 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7770 /* left operand is identityref */
7771 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7772 /* missing prefix in the right operand */
7773 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7774 if (!set2.val.str) {
7775 goto cleanup;
7776 }
7777
7778 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7779 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7780 set2.val.str[strlen(set->local_mod->name)] = ':';
7781 }
7782 }
7783
7784 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7785 LY_CHECK_GOTO(rc, cleanup);
7786 }
7787 }
7788
7789cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007790 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7791 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007792 return rc;
7793}
7794
7795/**
7796 * @brief Evaluate AndExpr. Logs directly on error.
7797 *
7798 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7799 *
7800 * @param[in] exp Parsed XPath expression.
7801 * @param[in] exp_idx Position in the expression @p exp.
7802 * @param[in] repeat How many times this expression is repeated.
7803 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7804 * @param[in] options XPath options.
7805 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7806 */
7807static LY_ERR
7808eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7809{
7810 LY_ERR rc;
7811 struct lyxp_set orig_set, set2;
7812 uint16_t i;
7813
7814 assert(repeat);
7815
7816 set_init(&orig_set, set);
7817 set_init(&set2, set);
7818
7819 set_fill_set(&orig_set, set);
7820
7821 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7822 LY_CHECK_GOTO(rc, cleanup);
7823
7824 /* cast to boolean, we know that will be the final result */
7825 if (set && (options & LYXP_SCNODE_ALL)) {
7826 set_scnode_clear_ctx(set);
7827 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007828 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007829 }
7830
7831 /* ('and' EqualityExpr)* */
7832 for (i = 0; i < repeat; ++i) {
7833 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7834 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7835 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7836 ++(*exp_idx);
7837
7838 /* lazy evaluation */
7839 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7840 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7841 LY_CHECK_GOTO(rc, cleanup);
7842 continue;
7843 }
7844
7845 set_fill_set(&set2, &orig_set);
7846 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7847 LY_CHECK_GOTO(rc, cleanup);
7848
7849 /* eval - just get boolean value actually */
7850 if (set->type == LYXP_SET_SCNODE_SET) {
7851 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007852 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007853 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007854 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007855 set_fill_set(set, &set2);
7856 }
7857 }
7858
7859cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007860 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7861 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007862 return rc;
7863}
7864
7865/**
7866 * @brief Evaluate OrExpr. Logs directly on error.
7867 *
7868 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7869 *
7870 * @param[in] exp Parsed XPath expression.
7871 * @param[in] exp_idx Position in the expression @p exp.
7872 * @param[in] repeat How many times this expression is repeated.
7873 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7874 * @param[in] options XPath options.
7875 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7876 */
7877static LY_ERR
7878eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7879{
7880 LY_ERR rc;
7881 struct lyxp_set orig_set, set2;
7882 uint16_t i;
7883
7884 assert(repeat);
7885
7886 set_init(&orig_set, set);
7887 set_init(&set2, set);
7888
7889 set_fill_set(&orig_set, set);
7890
7891 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7892 LY_CHECK_GOTO(rc, cleanup);
7893
7894 /* cast to boolean, we know that will be the final result */
7895 if (set && (options & LYXP_SCNODE_ALL)) {
7896 set_scnode_clear_ctx(set);
7897 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007898 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007899 }
7900
7901 /* ('or' AndExpr)* */
7902 for (i = 0; i < repeat; ++i) {
7903 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7904 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7905 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7906 ++(*exp_idx);
7907
7908 /* lazy evaluation */
7909 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7910 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7911 LY_CHECK_GOTO(rc, cleanup);
7912 continue;
7913 }
7914
7915 set_fill_set(&set2, &orig_set);
7916 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7917 * but it does not matter */
7918 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7919 LY_CHECK_GOTO(rc, cleanup);
7920
7921 /* eval - just get boolean value actually */
7922 if (set->type == LYXP_SET_SCNODE_SET) {
7923 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007924 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007925 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007926 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007927 set_fill_set(set, &set2);
7928 }
7929 }
7930
7931cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007932 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7933 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007934 return rc;
7935}
7936
7937/**
7938 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7939 *
7940 * @param[in] exp Parsed XPath expression.
7941 * @param[in] exp_idx Position in the expression @p exp.
7942 * @param[in] etype Expression type to evaluate.
7943 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7944 * @param[in] options XPath options.
7945 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7946 */
7947static LY_ERR
7948eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7949{
7950 uint16_t i, count;
7951 enum lyxp_expr_type next_etype;
7952 LY_ERR rc;
7953
7954 /* process operator repeats */
7955 if (!exp->repeat[*exp_idx]) {
7956 next_etype = LYXP_EXPR_NONE;
7957 } else {
7958 /* find etype repeat */
7959 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7960
7961 /* select one-priority lower because etype expression called us */
7962 if (i) {
7963 next_etype = exp->repeat[*exp_idx][i - 1];
7964 /* count repeats for that expression */
7965 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7966 } else {
7967 next_etype = LYXP_EXPR_NONE;
7968 }
7969 }
7970
7971 /* decide what expression are we parsing based on the repeat */
7972 switch (next_etype) {
7973 case LYXP_EXPR_OR:
7974 rc = eval_or_expr(exp, exp_idx, count, set, options);
7975 break;
7976 case LYXP_EXPR_AND:
7977 rc = eval_and_expr(exp, exp_idx, count, set, options);
7978 break;
7979 case LYXP_EXPR_EQUALITY:
7980 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7981 break;
7982 case LYXP_EXPR_RELATIONAL:
7983 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7984 break;
7985 case LYXP_EXPR_ADDITIVE:
7986 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7987 break;
7988 case LYXP_EXPR_MULTIPLICATIVE:
7989 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7990 break;
7991 case LYXP_EXPR_UNARY:
7992 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7993 break;
7994 case LYXP_EXPR_UNION:
7995 rc = eval_union_expr(exp, exp_idx, count, set, options);
7996 break;
7997 case LYXP_EXPR_NONE:
7998 rc = eval_path_expr(exp, exp_idx, set, options);
7999 break;
8000 default:
8001 LOGINT_RET(set->ctx);
8002 }
8003
8004 return rc;
8005}
8006
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008007/**
8008 * @brief Get root type.
8009 *
8010 * @param[in] ctx_node Context node.
8011 * @param[in] ctx_scnode Schema context node.
8012 * @param[in] options XPath options.
8013 * @return Root type.
8014 */
8015static enum lyxp_node_type
8016lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8017{
8018 if (options & LYXP_SCNODE_ALL) {
8019 if (options & LYXP_SCNODE) {
8020 /* general root that can access everything */
8021 return LYXP_NODE_ROOT;
8022 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8023 /* root context node can access only config data (because we said so, it is unspecified) */
8024 return LYXP_NODE_ROOT_CONFIG;
8025 } else {
8026 return LYXP_NODE_ROOT;
8027 }
8028 }
8029
8030 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8031 /* root context node can access only config data (because we said so, it is unspecified) */
8032 return LYXP_NODE_ROOT_CONFIG;
8033 }
8034
8035 return LYXP_NODE_ROOT;
8036}
8037
Michal Vasko03ff5a72019-09-11 13:49:33 +02008038LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008039lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
Michal Vasko03ff5a72019-09-11 13:49:33 +02008040 enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
8041{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008042 uint16_t exp_idx = 0;
8043 LY_ERR rc;
8044
Michal Vaskoecd62de2019-11-13 12:35:11 +01008045 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008046
8047 /* prepare set for evaluation */
8048 exp_idx = 0;
8049 memset(set, 0, sizeof *set);
8050 set->type = LYXP_SET_EMPTY;
8051 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, options);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008052 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008053 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008054 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008055 set->local_mod = local_mod;
8056 set->trees = trees;
8057 set->format = format;
8058
8059 /* evaluate */
8060 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8061 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008062 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008063 }
8064
Michal Vasko03ff5a72019-09-11 13:49:33 +02008065 return rc;
8066}
8067
8068#if 0
8069
8070/* full xml printing of set elements, not used currently */
8071
8072void
8073lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8074{
8075 uint32_t i;
8076 char *str_num;
8077 struct lyout out;
8078
8079 memset(&out, 0, sizeof out);
8080
8081 out.type = LYOUT_STREAM;
8082 out.method.f = f;
8083
8084 switch (set->type) {
8085 case LYXP_SET_EMPTY:
8086 ly_print(&out, "Empty XPath set\n\n");
8087 break;
8088 case LYXP_SET_BOOLEAN:
8089 ly_print(&out, "Boolean XPath set:\n");
8090 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8091 break;
8092 case LYXP_SET_STRING:
8093 ly_print(&out, "String XPath set:\n");
8094 ly_print(&out, "\"%s\"\n\n", set->value.str);
8095 break;
8096 case LYXP_SET_NUMBER:
8097 ly_print(&out, "Number XPath set:\n");
8098
8099 if (isnan(set->value.num)) {
8100 str_num = strdup("NaN");
8101 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8102 str_num = strdup("0");
8103 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8104 str_num = strdup("Infinity");
8105 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8106 str_num = strdup("-Infinity");
8107 } else if ((long long)set->value.num == set->value.num) {
8108 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8109 str_num = NULL;
8110 }
8111 } else {
8112 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8113 str_num = NULL;
8114 }
8115 }
8116 if (!str_num) {
8117 LOGMEM;
8118 return;
8119 }
8120 ly_print(&out, "%s\n\n", str_num);
8121 free(str_num);
8122 break;
8123 case LYXP_SET_NODE_SET:
8124 ly_print(&out, "Node XPath set:\n");
8125
8126 for (i = 0; i < set->used; ++i) {
8127 ly_print(&out, "%d. ", i + 1);
8128 switch (set->node_type[i]) {
8129 case LYXP_NODE_ROOT_ALL:
8130 ly_print(&out, "ROOT all\n\n");
8131 break;
8132 case LYXP_NODE_ROOT_CONFIG:
8133 ly_print(&out, "ROOT config\n\n");
8134 break;
8135 case LYXP_NODE_ROOT_STATE:
8136 ly_print(&out, "ROOT state\n\n");
8137 break;
8138 case LYXP_NODE_ROOT_NOTIF:
8139 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8140 break;
8141 case LYXP_NODE_ROOT_RPC:
8142 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8143 break;
8144 case LYXP_NODE_ROOT_OUTPUT:
8145 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8146 break;
8147 case LYXP_NODE_ELEM:
8148 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8149 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8150 ly_print(&out, "\n");
8151 break;
8152 case LYXP_NODE_TEXT:
8153 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8154 break;
8155 case LYXP_NODE_ATTR:
8156 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8157 break;
8158 }
8159 }
8160 break;
8161 }
8162}
8163
8164#endif
8165
8166LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008167lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008168{
8169 long double num;
8170 char *str;
8171 LY_ERR rc;
8172
8173 if (!set || (set->type == target)) {
8174 return LY_SUCCESS;
8175 }
8176
8177 /* it's not possible to convert anything into a node set */
8178 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8179
8180 if (set->type == LYXP_SET_SCNODE_SET) {
8181 set_free_content(set);
8182 return LY_EINVAL;
8183 }
8184
8185 /* to STRING */
8186 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8187 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8188 switch (set->type) {
8189 case LYXP_SET_NUMBER:
8190 if (isnan(set->val.num)) {
8191 set->val.str = strdup("NaN");
8192 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8193 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8194 set->val.str = strdup("0");
8195 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8196 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8197 set->val.str = strdup("Infinity");
8198 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8199 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8200 set->val.str = strdup("-Infinity");
8201 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8202 } else if ((long long)set->val.num == set->val.num) {
8203 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8204 LOGMEM_RET(set->ctx);
8205 }
8206 set->val.str = str;
8207 } else {
8208 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8209 LOGMEM_RET(set->ctx);
8210 }
8211 set->val.str = str;
8212 }
8213 break;
8214 case LYXP_SET_BOOLEAN:
8215 if (set->val.bool) {
8216 set->val.str = strdup("true");
8217 } else {
8218 set->val.str = strdup("false");
8219 }
8220 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8221 break;
8222 case LYXP_SET_NODE_SET:
8223 assert(set->used);
8224
8225 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008226 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008227
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008228 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008229 LY_CHECK_RET(rc);
8230 set_free_content(set);
8231 set->val.str = str;
8232 break;
8233 case LYXP_SET_EMPTY:
8234 set->val.str = strdup("");
8235 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8236 break;
8237 default:
8238 LOGINT_RET(set->ctx);
8239 }
8240 set->type = LYXP_SET_STRING;
8241 }
8242
8243 /* to NUMBER */
8244 if (target == LYXP_SET_NUMBER) {
8245 switch (set->type) {
8246 case LYXP_SET_STRING:
8247 num = cast_string_to_number(set->val.str);
8248 set_free_content(set);
8249 set->val.num = num;
8250 break;
8251 case LYXP_SET_BOOLEAN:
8252 if (set->val.bool) {
8253 set->val.num = 1;
8254 } else {
8255 set->val.num = 0;
8256 }
8257 break;
8258 default:
8259 LOGINT_RET(set->ctx);
8260 }
8261 set->type = LYXP_SET_NUMBER;
8262 }
8263
8264 /* to BOOLEAN */
8265 if (target == LYXP_SET_BOOLEAN) {
8266 switch (set->type) {
8267 case LYXP_SET_NUMBER:
8268 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8269 set->val.bool = 0;
8270 } else {
8271 set->val.bool = 1;
8272 }
8273 break;
8274 case LYXP_SET_STRING:
8275 if (set->val.str[0]) {
8276 set_free_content(set);
8277 set->val.bool = 1;
8278 } else {
8279 set_free_content(set);
8280 set->val.bool = 0;
8281 }
8282 break;
8283 case LYXP_SET_NODE_SET:
8284 set_free_content(set);
8285
8286 assert(set->used);
8287 set->val.bool = 1;
8288 break;
8289 case LYXP_SET_EMPTY:
8290 set->val.bool = 0;
8291 break;
8292 default:
8293 LOGINT_RET(set->ctx);
8294 }
8295 set->type = LYXP_SET_BOOLEAN;
8296 }
8297
8298 /* to EMPTY */
8299 if (target == LYXP_SET_EMPTY) {
8300 set_free_content(set);
8301 set->type = LYXP_SET_EMPTY;
8302 }
8303
8304 return LY_SUCCESS;
8305}
8306
8307LY_ERR
8308lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8309 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8310{
8311 struct ly_ctx *ctx;
8312 uint16_t exp_idx = 0;
8313
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008314 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008315
8316 ctx = local_mod->ctx;
8317
8318 /* prepare set for evaluation */
8319 exp_idx = 0;
8320 memset(set, 0, sizeof *set);
8321 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008322 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008323 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008324 set->ctx = ctx;
8325 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008326 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008327 set->local_mod = local_mod;
8328 set->format = format;
8329
8330 /* evaluate */
8331 return eval_expr_select(exp, &exp_idx, 0, set, options);
8332}