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