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