blob: e84bad9096a74447aa85426262857c484e36a29a [file] [log] [blame]
Radek Krejcib1646a92018-11-02 16:08:26 +01001/**
2 * @file xpath.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief YANG XPath evaluation functions
5 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02006 * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
Radek Krejcib1646a92018-11-02 16:08:26 +01007 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Michal Vasko03ff5a72019-09-11 13:49:33 +020014#define _GNU_SOURCE
15
16/* needed by libmath functions isfinite(), isinf(), isnan(), signbit(), ... */
17#define _ISOC99_SOURCE
Radek Krejcib1646a92018-11-02 16:08:26 +010018
19#include "common.h"
20
Michal Vasko03ff5a72019-09-11 13:49:33 +020021#include <math.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010022#include <ctype.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdint.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010024#include <stdio.h>
25#include <stdlib.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010026#include <string.h>
Michal Vasko03ff5a72019-09-11 13:49:33 +020027#include <errno.h>
28#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010029
30#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "dict.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010032#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020033#include "printer_data.h"
34#include "tree_schema_internal.h"
35#include "plugins_types.h"
36
Michal Vasko03ff5a72019-09-11 13:49:33 +020037static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +020038static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
39
40/**
41 * @brief Print the type of an XPath \p set.
42 *
43 * @param[in] set Set to use.
44 * @return Set type string.
45 */
46static const char *
47print_set_type(struct lyxp_set *set)
48{
49 switch (set->type) {
50 case LYXP_SET_EMPTY:
51 return "empty";
52 case LYXP_SET_NODE_SET:
53 return "node set";
54 case LYXP_SET_SCNODE_SET:
55 return "schema node set";
56 case LYXP_SET_BOOLEAN:
57 return "boolean";
58 case LYXP_SET_NUMBER:
59 return "number";
60 case LYXP_SET_STRING:
61 return "string";
62 }
63
64 return NULL;
65}
66
67/**
68 * @brief Print an XPath token \p tok type.
69 *
70 * @param[in] tok Token to use.
71 * @return Token type string.
72 */
73static const char *
74print_token(enum lyxp_token tok)
75{
76 switch (tok) {
77 case LYXP_TOKEN_PAR1:
78 return "(";
79 case LYXP_TOKEN_PAR2:
80 return ")";
81 case LYXP_TOKEN_BRACK1:
82 return "[";
83 case LYXP_TOKEN_BRACK2:
84 return "]";
85 case LYXP_TOKEN_DOT:
86 return ".";
87 case LYXP_TOKEN_DDOT:
88 return "..";
89 case LYXP_TOKEN_AT:
90 return "@";
91 case LYXP_TOKEN_COMMA:
92 return ",";
93 case LYXP_TOKEN_NAMETEST:
94 return "NameTest";
95 case LYXP_TOKEN_NODETYPE:
96 return "NodeType";
97 case LYXP_TOKEN_FUNCNAME:
98 return "FunctionName";
99 case LYXP_TOKEN_OPERATOR_LOG:
100 return "Operator(Logic)";
101 case LYXP_TOKEN_OPERATOR_COMP:
102 return "Operator(Comparison)";
103 case LYXP_TOKEN_OPERATOR_MATH:
104 return "Operator(Math)";
105 case LYXP_TOKEN_OPERATOR_UNI:
106 return "Operator(Union)";
107 case LYXP_TOKEN_OPERATOR_PATH:
108 return "Operator(Path)";
109 case LYXP_TOKEN_LITERAL:
110 return "Literal";
111 case LYXP_TOKEN_NUMBER:
112 return "Number";
113 default:
114 LOGINT(NULL);
115 return "";
116 }
117}
118
119/**
120 * @brief Print the whole expression \p exp to debug output.
121 *
122 * @param[in] exp Expression to use.
123 */
124static void
125print_expr_struct_debug(struct lyxp_expr *exp)
126{
127 uint16_t i, j;
128 char tmp[128];
129
130 if (!exp || (ly_log_level < LY_LLDBG)) {
131 return;
132 }
133
134 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
135 for (i = 0; i < exp->used; ++i) {
136 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", print_token(exp->tokens[i]), exp->tok_len[i],
137 &exp->expr[exp->tok_pos[i]]);
138 if (exp->repeat[i]) {
139 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
140 for (j = 1; exp->repeat[i][j]; ++j) {
141 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
142 }
143 strcat(tmp, ")");
144 }
145 LOGDBG(LY_LDGXPATH, tmp);
146 }
147}
148
149#ifndef NDEBUG
150
151/**
152 * @brief Print XPath set content to debug output.
153 *
154 * @param[in] set Set to print.
155 */
156static void
157print_set_debug(struct lyxp_set *set)
158{
159 uint32_t i;
160 char *str;
161 int dynamic;
162 struct lyxp_set_node *item;
163 struct lyxp_set_scnode *sitem;
164
165 if (ly_log_level < LY_LLDBG) {
166 return;
167 }
168
169 switch (set->type) {
170 case LYXP_SET_NODE_SET:
171 LOGDBG(LY_LDGXPATH, "set NODE SET:");
172 for (i = 0; i < set->used; ++i) {
173 item = &set->val.nodes[i];
174
175 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100176 case LYXP_NODE_NONE:
177 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
178 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200179 case LYXP_NODE_ROOT:
180 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
181 break;
182 case LYXP_NODE_ROOT_CONFIG:
183 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
184 break;
185 case LYXP_NODE_ELEM:
186 if ((item->node->schema->nodetype == LYS_LIST)
187 && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
188 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
189 item->node->schema->name,
190 (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node), &dynamic)));
191 if (dynamic) {
192 free(str);
193 }
194 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
195 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
196 item->node->schema->name,
197 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
198 if (dynamic) {
199 free(str);
200 }
201 } else {
202 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
203 }
204 break;
205 case LYXP_NODE_TEXT:
206 if (item->node->schema->nodetype & LYS_ANYDATA) {
207 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
208 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
209 } else {
210 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
211 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
212 if (dynamic) {
213 free(str);
214 }
215 }
216 break;
Michal Vasko9f96a052020-03-10 09:41:45 +0100217 case LYXP_NODE_META:
218 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): META %s = %s", i + 1, item->pos, set->val.meta[i].meta->name,
219 set->val.meta[i].meta->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200220 break;
221 }
222 }
223 break;
224
225 case LYXP_SET_SCNODE_SET:
226 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
227 for (i = 0; i < set->used; ++i) {
228 sitem = &set->val.scnodes[i];
229
230 switch (sitem->type) {
231 case LYXP_NODE_ROOT:
232 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
233 break;
234 case LYXP_NODE_ROOT_CONFIG:
235 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
236 break;
237 case LYXP_NODE_ELEM:
238 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
239 break;
240 default:
241 LOGINT(NULL);
242 break;
243 }
244 }
245 break;
246
247 case LYXP_SET_EMPTY:
248 LOGDBG(LY_LDGXPATH, "set EMPTY");
249 break;
250
251 case LYXP_SET_BOOLEAN:
252 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
253 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
254 break;
255
256 case LYXP_SET_STRING:
257 LOGDBG(LY_LDGXPATH, "set STRING");
258 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
259 break;
260
261 case LYXP_SET_NUMBER:
262 LOGDBG(LY_LDGXPATH, "set NUMBER");
263
264 if (isnan(set->val.num)) {
265 str = strdup("NaN");
266 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
267 str = strdup("0");
268 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
269 str = strdup("Infinity");
270 } else if (isinf(set->val.num) && signbit(set->val.num)) {
271 str = strdup("-Infinity");
272 } else if ((long long)set->val.num == set->val.num) {
273 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
274 str = NULL;
275 }
276 } else {
277 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
278 str = NULL;
279 }
280 }
281 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
282
283 LOGDBG(LY_LDGXPATH, "\t%s", str);
284 free(str);
285 }
286}
287
288#endif
289
290/**
291 * @brief Realloc the string \p str.
292 *
293 * @param[in] ctx libyang context for logging.
294 * @param[in] needed How much free space is required.
295 * @param[in,out] str Pointer to the string to use.
296 * @param[in,out] used Used bytes in \p str.
297 * @param[in,out] size Allocated bytes in \p str.
298 * @return LY_ERR
299 */
300static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100301cast_string_realloc(const struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200302{
303 if (*size - *used < needed) {
304 do {
305 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
306 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
307 return LY_EINVAL;
308 }
309 *size += LYXP_STRING_CAST_SIZE_STEP;
310 } while (*size - *used < needed);
311 *str = ly_realloc(*str, *size * sizeof(char));
312 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
313 }
314
315 return LY_SUCCESS;
316}
317
318/**
319 * @brief Cast nodes recursively to one string @p str.
320 *
321 * @param[in] node Node to cast.
322 * @param[in] fake_cont Whether to put the data into a "fake" container.
323 * @param[in] root_type Type of the XPath root.
324 * @param[in] indent Current indent.
325 * @param[in,out] str Resulting string.
326 * @param[in,out] used Used bytes in @p str.
327 * @param[in,out] size Allocated bytes in @p str.
328 * @return LY_ERR
329 */
330static LY_ERR
331cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
332 uint16_t *used, uint16_t *size)
333{
334 char *buf, *line, *ptr;
335 const char *value_str;
336 int dynamic;
337 const struct lyd_node *child;
338 struct lyd_node_any *any;
339 LY_ERR rc;
340
341 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
342 return LY_SUCCESS;
343 }
344
345 if (fake_cont) {
346 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
347 LY_CHECK_RET(rc);
348 strcpy(*str + (*used - 1), "\n");
349 ++(*used);
350
351 ++indent;
352 }
353
354 switch (node->schema->nodetype) {
355 case LYS_CONTAINER:
356 case LYS_LIST:
357 case LYS_RPC:
358 case LYS_NOTIF:
359 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
360 LY_CHECK_RET(rc);
361 strcpy(*str + (*used - 1), "\n");
362 ++(*used);
363
364 for (child = lyd_node_children(node); child; child = child->next) {
365 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
366 LY_CHECK_RET(rc);
367 }
368
369 break;
370
371 case LYS_LEAF:
372 case LYS_LEAFLIST:
373 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
374
375 /* print indent */
376 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
377 if (rc != LY_SUCCESS) {
378 if (dynamic) {
379 free((char *)value_str);
380 }
381 return rc;
382 }
383 memset(*str + (*used - 1), ' ', indent * 2);
384 *used += indent * 2;
385
386 /* print value */
387 if (*used == 1) {
388 sprintf(*str + (*used - 1), "%s", value_str);
389 *used += strlen(value_str);
390 } else {
391 sprintf(*str + (*used - 1), "%s\n", value_str);
392 *used += strlen(value_str) + 1;
393 }
394 if (dynamic) {
395 free((char *)value_str);
396 }
397
398 break;
399
400 case LYS_ANYXML:
401 case LYS_ANYDATA:
402 any = (struct lyd_node_any *)node;
403 if (!(void *)any->value.tree) {
404 /* no content */
405 buf = strdup("");
406 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
407 } else {
408 switch (any->value_type) {
409 case LYD_ANYDATA_STRING:
410 case LYD_ANYDATA_XML:
411 case LYD_ANYDATA_JSON:
412 buf = strdup(any->value.json);
413 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
414 break;
415 case LYD_ANYDATA_DATATREE:
416 rc = lyd_print_mem(&buf, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
417 LY_CHECK_RET(rc);
418 break;
419 /* TODO case LYD_ANYDATA_LYB:
420 LOGERR(LYD_NODE_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
421 return -1;*/
422 }
423 }
424
425 line = strtok_r(buf, "\n", &ptr);
426 do {
427 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
428 if (rc != LY_SUCCESS) {
429 free(buf);
430 return rc;
431 }
432 memset(*str + (*used - 1), ' ', indent * 2);
433 *used += indent * 2;
434
435 strcpy(*str + (*used - 1), line);
436 *used += strlen(line);
437
438 strcpy(*str + (*used - 1), "\n");
439 *used += 1;
440 } while ((line = strtok_r(NULL, "\n", &ptr)));
441
442 free(buf);
443 break;
444
445 default:
446 LOGINT_RET(LYD_NODE_CTX(node));
447 }
448
449 if (fake_cont) {
450 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
451 LY_CHECK_RET(rc);
452 strcpy(*str + (*used - 1), "\n");
453 ++(*used);
454
455 --indent;
456 }
457
458 return LY_SUCCESS;
459}
460
461/**
462 * @brief Cast an element into a string.
463 *
464 * @param[in] node Node to cast.
465 * @param[in] fake_cont Whether to put the data into a "fake" container.
466 * @param[in] root_type Type of the XPath root.
467 * @param[out] str Element cast to dynamically-allocated string.
468 * @return LY_ERR
469 */
470static LY_ERR
471cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, char **str)
472{
473 uint16_t used, size;
474 LY_ERR rc;
475
476 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
477 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
478 (*str)[0] = '\0';
479 used = 1;
480 size = LYXP_STRING_CAST_SIZE_START;
481
482 rc = cast_string_recursive(node, fake_cont, root_type, 0, str, &used, &size);
483 if (rc != LY_SUCCESS) {
484 free(*str);
485 return rc;
486 }
487
488 if (size > used) {
489 *str = ly_realloc(*str, used * sizeof(char));
490 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
491 }
492 return LY_SUCCESS;
493}
494
495/**
496 * @brief Cast a LYXP_SET_NODE_SET set into a string.
497 * Context position aware.
498 *
499 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200500 * @param[out] str Cast dynamically-allocated string.
501 * @return LY_ERR
502 */
503static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100504cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200505{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200506 int dynamic;
507
Michal Vasko03ff5a72019-09-11 13:49:33 +0200508 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100509 case LYXP_NODE_NONE:
510 /* invalid */
511 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200512 case LYXP_NODE_ROOT:
513 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100514 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200515 case LYXP_NODE_ELEM:
516 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100517 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko9f96a052020-03-10 09:41:45 +0100518 case LYXP_NODE_META:
519 *str = (char *)lyd_meta2str(set->val.meta[0].meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200520 if (!dynamic) {
521 *str = strdup(*str);
522 if (!*str) {
523 LOGMEM_RET(set->ctx);
524 }
525 }
526 return LY_SUCCESS;
527 }
528
529 LOGINT_RET(set->ctx);
530}
531
532/**
533 * @brief Cast a string into an XPath number.
534 *
535 * @param[in] str String to use.
536 * @return Cast number.
537 */
538static long double
539cast_string_to_number(const char *str)
540{
541 long double num;
542 char *ptr;
543
544 errno = 0;
545 num = strtold(str, &ptr);
546 if (errno || *ptr) {
547 num = NAN;
548 }
549 return num;
550}
551
552/**
553 * @brief Callback for checking value equality.
554 *
555 * @param[in] val1_p First value.
556 * @param[in] val2_p Second value.
557 * @param[in] mod Whether hash table is being modified.
558 * @param[in] cb_data Callback data.
559 * @return 0 if not equal, non-zero if equal.
560 */
561static int
562set_values_equal_cb(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
563{
564 struct lyxp_set_hash_node *val1, *val2;
565
566 val1 = (struct lyxp_set_hash_node *)val1_p;
567 val2 = (struct lyxp_set_hash_node *)val2_p;
568
569 if ((val1->node == val2->node) && (val1->type == val2->type)) {
570 return 1;
571 }
572
573 return 0;
574}
575
576/**
577 * @brief Insert node and its hash into set.
578 *
579 * @param[in] set et to insert to.
580 * @param[in] node Node with hash.
581 * @param[in] type Node type.
582 */
583static void
584set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
585{
586 int r;
587 uint32_t i, hash;
588 struct lyxp_set_hash_node hnode;
589
590 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
591 /* create hash table and add all the nodes */
592 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
593 for (i = 0; i < set->used; ++i) {
594 hnode.node = set->val.nodes[i].node;
595 hnode.type = set->val.nodes[i].type;
596
597 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
598 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
599 hash = dict_hash_multi(hash, NULL, 0);
600
601 r = lyht_insert(set->ht, &hnode, hash, NULL);
602 assert(!r);
603 (void)r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200604
Michal Vasko9d6befd2019-12-11 14:56:56 +0100605 if (hnode.node == node) {
606 /* it was just added, do not add it twice */
607 node = NULL;
608 }
609 }
610 }
611
612 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200613 /* add the new node into hash table */
614 hnode.node = node;
615 hnode.type = type;
616
617 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
618 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
619 hash = dict_hash_multi(hash, NULL, 0);
620
621 r = lyht_insert(set->ht, &hnode, hash, NULL);
622 assert(!r);
623 (void)r;
624 }
625}
626
627/**
628 * @brief Remove node and its hash from set.
629 *
630 * @param[in] set Set to remove from.
631 * @param[in] node Node to remove.
632 * @param[in] type Node type.
633 */
634static void
635set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
636{
637 int r;
638 struct lyxp_set_hash_node hnode;
639 uint32_t hash;
640
641 if (set->ht) {
642 hnode.node = node;
643 hnode.type = type;
644
645 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
646 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
647 hash = dict_hash_multi(hash, NULL, 0);
648
649 r = lyht_remove(set->ht, &hnode, hash);
650 assert(!r);
651 (void)r;
652
653 if (!set->ht->used) {
654 lyht_free(set->ht);
655 set->ht = NULL;
656 }
657 }
658}
659
660/**
661 * @brief Check whether node is in set based on its hash.
662 *
663 * @param[in] set Set to search in.
664 * @param[in] node Node to search for.
665 * @param[in] type Node type.
666 * @param[in] skip_idx Index in @p set to skip.
667 * @return LY_ERR
668 */
669static LY_ERR
670set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
671{
672 struct lyxp_set_hash_node hnode, *match_p;
673 uint32_t hash;
674
675 hnode.node = node;
676 hnode.type = type;
677
678 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
679 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
680 hash = dict_hash_multi(hash, NULL, 0);
681
682 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
683 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
684 /* we found it on the index that should be skipped, find another */
685 hnode = *match_p;
686 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
687 /* none other found */
688 return LY_SUCCESS;
689 }
690 }
691
692 return LY_EEXIST;
693 }
694
695 /* not found */
696 return LY_SUCCESS;
697}
698
699/**
700 * @brief Free dynamic content of a set.
701 *
702 * @param[in] set Set to modify.
703 */
704static void
705set_free_content(struct lyxp_set *set)
706{
707 if (!set) {
708 return;
709 }
710
711 if (set->type == LYXP_SET_NODE_SET) {
712 free(set->val.nodes);
713 lyht_free(set->ht);
714 set->ht = NULL;
715 } else if (set->type == LYXP_SET_SCNODE_SET) {
716 free(set->val.scnodes);
717 } else if (set->type == LYXP_SET_STRING) {
718 free(set->val.str);
719 }
720 set->type = LYXP_SET_EMPTY;
721}
722
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100723/**
724 * @brief Free dynamically-allocated set.
725 *
726 * @param[in] set Set to free.
727 */
728static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200729lyxp_set_free(struct lyxp_set *set)
730{
731 if (!set) {
732 return;
733 }
734
735 set_free_content(set);
736 free(set);
737}
738
739/**
740 * @brief Initialize set context.
741 *
742 * @param[in] new Set to initialize.
743 * @param[in] set Arbitrary initialized set.
744 */
745static void
746set_init(struct lyxp_set *new, struct lyxp_set *set)
747{
748 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200749 if (set) {
750 new->ctx = set->ctx;
751 new->ctx_node = set->ctx_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100752 new->root_type = set->root_type;
Michal Vasko02a77382019-09-12 11:47:35 +0200753 new->local_mod = set->local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +0100754 new->tree = set->tree;
Michal Vasko02a77382019-09-12 11:47:35 +0200755 new->format = set->format;
756 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200757}
758
759/**
760 * @brief Create a deep copy of a set.
761 *
762 * @param[in] set Set to copy.
763 * @return Copy of @p set.
764 */
765static struct lyxp_set *
766set_copy(struct lyxp_set *set)
767{
768 struct lyxp_set *ret;
769 uint16_t i;
Michal Vaskoba716542019-12-16 10:01:58 +0100770 int idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200771
772 if (!set) {
773 return NULL;
774 }
775
776 ret = malloc(sizeof *ret);
777 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
778 set_init(ret, set);
779
780 if (set->type == LYXP_SET_SCNODE_SET) {
781 ret->type = set->type;
782
783 for (i = 0; i < set->used; ++i) {
Michal Vaskoba716542019-12-16 10:01:58 +0100784 if ((set->val.scnodes[i].in_ctx == 1) || (set->val.scnodes[i].in_ctx == -2)) {
785 idx = lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type);
Michal Vasko3f27c522020-01-06 08:37:49 +0100786 /* coverity seems to think scnodes can be NULL */
787 if ((idx == -1) || !ret->val.scnodes) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200788 lyxp_set_free(ret);
789 return NULL;
790 }
Michal Vaskoba716542019-12-16 10:01:58 +0100791 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200792 }
793 }
794 } else if (set->type == LYXP_SET_NODE_SET) {
795 ret->type = set->type;
796 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
797 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
798 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
799
800 ret->used = ret->size = set->used;
801 ret->ctx_pos = set->ctx_pos;
802 ret->ctx_size = set->ctx_size;
803 ret->ht = lyht_dup(set->ht);
804 } else {
805 memcpy(ret, set, sizeof *ret);
806 if (set->type == LYXP_SET_STRING) {
807 ret->val.str = strdup(set->val.str);
808 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
809 }
810 }
811
812 return ret;
813}
814
815/**
816 * @brief Fill XPath set with a string. Any current data are disposed of.
817 *
818 * @param[in] set Set to fill.
819 * @param[in] string String to fill into \p set.
820 * @param[in] str_len Length of \p string. 0 is a valid value!
821 */
822static void
823set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
824{
825 set_free_content(set);
826
827 set->type = LYXP_SET_STRING;
828 if ((str_len == 0) && (string[0] != '\0')) {
829 string = "";
830 }
831 set->val.str = strndup(string, str_len);
832}
833
834/**
835 * @brief Fill XPath set with a number. Any current data are disposed of.
836 *
837 * @param[in] set Set to fill.
838 * @param[in] number Number to fill into \p set.
839 */
840static void
841set_fill_number(struct lyxp_set *set, long double number)
842{
843 set_free_content(set);
844
845 set->type = LYXP_SET_NUMBER;
846 set->val.num = number;
847}
848
849/**
850 * @brief Fill XPath set with a boolean. Any current data are disposed of.
851 *
852 * @param[in] set Set to fill.
853 * @param[in] boolean Boolean to fill into \p set.
854 */
855static void
856set_fill_boolean(struct lyxp_set *set, int boolean)
857{
858 set_free_content(set);
859
860 set->type = LYXP_SET_BOOLEAN;
861 set->val.bool = boolean;
862}
863
864/**
865 * @brief Fill XPath set with the value from another set (deep assign).
866 * Any current data are disposed of.
867 *
868 * @param[in] trg Set to fill.
869 * @param[in] src Source set to copy into \p trg.
870 */
871static void
872set_fill_set(struct lyxp_set *trg, struct lyxp_set *src)
873{
874 if (!trg || !src) {
875 return;
876 }
877
878 if (trg->type == LYXP_SET_NODE_SET) {
879 free(trg->val.nodes);
880 } else if (trg->type == LYXP_SET_STRING) {
881 free(trg->val.str);
882 }
883 set_init(trg, src);
884
885 if (src->type == LYXP_SET_SCNODE_SET) {
886 trg->type = LYXP_SET_SCNODE_SET;
887 trg->used = src->used;
888 trg->size = src->used;
889
890 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
891 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
892 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
893 } else if (src->type == LYXP_SET_BOOLEAN) {
894 set_fill_boolean(trg, src->val.bool);
895 } else if (src->type == LYXP_SET_NUMBER) {
896 set_fill_number(trg, src->val.num);
897 } else if (src->type == LYXP_SET_STRING) {
898 set_fill_string(trg, src->val.str, strlen(src->val.str));
899 } else {
900 if (trg->type == LYXP_SET_NODE_SET) {
901 free(trg->val.nodes);
902 } else if (trg->type == LYXP_SET_STRING) {
903 free(trg->val.str);
904 }
905
906 if (src->type == LYXP_SET_EMPTY) {
907 trg->type = LYXP_SET_EMPTY;
908 } else {
909 assert(src->type == LYXP_SET_NODE_SET);
910
911 trg->type = LYXP_SET_NODE_SET;
912 trg->used = src->used;
913 trg->size = src->used;
914 trg->ctx_pos = src->ctx_pos;
915 trg->ctx_size = src->ctx_size;
916
917 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
918 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
919 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
Michal Vasko9b368d32020-02-14 13:53:31 +0100920 if (src->ht) {
921 trg->ht = lyht_dup(src->ht);
922 } else {
923 trg->ht = NULL;
924 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200925 }
926 }
927}
928
929/**
930 * @brief Clear context of all schema nodes.
931 *
932 * @param[in] set Set to clear.
933 */
934static void
935set_scnode_clear_ctx(struct lyxp_set *set)
936{
937 uint32_t i;
938
939 for (i = 0; i < set->used; ++i) {
940 if (set->val.scnodes[i].in_ctx == 1) {
941 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100942 } else if (set->val.scnodes[i].in_ctx == -2) {
943 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200944 }
945 }
946}
947
948/**
949 * @brief Remove a node from a set. Removing last node changes
950 * set into LYXP_SET_EMPTY. Context position aware.
951 *
952 * @param[in] set Set to use.
953 * @param[in] idx Index from @p set of the node to be removed.
954 */
955static void
956set_remove_node(struct lyxp_set *set, uint32_t idx)
957{
958 assert(set && (set->type == LYXP_SET_NODE_SET));
959 assert(idx < set->used);
960
961 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
962
963 --set->used;
964 if (set->used) {
965 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
966 (set->used - idx) * sizeof *set->val.nodes);
967 } else {
968 set_free_content(set);
969 set->type = LYXP_SET_EMPTY;
970 }
971}
972
973/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100974 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200975 *
976 * @param[in] set Set to use.
977 * @param[in] idx Index from @p set of the node to be removed.
978 */
979static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100980set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200981{
982 assert(set && (set->type == LYXP_SET_NODE_SET));
983 assert(idx < set->used);
984
Michal Vasko2caefc12019-11-14 16:07:56 +0100985 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
986 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
987 }
988 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200989}
990
991/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100992 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200993 * set into LYXP_SET_EMPTY. Context position aware.
994 *
995 * @param[in] set Set to consolidate.
996 */
997static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100998set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200999{
1000 uint16_t i, orig_used, end;
1001 int32_t start;
1002
Michal Vasko2caefc12019-11-14 16:07:56 +01001003 assert(set && (set->type != LYXP_SET_EMPTY));
Michal Vasko57eab132019-09-24 11:46:26 +02001004
1005 orig_used = set->used;
1006 set->used = 0;
1007 for (i = 0; i < orig_used;) {
1008 start = -1;
1009 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001010 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001011 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001012 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001013 end = i;
1014 ++i;
1015 break;
1016 }
1017
1018 ++i;
1019 if (i == orig_used) {
1020 end = i;
1021 }
1022 } while (i < orig_used);
1023
1024 if (start > -1) {
1025 /* move the whole chunk of valid nodes together */
1026 if (set->used != (unsigned)start) {
1027 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1028 }
1029 set->used += end - start;
1030 }
1031 }
1032
1033 if (!set->used) {
1034 set_free_content(set);
1035 /* this changes it to LYXP_SET_EMPTY */
1036 memset(set, 0, sizeof *set);
1037 }
1038}
1039
1040/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001041 * @brief Check for duplicates in a node set.
1042 *
1043 * @param[in] set Set to check.
1044 * @param[in] node Node to look for in @p set.
1045 * @param[in] node_type Type of @p node.
1046 * @param[in] skip_idx Index from @p set to skip.
1047 * @return LY_ERR
1048 */
1049static LY_ERR
1050set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1051{
1052 uint32_t i;
1053
Michal Vasko2caefc12019-11-14 16:07:56 +01001054 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001055 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1056 }
1057
1058 for (i = 0; i < set->used; ++i) {
1059 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1060 continue;
1061 }
1062
1063 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1064 return LY_EEXIST;
1065 }
1066 }
1067
1068 return LY_SUCCESS;
1069}
1070
Michal Vaskoecd62de2019-11-13 12:35:11 +01001071int
1072lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001073{
1074 uint32_t i;
1075
1076 for (i = 0; i < set->used; ++i) {
1077 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1078 continue;
1079 }
1080
1081 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1082 return i;
1083 }
1084 }
1085
1086 return -1;
1087}
1088
Michal Vaskoecd62de2019-11-13 12:35:11 +01001089void
1090lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001091{
1092 uint32_t orig_used, i, j;
1093
1094 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1095 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1096
1097 if (set2->type == LYXP_SET_EMPTY) {
1098 return;
1099 }
1100
1101 if (set1->type == LYXP_SET_EMPTY) {
1102 memcpy(set1, set2, sizeof *set1);
1103 return;
1104 }
1105
1106 if (set1->used + set2->used > set1->size) {
1107 set1->size = set1->used + set2->used;
1108 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1109 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1110 }
1111
1112 orig_used = set1->used;
1113
1114 for (i = 0; i < set2->used; ++i) {
1115 for (j = 0; j < orig_used; ++j) {
1116 /* detect duplicities */
1117 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1118 break;
1119 }
1120 }
1121
1122 if (j == orig_used) {
1123 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1124 ++set1->used;
1125 }
1126 }
1127
1128 set_free_content(set2);
1129 set2->type = LYXP_SET_EMPTY;
1130}
1131
1132/**
1133 * @brief Insert a node into a set. Context position aware.
1134 *
1135 * @param[in] set Set to use.
1136 * @param[in] node Node to insert to @p set.
1137 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1138 * @param[in] node_type Node type of @p node.
1139 * @param[in] idx Index in @p set to insert into.
1140 */
1141static void
1142set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1143{
1144 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1145
1146 if (set->type == LYXP_SET_EMPTY) {
1147 /* first item */
1148 if (idx) {
1149 /* no real harm done, but it is a bug */
1150 LOGINT(set->ctx);
1151 idx = 0;
1152 }
1153 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1154 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1155 set->type = LYXP_SET_NODE_SET;
1156 set->used = 0;
1157 set->size = LYXP_SET_SIZE_START;
1158 set->ctx_pos = 1;
1159 set->ctx_size = 1;
1160 set->ht = NULL;
1161 } else {
1162 /* not an empty set */
1163 if (set->used == set->size) {
1164
1165 /* set is full */
1166 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1167 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1168 set->size += LYXP_SET_SIZE_STEP;
1169 }
1170
1171 if (idx > set->used) {
1172 LOGINT(set->ctx);
1173 idx = set->used;
1174 }
1175
1176 /* make space for the new node */
1177 if (idx < set->used) {
1178 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1179 }
1180 }
1181
1182 /* finally assign the value */
1183 set->val.nodes[idx].node = (struct lyd_node *)node;
1184 set->val.nodes[idx].type = node_type;
1185 set->val.nodes[idx].pos = pos;
1186 ++set->used;
1187
Michal Vasko2caefc12019-11-14 16:07:56 +01001188 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1189 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1190 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001191}
1192
Michal Vaskoecd62de2019-11-13 12:35:11 +01001193int
1194lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001195{
1196 int ret;
1197
1198 assert(set->type == LYXP_SET_SCNODE_SET);
1199
Michal Vaskoecd62de2019-11-13 12:35:11 +01001200 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001201 if (ret > -1) {
1202 set->val.scnodes[ret].in_ctx = 1;
1203 } else {
1204 if (set->used == set->size) {
1205 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1206 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1207 set->size += LYXP_SET_SIZE_STEP;
1208 }
1209
1210 ret = set->used;
1211 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1212 set->val.scnodes[ret].type = node_type;
1213 set->val.scnodes[ret].in_ctx = 1;
1214 ++set->used;
1215 }
1216
1217 return ret;
1218}
1219
1220/**
1221 * @brief Replace a node in a set with another. Context position aware.
1222 *
1223 * @param[in] set Set to use.
1224 * @param[in] node Node to insert to @p set.
1225 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1226 * @param[in] node_type Node type of @p node.
1227 * @param[in] idx Index in @p set of the node to replace.
1228 */
1229static void
1230set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1231{
1232 assert(set && (idx < set->used));
1233
Michal Vasko2caefc12019-11-14 16:07:56 +01001234 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1235 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1236 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001237 set->val.nodes[idx].node = (struct lyd_node *)node;
1238 set->val.nodes[idx].type = node_type;
1239 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001240 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1241 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1242 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001243}
1244
1245/**
1246 * @brief Set all nodes with ctx 1 to a new unique context value.
1247 *
1248 * @param[in] set Set to modify.
1249 * @return New context value.
1250 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001251static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001252set_scnode_new_in_ctx(struct lyxp_set *set)
1253{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001254 uint32_t i;
1255 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001256
1257 assert(set->type == LYXP_SET_SCNODE_SET);
1258
1259 ret_ctx = 3;
1260retry:
1261 for (i = 0; i < set->used; ++i) {
1262 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1263 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1264 goto retry;
1265 }
1266 }
1267 for (i = 0; i < set->used; ++i) {
1268 if (set->val.scnodes[i].in_ctx == 1) {
1269 set->val.scnodes[i].in_ctx = ret_ctx;
1270 }
1271 }
1272
1273 return ret_ctx;
1274}
1275
1276/**
1277 * @brief Get unique @p node position in the data.
1278 *
1279 * @param[in] node Node to find.
1280 * @param[in] node_type Node type of @p node.
1281 * @param[in] root Root node.
1282 * @param[in] root_type Type of the XPath @p root node.
1283 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1284 * be used to increase efficiency and start the DFS from this node.
1285 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1286 * @return Node position.
1287 */
1288static uint32_t
1289get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1290 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1291{
1292 const struct lyd_node *next, *elem, *top_sibling;
1293 uint32_t pos = 1;
1294
1295 assert(prev && prev_pos && !root->prev->next);
1296
1297 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1298 return 0;
1299 }
1300
1301 if (*prev) {
1302 /* start from the previous element instead from the root */
1303 elem = next = *prev;
1304 pos = *prev_pos;
1305 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1306 goto dfs_search;
1307 }
1308
1309 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1310 /* TREE DFS */
1311 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1312dfs_search:
1313 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1314 goto skip_children;
1315 }
1316
1317 if (elem == node) {
1318 break;
1319 }
1320 ++pos;
1321
1322 /* TREE DFS END */
1323 /* select element for the next run - children first,
1324 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1325 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1326 next = NULL;
1327 } else {
1328 next = lyd_node_children(elem);
1329 }
1330 if (!next) {
1331skip_children:
1332 /* no children */
1333 if (elem == top_sibling) {
1334 /* we are done, root has no children */
1335 elem = NULL;
1336 break;
1337 }
1338 /* try siblings */
1339 next = elem->next;
1340 }
1341 while (!next) {
1342 /* no siblings, go back through parents */
1343 if (elem->parent == top_sibling->parent) {
1344 /* we are done, no next element to process */
1345 elem = NULL;
1346 break;
1347 }
1348 /* parent is already processed, go to its sibling */
1349 elem = (struct lyd_node *)elem->parent;
1350 next = elem->next;
1351 }
1352 }
1353
1354 /* node found */
1355 if (elem) {
1356 break;
1357 }
1358 }
1359
1360 if (!elem) {
1361 if (!(*prev)) {
1362 /* we went from root and failed to find it, cannot be */
1363 LOGINT(node->schema->module->ctx);
1364 return 0;
1365 } else {
1366 *prev = NULL;
1367 *prev_pos = 0;
1368
1369 elem = next = top_sibling = root;
1370 pos = 1;
1371 goto dfs_search;
1372 }
1373 }
1374
1375 /* remember the last found node for next time */
1376 *prev = node;
1377 *prev_pos = pos;
1378
1379 return pos;
1380}
1381
1382/**
1383 * @brief Assign (fill) missing node positions.
1384 *
1385 * @param[in] set Set to fill positions in.
1386 * @param[in] root Context root node.
1387 * @param[in] root_type Context root type.
1388 * @return LY_ERR
1389 */
1390static LY_ERR
1391set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1392{
1393 const struct lyd_node *prev = NULL, *tmp_node;
1394 uint32_t i, tmp_pos = 0;
1395
1396 for (i = 0; i < set->used; ++i) {
1397 if (!set->val.nodes[i].pos) {
1398 tmp_node = NULL;
1399 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001400 case LYXP_NODE_META:
1401 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001402 if (!tmp_node) {
1403 LOGINT_RET(root->schema->module->ctx);
1404 }
1405 /* fallthrough */
1406 case LYXP_NODE_ELEM:
1407 case LYXP_NODE_TEXT:
1408 if (!tmp_node) {
1409 tmp_node = set->val.nodes[i].node;
1410 }
1411 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1412 break;
1413 default:
1414 /* all roots have position 0 */
1415 break;
1416 }
1417 }
1418 }
1419
1420 return LY_SUCCESS;
1421}
1422
1423/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001424 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001425 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001426 * @param[in] meta Metadata to use.
1427 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001428 */
1429static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001430get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001431{
1432 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001433 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001434
Michal Vasko9f96a052020-03-10 09:41:45 +01001435 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001436 ++pos;
1437 }
1438
Michal Vasko9f96a052020-03-10 09:41:45 +01001439 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001440 return pos;
1441}
1442
1443/**
1444 * @brief Compare 2 nodes in respect to XPath document order.
1445 *
1446 * @param[in] item1 1st node.
1447 * @param[in] item2 2nd node.
1448 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1449 */
1450static int
1451set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1452{
Michal Vasko9f96a052020-03-10 09:41:45 +01001453 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001454
1455 if (item1->pos < item2->pos) {
1456 return -1;
1457 }
1458
1459 if (item1->pos > item2->pos) {
1460 return 1;
1461 }
1462
1463 /* node positions are equal, the fun case */
1464
1465 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1466 /* special case since text nodes are actually saved as their parents */
1467 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1468 if (item1->type == LYXP_NODE_ELEM) {
1469 assert(item2->type == LYXP_NODE_TEXT);
1470 return -1;
1471 } else {
1472 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1473 return 1;
1474 }
1475 }
1476
Michal Vasko9f96a052020-03-10 09:41:45 +01001477 /* we need meta positions now */
1478 if (item1->type == LYXP_NODE_META) {
1479 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001480 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001481 if (item2->type == LYXP_NODE_META) {
1482 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001483 }
1484
Michal Vasko9f96a052020-03-10 09:41:45 +01001485 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001486 /* check for duplicates */
1487 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001488 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001489 return 0;
1490 }
1491
Michal Vasko9f96a052020-03-10 09:41:45 +01001492 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001493 /* elem is always first, 2nd node is after it */
1494 if (item1->type == LYXP_NODE_ELEM) {
1495 assert(item2->type != LYXP_NODE_ELEM);
1496 return -1;
1497 }
1498
Michal Vasko9f96a052020-03-10 09:41:45 +01001499 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd META, 1st META - any pos - 2nd ELEM, 1st META - >pos> - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001500 /* 2nd is before 1st */
1501 if (((item1->type == LYXP_NODE_TEXT)
Michal Vasko9f96a052020-03-10 09:41:45 +01001502 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META)))
1503 || ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM))
1504 || (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META))
1505 && (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001506 return 1;
1507 }
1508
Michal Vasko9f96a052020-03-10 09:41:45 +01001509 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001510 /* 2nd is after 1st */
1511 return -1;
1512}
1513
1514/**
1515 * @brief Set cast for comparisons.
1516 *
1517 * @param[in] trg Target set to cast source into.
1518 * @param[in] src Source set.
1519 * @param[in] type Target set type.
1520 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001521 * @return LY_ERR
1522 */
1523static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001524set_comp_cast(struct lyxp_set *trg, struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001525{
1526 assert(src->type == LYXP_SET_NODE_SET);
1527
1528 set_init(trg, src);
1529
1530 /* insert node into target set */
1531 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1532
1533 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001534 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001535}
1536
1537#ifndef NDEBUG
1538
1539/**
1540 * @brief Bubble sort @p set into XPath document order.
1541 * Context position aware. Unused in the 'Release' build target.
1542 *
1543 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001544 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1545 */
1546static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001547set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001548{
1549 uint32_t i, j;
1550 int ret = 0, cmp, inverted, change;
1551 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001552 struct lyxp_set_node item;
1553 struct lyxp_set_hash_node hnode;
1554 uint64_t hash;
1555
1556 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1557 return 0;
1558 }
1559
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001560 /* find first top-level node to be used as anchor for positions */
1561 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1562 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001563
1564 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001565 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001566 return -1;
1567 }
1568
1569 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1570 print_set_debug(set);
1571
1572 for (i = 0; i < set->used; ++i) {
1573 inverted = 0;
1574 change = 0;
1575
1576 for (j = 1; j < set->used - i; ++j) {
1577 /* compare node positions */
1578 if (inverted) {
1579 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1580 } else {
1581 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1582 }
1583
1584 /* swap if needed */
1585 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1586 change = 1;
1587
1588 item = set->val.nodes[j - 1];
1589 set->val.nodes[j - 1] = set->val.nodes[j];
1590 set->val.nodes[j] = item;
1591 } else {
1592 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1593 inverted = !inverted;
1594 }
1595 }
1596
1597 ++ret;
1598
1599 if (!change) {
1600 break;
1601 }
1602 }
1603
1604 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1605 print_set_debug(set);
1606
1607 /* check node hashes */
1608 if (set->used >= LYD_HT_MIN_ITEMS) {
1609 assert(set->ht);
1610 for (i = 0; i < set->used; ++i) {
1611 hnode.node = set->val.nodes[i].node;
1612 hnode.type = set->val.nodes[i].type;
1613
1614 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1615 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1616 hash = dict_hash_multi(hash, NULL, 0);
1617
1618 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1619 }
1620 }
1621
1622 return ret - 1;
1623}
1624
1625/**
1626 * @brief Remove duplicate entries in a sorted node set.
1627 *
1628 * @param[in] set Sorted set to check.
1629 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1630 */
1631static LY_ERR
1632set_sorted_dup_node_clean(struct lyxp_set *set)
1633{
1634 uint32_t i = 0;
1635 LY_ERR ret = LY_SUCCESS;
1636
1637 if (set->used > 1) {
1638 while (i < set->used - 1) {
1639 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1640 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001641 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001642 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001643 }
Michal Vasko57eab132019-09-24 11:46:26 +02001644 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001645 }
1646 }
1647
Michal Vasko2caefc12019-11-14 16:07:56 +01001648 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001649 return ret;
1650}
1651
1652#endif
1653
1654/**
1655 * @brief Merge 2 sorted sets into one.
1656 *
1657 * @param[in,out] trg Set to merge into. Duplicates are removed.
1658 * @param[in] src Set to be merged into @p trg. It is cast to #LYXP_SET_EMPTY on success.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001659 * @return LY_ERR
1660 */
1661static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001662set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001663{
1664 uint32_t i, j, k, count, dup_count;
1665 int cmp;
1666 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001667
1668 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1669 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1670 return LY_EINVAL;
1671 }
1672
1673 if (src->type == LYXP_SET_EMPTY) {
1674 return LY_SUCCESS;
1675 } else if (trg->type == LYXP_SET_EMPTY) {
1676 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001677 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001678 return LY_SUCCESS;
1679 }
1680
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001681 /* find first top-level node to be used as anchor for positions */
1682 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1683 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001684
1685 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001686 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001687 return LY_EINT;
1688 }
1689
1690#ifndef NDEBUG
1691 LOGDBG(LY_LDGXPATH, "MERGE target");
1692 print_set_debug(trg);
1693 LOGDBG(LY_LDGXPATH, "MERGE source");
1694 print_set_debug(src);
1695#endif
1696
1697 /* make memory for the merge (duplicates are not detected yet, so space
1698 * will likely be wasted on them, too bad) */
1699 if (trg->size - trg->used < src->used) {
1700 trg->size = trg->used + src->used;
1701
1702 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1703 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1704 }
1705
1706 i = 0;
1707 j = 0;
1708 count = 0;
1709 dup_count = 0;
1710 do {
1711 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1712 if (!cmp) {
1713 if (!count) {
1714 /* duplicate, just skip it */
1715 ++i;
1716 ++j;
1717 } else {
1718 /* we are copying something already, so let's copy the duplicate too,
1719 * we are hoping that afterwards there are some more nodes to
1720 * copy and this way we can copy them all together */
1721 ++count;
1722 ++dup_count;
1723 ++i;
1724 ++j;
1725 }
1726 } else if (cmp < 0) {
1727 /* inserting src node into trg, just remember it for now */
1728 ++count;
1729 ++i;
1730
1731 /* insert the hash now */
1732 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1733 } else if (count) {
1734copy_nodes:
1735 /* time to actually copy the nodes, we have found the largest block of nodes */
1736 memmove(&trg->val.nodes[j + (count - dup_count)],
1737 &trg->val.nodes[j],
1738 (trg->used - j) * sizeof *trg->val.nodes);
1739 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1740
1741 trg->used += count - dup_count;
1742 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1743 j += count - dup_count;
1744
1745 count = 0;
1746 dup_count = 0;
1747 } else {
1748 ++j;
1749 }
1750 } while ((i < src->used) && (j < trg->used));
1751
1752 if ((i < src->used) || count) {
1753 /* insert all the hashes first */
1754 for (k = i; k < src->used; ++k) {
1755 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1756 }
1757
1758 /* loop ended, but we need to copy something at trg end */
1759 count += src->used - i;
1760 i = src->used;
1761 goto copy_nodes;
1762 }
1763
1764 /* we are inserting hashes before the actual node insert, which causes
1765 * situations when there were initially not enough items for a hash table,
1766 * but even after some were inserted, hash table was not created (during
1767 * insertion the number of items is not updated yet) */
1768 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1769 set_insert_node_hash(trg, NULL, 0);
1770 }
1771
1772#ifndef NDEBUG
1773 LOGDBG(LY_LDGXPATH, "MERGE result");
1774 print_set_debug(trg);
1775#endif
1776
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001777 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001778 return LY_SUCCESS;
1779}
1780
1781/*
1782 * (re)parse functions
1783 *
1784 * Parse functions parse the expression into
1785 * tokens (syntactic analysis).
1786 *
1787 * Reparse functions perform semantic analysis
1788 * (do not save the result, just a check) of
1789 * the expression and fill repeat indices.
1790 */
1791
1792/**
1793 * @brief Look at the next token and check its kind.
1794 *
1795 * @param[in] ctx Context for logging.
1796 * @param[in] exp Expression to use.
1797 * @param[in] exp_idx Position in the expression \p exp.
1798 * @param[in] want_tok Expected token.
1799 * @param[in] strict Whether the token is strictly required (print error if
1800 * not the next one) or we simply want to check whether it is the next or not.
1801 * @return LY_ERR
1802 */
1803static LY_ERR
1804exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1805{
1806 if (exp->used == exp_idx) {
1807 if (strict) {
1808 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1809 }
1810 return LY_EINVAL;
1811 }
1812
1813 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1814 if (strict) {
1815 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1816 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1817 }
1818 return LY_EINVAL;
1819 }
1820
1821 return LY_SUCCESS;
1822}
1823
1824/**
1825 * @brief Stack operation push on the repeat array.
1826 *
1827 * @param[in] exp Expression to use.
1828 * @param[in] exp_idx Position in the expresion \p exp.
1829 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1830 */
1831static void
1832exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1833{
1834 uint16_t i;
1835
1836 if (exp->repeat[exp_idx]) {
1837 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1838 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1839 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1840 exp->repeat[exp_idx][i] = repeat_op_idx;
1841 exp->repeat[exp_idx][i + 1] = 0;
1842 } else {
1843 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1844 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1845 exp->repeat[exp_idx][0] = repeat_op_idx;
1846 }
1847}
1848
1849/**
1850 * @brief Reparse Predicate. Logs directly on error.
1851 *
1852 * [7] Predicate ::= '[' Expr ']'
1853 *
1854 * @param[in] ctx Context for logging.
1855 * @param[in] exp Parsed XPath expression.
1856 * @param[in] exp_idx Position in the expression @p exp.
1857 * @return LY_ERR
1858 */
1859static LY_ERR
1860reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1861{
1862 LY_ERR rc;
1863
1864 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1865 LY_CHECK_RET(rc);
1866 ++(*exp_idx);
1867
1868 rc = reparse_or_expr(ctx, exp, exp_idx);
1869 LY_CHECK_RET(rc);
1870
1871 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1872 LY_CHECK_RET(rc);
1873 ++(*exp_idx);
1874
1875 return LY_SUCCESS;
1876}
1877
1878/**
1879 * @brief Reparse RelativeLocationPath. Logs directly on error.
1880 *
1881 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1882 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1883 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1884 *
1885 * @param[in] ctx Context for logging.
1886 * @param[in] exp Parsed XPath expression.
1887 * @param[in] exp_idx Position in the expression \p exp.
1888 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1889 */
1890static LY_ERR
1891reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1892{
1893 LY_ERR rc;
1894
1895 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1896 LY_CHECK_RET(rc);
1897
1898 goto step;
1899 do {
1900 /* '/' or '//' */
1901 ++(*exp_idx);
1902
1903 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1904 LY_CHECK_RET(rc);
1905step:
1906 /* Step */
1907 switch (exp->tokens[*exp_idx]) {
1908 case LYXP_TOKEN_DOT:
1909 ++(*exp_idx);
1910 break;
1911
1912 case LYXP_TOKEN_DDOT:
1913 ++(*exp_idx);
1914 break;
1915
1916 case LYXP_TOKEN_AT:
1917 ++(*exp_idx);
1918
1919 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1920 LY_CHECK_RET(rc);
1921 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1922 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1923 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1924 return LY_EVALID;
1925 }
1926 /* fall through */
1927 case LYXP_TOKEN_NAMETEST:
1928 ++(*exp_idx);
1929 goto reparse_predicate;
1930 break;
1931
1932 case LYXP_TOKEN_NODETYPE:
1933 ++(*exp_idx);
1934
1935 /* '(' */
1936 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1937 LY_CHECK_RET(rc);
1938 ++(*exp_idx);
1939
1940 /* ')' */
1941 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1942 LY_CHECK_RET(rc);
1943 ++(*exp_idx);
1944
1945reparse_predicate:
1946 /* Predicate* */
1947 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1948 rc = reparse_predicate(ctx, exp, exp_idx);
1949 LY_CHECK_RET(rc);
1950 }
1951 break;
1952 default:
1953 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1954 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1955 return LY_EVALID;
1956 }
1957 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1958
1959 return LY_SUCCESS;
1960}
1961
1962/**
1963 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1964 *
1965 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1966 *
1967 * @param[in] ctx Context for logging.
1968 * @param[in] exp Parsed XPath expression.
1969 * @param[in] exp_idx Position in the expression \p exp.
1970 * @return LY_ERR
1971 */
1972static LY_ERR
1973reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1974{
1975 LY_ERR rc;
1976
1977 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1978 LY_CHECK_RET(rc);
1979
1980 /* '/' RelativeLocationPath? */
1981 if (exp->tok_len[*exp_idx] == 1) {
1982 /* '/' */
1983 ++(*exp_idx);
1984
1985 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1986 return LY_SUCCESS;
1987 }
1988 switch (exp->tokens[*exp_idx]) {
1989 case LYXP_TOKEN_DOT:
1990 case LYXP_TOKEN_DDOT:
1991 case LYXP_TOKEN_AT:
1992 case LYXP_TOKEN_NAMETEST:
1993 case LYXP_TOKEN_NODETYPE:
1994 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1995 LY_CHECK_RET(rc);
1996 /* fall through */
1997 default:
1998 break;
1999 }
2000
2001 /* '//' RelativeLocationPath */
2002 } else {
2003 /* '//' */
2004 ++(*exp_idx);
2005
2006 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2007 LY_CHECK_RET(rc);
2008 }
2009
2010 return LY_SUCCESS;
2011}
2012
2013/**
2014 * @brief Reparse FunctionCall. Logs directly on error.
2015 *
2016 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2017 *
2018 * @param[in] ctx Context for logging.
2019 * @param[in] exp Parsed XPath expression.
2020 * @param[in] exp_idx Position in the expression @p exp.
2021 * @return LY_ERR
2022 */
2023static LY_ERR
2024reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2025{
2026 int min_arg_count = -1, max_arg_count, arg_count;
2027 uint16_t func_exp_idx;
2028 LY_ERR rc;
2029
2030 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2031 LY_CHECK_RET(rc);
2032 func_exp_idx = *exp_idx;
2033 switch (exp->tok_len[*exp_idx]) {
2034 case 3:
2035 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2036 min_arg_count = 1;
2037 max_arg_count = 1;
2038 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2039 min_arg_count = 1;
2040 max_arg_count = 1;
2041 }
2042 break;
2043 case 4:
2044 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2045 min_arg_count = 1;
2046 max_arg_count = 1;
2047 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2048 min_arg_count = 0;
2049 max_arg_count = 0;
2050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2051 min_arg_count = 0;
2052 max_arg_count = 1;
2053 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2054 min_arg_count = 0;
2055 max_arg_count = 0;
2056 }
2057 break;
2058 case 5:
2059 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2060 min_arg_count = 1;
2061 max_arg_count = 1;
2062 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2063 min_arg_count = 0;
2064 max_arg_count = 0;
2065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2066 min_arg_count = 1;
2067 max_arg_count = 1;
2068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2069 min_arg_count = 1;
2070 max_arg_count = 1;
2071 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2072 min_arg_count = 1;
2073 max_arg_count = 1;
2074 }
2075 break;
2076 case 6:
2077 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2078 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002079 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002080 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2081 min_arg_count = 0;
2082 max_arg_count = 1;
2083 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2084 min_arg_count = 0;
2085 max_arg_count = 1;
2086 }
2087 break;
2088 case 7:
2089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2090 min_arg_count = 1;
2091 max_arg_count = 1;
2092 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2093 min_arg_count = 1;
2094 max_arg_count = 1;
2095 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2096 min_arg_count = 0;
2097 max_arg_count = 0;
2098 }
2099 break;
2100 case 8:
2101 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2102 min_arg_count = 2;
2103 max_arg_count = 2;
2104 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2105 min_arg_count = 0;
2106 max_arg_count = 0;
2107 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2108 min_arg_count = 2;
2109 max_arg_count = 2;
2110 }
2111 break;
2112 case 9:
2113 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2114 min_arg_count = 2;
2115 max_arg_count = 3;
2116 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2117 min_arg_count = 3;
2118 max_arg_count = 3;
2119 }
2120 break;
2121 case 10:
2122 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2123 min_arg_count = 0;
2124 max_arg_count = 1;
2125 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2126 min_arg_count = 1;
2127 max_arg_count = 1;
2128 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2129 min_arg_count = 2;
2130 max_arg_count = 2;
2131 }
2132 break;
2133 case 11:
2134 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2135 min_arg_count = 2;
2136 max_arg_count = 2;
2137 }
2138 break;
2139 case 12:
2140 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2141 min_arg_count = 2;
2142 max_arg_count = 2;
2143 }
2144 break;
2145 case 13:
2146 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2147 min_arg_count = 0;
2148 max_arg_count = 1;
2149 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2150 min_arg_count = 0;
2151 max_arg_count = 1;
2152 }
2153 break;
2154 case 15:
2155 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2156 min_arg_count = 0;
2157 max_arg_count = 1;
2158 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2159 min_arg_count = 2;
2160 max_arg_count = 2;
2161 }
2162 break;
2163 case 16:
2164 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2165 min_arg_count = 2;
2166 max_arg_count = 2;
2167 }
2168 break;
2169 case 20:
2170 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2171 min_arg_count = 2;
2172 max_arg_count = 2;
2173 }
2174 break;
2175 }
2176 if (min_arg_count == -1) {
2177 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2178 return LY_EINVAL;
2179 }
2180 ++(*exp_idx);
2181
2182 /* '(' */
2183 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2184 LY_CHECK_RET(rc);
2185 ++(*exp_idx);
2186
2187 /* ( Expr ( ',' Expr )* )? */
2188 arg_count = 0;
2189 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2190 LY_CHECK_RET(rc);
2191 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2192 ++arg_count;
2193 rc = reparse_or_expr(ctx, exp, exp_idx);
2194 LY_CHECK_RET(rc);
2195 }
2196 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2197 ++(*exp_idx);
2198
2199 ++arg_count;
2200 rc = reparse_or_expr(ctx, exp, exp_idx);
2201 LY_CHECK_RET(rc);
2202 }
2203
2204 /* ')' */
2205 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2206 LY_CHECK_RET(rc);
2207 ++(*exp_idx);
2208
2209 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2210 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2211 &exp->expr[exp->tok_pos[func_exp_idx]]);
2212 return LY_EVALID;
2213 }
2214
2215 return LY_SUCCESS;
2216}
2217
2218/**
2219 * @brief Reparse PathExpr. Logs directly on error.
2220 *
2221 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2222 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2223 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2224 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2225 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2226 *
2227 * @param[in] ctx Context for logging.
2228 * @param[in] exp Parsed XPath expression.
2229 * @param[in] exp_idx Position in the expression @p exp.
2230 * @return LY_ERR
2231 */
2232static LY_ERR
2233reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2234{
2235 LY_ERR rc;
2236
2237 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2238 return -1;
2239 }
2240
2241 switch (exp->tokens[*exp_idx]) {
2242 case LYXP_TOKEN_PAR1:
2243 /* '(' Expr ')' Predicate* */
2244 ++(*exp_idx);
2245
2246 rc = reparse_or_expr(ctx, exp, exp_idx);
2247 LY_CHECK_RET(rc);
2248
2249 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2250 LY_CHECK_RET(rc);
2251 ++(*exp_idx);
2252 goto predicate;
2253 break;
2254 case LYXP_TOKEN_DOT:
2255 case LYXP_TOKEN_DDOT:
2256 case LYXP_TOKEN_AT:
2257 case LYXP_TOKEN_NAMETEST:
2258 case LYXP_TOKEN_NODETYPE:
2259 /* RelativeLocationPath */
2260 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2261 LY_CHECK_RET(rc);
2262 break;
2263 case LYXP_TOKEN_FUNCNAME:
2264 /* FunctionCall */
2265 rc = reparse_function_call(ctx, exp, exp_idx);
2266 LY_CHECK_RET(rc);
2267 goto predicate;
2268 break;
2269 case LYXP_TOKEN_OPERATOR_PATH:
2270 /* AbsoluteLocationPath */
2271 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2272 LY_CHECK_RET(rc);
2273 break;
2274 case LYXP_TOKEN_LITERAL:
2275 /* Literal */
2276 ++(*exp_idx);
2277 goto predicate;
2278 break;
2279 case LYXP_TOKEN_NUMBER:
2280 /* Number */
2281 ++(*exp_idx);
2282 goto predicate;
2283 break;
2284 default:
2285 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2286 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2287 return LY_EVALID;
2288 }
2289
2290 return LY_SUCCESS;
2291
2292predicate:
2293 /* Predicate* */
2294 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2295 rc = reparse_predicate(ctx, exp, exp_idx);
2296 LY_CHECK_RET(rc);
2297 }
2298
2299 /* ('/' or '//') RelativeLocationPath */
2300 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2301
2302 /* '/' or '//' */
2303 ++(*exp_idx);
2304
2305 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2306 LY_CHECK_RET(rc);
2307 }
2308
2309 return LY_SUCCESS;
2310}
2311
2312/**
2313 * @brief Reparse UnaryExpr. Logs directly on error.
2314 *
2315 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2316 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2317 *
2318 * @param[in] ctx Context for logging.
2319 * @param[in] exp Parsed XPath expression.
2320 * @param[in] exp_idx Position in the expression @p exp.
2321 * @return LY_ERR
2322 */
2323static LY_ERR
2324reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2325{
2326 uint16_t prev_exp;
2327 LY_ERR rc;
2328
2329 /* ('-')* */
2330 prev_exp = *exp_idx;
2331 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2332 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2333 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2334 ++(*exp_idx);
2335 }
2336
2337 /* PathExpr */
2338 prev_exp = *exp_idx;
2339 rc = reparse_path_expr(ctx, exp, exp_idx);
2340 LY_CHECK_RET(rc);
2341
2342 /* ('|' PathExpr)* */
2343 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2344 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2345 ++(*exp_idx);
2346
2347 rc = reparse_path_expr(ctx, exp, exp_idx);
2348 LY_CHECK_RET(rc);
2349 }
2350
2351 return LY_SUCCESS;
2352}
2353
2354/**
2355 * @brief Reparse AdditiveExpr. Logs directly on error.
2356 *
2357 * [15] AdditiveExpr ::= MultiplicativeExpr
2358 * | AdditiveExpr '+' MultiplicativeExpr
2359 * | AdditiveExpr '-' MultiplicativeExpr
2360 * [16] MultiplicativeExpr ::= UnaryExpr
2361 * | MultiplicativeExpr '*' UnaryExpr
2362 * | MultiplicativeExpr 'div' UnaryExpr
2363 * | MultiplicativeExpr 'mod' UnaryExpr
2364 *
2365 * @param[in] ctx Context for logging.
2366 * @param[in] exp Parsed XPath expression.
2367 * @param[in] exp_idx Position in the expression @p exp.
2368 * @return LY_ERR
2369 */
2370static LY_ERR
2371reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2372{
2373 uint16_t prev_add_exp, prev_mul_exp;
2374 LY_ERR rc;
2375
2376 prev_add_exp = *exp_idx;
2377 goto reparse_multiplicative_expr;
2378
2379 /* ('+' / '-' MultiplicativeExpr)* */
2380 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2381 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2382 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2383 ++(*exp_idx);
2384
2385reparse_multiplicative_expr:
2386 /* UnaryExpr */
2387 prev_mul_exp = *exp_idx;
2388 rc = reparse_unary_expr(ctx, exp, exp_idx);
2389 LY_CHECK_RET(rc);
2390
2391 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2392 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2393 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2394 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2395 ++(*exp_idx);
2396
2397 rc = reparse_unary_expr(ctx, exp, exp_idx);
2398 LY_CHECK_RET(rc);
2399 }
2400 }
2401
2402 return LY_SUCCESS;
2403}
2404
2405/**
2406 * @brief Reparse EqualityExpr. Logs directly on error.
2407 *
2408 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2409 * | EqualityExpr '!=' RelationalExpr
2410 * [14] RelationalExpr ::= AdditiveExpr
2411 * | RelationalExpr '<' AdditiveExpr
2412 * | RelationalExpr '>' AdditiveExpr
2413 * | RelationalExpr '<=' AdditiveExpr
2414 * | RelationalExpr '>=' AdditiveExpr
2415 *
2416 * @param[in] ctx Context for logging.
2417 * @param[in] exp Parsed XPath expression.
2418 * @param[in] exp_idx Position in the expression @p exp.
2419 * @return LY_ERR
2420 */
2421static LY_ERR
2422reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2423{
2424 uint16_t prev_eq_exp, prev_rel_exp;
2425 LY_ERR rc;
2426
2427 prev_eq_exp = *exp_idx;
2428 goto reparse_additive_expr;
2429
2430 /* ('=' / '!=' RelationalExpr)* */
2431 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2432 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2433 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2434 ++(*exp_idx);
2435
2436reparse_additive_expr:
2437 /* AdditiveExpr */
2438 prev_rel_exp = *exp_idx;
2439 rc = reparse_additive_expr(ctx, exp, exp_idx);
2440 LY_CHECK_RET(rc);
2441
2442 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2443 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2444 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2445 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2446 ++(*exp_idx);
2447
2448 rc = reparse_additive_expr(ctx, exp, exp_idx);
2449 LY_CHECK_RET(rc);
2450 }
2451 }
2452
2453 return LY_SUCCESS;
2454}
2455
2456/**
2457 * @brief Reparse OrExpr. Logs directly on error.
2458 *
2459 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2460 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2461 *
2462 * @param[in] ctx Context for logging.
2463 * @param[in] exp Parsed XPath expression.
2464 * @param[in] exp_idx Position in the expression @p exp.
2465 * @return LY_ERR
2466 */
2467static LY_ERR
2468reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2469{
2470 uint16_t prev_or_exp, prev_and_exp;
2471 LY_ERR rc;
2472
2473 prev_or_exp = *exp_idx;
2474 goto reparse_equality_expr;
2475
2476 /* ('or' AndExpr)* */
2477 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2478 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2479 ++(*exp_idx);
2480
2481reparse_equality_expr:
2482 /* EqualityExpr */
2483 prev_and_exp = *exp_idx;
2484 rc = reparse_equality_expr(ctx, exp, exp_idx);
2485 LY_CHECK_RET(rc);
2486
2487 /* ('and' EqualityExpr)* */
2488 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2489 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2490 ++(*exp_idx);
2491
2492 rc = reparse_equality_expr(ctx, exp, exp_idx);
2493 LY_CHECK_RET(rc);
2494 }
2495 }
2496
2497 return LY_SUCCESS;
2498}
Radek Krejcib1646a92018-11-02 16:08:26 +01002499
2500/**
2501 * @brief Parse NCName.
2502 *
2503 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002504 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002505 */
Radek Krejcid4270262019-01-07 15:07:25 +01002506static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002507parse_ncname(const char *ncname)
2508{
2509 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002510 size_t size;
2511 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002512
2513 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2514 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2515 return len;
2516 }
2517
2518 do {
2519 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002520 if (!*ncname) {
2521 break;
2522 }
Radek Krejcid4270262019-01-07 15:07:25 +01002523 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002524 } while (is_xmlqnamechar(uc) && (uc != ':'));
2525
2526 return len;
2527}
2528
2529/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002530 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002531 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002532 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002533 * @param[in] exp Expression to use.
2534 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002535 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002536 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002537 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002538 */
2539static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002540exp_add_token(struct ly_ctx *ctx, struct lyxp_expr *exp, enum lyxp_token token, uint16_t tok_pos, uint16_t tok_len)
Radek Krejcib1646a92018-11-02 16:08:26 +01002541{
2542 uint32_t prev;
2543
2544 if (exp->used == exp->size) {
2545 prev = exp->size;
2546 exp->size += LYXP_EXPR_SIZE_STEP;
2547 if (prev > exp->size) {
2548 LOGINT(ctx);
2549 return LY_EINT;
2550 }
2551
2552 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2553 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2554 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2555 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2556 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2557 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2558 }
2559
2560 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002561 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002562 exp->tok_len[exp->used] = tok_len;
2563 ++exp->used;
2564 return LY_SUCCESS;
2565}
2566
2567void
2568lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2569{
2570 uint16_t i;
2571
2572 if (!expr) {
2573 return;
2574 }
2575
2576 lydict_remove(ctx, expr->expr);
2577 free(expr->tokens);
2578 free(expr->tok_pos);
2579 free(expr->tok_len);
2580 if (expr->repeat) {
2581 for (i = 0; i < expr->used; ++i) {
2582 free(expr->repeat[i]);
2583 }
2584 }
2585 free(expr->repeat);
2586 free(expr);
2587}
2588
2589struct lyxp_expr *
2590lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2591{
2592 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002593 size_t parsed = 0, tok_len;
2594 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002595 enum lyxp_token tok_type;
2596 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002597 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002598
2599 if (strlen(expr) > UINT16_MAX) {
2600 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2601 return NULL;
2602 }
2603
2604 /* init lyxp_expr structure */
2605 ret = calloc(1, sizeof *ret);
2606 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2607 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2608 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2609 ret->used = 0;
2610 ret->size = LYXP_EXPR_SIZE_START;
2611 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2612 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2613
2614 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2615 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2616
2617 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2618 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2619
2620 while (is_xmlws(expr[parsed])) {
2621 ++parsed;
2622 }
2623
2624 do {
2625 if (expr[parsed] == '(') {
2626
2627 /* '(' */
2628 tok_len = 1;
2629 tok_type = LYXP_TOKEN_PAR1;
2630
2631 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2632 /* it is a NodeType/FunctionName after all */
2633 if (((ret->tok_len[ret->used - 1] == 4)
2634 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2635 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2636 ((ret->tok_len[ret->used - 1] == 7)
2637 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2638 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2639 } else {
2640 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2641 }
2642 prev_function_check = 0;
2643 }
2644
2645 } else if (expr[parsed] == ')') {
2646
2647 /* ')' */
2648 tok_len = 1;
2649 tok_type = LYXP_TOKEN_PAR2;
2650
2651 } else if (expr[parsed] == '[') {
2652
2653 /* '[' */
2654 tok_len = 1;
2655 tok_type = LYXP_TOKEN_BRACK1;
2656
2657 } else if (expr[parsed] == ']') {
2658
2659 /* ']' */
2660 tok_len = 1;
2661 tok_type = LYXP_TOKEN_BRACK2;
2662
2663 } else if (!strncmp(&expr[parsed], "..", 2)) {
2664
2665 /* '..' */
2666 tok_len = 2;
2667 tok_type = LYXP_TOKEN_DDOT;
2668
2669 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2670
2671 /* '.' */
2672 tok_len = 1;
2673 tok_type = LYXP_TOKEN_DOT;
2674
2675 } else if (expr[parsed] == '@') {
2676
2677 /* '@' */
2678 tok_len = 1;
2679 tok_type = LYXP_TOKEN_AT;
2680
2681 } else if (expr[parsed] == ',') {
2682
2683 /* ',' */
2684 tok_len = 1;
2685 tok_type = LYXP_TOKEN_COMMA;
2686
2687 } else if (expr[parsed] == '\'') {
2688
2689 /* Literal with ' */
2690 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2691 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2692 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2693 ++tok_len;
2694 tok_type = LYXP_TOKEN_LITERAL;
2695
2696 } else if (expr[parsed] == '\"') {
2697
2698 /* Literal with " */
2699 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2700 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2701 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2702 ++tok_len;
2703 tok_type = LYXP_TOKEN_LITERAL;
2704
2705 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2706
2707 /* Number */
2708 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2709 if (expr[parsed + tok_len] == '.') {
2710 ++tok_len;
2711 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2712 }
2713 tok_type = LYXP_TOKEN_NUMBER;
2714
2715 } else if (expr[parsed] == '/') {
2716
2717 /* Operator '/', '//' */
2718 if (!strncmp(&expr[parsed], "//", 2)) {
2719 tok_len = 2;
2720 } else {
2721 tok_len = 1;
2722 }
2723 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2724
2725 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2726 || !strncmp(&expr[parsed], ">=", 2)) {
2727
2728 /* Operator '!=', '<=', '>=' */
2729 tok_len = 2;
2730 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2731
2732 } else if (expr[parsed] == '|') {
2733
2734 /* Operator '|' */
2735 tok_len = 1;
2736 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2737
2738 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2739
2740 /* Operator '+', '-' */
2741 tok_len = 1;
2742 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2743
2744 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2745
2746 /* Operator '=', '<', '>' */
2747 tok_len = 1;
2748 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2749
2750 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2751 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2752 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2753 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2754 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2755 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2756 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2757 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2758 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2759
2760 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2761 if (expr[parsed] == '*') {
2762 tok_len = 1;
2763 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2764
2765 } else if (!strncmp(&expr[parsed], "or", 2)) {
2766 tok_len = 2;
2767 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2768
2769 } else if (!strncmp(&expr[parsed], "and", 3)) {
2770 tok_len = 3;
2771 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2772
2773 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2774 tok_len = 3;
2775 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2776
2777 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002778 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2779 expr[parsed], expr[parsed], ret->tok_len[ret->used - 1], &ret->expr[ret->tok_pos[ret->used - 1]]);
Radek Krejcib1646a92018-11-02 16:08:26 +01002780 goto error;
2781 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002782 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002783 goto error;
2784 }
2785 } else if (expr[parsed] == '*') {
2786
2787 /* NameTest '*' */
2788 tok_len = 1;
2789 tok_type = LYXP_TOKEN_NAMETEST;
2790
2791 } else {
2792
2793 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2794 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002795 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002796 tok_len = ncname_len;
2797
2798 if (expr[parsed + tok_len] == ':') {
2799 ++tok_len;
2800 if (expr[parsed + tok_len] == '*') {
2801 ++tok_len;
2802 } else {
2803 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002804 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002805 tok_len += ncname_len;
2806 }
2807 /* remove old flag to prevent ambiguities */
2808 prev_function_check = 0;
2809 tok_type = LYXP_TOKEN_NAMETEST;
2810 } else {
2811 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2812 prev_function_check = 1;
2813 tok_type = LYXP_TOKEN_NAMETEST;
2814 }
2815 }
2816
2817 /* store the token, move on to the next one */
2818 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2819 parsed += tok_len;
2820 while (is_xmlws(expr[parsed])) {
2821 ++parsed;
2822 }
2823
2824 } while (expr[parsed]);
2825
2826 /* prealloc repeat */
2827 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2828 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2829
Michal Vasko03ff5a72019-09-11 13:49:33 +02002830 /* fill repeat */
2831 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2832 if (ret->used > exp_idx) {
2833 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2834 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2835 &ret->expr[ret->tok_pos[exp_idx]]);
2836 goto error;
2837 }
2838
2839 print_expr_struct_debug(ret);
2840
Radek Krejcib1646a92018-11-02 16:08:26 +01002841 return ret;
2842
2843error:
2844 lyxp_expr_free(ctx, ret);
2845 return NULL;
2846}
2847
Michal Vasko03ff5a72019-09-11 13:49:33 +02002848/*
2849 * warn functions
2850 *
2851 * Warn functions check specific reasonable conditions for schema XPath
2852 * and print a warning if they are not satisfied.
2853 */
2854
2855/**
2856 * @brief Get the last-added schema node that is currently in the context.
2857 *
2858 * @param[in] set Set to search in.
2859 * @return Last-added schema context node, NULL if no node is in context.
2860 */
2861static struct lysc_node *
2862warn_get_scnode_in_ctx(struct lyxp_set *set)
2863{
2864 uint32_t i;
2865
2866 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2867 return NULL;
2868 }
2869
2870 i = set->used;
2871 do {
2872 --i;
2873 if (set->val.scnodes[i].in_ctx == 1) {
2874 /* if there are more, simply return the first found (last added) */
2875 return set->val.scnodes[i].scnode;
2876 }
2877 } while (i);
2878
2879 return NULL;
2880}
2881
2882/**
2883 * @brief Test whether a type is numeric - integer type or decimal64.
2884 *
2885 * @param[in] type Type to test.
2886 * @return 1 if numeric, 0 otherwise.
2887 */
2888static int
2889warn_is_numeric_type(struct lysc_type *type)
2890{
2891 struct lysc_type_union *uni;
2892 int ret;
2893 uint32_t i;
2894
2895 switch (type->basetype) {
2896 case LY_TYPE_DEC64:
2897 case LY_TYPE_INT8:
2898 case LY_TYPE_UINT8:
2899 case LY_TYPE_INT16:
2900 case LY_TYPE_UINT16:
2901 case LY_TYPE_INT32:
2902 case LY_TYPE_UINT32:
2903 case LY_TYPE_INT64:
2904 case LY_TYPE_UINT64:
2905 return 1;
2906 case LY_TYPE_UNION:
2907 uni = (struct lysc_type_union *)type;
2908 LY_ARRAY_FOR(uni->types, i) {
2909 ret = warn_is_numeric_type(uni->types[i]);
2910 if (ret) {
2911 /* found a suitable type */
2912 return 1;
2913 }
2914 }
2915 /* did not find any suitable type */
2916 return 0;
2917 case LY_TYPE_LEAFREF:
2918 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2919 default:
2920 return 0;
2921 }
2922}
2923
2924/**
2925 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2926 *
2927 * @param[in] type Type to test.
2928 * @return 1 if string, 0 otherwise.
2929 */
2930static int
2931warn_is_string_type(struct lysc_type *type)
2932{
2933 struct lysc_type_union *uni;
2934 int ret;
2935 uint32_t i;
2936
2937 switch (type->basetype) {
2938 case LY_TYPE_BITS:
2939 case LY_TYPE_ENUM:
2940 case LY_TYPE_IDENT:
2941 case LY_TYPE_INST:
2942 case LY_TYPE_STRING:
2943 return 1;
2944 case LY_TYPE_UNION:
2945 uni = (struct lysc_type_union *)type;
2946 LY_ARRAY_FOR(uni->types, i) {
2947 ret = warn_is_string_type(uni->types[i]);
2948 if (ret) {
2949 /* found a suitable type */
2950 return 1;
2951 }
2952 }
2953 /* did not find any suitable type */
2954 return 0;
2955 case LY_TYPE_LEAFREF:
2956 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2957 default:
2958 return 0;
2959 }
2960}
2961
2962/**
2963 * @brief Test whether a type is one specific type.
2964 *
2965 * @param[in] type Type to test.
2966 * @param[in] base Expected type.
2967 * @return 1 if it is, 0 otherwise.
2968 */
2969static int
2970warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2971{
2972 struct lysc_type_union *uni;
2973 int ret;
2974 uint32_t i;
2975
2976 if (type->basetype == base) {
2977 return 1;
2978 } else if (type->basetype == LY_TYPE_UNION) {
2979 uni = (struct lysc_type_union *)type;
2980 LY_ARRAY_FOR(uni->types, i) {
2981 ret = warn_is_specific_type(uni->types[i], base);
2982 if (ret) {
2983 /* found a suitable type */
2984 return 1;
2985 }
2986 }
2987 /* did not find any suitable type */
2988 return 0;
2989 } else if (type->basetype == LY_TYPE_LEAFREF) {
2990 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2991 }
2992
2993 return 0;
2994}
2995
2996/**
2997 * @brief Get next type of a (union) type.
2998 *
2999 * @param[in] type Base type.
3000 * @param[in] prev_type Previously returned type.
3001 * @return Next type or NULL.
3002 */
3003static struct lysc_type *
3004warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3005{
3006 struct lysc_type_union *uni;
3007 int found = 0;
3008 uint32_t i;
3009
3010 switch (type->basetype) {
3011 case LY_TYPE_UNION:
3012 uni = (struct lysc_type_union *)type;
3013 if (!prev_type) {
3014 return uni->types[0];
3015 }
3016 LY_ARRAY_FOR(uni->types, i) {
3017 if (found) {
3018 return uni->types[i];
3019 }
3020 if (prev_type == uni->types[i]) {
3021 found = 1;
3022 }
3023 }
3024 return NULL;
3025 default:
3026 if (prev_type) {
3027 assert(type == prev_type);
3028 return NULL;
3029 } else {
3030 return type;
3031 }
3032 }
3033}
3034
3035/**
3036 * @brief Test whether 2 types have a common type.
3037 *
3038 * @param[in] type1 First type.
3039 * @param[in] type2 Second type.
3040 * @return 1 if they do, 0 otherwise.
3041 */
3042static int
3043warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3044{
3045 struct lysc_type *t1, *rt1, *t2, *rt2;
3046
3047 t1 = NULL;
3048 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3049 if (t1->basetype == LY_TYPE_LEAFREF) {
3050 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3051 } else {
3052 rt1 = t1;
3053 }
3054
3055 t2 = NULL;
3056 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3057 if (t2->basetype == LY_TYPE_LEAFREF) {
3058 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3059 } else {
3060 rt2 = t2;
3061 }
3062
3063 if (rt2->basetype == rt1->basetype) {
3064 /* match found */
3065 return 1;
3066 }
3067 }
3068 }
3069
3070 return 0;
3071}
3072
3073/**
3074 * @brief Check both operands of comparison operators.
3075 *
3076 * @param[in] ctx Context for errors.
3077 * @param[in] set1 First operand set.
3078 * @param[in] set2 Second operand set.
3079 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3080 * @param[in] expr Start of the expression to print with the warning.
3081 * @param[in] tok_pos Token position.
3082 */
3083static void
3084warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3085{
3086 struct lysc_node_leaf *node1, *node2;
3087 int leaves = 1, warning = 0;
3088
3089 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3090 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3091
3092 if (!node1 && !node2) {
3093 /* no node-sets involved, nothing to do */
3094 return;
3095 }
3096
3097 if (node1) {
3098 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3099 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3100 warning = 1;
3101 leaves = 0;
3102 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3103 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3104 warning = 1;
3105 }
3106 }
3107
3108 if (node2) {
3109 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3110 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3111 warning = 1;
3112 leaves = 0;
3113 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3114 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3115 warning = 1;
3116 }
3117 }
3118
3119 if (node1 && node2 && leaves && !numbers_only) {
3120 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3121 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3122 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3123 && !warn_is_equal_type(node1->type, node2->type))) {
3124 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3125 warning = 1;
3126 }
3127 }
3128
3129 if (warning) {
3130 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3131 }
3132}
3133
3134/**
3135 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3136 *
3137 * @param[in] exp Parsed XPath expression.
3138 * @param[in] set Set with the leaf/leaf-list.
3139 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3140 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3141 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3142 */
3143static void
3144warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3145{
3146 struct lysc_node *scnode;
3147 struct lysc_type *type;
3148 char *value;
3149 LY_ERR rc;
3150 struct ly_err_item *err = NULL;
3151
3152 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3153 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3154 /* check that the node can have the specified value */
3155 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3156 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3157 } else {
3158 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3159 }
3160 if (!value) {
3161 LOGMEM(set->ctx);
3162 return;
3163 }
3164
3165 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3166 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3167 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3168 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3169 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3170 exp->expr + exp->tok_pos[equal_exp]);
3171 }
3172
3173 type = ((struct lysc_node_leaf *)scnode)->type;
3174 if (type->basetype != LY_TYPE_IDENT) {
3175 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3176 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3177
3178 if (err) {
3179 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3180 ly_err_free(err);
3181 } else if (rc != LY_SUCCESS) {
3182 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3183 }
3184 if (rc != LY_SUCCESS) {
3185 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3186 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3187 exp->expr + exp->tok_pos[equal_exp]);
3188 }
3189 }
3190 free(value);
3191 }
3192}
3193
3194/*
3195 * XPath functions
3196 */
3197
3198/**
3199 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3200 * depending on whether the first node bit value from the second argument is set.
3201 *
3202 * @param[in] args Array of arguments.
3203 * @param[in] arg_count Count of elements in @p args.
3204 * @param[in,out] set Context and result set at the same time.
3205 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003206 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003207 */
3208static LY_ERR
3209xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3210{
3211 struct lyd_node_term *leaf;
3212 struct lysc_node_leaf *sleaf;
3213 struct lysc_type_bits *bits;
3214 LY_ERR rc = LY_SUCCESS;
3215 uint32_t i;
3216
3217 if (options & LYXP_SCNODE_ALL) {
3218 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3219 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003220 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3221 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003222 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3223 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003224 }
3225
3226 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3227 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3228 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003229 } else if (!warn_is_string_type(sleaf->type)) {
3230 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003231 }
3232 }
3233 set_scnode_clear_ctx(set);
3234 return rc;
3235 }
3236
3237 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3238 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "bit-is-set(node-set, string)");
3239 return LY_EVALID;
3240 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003241 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003242 LY_CHECK_RET(rc);
3243
3244 set_fill_boolean(set, 0);
3245 if (args[0]->type == LYXP_SET_NODE_SET) {
3246 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3247 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3248 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3249 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
3250 LY_ARRAY_FOR(bits->bits, i) {
3251 if (!strcmp(bits->bits[i].name, args[1]->val.str)) {
3252 set_fill_boolean(set, 1);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258
3259 return LY_SUCCESS;
3260}
3261
3262/**
3263 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3264 * with the argument converted to boolean.
3265 *
3266 * @param[in] args Array of arguments.
3267 * @param[in] arg_count Count of elements in @p args.
3268 * @param[in,out] set Context and result set at the same time.
3269 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003270 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003271 */
3272static LY_ERR
3273xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3274{
3275 LY_ERR rc;
3276
3277 if (options & LYXP_SCNODE_ALL) {
3278 set_scnode_clear_ctx(set);
3279 return LY_SUCCESS;
3280 }
3281
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003282 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003283 LY_CHECK_RET(rc);
3284 set_fill_set(set, args[0]);
3285
3286 return LY_SUCCESS;
3287}
3288
3289/**
3290 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3291 * with the first argument rounded up to the nearest integer.
3292 *
3293 * @param[in] args Array of arguments.
3294 * @param[in] arg_count Count of elements in @p args.
3295 * @param[in,out] set Context and result set at the same time.
3296 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003297 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003298 */
3299static LY_ERR
3300xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3301{
3302 struct lysc_node_leaf *sleaf;
3303 LY_ERR rc = LY_SUCCESS;
3304
3305 if (options & LYXP_SCNODE_ALL) {
3306 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3307 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003308 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3309 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003310 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3311 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003312 }
3313 set_scnode_clear_ctx(set);
3314 return rc;
3315 }
3316
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003317 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003318 LY_CHECK_RET(rc);
3319 if ((long long)args[0]->val.num != args[0]->val.num) {
3320 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3321 } else {
3322 set_fill_number(set, args[0]->val.num);
3323 }
3324
3325 return LY_SUCCESS;
3326}
3327
3328/**
3329 * @brief Execute the XPath concat(string, string, string*) function.
3330 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3331 *
3332 * @param[in] args Array of arguments.
3333 * @param[in] arg_count Count of elements in @p args.
3334 * @param[in,out] set Context and result set at the same time.
3335 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003336 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003337 */
3338static LY_ERR
3339xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3340{
3341 uint16_t i;
3342 char *str = NULL;
3343 size_t used = 1;
3344 LY_ERR rc = LY_SUCCESS;
3345 struct lysc_node_leaf *sleaf;
3346
3347 if (options & LYXP_SCNODE_ALL) {
3348 for (i = 0; i < arg_count; ++i) {
3349 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3350 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3351 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3352 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003353 } else if (!warn_is_string_type(sleaf->type)) {
3354 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", __func__, i + 1, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003355 }
3356 }
3357 }
3358 set_scnode_clear_ctx(set);
3359 return rc;
3360 }
3361
3362 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003363 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003364 if (rc != LY_SUCCESS) {
3365 free(str);
3366 return rc;
3367 }
3368
3369 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3370 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3371 strcpy(str + used - 1, args[i]->val.str);
3372 used += strlen(args[i]->val.str);
3373 }
3374
3375 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003376 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003377 set->type = LYXP_SET_STRING;
3378 set->val.str = str;
3379
3380 return LY_SUCCESS;
3381}
3382
3383/**
3384 * @brief Execute the XPath contains(string, string) function.
3385 * Returns LYXP_SET_BOOLEAN whether the second argument can
3386 * be found in the first or not.
3387 *
3388 * @param[in] args Array of arguments.
3389 * @param[in] arg_count Count of elements in @p args.
3390 * @param[in,out] set Context and result set at the same time.
3391 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003392 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003393 */
3394static LY_ERR
3395xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3396{
3397 struct lysc_node_leaf *sleaf;
3398 LY_ERR rc = LY_SUCCESS;
3399
3400 if (options & LYXP_SCNODE_ALL) {
3401 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3402 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3403 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003404 } else if (!warn_is_string_type(sleaf->type)) {
3405 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003406 }
3407 }
3408
3409 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3410 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3411 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003412 } else if (!warn_is_string_type(sleaf->type)) {
3413 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003414 }
3415 }
3416 set_scnode_clear_ctx(set);
3417 return rc;
3418 }
3419
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003420 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003421 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003422 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003423 LY_CHECK_RET(rc);
3424
3425 if (strstr(args[0]->val.str, args[1]->val.str)) {
3426 set_fill_boolean(set, 1);
3427 } else {
3428 set_fill_boolean(set, 0);
3429 }
3430
3431 return LY_SUCCESS;
3432}
3433
3434/**
3435 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3436 * with the size of the node-set from the argument.
3437 *
3438 * @param[in] args Array of arguments.
3439 * @param[in] arg_count Count of elements in @p args.
3440 * @param[in,out] set Context and result set at the same time.
3441 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003442 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003443 */
3444static LY_ERR
3445xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3446{
3447 struct lysc_node *scnode = NULL;
3448 LY_ERR rc = LY_SUCCESS;
3449
3450 if (options & LYXP_SCNODE_ALL) {
3451 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3452 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003453 }
3454 set_scnode_clear_ctx(set);
3455 return rc;
3456 }
3457
3458 if (args[0]->type == LYXP_SET_EMPTY) {
3459 set_fill_number(set, 0);
3460 return LY_SUCCESS;
3461 }
3462
3463 if (args[0]->type != LYXP_SET_NODE_SET) {
3464 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3465 return LY_EVALID;
3466 }
3467
3468 set_fill_number(set, args[0]->used);
3469 return LY_SUCCESS;
3470}
3471
3472/**
3473 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3474 * with the context with the intial node.
3475 *
3476 * @param[in] args Array of arguments.
3477 * @param[in] arg_count Count of elements in @p args.
3478 * @param[in,out] set Context and result set at the same time.
3479 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003480 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003481 */
3482static LY_ERR
3483xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3484{
3485 if (arg_count || args) {
3486 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3487 return LY_EVALID;
3488 }
3489
3490 if (options & LYXP_SCNODE_ALL) {
3491 set_scnode_clear_ctx(set);
3492
Michal Vaskoecd62de2019-11-13 12:35:11 +01003493 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003494 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003495 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003496
3497 /* position is filled later */
3498 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3499 }
3500
3501 return LY_SUCCESS;
3502}
3503
3504/**
3505 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3506 * leafref or instance-identifier target node(s).
3507 *
3508 * @param[in] args Array of arguments.
3509 * @param[in] arg_count Count of elements in @p args.
3510 * @param[in,out] set Context and result set at the same time.
3511 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003512 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003513 */
3514static LY_ERR
3515xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3516{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003517 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003518 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003519 struct lysc_node_leaf *sleaf = NULL;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003520 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003521 const struct lyd_node *node;
3522 char *errmsg = NULL;
3523 const char *val;
3524 int dynamic;
3525 LY_ERR rc = LY_SUCCESS;
3526
3527 if (options & LYXP_SCNODE_ALL) {
3528 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3529 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003530 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3531 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003532 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3533 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3534 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003535 }
3536 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003537 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003538 cctx.ctx = set->ctx;
3539 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3540 /* it was already validated, it must succeed */
3541 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003542 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003543 }
3544 }
3545
Michal Vasko03ff5a72019-09-11 13:49:33 +02003546 return rc;
3547 }
3548
3549 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3550 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3551 return LY_EVALID;
3552 }
3553
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003554 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003555 if (args[0]->type != LYXP_SET_EMPTY) {
3556 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3557 sleaf = (struct lysc_node_leaf *)leaf->schema;
3558 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3559 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3560 /* find leafref target */
3561 val = lyd_value2str(leaf, &dynamic);
3562 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
Michal Vaskof03ed032020-03-04 13:31:44 +01003563 set->tree, &leaf->value, &errmsg);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003564 if (dynamic) {
3565 free((char *)val);
3566 }
3567 if (!node) {
3568 LOGERR(set->ctx, LY_EINVAL, errmsg);
3569 free(errmsg);
3570 return LY_EINVAL;
3571 }
3572
3573 /* insert it */
3574 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3575 } else {
3576 assert(sleaf->type->basetype == LY_TYPE_INST);
Michal Vaskof03ed032020-03-04 13:31:44 +01003577 node = (struct lyd_node *)lyd_target(leaf->value.target, set->tree);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003578 if (!node) {
3579 val = lyd_value2str(leaf, &dynamic);
3580 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3581 if (dynamic) {
3582 free((char *)val);
3583 }
3584 return LY_EVALID;
3585 }
3586 }
3587 }
3588 }
3589
3590 return LY_SUCCESS;
3591}
3592
3593/**
3594 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3595 * on whether the first argument nodes contain a node of an identity derived from the second
3596 * argument identity.
3597 *
3598 * @param[in] args Array of arguments.
3599 * @param[in] arg_count Count of elements in @p args.
3600 * @param[in,out] set Context and result set at the same time.
3601 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003602 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003603 */
3604static LY_ERR
3605xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3606{
3607 uint16_t i;
3608 struct lyd_node_term *leaf;
3609 struct lysc_node_leaf *sleaf;
3610 struct lyd_value data = {0};
3611 struct ly_err_item *err = NULL;
3612 LY_ERR rc = LY_SUCCESS;
3613 int found;
3614
3615 if (options & LYXP_SCNODE_ALL) {
3616 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3617 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003618 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3619 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003620 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3621 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003622 }
3623
3624 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3625 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3626 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003627 } else if (!warn_is_string_type(sleaf->type)) {
3628 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003629 }
3630 }
3631 set_scnode_clear_ctx(set);
3632 return rc;
3633 }
3634
3635 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3636 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3637 return LY_EVALID;
3638 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003639 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003640 LY_CHECK_RET(rc);
3641
3642 set_fill_boolean(set, 0);
3643 if (args[0]->type != LYXP_SET_EMPTY) {
3644 found = 0;
3645 for (i = 0; i < args[0]->used; ++i) {
3646 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3647 sleaf = (struct lysc_node_leaf *)leaf->schema;
3648 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3649 /* store args[1] into ident */
3650 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3651 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
Michal Vaskof03ed032020-03-04 13:31:44 +01003652 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003653 if (err) {
3654 ly_err_print(err);
3655 ly_err_free(err);
3656 }
3657 LY_CHECK_RET(rc);
3658
3659 LY_ARRAY_FOR(data.ident->derived, i) {
3660 if (data.ident->derived[i] == leaf->value.ident) {
3661 set_fill_boolean(set, 1);
3662 found = 1;
3663 break;
3664 }
3665 }
3666 if (found) {
3667 break;
3668 }
3669 }
3670 }
3671 }
3672
3673 return LY_SUCCESS;
3674}
3675
3676/**
3677 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3678 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3679 * the second argument identity.
3680 *
3681 * @param[in] args Array of arguments.
3682 * @param[in] arg_count Count of elements in @p args.
3683 * @param[in,out] set Context and result set at the same time.
3684 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003685 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003686 */
3687static LY_ERR
3688xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3689{
3690 uint16_t i;
3691 struct lyd_node_term *leaf;
3692 struct lysc_node_leaf *sleaf;
3693 struct lyd_value data = {0};
3694 struct ly_err_item *err = NULL;
3695 LY_ERR rc = LY_SUCCESS;
3696 int found;
3697
3698 if (options & LYXP_SCNODE_ALL) {
3699 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3700 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003701 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3702 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003703 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3704 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003705 }
3706
3707 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3708 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3709 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003710 } else if (!warn_is_string_type(sleaf->type)) {
3711 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003712 }
3713 }
3714 set_scnode_clear_ctx(set);
3715 return rc;
3716 }
3717
3718 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3719 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from-or-self(node-set, string)");
3720 return LY_EVALID;
3721 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003722 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003723 LY_CHECK_RET(rc);
3724
3725 set_fill_boolean(set, 0);
3726 if (args[0]->type != LYXP_SET_EMPTY) {
3727 found = 0;
3728 for (i = 0; i < args[0]->used; ++i) {
3729 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3730 sleaf = (struct lysc_node_leaf *)leaf->schema;
3731 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3732 /* store args[1] into ident */
3733 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3734 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
Michal Vaskof03ed032020-03-04 13:31:44 +01003735 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003736 if (err) {
3737 ly_err_print(err);
3738 ly_err_free(err);
3739 }
3740 LY_CHECK_RET(rc);
3741
3742 if (data.ident == leaf->value.ident) {
3743 set_fill_boolean(set, 1);
3744 break;
3745 }
3746 LY_ARRAY_FOR(data.ident->derived, i) {
3747 if (data.ident->derived[i] == leaf->value.ident) {
3748 set_fill_boolean(set, 1);
3749 found = 1;
3750 break;
3751 }
3752 }
3753 if (found) {
3754 break;
3755 }
3756 }
3757 }
3758 }
3759
3760 return LY_SUCCESS;
3761}
3762
3763/**
3764 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3765 * with the integer value of the first node's enum value, otherwise NaN.
3766 *
3767 * @param[in] args Array of arguments.
3768 * @param[in] arg_count Count of elements in @p args.
3769 * @param[in,out] set Context and result set at the same time.
3770 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003771 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003772 */
3773static LY_ERR
3774xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3775{
3776 struct lyd_node_term *leaf;
3777 struct lysc_node_leaf *sleaf;
3778 LY_ERR rc = LY_SUCCESS;
3779
3780 if (options & LYXP_SCNODE_ALL) {
3781 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3782 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003783 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3784 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003785 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3786 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003787 }
3788 set_scnode_clear_ctx(set);
3789 return rc;
3790 }
3791
3792 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3793 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3794 return LY_EVALID;
3795 }
3796
3797 set_fill_number(set, NAN);
3798 if (args[0]->type == LYXP_SET_NODE_SET) {
3799 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3800 sleaf = (struct lysc_node_leaf *)leaf->schema;
3801 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3802 set_fill_number(set, leaf->value.enum_item->value);
3803 }
3804 }
3805
3806 return LY_SUCCESS;
3807}
3808
3809/**
3810 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3811 * with false value.
3812 *
3813 * @param[in] args Array of arguments.
3814 * @param[in] arg_count Count of elements in @p args.
3815 * @param[in,out] set Context and result set at the same time.
3816 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003817 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003818 */
3819static LY_ERR
3820xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3821{
3822 if (options & LYXP_SCNODE_ALL) {
3823 set_scnode_clear_ctx(set);
3824 return LY_SUCCESS;
3825 }
3826
3827 set_fill_boolean(set, 0);
3828 return LY_SUCCESS;
3829}
3830
3831/**
3832 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3833 * with the first argument floored (truncated).
3834 *
3835 * @param[in] args Array of arguments.
3836 * @param[in] arg_count Count of elements in @p args.
3837 * @param[in,out] set Context and result set at the same time.
3838 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003839 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003840 */
3841static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003842xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003843{
3844 LY_ERR rc;
3845
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003846 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003847 LY_CHECK_RET(rc);
3848 if (isfinite(args[0]->val.num)) {
3849 set_fill_number(set, (long long)args[0]->val.num);
3850 }
3851
3852 return LY_SUCCESS;
3853}
3854
3855/**
3856 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3857 * whether the language of the text matches the one from the argument.
3858 *
3859 * @param[in] args Array of arguments.
3860 * @param[in] arg_count Count of elements in @p args.
3861 * @param[in,out] set Context and result set at the same time.
3862 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003863 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003864 */
3865static LY_ERR
3866xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3867{
3868 const struct lyd_node *node;
3869 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01003870 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003871 const char *val;
3872 int i, dynamic;
3873 LY_ERR rc = LY_SUCCESS;
3874
3875 if (options & LYXP_SCNODE_ALL) {
3876 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3877 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3878 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003879 } else if (!warn_is_string_type(sleaf->type)) {
3880 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003881 }
3882 }
3883 set_scnode_clear_ctx(set);
3884 return rc;
3885 }
3886
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003887 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003888 LY_CHECK_RET(rc);
3889
3890 if (set->type == LYXP_SET_EMPTY) {
3891 set_fill_boolean(set, 0);
3892 return LY_SUCCESS;
3893 }
3894 if (set->type != LYXP_SET_NODE_SET) {
3895 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3896 return LY_EVALID;
3897 }
3898
3899 switch (set->val.nodes[0].type) {
3900 case LYXP_NODE_ELEM:
3901 case LYXP_NODE_TEXT:
3902 node = set->val.nodes[0].node;
3903 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01003904 case LYXP_NODE_META:
3905 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003906 break;
3907 default:
3908 /* nothing to do with roots */
3909 set_fill_boolean(set, 0);
3910 return LY_SUCCESS;
3911 }
3912
Michal Vasko9f96a052020-03-10 09:41:45 +01003913 /* find lang metadata */
Michal Vasko03ff5a72019-09-11 13:49:33 +02003914 for (; node; node = (struct lyd_node *)node->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01003915 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003916 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01003917 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003918 break;
3919 }
3920 }
3921
Michal Vasko9f96a052020-03-10 09:41:45 +01003922 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003923 break;
3924 }
3925 }
3926
3927 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01003928 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003929 set_fill_boolean(set, 0);
3930 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01003931 val = lyd_meta2str(meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003932 for (i = 0; args[0]->val.str[i]; ++i) {
3933 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3934 set_fill_boolean(set, 0);
3935 break;
3936 }
3937 }
3938 if (!args[0]->val.str[i]) {
3939 if (!val[i] || (val[i] == '-')) {
3940 set_fill_boolean(set, 1);
3941 } else {
3942 set_fill_boolean(set, 0);
3943 }
3944 }
3945 if (dynamic) {
3946 free((char *)val);
3947 }
3948 }
3949
3950 return LY_SUCCESS;
3951}
3952
3953/**
3954 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3955 * with the context size.
3956 *
3957 * @param[in] args Array of arguments.
3958 * @param[in] arg_count Count of elements in @p args.
3959 * @param[in,out] set Context and result set at the same time.
3960 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003961 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003962 */
3963static LY_ERR
3964xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3965{
3966 if (options & LYXP_SCNODE_ALL) {
3967 set_scnode_clear_ctx(set);
3968 return LY_SUCCESS;
3969 }
3970
3971 if (set->type == LYXP_SET_EMPTY) {
3972 set_fill_number(set, 0);
3973 return LY_SUCCESS;
3974 }
3975 if (set->type != LYXP_SET_NODE_SET) {
3976 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3977 return LY_EVALID;
3978 }
3979
3980 set_fill_number(set, set->ctx_size);
3981 return LY_SUCCESS;
3982}
3983
3984/**
3985 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3986 * with the node name without namespace from the argument or the context.
3987 *
3988 * @param[in] args Array of arguments.
3989 * @param[in] arg_count Count of elements in @p args.
3990 * @param[in,out] set Context and result set at the same time.
3991 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003992 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003993 */
3994static LY_ERR
3995xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3996{
3997 struct lyxp_set_node *item;
3998 /* suppress unused variable warning */
3999 (void)options;
4000
4001 if (options & LYXP_SCNODE_ALL) {
4002 set_scnode_clear_ctx(set);
4003 return LY_SUCCESS;
4004 }
4005
4006 if (arg_count) {
4007 if (args[0]->type == LYXP_SET_EMPTY) {
4008 set_fill_string(set, "", 0);
4009 return LY_SUCCESS;
4010 }
4011 if (args[0]->type != LYXP_SET_NODE_SET) {
4012 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4013 return LY_EVALID;
4014 }
4015
4016 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004017 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004018
4019 item = &args[0]->val.nodes[0];
4020 } else {
4021 if (set->type == LYXP_SET_EMPTY) {
4022 set_fill_string(set, "", 0);
4023 return LY_SUCCESS;
4024 }
4025 if (set->type != LYXP_SET_NODE_SET) {
4026 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4027 return LY_EVALID;
4028 }
4029
4030 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004031 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004032
4033 item = &set->val.nodes[0];
4034 }
4035
4036 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004037 case LYXP_NODE_NONE:
4038 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004039 case LYXP_NODE_ROOT:
4040 case LYXP_NODE_ROOT_CONFIG:
4041 case LYXP_NODE_TEXT:
4042 set_fill_string(set, "", 0);
4043 break;
4044 case LYXP_NODE_ELEM:
4045 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4046 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004047 case LYXP_NODE_META:
4048 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004049 break;
4050 }
4051
4052 return LY_SUCCESS;
4053}
4054
4055/**
4056 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4057 * with the node name fully qualified (with namespace) from the argument or the context.
4058 *
4059 * @param[in] args Array of arguments.
4060 * @param[in] arg_count Count of elements in @p args.
4061 * @param[in,out] set Context and result set at the same time.
4062 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004063 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004064 */
4065static LY_ERR
4066xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4067{
4068 struct lyxp_set_node *item;
4069 struct lys_module *mod;
4070 char *str;
4071 const char *name;
4072 int rc;
4073
4074 if (options & LYXP_SCNODE_ALL) {
4075 set_scnode_clear_ctx(set);
4076 return LY_SUCCESS;
4077 }
4078
4079 if (arg_count) {
4080 if (args[0]->type == LYXP_SET_EMPTY) {
4081 set_fill_string(set, "", 0);
4082 return LY_SUCCESS;
4083 }
4084 if (args[0]->type != LYXP_SET_NODE_SET) {
4085 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4086 return LY_EVALID;
4087 }
4088
4089 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004090 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004091
4092 item = &args[0]->val.nodes[0];
4093 } else {
4094 if (set->type == LYXP_SET_EMPTY) {
4095 set_fill_string(set, "", 0);
4096 return LY_SUCCESS;
4097 }
4098 if (set->type != LYXP_SET_NODE_SET) {
4099 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4100 return LY_EVALID;
4101 }
4102
4103 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004104 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004105
4106 item = &set->val.nodes[0];
4107 }
4108
4109 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004110 case LYXP_NODE_NONE:
4111 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004112 case LYXP_NODE_ROOT:
4113 case LYXP_NODE_ROOT_CONFIG:
4114 case LYXP_NODE_TEXT:
4115 mod = NULL;
4116 name = NULL;
4117 break;
4118 case LYXP_NODE_ELEM:
4119 mod = item->node->schema->module;
4120 name = item->node->schema->name;
4121 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004122 case LYXP_NODE_META:
4123 mod = ((struct lyd_meta *)item->node)->annotation->module;
4124 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004125 break;
4126 }
4127
4128 if (mod && name) {
4129 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01004130 case LYD_SCHEMA:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004131 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4132 break;
4133 case LYD_JSON:
4134 rc = asprintf(&str, "%s:%s", mod->name, name);
4135 break;
Michal Vasko52927e22020-03-16 17:26:14 +01004136 case LYD_XML:
Michal Vasko9409ef62019-09-12 11:47:17 +02004137 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004138 }
4139 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4140 set_fill_string(set, str, strlen(str));
4141 free(str);
4142 } else {
4143 set_fill_string(set, "", 0);
4144 }
4145
4146 return LY_SUCCESS;
4147}
4148
4149/**
4150 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4151 * with the namespace of the node from the argument or the context.
4152 *
4153 * @param[in] args Array of arguments.
4154 * @param[in] arg_count Count of elements in @p args.
4155 * @param[in,out] set Context and result set at the same time.
4156 * @param[in] options XPath options.
4157 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4158 */
4159static LY_ERR
4160xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4161{
4162 struct lyxp_set_node *item;
4163 struct lys_module *mod;
4164 /* suppress unused variable warning */
4165 (void)options;
4166
4167 if (options & LYXP_SCNODE_ALL) {
4168 set_scnode_clear_ctx(set);
4169 return LY_SUCCESS;
4170 }
4171
4172 if (arg_count) {
4173 if (args[0]->type == LYXP_SET_EMPTY) {
4174 set_fill_string(set, "", 0);
4175 return LY_SUCCESS;
4176 }
4177 if (args[0]->type != LYXP_SET_NODE_SET) {
4178 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4179 return LY_EVALID;
4180 }
4181
4182 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004183 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004184
4185 item = &args[0]->val.nodes[0];
4186 } else {
4187 if (set->type == LYXP_SET_EMPTY) {
4188 set_fill_string(set, "", 0);
4189 return LY_SUCCESS;
4190 }
4191 if (set->type != LYXP_SET_NODE_SET) {
4192 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4193 return LY_EVALID;
4194 }
4195
4196 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004197 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004198
4199 item = &set->val.nodes[0];
4200 }
4201
4202 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004203 case LYXP_NODE_NONE:
4204 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004205 case LYXP_NODE_ROOT:
4206 case LYXP_NODE_ROOT_CONFIG:
4207 case LYXP_NODE_TEXT:
4208 set_fill_string(set, "", 0);
4209 break;
4210 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004211 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004212 if (item->type == LYXP_NODE_ELEM) {
4213 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004214 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004215 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004216 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004217 }
4218
4219 set_fill_string(set, mod->ns, strlen(mod->ns));
4220 break;
4221 }
4222
4223 return LY_SUCCESS;
4224}
4225
4226/**
4227 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4228 * with only nodes from the context. In practice it either leaves the context
4229 * as it is or returns an empty node set.
4230 *
4231 * @param[in] args Array of arguments.
4232 * @param[in] arg_count Count of elements in @p args.
4233 * @param[in,out] set Context and result set at the same time.
4234 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004235 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004236 */
4237static LY_ERR
4238xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4239{
4240 if (options & LYXP_SCNODE_ALL) {
4241 set_scnode_clear_ctx(set);
4242 return LY_SUCCESS;
4243 }
4244
4245 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004246 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004247 }
4248 return LY_SUCCESS;
4249}
4250
4251/**
4252 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4253 * with normalized value (no leading, trailing, double white spaces) of the node
4254 * from the argument or the context.
4255 *
4256 * @param[in] args Array of arguments.
4257 * @param[in] arg_count Count of elements in @p args.
4258 * @param[in,out] set Context and result set at the same time.
4259 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004260 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004261 */
4262static LY_ERR
4263xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4264{
4265 uint16_t i, new_used;
4266 char *new;
4267 int have_spaces = 0, space_before = 0;
4268 struct lysc_node_leaf *sleaf;
4269 LY_ERR rc = LY_SUCCESS;
4270
4271 if (options & LYXP_SCNODE_ALL) {
4272 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4273 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4274 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004275 } else if (!warn_is_string_type(sleaf->type)) {
4276 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004277 }
4278 }
4279 set_scnode_clear_ctx(set);
4280 return rc;
4281 }
4282
4283 if (arg_count) {
4284 set_fill_set(set, args[0]);
4285 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004286 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004287 LY_CHECK_RET(rc);
4288
4289 /* is there any normalization necessary? */
4290 for (i = 0; set->val.str[i]; ++i) {
4291 if (is_xmlws(set->val.str[i])) {
4292 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4293 have_spaces = 1;
4294 break;
4295 }
4296 space_before = 1;
4297 } else {
4298 space_before = 0;
4299 }
4300 }
4301
4302 /* yep, there is */
4303 if (have_spaces) {
4304 /* it's enough, at least one character will go, makes space for ending '\0' */
4305 new = malloc(strlen(set->val.str) * sizeof(char));
4306 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4307 new_used = 0;
4308
4309 space_before = 0;
4310 for (i = 0; set->val.str[i]; ++i) {
4311 if (is_xmlws(set->val.str[i])) {
4312 if ((i == 0) || space_before) {
4313 space_before = 1;
4314 continue;
4315 } else {
4316 space_before = 1;
4317 }
4318 } else {
4319 space_before = 0;
4320 }
4321
4322 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4323 ++new_used;
4324 }
4325
4326 /* at worst there is one trailing space now */
4327 if (new_used && is_xmlws(new[new_used - 1])) {
4328 --new_used;
4329 }
4330
4331 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4332 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4333 new[new_used] = '\0';
4334
4335 free(set->val.str);
4336 set->val.str = new;
4337 }
4338
4339 return LY_SUCCESS;
4340}
4341
4342/**
4343 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4344 * with the argument converted to boolean and logically inverted.
4345 *
4346 * @param[in] args Array of arguments.
4347 * @param[in] arg_count Count of elements in @p args.
4348 * @param[in,out] set Context and result set at the same time.
4349 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004350 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004351 */
4352static LY_ERR
4353xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4354{
4355 if (options & LYXP_SCNODE_ALL) {
4356 set_scnode_clear_ctx(set);
4357 return LY_SUCCESS;
4358 }
4359
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004360 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004361 if (args[0]->val.bool) {
4362 set_fill_boolean(set, 0);
4363 } else {
4364 set_fill_boolean(set, 1);
4365 }
4366
4367 return LY_SUCCESS;
4368}
4369
4370/**
4371 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4372 * with the number representation of either the argument or the context.
4373 *
4374 * @param[in] args Array of arguments.
4375 * @param[in] arg_count Count of elements in @p args.
4376 * @param[in,out] set Context and result set at the same time.
4377 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004378 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004379 */
4380static LY_ERR
4381xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4382{
4383 LY_ERR rc;
4384
4385 if (options & LYXP_SCNODE_ALL) {
4386 set_scnode_clear_ctx(set);
4387 return LY_SUCCESS;
4388 }
4389
4390 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004391 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004392 LY_CHECK_RET(rc);
4393 set_fill_set(set, args[0]);
4394 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004395 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004396 LY_CHECK_RET(rc);
4397 }
4398
4399 return LY_SUCCESS;
4400}
4401
4402/**
4403 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4404 * with the context position.
4405 *
4406 * @param[in] args Array of arguments.
4407 * @param[in] arg_count Count of elements in @p args.
4408 * @param[in,out] set Context and result set at the same time.
4409 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004410 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004411 */
4412static LY_ERR
4413xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4414{
4415 if (options & LYXP_SCNODE_ALL) {
4416 set_scnode_clear_ctx(set);
4417 return LY_SUCCESS;
4418 }
4419
4420 if (set->type == LYXP_SET_EMPTY) {
4421 set_fill_number(set, 0);
4422 return LY_SUCCESS;
4423 }
4424 if (set->type != LYXP_SET_NODE_SET) {
4425 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4426 return LY_EVALID;
4427 }
4428
4429 set_fill_number(set, set->ctx_pos);
4430
4431 /* UNUSED in 'Release' build type */
4432 (void)options;
4433 return LY_SUCCESS;
4434}
4435
4436/**
4437 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4438 * depending on whether the second argument regex matches the first argument string. For details refer to
4439 * YANG 1.1 RFC section 10.2.1.
4440 *
4441 * @param[in] args Array of arguments.
4442 * @param[in] arg_count Count of elements in @p args.
4443 * @param[in,out] set Context and result set at the same time.
4444 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004445 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004446 */
4447static LY_ERR
4448xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4449{
4450 struct lysc_pattern **patterns = NULL, **pattern;
4451 struct lysc_node_leaf *sleaf;
4452 char *path;
4453 LY_ERR rc = LY_SUCCESS;
4454 struct ly_err_item *err;
4455
4456 if (options & LYXP_SCNODE_ALL) {
4457 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4458 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4459 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004460 } else if (!warn_is_string_type(sleaf->type)) {
4461 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004462 }
4463 }
4464
4465 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4466 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4467 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004468 } else if (!warn_is_string_type(sleaf->type)) {
4469 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004470 }
4471 }
4472 set_scnode_clear_ctx(set);
4473 return rc;
4474 }
4475
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004476 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004477 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004478 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004479 LY_CHECK_RET(rc);
4480
4481 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4482 *pattern = malloc(sizeof **pattern);
4483 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4484 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4485 free(path);
4486 if (rc != LY_SUCCESS) {
4487 LY_ARRAY_FREE(patterns);
4488 return rc;
4489 }
4490
4491 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4492 pcre2_code_free((*pattern)->code);
4493 free(*pattern);
4494 LY_ARRAY_FREE(patterns);
4495 if (rc && (rc != LY_EVALID)) {
4496 ly_err_print(err);
4497 ly_err_free(err);
4498 return rc;
4499 }
4500
4501 if (rc == LY_EVALID) {
4502 ly_err_free(err);
4503 set_fill_boolean(set, 0);
4504 } else {
4505 set_fill_boolean(set, 1);
4506 }
4507
4508 return LY_SUCCESS;
4509}
4510
4511/**
4512 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4513 * with the rounded first argument. For details refer to
4514 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4515 *
4516 * @param[in] args Array of arguments.
4517 * @param[in] arg_count Count of elements in @p args.
4518 * @param[in,out] set Context and result set at the same time.
4519 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004520 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004521 */
4522static LY_ERR
4523xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4524{
4525 struct lysc_node_leaf *sleaf;
4526 LY_ERR rc = LY_SUCCESS;
4527
4528 if (options & LYXP_SCNODE_ALL) {
4529 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4530 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004531 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4532 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004533 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4534 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004535 }
4536 set_scnode_clear_ctx(set);
4537 return rc;
4538 }
4539
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004540 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004541 LY_CHECK_RET(rc);
4542
4543 /* cover only the cases where floor can't be used */
4544 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4545 set_fill_number(set, -0.0f);
4546 } else {
4547 args[0]->val.num += 0.5;
4548 rc = xpath_floor(args, 1, args[0], options);
4549 LY_CHECK_RET(rc);
4550 set_fill_number(set, args[0]->val.num);
4551 }
4552
4553 return LY_SUCCESS;
4554}
4555
4556/**
4557 * @brief Execute the XPath starts-with(string, string) function.
4558 * Returns LYXP_SET_BOOLEAN whether the second argument is
4559 * the prefix of the first or not.
4560 *
4561 * @param[in] args Array of arguments.
4562 * @param[in] arg_count Count of elements in @p args.
4563 * @param[in,out] set Context and result set at the same time.
4564 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004565 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004566 */
4567static LY_ERR
4568xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4569{
4570 struct lysc_node_leaf *sleaf;
4571 LY_ERR rc = LY_SUCCESS;
4572
4573 if (options & LYXP_SCNODE_ALL) {
4574 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4575 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4576 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004577 } else if (!warn_is_string_type(sleaf->type)) {
4578 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004579 }
4580 }
4581
4582 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4583 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4584 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004585 } else if (!warn_is_string_type(sleaf->type)) {
4586 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004587 }
4588 }
4589 set_scnode_clear_ctx(set);
4590 return rc;
4591 }
4592
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004593 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004594 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004595 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004596 LY_CHECK_RET(rc);
4597
4598 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4599 set_fill_boolean(set, 0);
4600 } else {
4601 set_fill_boolean(set, 1);
4602 }
4603
4604 return LY_SUCCESS;
4605}
4606
4607/**
4608 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4609 * with the string representation of either the argument or the context.
4610 *
4611 * @param[in] args Array of arguments.
4612 * @param[in] arg_count Count of elements in @p args.
4613 * @param[in,out] set Context and result set at the same time.
4614 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004615 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004616 */
4617static LY_ERR
4618xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4619{
4620 LY_ERR rc;
4621
4622 if (options & LYXP_SCNODE_ALL) {
4623 set_scnode_clear_ctx(set);
4624 return LY_SUCCESS;
4625 }
4626
4627 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004628 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004629 LY_CHECK_RET(rc);
4630 set_fill_set(set, args[0]);
4631 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004632 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004633 LY_CHECK_RET(rc);
4634 }
4635
4636 return LY_SUCCESS;
4637}
4638
4639/**
4640 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4641 * with the length of the string in either the argument or the context.
4642 *
4643 * @param[in] args Array of arguments.
4644 * @param[in] arg_count Count of elements in @p args.
4645 * @param[in,out] set Context and result set at the same time.
4646 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004647 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004648 */
4649static LY_ERR
4650xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4651{
4652 struct lysc_node_leaf *sleaf;
4653 LY_ERR rc = LY_SUCCESS;
4654
4655 if (options & LYXP_SCNODE_ALL) {
4656 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4657 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4658 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004659 } else if (!warn_is_string_type(sleaf->type)) {
4660 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004661 }
4662 }
4663 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4664 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4665 LOGWRN(set->ctx, "Argument #0 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004666 } else if (!warn_is_string_type(sleaf->type)) {
4667 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004668 }
4669 }
4670 set_scnode_clear_ctx(set);
4671 return rc;
4672 }
4673
4674 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004675 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004676 LY_CHECK_RET(rc);
4677 set_fill_number(set, strlen(args[0]->val.str));
4678 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004679 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004680 LY_CHECK_RET(rc);
4681 set_fill_number(set, strlen(set->val.str));
4682 }
4683
4684 return LY_SUCCESS;
4685}
4686
4687/**
4688 * @brief Execute the XPath substring(string, number, number?) function.
4689 * Returns LYXP_SET_STRING substring of the first argument starting
4690 * on the second argument index ending on the third argument index,
4691 * indexed from 1. For exact definition refer to
4692 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4693 *
4694 * @param[in] args Array of arguments.
4695 * @param[in] arg_count Count of elements in @p args.
4696 * @param[in,out] set Context and result set at the same time.
4697 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004698 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004699 */
4700static LY_ERR
4701xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4702{
4703 int start, len;
4704 uint16_t str_start, str_len, pos;
4705 struct lysc_node_leaf *sleaf;
4706 LY_ERR rc = LY_SUCCESS;
4707
4708 if (options & LYXP_SCNODE_ALL) {
4709 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4710 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4711 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004712 } else if (!warn_is_string_type(sleaf->type)) {
4713 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004714 }
4715 }
4716
4717 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4718 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4719 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004720 } else if (!warn_is_numeric_type(sleaf->type)) {
4721 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004722 }
4723 }
4724
4725 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4726 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4727 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4728 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004729 } else if (!warn_is_numeric_type(sleaf->type)) {
4730 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004731 }
4732 }
4733 set_scnode_clear_ctx(set);
4734 return rc;
4735 }
4736
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004737 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004738 LY_CHECK_RET(rc);
4739
4740 /* start */
4741 if (xpath_round(&args[1], 1, args[1], options)) {
4742 return -1;
4743 }
4744 if (isfinite(args[1]->val.num)) {
4745 start = args[1]->val.num - 1;
4746 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4747 start = INT_MIN;
4748 } else {
4749 start = INT_MAX;
4750 }
4751
4752 /* len */
4753 if (arg_count == 3) {
4754 rc = xpath_round(&args[2], 1, args[2], options);
4755 LY_CHECK_RET(rc);
4756 if (isfinite(args[2]->val.num)) {
4757 len = args[2]->val.num;
4758 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4759 len = 0;
4760 } else {
4761 len = INT_MAX;
4762 }
4763 } else {
4764 len = INT_MAX;
4765 }
4766
4767 /* find matching character positions */
4768 str_start = 0;
4769 str_len = 0;
4770 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4771 if (pos < start) {
4772 ++str_start;
4773 } else if (pos < start + len) {
4774 ++str_len;
4775 } else {
4776 break;
4777 }
4778 }
4779
4780 set_fill_string(set, args[0]->val.str + str_start, str_len);
4781 return LY_SUCCESS;
4782}
4783
4784/**
4785 * @brief Execute the XPath substring-after(string, string) function.
4786 * Returns LYXP_SET_STRING with the string succeeding the occurance
4787 * of the second argument in the first or an empty string.
4788 *
4789 * @param[in] args Array of arguments.
4790 * @param[in] arg_count Count of elements in @p args.
4791 * @param[in,out] set Context and result set at the same time.
4792 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004793 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004794 */
4795static LY_ERR
4796xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4797{
4798 char *ptr;
4799 struct lysc_node_leaf *sleaf;
4800 LY_ERR rc = LY_SUCCESS;
4801
4802 if (options & LYXP_SCNODE_ALL) {
4803 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4804 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4805 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004806 } else if (!warn_is_string_type(sleaf->type)) {
4807 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004808 }
4809 }
4810
4811 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4812 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4813 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004814 } else if (!warn_is_string_type(sleaf->type)) {
4815 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004816 }
4817 }
4818 set_scnode_clear_ctx(set);
4819 return rc;
4820 }
4821
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004822 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004823 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004824 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004825 LY_CHECK_RET(rc);
4826
4827 ptr = strstr(args[0]->val.str, args[1]->val.str);
4828 if (ptr) {
4829 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4830 } else {
4831 set_fill_string(set, "", 0);
4832 }
4833
4834 return LY_SUCCESS;
4835}
4836
4837/**
4838 * @brief Execute the XPath substring-before(string, string) function.
4839 * Returns LYXP_SET_STRING with the string preceding the occurance
4840 * of the second argument in the first or an empty string.
4841 *
4842 * @param[in] args Array of arguments.
4843 * @param[in] arg_count Count of elements in @p args.
4844 * @param[in,out] set Context and result set at the same time.
4845 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004846 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004847 */
4848static LY_ERR
4849xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4850{
4851 char *ptr;
4852 struct lysc_node_leaf *sleaf;
4853 LY_ERR rc = LY_SUCCESS;
4854
4855 if (options & LYXP_SCNODE_ALL) {
4856 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4857 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4858 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004859 } else if (!warn_is_string_type(sleaf->type)) {
4860 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004861 }
4862 }
4863
4864 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4865 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4866 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004867 } else if (!warn_is_string_type(sleaf->type)) {
4868 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004869 }
4870 }
4871 set_scnode_clear_ctx(set);
4872 return rc;
4873 }
4874
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004875 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004876 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004877 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004878 LY_CHECK_RET(rc);
4879
4880 ptr = strstr(args[0]->val.str, args[1]->val.str);
4881 if (ptr) {
4882 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4883 } else {
4884 set_fill_string(set, "", 0);
4885 }
4886
4887 return LY_SUCCESS;
4888}
4889
4890/**
4891 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4892 * with the sum of all the nodes in the context.
4893 *
4894 * @param[in] args Array of arguments.
4895 * @param[in] arg_count Count of elements in @p args.
4896 * @param[in,out] set Context and result set at the same time.
4897 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004898 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004899 */
4900static LY_ERR
4901xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4902{
4903 long double num;
4904 char *str;
4905 uint16_t i;
4906 struct lyxp_set set_item;
4907 struct lysc_node_leaf *sleaf;
4908 LY_ERR rc = LY_SUCCESS;
4909
4910 if (options & LYXP_SCNODE_ALL) {
4911 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4912 for (i = 0; i < args[0]->used; ++i) {
4913 if (args[0]->val.scnodes[i].in_ctx == 1) {
4914 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4915 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4916 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4917 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004918 } else if (!warn_is_numeric_type(sleaf->type)) {
4919 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004920 }
4921 }
4922 }
4923 }
4924 set_scnode_clear_ctx(set);
4925 return rc;
4926 }
4927
4928 set_fill_number(set, 0);
4929 if (args[0]->type == LYXP_SET_EMPTY) {
4930 return LY_SUCCESS;
4931 }
4932
4933 if (args[0]->type != LYXP_SET_NODE_SET) {
4934 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4935 return LY_EVALID;
4936 }
4937
Michal Vasko5c4e5892019-11-14 12:31:38 +01004938 set_init(&set_item, set);
4939
Michal Vasko03ff5a72019-09-11 13:49:33 +02004940 set_item.type = LYXP_SET_NODE_SET;
4941 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4942 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4943
4944 set_item.used = 1;
4945 set_item.size = 1;
4946
4947 for (i = 0; i < args[0]->used; ++i) {
4948 set_item.val.nodes[0] = args[0]->val.nodes[i];
4949
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004950 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004951 LY_CHECK_RET(rc);
4952 num = cast_string_to_number(str);
4953 free(str);
4954 set->val.num += num;
4955 }
4956
4957 free(set_item.val.nodes);
4958
4959 return LY_SUCCESS;
4960}
4961
4962/**
4963 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4964 * with the text content of the nodes in the context.
4965 *
4966 * @param[in] args Array of arguments.
4967 * @param[in] arg_count Count of elements in @p args.
4968 * @param[in,out] set Context and result set at the same time.
4969 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004970 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004971 */
4972static LY_ERR
4973xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4974{
4975 uint32_t i;
4976
4977 if (options & LYXP_SCNODE_ALL) {
4978 set_scnode_clear_ctx(set);
4979 return LY_SUCCESS;
4980 }
4981
4982 if (set->type == LYXP_SET_EMPTY) {
4983 return LY_SUCCESS;
4984 }
4985 if (set->type != LYXP_SET_NODE_SET) {
4986 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4987 return LY_EVALID;
4988 }
4989
4990 for (i = 0; i < set->used;) {
4991 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004992 case LYXP_NODE_NONE:
4993 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004994 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004995 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4996 set->val.nodes[i].type = LYXP_NODE_TEXT;
4997 ++i;
4998 break;
4999 }
5000 /* fall through */
5001 case LYXP_NODE_ROOT:
5002 case LYXP_NODE_ROOT_CONFIG:
5003 case LYXP_NODE_TEXT:
Michal Vasko9f96a052020-03-10 09:41:45 +01005004 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02005005 set_remove_node(set, i);
5006 break;
5007 }
5008 }
5009
5010 return LY_SUCCESS;
5011}
5012
5013/**
5014 * @brief Execute the XPath translate(string, string, string) function.
5015 * Returns LYXP_SET_STRING with the first argument with the characters
5016 * from the second argument replaced by those on the corresponding
5017 * positions in the third argument.
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.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005023 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005024 */
5025static LY_ERR
5026xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5027{
5028 uint16_t i, j, new_used;
5029 char *new;
5030 int found, have_removed;
5031 struct lysc_node_leaf *sleaf;
5032 LY_ERR rc = LY_SUCCESS;
5033
5034 if (options & LYXP_SCNODE_ALL) {
5035 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5036 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5037 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005038 } else if (!warn_is_string_type(sleaf->type)) {
5039 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005040 }
5041 }
5042
5043 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5044 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5045 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005046 } else if (!warn_is_string_type(sleaf->type)) {
5047 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005048 }
5049 }
5050
5051 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5052 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5053 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005054 } else if (!warn_is_string_type(sleaf->type)) {
5055 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005056 }
5057 }
5058 set_scnode_clear_ctx(set);
5059 return rc;
5060 }
5061
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005062 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005063 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005064 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005065 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005066 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005067 LY_CHECK_RET(rc);
5068
5069 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5070 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5071 new_used = 0;
5072
5073 have_removed = 0;
5074 for (i = 0; args[0]->val.str[i]; ++i) {
5075 found = 0;
5076
5077 for (j = 0; args[1]->val.str[j]; ++j) {
5078 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5079 /* removing this char */
5080 if (j >= strlen(args[2]->val.str)) {
5081 have_removed = 1;
5082 found = 1;
5083 break;
5084 }
5085 /* replacing this char */
5086 new[new_used] = args[2]->val.str[j];
5087 ++new_used;
5088 found = 1;
5089 break;
5090 }
5091 }
5092
5093 /* copying this char */
5094 if (!found) {
5095 new[new_used] = args[0]->val.str[i];
5096 ++new_used;
5097 }
5098 }
5099
5100 if (have_removed) {
5101 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5102 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5103 }
5104 new[new_used] = '\0';
5105
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005106 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005107 set->type = LYXP_SET_STRING;
5108 set->val.str = new;
5109
5110 return LY_SUCCESS;
5111}
5112
5113/**
5114 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5115 * with true value.
5116 *
5117 * @param[in] args Array of arguments.
5118 * @param[in] arg_count Count of elements in @p args.
5119 * @param[in,out] set Context and result set at the same time.
5120 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005121 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005122 */
5123static LY_ERR
5124xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5125{
5126 if (options & LYXP_SCNODE_ALL) {
5127 set_scnode_clear_ctx(set);
5128 return LY_SUCCESS;
5129 }
5130
5131 set_fill_boolean(set, 1);
5132 return LY_SUCCESS;
5133}
5134
5135/*
5136 * moveto functions
5137 *
5138 * They and only they actually change the context (set).
5139 */
5140
5141/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005142 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005143 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005144 * XPath @p set is expected to be a (sc)node set!
5145 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005146 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5147 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5148 * @param[in] set Set with XPath context.
5149 * @param[out] moveto_mod Expected module of a matching node.
5150 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005151 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005152static LY_ERR
5153moveto_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 +02005154{
Michal Vasko6346ece2019-09-24 13:12:53 +02005155 const struct lys_module *mod;
5156 const char *ptr;
5157 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005158 char *str;
5159
Michal Vasko2104e9f2020-03-06 08:23:25 +01005160 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5161
Michal Vasko6346ece2019-09-24 13:12:53 +02005162 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5163 /* specific module */
5164 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005165
Michal Vasko6346ece2019-09-24 13:12:53 +02005166 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01005167 case LYD_SCHEMA:
Michal Vasko6346ece2019-09-24 13:12:53 +02005168 /* schema, search all local module imports */
5169 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5170 break;
5171 case LYD_JSON:
5172 /* JSON data, search in context */
5173 str = strndup(*qname, pref_len);
5174 mod = ly_ctx_get_module(set->ctx, str, NULL);
5175 free(str);
5176 break;
Michal Vasko52927e22020-03-16 17:26:14 +01005177 case LYD_XML:
Michal Vasko6346ece2019-09-24 13:12:53 +02005178 LOGINT_RET(set->ctx);
5179 }
5180
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005181 /* Check for errors and non-implemented modules, as they are not valid */
5182 if (!mod || !mod->implemented) {
Michal Vasko2104e9f2020-03-06 08:23:25 +01005183 if (set->type == LYXP_SET_SCNODE_SET) {
5184 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INMOD, pref_len, *qname);
5185 } else {
5186 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5187 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005188 return LY_EVALID;
5189 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005190
Michal Vasko6346ece2019-09-24 13:12:53 +02005191 *qname += pref_len + 1;
5192 *qname_len -= pref_len + 1;
5193 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5194 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005195 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005196 } else {
5197 /* local module */
5198 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005199 }
5200
Michal Vasko6346ece2019-09-24 13:12:53 +02005201 *moveto_mod = mod;
5202 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005203}
5204
5205/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005206 * @brief Move context @p set to the root. Handles absolute path.
5207 * Result is LYXP_SET_NODE_SET.
5208 *
5209 * @param[in,out] set Set to use.
5210 * @param[in] options Xpath options.
5211 */
5212static void
5213moveto_root(struct lyxp_set *set, int options)
5214{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005215 if (!set) {
5216 return;
5217 }
5218
5219 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005220 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005221 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005222 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005223 lyxp_set_cast(set, LYXP_SET_EMPTY);
5224 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005225 }
5226}
5227
5228/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005229 * @brief Check whether a node has some unresolved "when".
5230 *
5231 * @param[in] node Node to check.
5232 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5233 */
5234static LY_ERR
5235moveto_when_check(const struct lyd_node *node)
5236{
5237 const struct lysc_node *schema;
5238
5239 if (!node) {
5240 return LY_SUCCESS;
5241 }
5242
5243 schema = node->schema;
5244 do {
5245 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5246 return LY_EINCOMPLETE;
5247 }
5248 schema = schema->parent;
5249 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5250
5251 return LY_SUCCESS;
5252}
5253
5254/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005255 * @brief Check @p node as a part of NameTest processing.
5256 *
5257 * @param[in] node Node to check.
5258 * @param[in] root_type XPath root node type.
5259 * @param[in] node_name Node name to move to. Must be in the dictionary!
5260 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005261 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5262 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005263 */
5264static LY_ERR
5265moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5266 const struct lys_module *moveto_mod)
5267{
5268 /* module check */
5269 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005270 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005271 }
5272
Michal Vasko5c4e5892019-11-14 12:31:38 +01005273 /* context check */
5274 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005275 return LY_EINVAL;
5276 }
5277
5278 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005279 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005280 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005281 }
5282
Michal Vaskoa1424542019-11-14 16:08:52 +01005283 /* when check */
5284 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005285 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005286 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005287
5288 /* match */
5289 return LY_SUCCESS;
5290}
5291
5292/**
5293 * @brief Check @p node as a part of schema NameTest processing.
5294 *
5295 * @param[in] node Schema node to check.
5296 * @param[in] root_type XPath root node type.
5297 * @param[in] node_name Node name to move to. Must be in the dictionary!
5298 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005299 * @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 +02005300 */
5301static LY_ERR
5302moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005303 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005304{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005305 /* module check */
5306 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005307 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005308 }
5309
5310 /* context check */
5311 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5312 return LY_EINVAL;
5313 }
5314
5315 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005316 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005317 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005318 }
5319
5320 /* match */
5321 return LY_SUCCESS;
5322}
5323
5324/**
5325 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5326 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5327 *
5328 * @param[in,out] set Set to use.
5329 * @param[in] qname Qualified node name to move to.
5330 * @param[in] qname_len Length of @p qname.
5331 * @param[in] options XPath options.
5332 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5333 */
5334static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005335moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005336{
Michal Vaskof03ed032020-03-04 13:31:44 +01005337 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005338 int replaced;
5339 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005340 const struct lys_module *moveto_mod;
5341 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005342 LY_ERR rc;
5343
5344 if (!set || (set->type == LYXP_SET_EMPTY)) {
5345 return LY_SUCCESS;
5346 }
5347
5348 if (set->type != LYXP_SET_NODE_SET) {
5349 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5350 return LY_EVALID;
5351 }
5352
Michal Vasko6346ece2019-09-24 13:12:53 +02005353 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5354 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005355
5356 /* name */
5357 name_dict = lydict_insert(set->ctx, qname, qname_len);
5358
5359 for (i = 0; i < set->used; ) {
5360 replaced = 0;
5361
5362 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 +01005363 assert(!set->val.nodes[i].node);
5364 /* search in all the trees */
Michal Vaskof03ed032020-03-04 13:31:44 +01005365 for (sub = set->tree; sub; sub = sub->next) {
5366 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
5367 if (rc == LY_SUCCESS) {
5368 /* pos filled later */
5369 if (!replaced) {
5370 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5371 replaced = 1;
5372 } else {
5373 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005374 }
Michal Vaskof03ed032020-03-04 13:31:44 +01005375 ++i;
5376 } else if (rc == LY_EINCOMPLETE) {
5377 lydict_remove(set->ctx, name_dict);
5378 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005379 }
5380 }
5381
Michal Vasko5c4e5892019-11-14 12:31:38 +01005382 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5383 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005384
5385 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005386 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005387 if (rc == LY_SUCCESS) {
5388 if (!replaced) {
5389 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5390 replaced = 1;
5391 } else {
5392 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5393 }
5394 ++i;
5395 } else if (rc == LY_EINCOMPLETE) {
5396 lydict_remove(set->ctx, name_dict);
5397 return rc;
5398 }
5399 }
5400 }
5401
5402 if (!replaced) {
5403 /* no match */
5404 set_remove_node(set, i);
5405 }
5406 }
5407 lydict_remove(set->ctx, name_dict);
5408
5409 return LY_SUCCESS;
5410}
5411
5412/**
5413 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5414 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5415 *
5416 * @param[in,out] set Set to use.
5417 * @param[in] qname Qualified node name to move to.
5418 * @param[in] qname_len Length of @p qname.
5419 * @param[in] options XPath options.
5420 * @return LY_ERR
5421 */
5422static LY_ERR
5423moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5424{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005425 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005426 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005427 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005428 const struct lys_module *moveto_mod;
5429 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005430 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005431
5432 if (!set || (set->type == LYXP_SET_EMPTY)) {
5433 return LY_SUCCESS;
5434 }
5435
5436 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005437 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005438 return LY_EVALID;
5439 }
5440
Michal Vasko6346ece2019-09-24 13:12:53 +02005441 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5442 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005443
5444 /* name */
5445 name_dict = lydict_insert(set->ctx, qname, qname_len);
5446
Michal Vaskocafad9d2019-11-07 15:20:03 +01005447 /* getnext opts */
5448 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5449 if (options & LYXP_SCNODE_OUTPUT) {
5450 getnext_opts |= LYS_GETNEXT_OUTPUT;
5451 }
5452
Michal Vasko03ff5a72019-09-11 13:49:33 +02005453 orig_used = set->used;
5454 for (i = 0; i < orig_used; ++i) {
5455 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005456 if (set->val.scnodes[i].in_ctx != -2) {
5457 continue;
5458 }
5459
5460 /* remember context node */
5461 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005462 } else {
5463 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005464 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005465
5466 start_parent = set->val.scnodes[i].scnode;
5467
5468 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5469 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5470 * so use it directly (root node itself is useless in this case) */
5471 mod_idx = 0;
5472 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5473 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005474 /* module may not be implemented */
5475 while (moveto_mod->implemented && (sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
Michal Vaskocafad9d2019-11-07 15:20:03 +01005476 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005477 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005478 /* we need to prevent these nodes from being considered in this moveto */
5479 if ((idx < orig_used) && (idx > i)) {
5480 set->val.scnodes[idx].in_ctx = 2;
5481 temp_ctx = 1;
5482 }
5483 }
5484 }
5485
5486 if (!mod_idx) {
5487 /* moveto_mod was specified, we are not going through the whole context */
5488 break;
5489 }
5490 /* next iteration */
5491 moveto_mod = NULL;
5492 }
5493
5494 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5495 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5496 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005497 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5498 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005499 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005500 if ((idx < orig_used) && (idx > i)) {
5501 set->val.scnodes[idx].in_ctx = 2;
5502 temp_ctx = 1;
5503 }
5504 }
5505 }
5506 }
5507 }
5508 lydict_remove(set->ctx, name_dict);
5509
5510 /* correct temporary in_ctx values */
5511 if (temp_ctx) {
5512 for (i = 0; i < orig_used; ++i) {
5513 if (set->val.scnodes[i].in_ctx == 2) {
5514 set->val.scnodes[i].in_ctx = 1;
5515 }
5516 }
5517 }
5518
5519 return LY_SUCCESS;
5520}
5521
5522/**
5523 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5524 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5525 * Context position aware.
5526 *
5527 * @param[in] set Set to use.
5528 * @param[in] qname Qualified node name to move to.
5529 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005530 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5531 */
5532static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005533moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005534{
5535 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005536 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005537 const struct lyd_node *next, *elem, *start;
5538 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005539 struct lyxp_set ret_set;
5540 LY_ERR rc;
5541
5542 if (!set || (set->type == LYXP_SET_EMPTY)) {
5543 return LY_SUCCESS;
5544 }
5545
5546 if (set->type != LYXP_SET_NODE_SET) {
5547 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5548 return LY_EVALID;
5549 }
5550
Michal Vasko6346ece2019-09-24 13:12:53 +02005551 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5552 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005553
Michal Vasko9f96a052020-03-10 09:41:45 +01005554 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005555 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005556 LY_CHECK_RET(rc);
5557
Michal Vasko6346ece2019-09-24 13:12:53 +02005558 /* name */
5559 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005560
Michal Vasko6346ece2019-09-24 13:12:53 +02005561 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005562 set_init(&ret_set, set);
5563 for (i = 0; i < set->used; ++i) {
5564
5565 /* TREE DFS */
5566 start = set->val.nodes[i].node;
5567 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005568 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005569 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005570 /* add matching node into result set */
5571 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5572 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5573 /* the node is a duplicate, we'll process it later in the set */
5574 goto skip_children;
5575 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005576 } else if (rc == LY_EINCOMPLETE) {
5577 lydict_remove(set->ctx, name_dict);
5578 return rc;
5579 } else if (rc == LY_EINVAL) {
5580 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005581 }
5582
5583 /* TREE DFS NEXT ELEM */
5584 /* select element for the next run - children first */
5585 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5586 next = NULL;
5587 } else {
5588 next = lyd_node_children(elem);
5589 }
5590 if (!next) {
5591skip_children:
5592 /* no children, so try siblings, but only if it's not the start,
5593 * that is considered to be the root and it's siblings are not traversed */
5594 if (elem != start) {
5595 next = elem->next;
5596 } else {
5597 break;
5598 }
5599 }
5600 while (!next) {
5601 /* no siblings, go back through the parents */
5602 if ((struct lyd_node *)elem->parent == start) {
5603 /* we are done, no next element to process */
5604 break;
5605 }
5606 /* parent is already processed, go to its sibling */
5607 elem = (struct lyd_node *)elem->parent;
5608 next = elem->next;
5609 }
5610 }
5611 }
5612
5613 /* make the temporary set the current one */
5614 ret_set.ctx_pos = set->ctx_pos;
5615 ret_set.ctx_size = set->ctx_size;
5616 set_free_content(set);
5617 memcpy(set, &ret_set, sizeof *set);
5618
Michal Vasko6346ece2019-09-24 13:12:53 +02005619 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005620 return LY_SUCCESS;
5621}
5622
5623/**
5624 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5625 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5626 *
5627 * @param[in] set Set to use.
5628 * @param[in] qname Qualified node name to move to.
5629 * @param[in] qname_len Length of @p qname.
5630 * @param[in] options XPath options.
5631 * @return LY_ERR
5632 */
5633static LY_ERR
5634moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5635{
Michal Vasko6346ece2019-09-24 13:12:53 +02005636 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005637 const struct lysc_node *next, *elem, *start;
5638 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005639 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005640
5641 if (!set || (set->type == LYXP_SET_EMPTY)) {
5642 return LY_SUCCESS;
5643 }
5644
5645 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005646 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005647 return LY_EVALID;
5648 }
5649
Michal Vasko6346ece2019-09-24 13:12:53 +02005650 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5651 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005652
5653 orig_used = set->used;
5654 for (i = 0; i < orig_used; ++i) {
5655 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005656 if (set->val.scnodes[i].in_ctx != -2) {
5657 continue;
5658 }
5659
5660 /* remember context node */
5661 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005662 } else {
5663 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005664 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005665
5666 /* TREE DFS */
5667 start = set->val.scnodes[i].scnode;
5668 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005669 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5670 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005671 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005672 }
5673
Michal Vaskocafad9d2019-11-07 15:20:03 +01005674 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005675 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005676 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005677 set->val.scnodes[idx].in_ctx = 1;
5678 if (idx > i) {
5679 /* we will process it later in the set */
5680 goto skip_children;
5681 }
5682 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005683 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005684 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005685 } else if (rc == LY_EINVAL) {
5686 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005687 }
5688
5689next_iter:
5690 /* TREE DFS NEXT ELEM */
5691 /* select element for the next run - children first */
5692 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5693 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5694 next = NULL;
5695 }
5696 if (!next) {
5697skip_children:
5698 /* no children, so try siblings, but only if it's not the start,
5699 * that is considered to be the root and it's siblings are not traversed */
5700 if (elem != start) {
5701 next = elem->next;
5702 } else {
5703 break;
5704 }
5705 }
5706 while (!next) {
5707 /* no siblings, go back through the parents */
5708 if (elem->parent == start) {
5709 /* we are done, no next element to process */
5710 break;
5711 }
5712 /* parent is already processed, go to its sibling */
5713 elem = elem->parent;
5714 next = elem->next;
5715 }
5716 }
5717 }
5718
5719 return LY_SUCCESS;
5720}
5721
5722/**
5723 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5724 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5725 * Indirectly context position aware.
5726 *
5727 * @param[in,out] set Set to use.
5728 * @param[in] qname Qualified node name to move to.
5729 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005730 * @return LY_ERR
5731 */
5732static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005733moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005734{
5735 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005736 int replaced, all = 0;
5737 const struct lys_module *moveto_mod;
Michal Vasko9f96a052020-03-10 09:41:45 +01005738 struct lyd_meta *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005739 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005740
5741 if (!set || (set->type == LYXP_SET_EMPTY)) {
5742 return LY_SUCCESS;
5743 }
5744
5745 if (set->type != LYXP_SET_NODE_SET) {
5746 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5747 return LY_EVALID;
5748 }
5749
Michal Vasko6346ece2019-09-24 13:12:53 +02005750 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5751 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005752
5753 if ((qname_len == 1) && (qname[0] == '*')) {
5754 all = 1;
5755 }
5756
5757 for (i = 0; i < set->used; ) {
5758 replaced = 0;
5759
5760 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5761 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005762 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005763 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005764
5765 /* check "namespace" */
5766 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5767 continue;
5768 }
5769
5770 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5771 /* match */
5772 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005773 set->val.meta[i].meta = sub;
5774 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005775 /* pos does not change */
5776 replaced = 1;
5777 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005778 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005779 }
5780 ++i;
5781 }
5782 }
5783 }
5784
5785 if (!replaced) {
5786 /* no match */
5787 set_remove_node(set, i);
5788 }
5789 }
5790
5791 return LY_SUCCESS;
5792}
5793
5794/**
5795 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
5796 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5797 *
5798 * @param[in,out] set1 Set to use for the result.
5799 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005800 * @return LY_ERR
5801 */
5802static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005803moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005804{
5805 LY_ERR rc;
5806
5807 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5808 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5809 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5810 return LY_EVALID;
5811 }
5812
5813 /* set2 is empty or both set1 and set2 */
5814 if (set2->type == LYXP_SET_EMPTY) {
5815 return LY_SUCCESS;
5816 }
5817
5818 if (set1->type == LYXP_SET_EMPTY) {
5819 memcpy(set1, set2, sizeof *set1);
5820 /* dynamic memory belongs to set1 now, do not free */
5821 set2->type = LYXP_SET_EMPTY;
5822 return LY_SUCCESS;
5823 }
5824
5825 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005826 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005827
5828 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005829 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005830 LY_CHECK_RET(rc);
5831
5832 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005833 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005834
5835 return LY_SUCCESS;
5836}
5837
5838/**
5839 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5840 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5841 * Context position aware.
5842 *
5843 * @param[in,out] set Set to use.
5844 * @param[in] qname Qualified node name to move to.
5845 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005846 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5847 */
5848static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005849moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005850{
5851 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005852 int replaced, all = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01005853 struct lyd_meta *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005854 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005855 struct lyxp_set *set_all_desc = NULL;
5856 LY_ERR rc;
5857
5858 if (!set || (set->type == LYXP_SET_EMPTY)) {
5859 return LY_SUCCESS;
5860 }
5861
5862 if (set->type != LYXP_SET_NODE_SET) {
5863 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5864 return LY_EVALID;
5865 }
5866
Michal Vasko6346ece2019-09-24 13:12:53 +02005867 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5868 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005869
5870 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5871 * but it likely won't be used much, so it's a waste of time */
5872 /* copy the context */
5873 set_all_desc = set_copy(set);
5874 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005875 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005876 if (rc != LY_SUCCESS) {
5877 lyxp_set_free(set_all_desc);
5878 return rc;
5879 }
5880 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005881 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005882 if (rc != LY_SUCCESS) {
5883 lyxp_set_free(set_all_desc);
5884 return rc;
5885 }
5886 lyxp_set_free(set_all_desc);
5887
5888 if ((qname_len == 1) && (qname[0] == '*')) {
5889 all = 1;
5890 }
5891
5892 for (i = 0; i < set->used; ) {
5893 replaced = 0;
5894
5895 /* only attributes of an elem can be in the result, skip all the rest,
5896 * we have all attributes qualified in lyd tree */
5897 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005898 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005899 /* check "namespace" */
5900 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5901 continue;
5902 }
5903
5904 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5905 /* match */
5906 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005907 set->val.meta[i].meta = sub;
5908 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005909 /* pos does not change */
5910 replaced = 1;
5911 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005912 set_insert_node(set, (struct lyd_node *)sub, set->val.meta[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005913 }
5914 ++i;
5915 }
5916 }
5917 }
5918
5919 if (!replaced) {
5920 /* no match */
5921 set_remove_node(set, i);
5922 }
5923 }
5924
5925 return LY_SUCCESS;
5926}
5927
5928/**
5929 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5930 * (or LYXP_SET_EMPTY). Context position aware.
5931 *
5932 * @param[in] parent Current parent.
5933 * @param[in] parent_pos Position of @p parent.
5934 * @param[in] parent_type Node type of @p parent.
5935 * @param[in,out] to_set Set to use.
5936 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005937 * @param[in] options XPath options.
5938 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5939 */
5940static LY_ERR
5941moveto_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 +01005942 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005943{
5944 const struct lyd_node *sub;
5945 LY_ERR rc;
5946
5947 switch (parent_type) {
5948 case LYXP_NODE_ROOT:
5949 case LYXP_NODE_ROOT_CONFIG:
5950 /* add the same node but as an element */
5951 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5952 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5953
5954 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005955 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005956 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005957 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005958 LY_CHECK_RET(rc);
5959 }
5960 }
5961 break;
5962 case LYXP_NODE_ELEM:
5963 /* add all the children ... */
5964 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5965 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5966 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005967 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005968 continue;
5969 }
5970
Michal Vaskoa1424542019-11-14 16:08:52 +01005971 /* when check */
5972 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005973 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005974 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005975
5976 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5977 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5978
Michal Vasko5c4e5892019-11-14 12:31:38 +01005979 /* skip anydata/anyxml nodes */
5980 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005981 continue;
5982 }
5983
5984 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005985 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005986 LY_CHECK_RET(rc);
5987 }
5988 }
5989
5990 /* ... or add their text node, ... */
5991 } else {
5992 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5993 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5994 }
5995 }
5996 break;
5997 default:
5998 LOGINT_RET(parent->schema->module->ctx);
5999 }
6000
6001 return LY_SUCCESS;
6002}
6003
6004/**
6005 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
6006 * (or LYXP_SET_EMPTY). Context position aware.
6007 *
6008 * @param[in,out] set Set to use.
6009 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6010 * @param[in] options XPath options.
6011 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6012 */
6013static LY_ERR
6014moveto_self(struct lyxp_set *set, int all_desc, int options)
6015{
6016 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006017 struct lyxp_set ret_set;
6018 LY_ERR rc;
6019
6020 if (!set || (set->type == LYXP_SET_EMPTY)) {
6021 return LY_SUCCESS;
6022 }
6023
6024 if (set->type != LYXP_SET_NODE_SET) {
6025 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6026 return LY_EVALID;
6027 }
6028
6029 /* nothing to do */
6030 if (!all_desc) {
6031 return LY_SUCCESS;
6032 }
6033
Michal Vasko03ff5a72019-09-11 13:49:33 +02006034 /* add all the children, they get added recursively */
6035 set_init(&ret_set, set);
6036 for (i = 0; i < set->used; ++i) {
6037 /* copy the current node to tmp */
6038 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6039
6040 /* do not touch attributes and text nodes */
Michal Vasko9f96a052020-03-10 09:41:45 +01006041 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006042 continue;
6043 }
6044
Michal Vasko5c4e5892019-11-14 12:31:38 +01006045 /* skip anydata/anyxml nodes */
6046 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006047 continue;
6048 }
6049
6050 /* add all the children */
6051 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 +01006052 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006053 if (rc != LY_SUCCESS) {
6054 set_free_content(&ret_set);
6055 return rc;
6056 }
6057 }
6058
6059 /* use the temporary set as the current one */
6060 ret_set.ctx_pos = set->ctx_pos;
6061 ret_set.ctx_size = set->ctx_size;
6062 set_free_content(set);
6063 memcpy(set, &ret_set, sizeof *set);
6064
6065 return LY_SUCCESS;
6066}
6067
6068/**
6069 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6070 * (or LYXP_SET_EMPTY).
6071 *
6072 * @param[in,out] set Set to use.
6073 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6074 * @param[in] options XPath options.
6075 * @return LY_ERR
6076 */
6077static LY_ERR
6078moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6079{
6080 const struct lysc_node *sub;
6081 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006082
6083 if (!set || (set->type == LYXP_SET_EMPTY)) {
6084 return LY_SUCCESS;
6085 }
6086
6087 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006088 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006089 return LY_EVALID;
6090 }
6091
6092 /* nothing to do */
6093 if (!all_desc) {
6094 return LY_SUCCESS;
6095 }
6096
Michal Vasko03ff5a72019-09-11 13:49:33 +02006097 /* add all the children, they get added recursively */
6098 for (i = 0; i < set->used; ++i) {
6099 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006100 if (set->val.scnodes[i].in_ctx != -2) {
6101 continue;
6102 }
6103
6104 /* remember context node (it was traversed again so it changes to a normal node) */
6105 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006106 }
6107
6108 /* add all the children */
6109 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6110 sub = NULL;
6111 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6112 /* RPC input/output check */
6113 if (options & LYXP_SCNODE_OUTPUT) {
6114 if (sub->parent->nodetype == LYS_INPUT) {
6115 continue;
6116 }
6117 } else {
6118 if (sub->parent->nodetype == LYS_OUTPUT) {
6119 continue;
6120 }
6121 }
6122
6123 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006124 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006125 continue;
6126 }
6127
Michal Vaskoecd62de2019-11-13 12:35:11 +01006128 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006129 /* throw away the insert index, we want to consider that node again, recursively */
6130 }
6131 }
6132 }
6133
6134 return LY_SUCCESS;
6135}
6136
6137/**
6138 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6139 * (or LYXP_SET_EMPTY). Context position aware.
6140 *
6141 * @param[in] set Set to use.
6142 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6143 * @param[in] options XPath options.
6144 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6145 */
6146static LY_ERR
6147moveto_parent(struct lyxp_set *set, int all_desc, int options)
6148{
6149 LY_ERR rc;
6150 uint32_t i;
6151 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006152 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006153
6154 if (!set || (set->type == LYXP_SET_EMPTY)) {
6155 return LY_SUCCESS;
6156 }
6157
6158 if (set->type != LYXP_SET_NODE_SET) {
6159 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6160 return LY_EVALID;
6161 }
6162
6163 if (all_desc) {
6164 /* <path>//.. == <path>//./.. */
6165 rc = moveto_self(set, 1, options);
6166 LY_CHECK_RET(rc);
6167 }
6168
Michal Vasko57eab132019-09-24 11:46:26 +02006169 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006170 node = set->val.nodes[i].node;
6171
6172 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6173 new_node = (struct lyd_node *)node->parent;
6174 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6175 new_node = node;
Michal Vasko9f96a052020-03-10 09:41:45 +01006176 } else if (set->val.nodes[i].type == LYXP_NODE_META) {
6177 new_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006178 if (!new_node) {
6179 LOGINT_RET(set->ctx);
6180 }
6181 } else {
6182 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006183 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006184 continue;
6185 }
6186
Michal Vaskoa1424542019-11-14 16:08:52 +01006187 /* when check */
6188 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006189 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006190 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006191
6192 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006193 if (!new_node) {
6194 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006195
6196 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6197 } else {
6198 new_type = LYXP_NODE_ELEM;
6199 }
6200
Michal Vasko03ff5a72019-09-11 13:49:33 +02006201 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006202 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006203 } else {
6204 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006205 }
6206 }
6207
Michal Vasko2caefc12019-11-14 16:07:56 +01006208 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006209 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006210
6211 return LY_SUCCESS;
6212}
6213
6214/**
6215 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6216 * (or LYXP_SET_EMPTY).
6217 *
6218 * @param[in] set Set to use.
6219 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6220 * @param[in] options XPath options.
6221 * @return LY_ERR
6222 */
6223static LY_ERR
6224moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6225{
6226 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006227 const struct lysc_node *node, *new_node;
6228 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006229 LY_ERR rc;
6230
6231 if (!set || (set->type == LYXP_SET_EMPTY)) {
6232 return LY_SUCCESS;
6233 }
6234
6235 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006236 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006237 return LY_EVALID;
6238 }
6239
6240 if (all_desc) {
6241 /* <path>//.. == <path>//./.. */
6242 rc = moveto_scnode_self(set, 1, options);
6243 LY_CHECK_RET(rc);
6244 }
6245
Michal Vasko03ff5a72019-09-11 13:49:33 +02006246 orig_used = set->used;
6247 for (i = 0; i < orig_used; ++i) {
6248 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006249 if (set->val.scnodes[i].in_ctx != -2) {
6250 continue;
6251 }
6252
6253 /* remember context node */
6254 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006255 } else {
6256 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006257 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006258
6259 node = set->val.scnodes[i].scnode;
6260
6261 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6262 for (new_node = node->parent;
6263 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6264 new_node = new_node->parent);
6265 } else {
6266 /* root does not have a parent */
6267 continue;
6268 }
6269
Michal Vasko03ff5a72019-09-11 13:49:33 +02006270 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006271 if (!new_node) {
6272 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006273
6274 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6275 } else {
6276 new_type = LYXP_NODE_ELEM;
6277 }
6278
Michal Vaskoecd62de2019-11-13 12:35:11 +01006279 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006280 if ((idx < orig_used) && (idx > i)) {
6281 set->val.scnodes[idx].in_ctx = 2;
6282 temp_ctx = 1;
6283 }
6284 }
6285
6286 if (temp_ctx) {
6287 for (i = 0; i < orig_used; ++i) {
6288 if (set->val.scnodes[i].in_ctx == 2) {
6289 set->val.scnodes[i].in_ctx = 1;
6290 }
6291 }
6292 }
6293
6294 return LY_SUCCESS;
6295}
6296
6297/**
6298 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6299 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6300 *
6301 * @param[in,out] set1 Set to use for the result.
6302 * @param[in] set2 Set acting as the second operand for @p op.
6303 * @param[in] op Comparison operator to process.
6304 * @param[in] options XPath options.
6305 * @return LY_ERR
6306 */
6307static LY_ERR
6308moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6309{
6310 /*
6311 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6312 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6313 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6314 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6315 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6316 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6317 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6318 *
6319 * '=' or '!='
6320 * BOOLEAN + BOOLEAN
6321 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6322 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6323 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6324 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6325 * NUMBER + NUMBER
6326 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6327 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6328 * STRING + STRING
6329 *
6330 * '<=', '<', '>=', '>'
6331 * NUMBER + NUMBER
6332 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6333 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6334 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6335 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6336 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6337 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6338 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6339 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6340 */
6341 struct lyxp_set iter1, iter2;
6342 int result;
6343 int64_t i;
6344 LY_ERR rc;
6345
6346 iter1.type = LYXP_SET_EMPTY;
6347
6348 /* empty node-sets are always false */
6349 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6350 set_fill_boolean(set1, 0);
6351 return LY_SUCCESS;
6352 }
6353
6354 /* iterative evaluation with node-sets */
6355 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6356 if (set1->type == LYXP_SET_NODE_SET) {
6357 for (i = 0; i < set1->used; ++i) {
6358 switch (set2->type) {
6359 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006360 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006361 break;
6362 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006363 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006364 break;
6365 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006366 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006367 break;
6368 }
6369 LY_CHECK_RET(rc);
6370
6371 rc = moveto_op_comp(&iter1, set2, op, options);
6372 if (rc != LY_SUCCESS) {
6373 set_free_content(&iter1);
6374 return rc;
6375 }
6376
6377 /* lazy evaluation until true */
6378 if (iter1.val.bool) {
6379 set_fill_boolean(set1, 1);
6380 return LY_SUCCESS;
6381 }
6382 }
6383 } else {
6384 for (i = 0; i < set2->used; ++i) {
6385 switch (set1->type) {
6386 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006387 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006388 break;
6389 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006390 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006391 break;
6392 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006393 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006394 break;
6395 }
6396 LY_CHECK_RET(rc);
6397
6398 set_fill_set(&iter1, set1);
6399
6400 rc = moveto_op_comp(&iter1, &iter2, op, options);
6401 if (rc != LY_SUCCESS) {
6402 set_free_content(&iter1);
6403 set_free_content(&iter2);
6404 return rc;
6405 }
6406 set_free_content(&iter2);
6407
6408 /* lazy evaluation until true */
6409 if (iter1.val.bool) {
6410 set_fill_boolean(set1, 1);
6411 return LY_SUCCESS;
6412 }
6413 }
6414 }
6415
6416 /* false for all nodes */
6417 set_fill_boolean(set1, 0);
6418 return LY_SUCCESS;
6419 }
6420
6421 /* first convert properly */
6422 if ((op[0] == '=') || (op[0] == '!')) {
6423 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006424 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6425 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006426 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006427 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006428 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006429 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006430 LY_CHECK_RET(rc);
6431 } /* else we have 2 strings */
6432 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006433 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006434 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006435 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006436 LY_CHECK_RET(rc);
6437 }
6438
6439 assert(set1->type == set2->type);
6440
6441 /* compute result */
6442 if (op[0] == '=') {
6443 if (set1->type == LYXP_SET_BOOLEAN) {
6444 result = (set1->val.bool == set2->val.bool);
6445 } else if (set1->type == LYXP_SET_NUMBER) {
6446 result = (set1->val.num == set2->val.num);
6447 } else {
6448 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006449 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006450 }
6451 } else if (op[0] == '!') {
6452 if (set1->type == LYXP_SET_BOOLEAN) {
6453 result = (set1->val.bool != set2->val.bool);
6454 } else if (set1->type == LYXP_SET_NUMBER) {
6455 result = (set1->val.num != set2->val.num);
6456 } else {
6457 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006458 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006459 }
6460 } else {
6461 assert(set1->type == LYXP_SET_NUMBER);
6462 if (op[0] == '<') {
6463 if (op[1] == '=') {
6464 result = (set1->val.num <= set2->val.num);
6465 } else {
6466 result = (set1->val.num < set2->val.num);
6467 }
6468 } else {
6469 if (op[1] == '=') {
6470 result = (set1->val.num >= set2->val.num);
6471 } else {
6472 result = (set1->val.num > set2->val.num);
6473 }
6474 }
6475 }
6476
6477 /* assign result */
6478 if (result) {
6479 set_fill_boolean(set1, 1);
6480 } else {
6481 set_fill_boolean(set1, 0);
6482 }
6483
6484 return LY_SUCCESS;
6485}
6486
6487/**
6488 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6489 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6490 *
6491 * @param[in,out] set1 Set to use for the result.
6492 * @param[in] set2 Set acting as the second operand for @p op.
6493 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006494 * @return LY_ERR
6495 */
6496static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006497moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006498{
6499 LY_ERR rc;
6500
6501 /* unary '-' */
6502 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006503 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006504 LY_CHECK_RET(rc);
6505 set1->val.num *= -1;
6506 lyxp_set_free(set2);
6507 return LY_SUCCESS;
6508 }
6509
6510 assert(set1 && set2);
6511
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006512 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006513 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006514 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006515 LY_CHECK_RET(rc);
6516
6517 switch (op[0]) {
6518 /* '+' */
6519 case '+':
6520 set1->val.num += set2->val.num;
6521 break;
6522
6523 /* '-' */
6524 case '-':
6525 set1->val.num -= set2->val.num;
6526 break;
6527
6528 /* '*' */
6529 case '*':
6530 set1->val.num *= set2->val.num;
6531 break;
6532
6533 /* 'div' */
6534 case 'd':
6535 set1->val.num /= set2->val.num;
6536 break;
6537
6538 /* 'mod' */
6539 case 'm':
6540 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6541 break;
6542
6543 default:
6544 LOGINT_RET(set1->ctx);
6545 }
6546
6547 return LY_SUCCESS;
6548}
6549
6550/*
6551 * eval functions
6552 *
6553 * They execute a parsed XPath expression on some data subtree.
6554 */
6555
6556/**
6557 * @brief Evaluate Literal. Logs directly on error.
6558 *
6559 * @param[in] exp Parsed XPath expression.
6560 * @param[in] exp_idx Position in the expression @p exp.
6561 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6562 */
6563static void
6564eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6565{
6566 if (set) {
6567 if (exp->tok_len[*exp_idx] == 2) {
6568 set_fill_string(set, "", 0);
6569 } else {
6570 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6571 }
6572 }
6573 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6574 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6575 ++(*exp_idx);
6576}
6577
6578/**
6579 * @brief Evaluate NodeTest. Logs directly on error.
6580 *
6581 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6582 *
6583 * @param[in] exp Parsed XPath expression.
6584 * @param[in] exp_idx Position in the expression @p exp.
6585 * @param[in] attr_axis Whether to search attributes or standard nodes.
6586 * @param[in] all_desc Whether to search all the descendants or children only.
6587 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6588 * @param[in] options XPath options.
6589 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6590 */
6591static int
6592eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6593 struct lyxp_set *set, int options)
6594{
6595 int i;
6596 char *path;
6597 LY_ERR rc;
6598
6599 switch (exp->tokens[*exp_idx]) {
6600 case LYXP_TOKEN_NAMETEST:
6601 if (attr_axis) {
6602 if (set && (options & LYXP_SCNODE_ALL)) {
6603 set_scnode_clear_ctx(set);
6604 rc = LY_SUCCESS;
6605 } else {
6606 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006607 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006608 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006609 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006610 }
6611 }
6612 } else {
6613 if (all_desc) {
6614 if (set && (options & LYXP_SCNODE_ALL)) {
6615 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6616 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006617 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006618 }
6619 } else {
6620 if (set && (options & LYXP_SCNODE_ALL)) {
6621 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6622 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006623 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006624 }
6625 }
6626
6627 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6628 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006629 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006630 break;
6631 }
6632 }
6633 if (i == -1) {
6634 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6635 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6636 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6637 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6638 free(path);
6639 }
6640 }
6641 }
6642 LY_CHECK_RET(rc);
6643
6644 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6645 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6646 ++(*exp_idx);
6647 break;
6648
6649 case LYXP_TOKEN_NODETYPE:
6650 if (set) {
6651 assert(exp->tok_len[*exp_idx] == 4);
6652 if (set->type == LYXP_SET_SCNODE_SET) {
6653 set_scnode_clear_ctx(set);
6654 /* just for the debug message underneath */
6655 set = NULL;
6656 } else {
6657 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6658 rc = xpath_node(NULL, 0, set, options);
6659 LY_CHECK_RET(rc);
6660 } else {
6661 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6662 rc = xpath_text(NULL, 0, set, options);
6663 LY_CHECK_RET(rc);
6664 }
6665 }
6666 }
6667 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6668 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6669 ++(*exp_idx);
6670
6671 /* '(' */
6672 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6673 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6674 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6675 ++(*exp_idx);
6676
6677 /* ')' */
6678 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6679 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6680 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6681 ++(*exp_idx);
6682 break;
6683
6684 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006685 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006686 }
6687
6688 return LY_SUCCESS;
6689}
6690
6691/**
6692 * @brief Evaluate Predicate. Logs directly on error.
6693 *
6694 * [7] Predicate ::= '[' Expr ']'
6695 *
6696 * @param[in] exp Parsed XPath expression.
6697 * @param[in] exp_idx Position in the expression @p exp.
6698 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6699 * @param[in] options XPath options.
6700 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6701 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6702 */
6703static LY_ERR
6704eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6705{
6706 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006707 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006708 uint32_t orig_pos, orig_size;
6709 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006710 struct lyxp_set set2;
6711 struct lyd_node *orig_parent;
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 if (!set) {
6719only_parse:
6720 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6721 LY_CHECK_RET(rc);
6722 } else if (set->type == LYXP_SET_NODE_SET) {
6723 /* 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 +01006724 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006725
6726 /* empty set, nothing to evaluate */
6727 if (!set->used) {
6728 goto only_parse;
6729 }
6730
6731 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006732 orig_pos = 0;
6733 orig_size = set->used;
6734 orig_parent = NULL;
6735 for (i = 0; i < set->used; ) {
6736 set_init(&set2, set);
6737 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6738 /* remember the node context position for position() and context size for last(),
6739 * predicates should always be evaluated with respect to the child axis (since we do
6740 * not support explicit axes) so we assign positions based on their parents */
6741 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6742 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6743 orig_pos = 1;
6744 } else {
6745 ++orig_pos;
6746 }
6747
6748 set2.ctx_pos = orig_pos;
6749 set2.ctx_size = orig_size;
6750 *exp_idx = orig_exp;
6751
6752 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6753 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006754 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006755 return rc;
6756 }
6757
6758 /* number is a position */
6759 if (set2.type == LYXP_SET_NUMBER) {
6760 if ((long long)set2.val.num == orig_pos) {
6761 set2.val.num = 1;
6762 } else {
6763 set2.val.num = 0;
6764 }
6765 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006766 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006767
6768 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006769 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006770 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006771 }
6772 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006773 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006774
6775 } else if (set->type == LYXP_SET_SCNODE_SET) {
6776 for (i = 0; i < set->used; ++i) {
6777 if (set->val.scnodes[i].in_ctx == 1) {
6778 /* there is a currently-valid node */
6779 break;
6780 }
6781 }
6782 /* empty set, nothing to evaluate */
6783 if (i == set->used) {
6784 goto only_parse;
6785 }
6786
6787 orig_exp = *exp_idx;
6788
Michal Vasko03ff5a72019-09-11 13:49:33 +02006789 /* set special in_ctx to all the valid snodes */
6790 pred_in_ctx = set_scnode_new_in_ctx(set);
6791
6792 /* use the valid snodes one-by-one */
6793 for (i = 0; i < set->used; ++i) {
6794 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6795 continue;
6796 }
6797 set->val.scnodes[i].in_ctx = 1;
6798
6799 *exp_idx = orig_exp;
6800
6801 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6802 LY_CHECK_RET(rc);
6803
6804 set->val.scnodes[i].in_ctx = pred_in_ctx;
6805 }
6806
6807 /* restore the state as it was before the predicate */
6808 for (i = 0; i < set->used; ++i) {
6809 if (set->val.scnodes[i].in_ctx == 1) {
6810 set->val.scnodes[i].in_ctx = 0;
6811 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6812 set->val.scnodes[i].in_ctx = 1;
6813 }
6814 }
6815
6816 } else {
6817 set2.type = LYXP_SET_EMPTY;
6818 set_fill_set(&set2, set);
6819
6820 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6821 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006822 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006823 return rc;
6824 }
6825
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006826 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006827 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006828 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006829 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006830 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006831 }
6832
6833 /* ']' */
6834 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6835 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6836 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6837 ++(*exp_idx);
6838
6839 return LY_SUCCESS;
6840}
6841
6842/**
6843 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6844 *
6845 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6846 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6847 *
6848 * @param[in] exp Parsed XPath expression.
6849 * @param[in] exp_idx Position in the expression @p exp.
6850 * @param[in] all_desc Whether to search all the descendants or children only.
6851 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6852 * @param[in] options XPath options.
6853 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6854 */
6855static LY_ERR
6856eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6857{
6858 int attr_axis;
6859 LY_ERR rc;
6860
6861 goto step;
6862 do {
6863 /* evaluate '/' or '//' */
6864 if (exp->tok_len[*exp_idx] == 1) {
6865 all_desc = 0;
6866 } else {
6867 assert(exp->tok_len[*exp_idx] == 2);
6868 all_desc = 1;
6869 }
6870 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6871 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6872 ++(*exp_idx);
6873
6874step:
6875 /* Step */
6876 attr_axis = 0;
6877 switch (exp->tokens[*exp_idx]) {
6878 case LYXP_TOKEN_DOT:
6879 /* evaluate '.' */
6880 if (set && (options & LYXP_SCNODE_ALL)) {
6881 rc = moveto_scnode_self(set, all_desc, options);
6882 } else {
6883 rc = moveto_self(set, all_desc, options);
6884 }
6885 LY_CHECK_RET(rc);
6886 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6887 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6888 ++(*exp_idx);
6889 break;
6890
6891 case LYXP_TOKEN_DDOT:
6892 /* evaluate '..' */
6893 if (set && (options & LYXP_SCNODE_ALL)) {
6894 rc = moveto_scnode_parent(set, all_desc, options);
6895 } else {
6896 rc = moveto_parent(set, all_desc, options);
6897 }
6898 LY_CHECK_RET(rc);
6899 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6900 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6901 ++(*exp_idx);
6902 break;
6903
6904 case LYXP_TOKEN_AT:
6905 /* evaluate '@' */
6906 attr_axis = 1;
6907 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6908 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6909 ++(*exp_idx);
6910
6911 /* fall through */
6912 case LYXP_TOKEN_NAMETEST:
6913 case LYXP_TOKEN_NODETYPE:
6914 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6915 LY_CHECK_RET(rc);
6916
6917 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6918 rc = eval_predicate(exp, exp_idx, set, options, 1);
6919 LY_CHECK_RET(rc);
6920 }
6921 break;
6922
6923 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006924 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006925 }
6926 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6927
6928 return LY_SUCCESS;
6929}
6930
6931/**
6932 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6933 *
6934 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6935 *
6936 * @param[in] exp Parsed XPath expression.
6937 * @param[in] exp_idx Position in the expression @p exp.
6938 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6939 * @param[in] options XPath options.
6940 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6941 */
6942static LY_ERR
6943eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6944{
6945 int all_desc;
6946 LY_ERR rc;
6947
6948 if (set) {
6949 /* no matter what tokens follow, we need to be at the root */
6950 moveto_root(set, options);
6951 }
6952
6953 /* '/' RelativeLocationPath? */
6954 if (exp->tok_len[*exp_idx] == 1) {
6955 /* evaluate '/' - deferred */
6956 all_desc = 0;
6957 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6958 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6959 ++(*exp_idx);
6960
Michal Vasko4b9e1052019-09-13 11:25:37 +02006961 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006962 return LY_SUCCESS;
6963 }
6964 switch (exp->tokens[*exp_idx]) {
6965 case LYXP_TOKEN_DOT:
6966 case LYXP_TOKEN_DDOT:
6967 case LYXP_TOKEN_AT:
6968 case LYXP_TOKEN_NAMETEST:
6969 case LYXP_TOKEN_NODETYPE:
6970 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6971 LY_CHECK_RET(rc);
6972 break;
6973 default:
6974 break;
6975 }
6976
6977 /* '//' RelativeLocationPath */
6978 } else {
6979 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6980 all_desc = 1;
6981 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6982 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6983 ++(*exp_idx);
6984
6985 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6986 LY_CHECK_RET(rc);
6987 }
6988
6989 return LY_SUCCESS;
6990}
6991
6992/**
6993 * @brief Evaluate FunctionCall. Logs directly on error.
6994 *
6995 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6996 *
6997 * @param[in] exp Parsed XPath expression.
6998 * @param[in] exp_idx Position in the expression @p exp.
6999 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7000 * @param[in] options XPath options.
7001 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7002 */
7003static LY_ERR
7004eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7005{
7006 LY_ERR rc;
7007 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007008 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007009 struct lyxp_set **args = NULL, **args_aux;
7010
7011 if (set) {
7012 /* FunctionName */
7013 switch (exp->tok_len[*exp_idx]) {
7014 case 3:
7015 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7016 xpath_func = &xpath_not;
7017 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7018 xpath_func = &xpath_sum;
7019 }
7020 break;
7021 case 4:
7022 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7023 xpath_func = &xpath_lang;
7024 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7025 xpath_func = &xpath_last;
7026 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7027 xpath_func = &xpath_name;
7028 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7029 xpath_func = &xpath_true;
7030 }
7031 break;
7032 case 5:
7033 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7034 xpath_func = &xpath_count;
7035 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7036 xpath_func = &xpath_false;
7037 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7038 xpath_func = &xpath_floor;
7039 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7040 xpath_func = &xpath_round;
7041 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7042 xpath_func = &xpath_deref;
7043 }
7044 break;
7045 case 6:
7046 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7047 xpath_func = &xpath_concat;
7048 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7049 xpath_func = &xpath_number;
7050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7051 xpath_func = &xpath_string;
7052 }
7053 break;
7054 case 7:
7055 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7056 xpath_func = &xpath_boolean;
7057 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7058 xpath_func = &xpath_ceiling;
7059 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7060 xpath_func = &xpath_current;
7061 }
7062 break;
7063 case 8:
7064 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7065 xpath_func = &xpath_contains;
7066 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7067 xpath_func = &xpath_position;
7068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7069 xpath_func = &xpath_re_match;
7070 }
7071 break;
7072 case 9:
7073 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7074 xpath_func = &xpath_substring;
7075 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7076 xpath_func = &xpath_translate;
7077 }
7078 break;
7079 case 10:
7080 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7081 xpath_func = &xpath_local_name;
7082 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7083 xpath_func = &xpath_enum_value;
7084 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7085 xpath_func = &xpath_bit_is_set;
7086 }
7087 break;
7088 case 11:
7089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7090 xpath_func = &xpath_starts_with;
7091 }
7092 break;
7093 case 12:
7094 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7095 xpath_func = &xpath_derived_from;
7096 }
7097 break;
7098 case 13:
7099 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7100 xpath_func = &xpath_namespace_uri;
7101 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7102 xpath_func = &xpath_string_length;
7103 }
7104 break;
7105 case 15:
7106 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7107 xpath_func = &xpath_normalize_space;
7108 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7109 xpath_func = &xpath_substring_after;
7110 }
7111 break;
7112 case 16:
7113 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7114 xpath_func = &xpath_substring_before;
7115 }
7116 break;
7117 case 20:
7118 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7119 xpath_func = &xpath_derived_from_or_self;
7120 }
7121 break;
7122 }
7123
7124 if (!xpath_func) {
7125 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7126 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]]);
7127 return LY_EVALID;
7128 }
7129 }
7130
7131 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7132 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7133 ++(*exp_idx);
7134
7135 /* '(' */
7136 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7137 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7138 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7139 ++(*exp_idx);
7140
7141 /* ( Expr ( ',' Expr )* )? */
7142 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7143 if (set) {
7144 args = malloc(sizeof *args);
7145 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7146 arg_count = 1;
7147 args[0] = set_copy(set);
7148 if (!args[0]) {
7149 rc = LY_EMEM;
7150 goto cleanup;
7151 }
7152
7153 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7154 LY_CHECK_GOTO(rc, cleanup);
7155 } else {
7156 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7157 LY_CHECK_GOTO(rc, cleanup);
7158 }
7159 }
7160 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7161 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7162 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7163 ++(*exp_idx);
7164
7165 if (set) {
7166 ++arg_count;
7167 args_aux = realloc(args, arg_count * sizeof *args);
7168 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7169 args = args_aux;
7170 args[arg_count - 1] = set_copy(set);
7171 if (!args[arg_count - 1]) {
7172 rc = LY_EMEM;
7173 goto cleanup;
7174 }
7175
7176 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7177 LY_CHECK_GOTO(rc, cleanup);
7178 } else {
7179 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7180 LY_CHECK_GOTO(rc, cleanup);
7181 }
7182 }
7183
7184 /* ')' */
7185 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7186 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7187 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7188 ++(*exp_idx);
7189
7190 if (set) {
7191 /* evaluate function */
7192 rc = xpath_func(args, arg_count, set, options);
7193
7194 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007195 /* merge all nodes from arg evaluations */
7196 for (i = 0; i < arg_count; ++i) {
7197 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007198 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007199 }
7200 }
7201 } else {
7202 rc = LY_SUCCESS;
7203 }
7204
7205cleanup:
7206 for (i = 0; i < arg_count; ++i) {
7207 lyxp_set_free(args[i]);
7208 }
7209 free(args);
7210
7211 return rc;
7212}
7213
7214/**
7215 * @brief Evaluate Number. Logs directly on error.
7216 *
7217 * @param[in] ctx Context for errors.
7218 * @param[in] exp Parsed XPath expression.
7219 * @param[in] exp_idx Position in the expression @p exp.
7220 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7221 * @return LY_ERR
7222 */
7223static LY_ERR
7224eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7225{
7226 long double num;
7227 char *endptr;
7228
7229 if (set) {
7230 errno = 0;
7231 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7232 if (errno) {
7233 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7234 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7235 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7236 return LY_EVALID;
7237 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7238 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7239 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7240 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7241 return LY_EVALID;
7242 }
7243
7244 set_fill_number(set, num);
7245 }
7246
7247 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7248 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7249 ++(*exp_idx);
7250 return LY_SUCCESS;
7251}
7252
7253/**
7254 * @brief Evaluate PathExpr. Logs directly on error.
7255 *
7256 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7257 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7258 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7259 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7260 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7261 *
7262 * @param[in] exp Parsed XPath expression.
7263 * @param[in] exp_idx Position in the expression @p exp.
7264 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7265 * @param[in] options XPath options.
7266 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7267 */
7268static LY_ERR
7269eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7270{
7271 int all_desc, parent_pos_pred;
7272 LY_ERR rc;
7273
7274 switch (exp->tokens[*exp_idx]) {
7275 case LYXP_TOKEN_PAR1:
7276 /* '(' Expr ')' */
7277
7278 /* '(' */
7279 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7280 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7281 ++(*exp_idx);
7282
7283 /* Expr */
7284 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7285 LY_CHECK_RET(rc);
7286
7287 /* ')' */
7288 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7289 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7290 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7291 ++(*exp_idx);
7292
7293 parent_pos_pred = 0;
7294 goto predicate;
7295
7296 case LYXP_TOKEN_DOT:
7297 case LYXP_TOKEN_DDOT:
7298 case LYXP_TOKEN_AT:
7299 case LYXP_TOKEN_NAMETEST:
7300 case LYXP_TOKEN_NODETYPE:
7301 /* RelativeLocationPath */
7302 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7303 LY_CHECK_RET(rc);
7304 break;
7305
7306 case LYXP_TOKEN_FUNCNAME:
7307 /* FunctionCall */
7308 if (!set) {
7309 rc = eval_function_call(exp, exp_idx, NULL, options);
7310 } else {
7311 rc = eval_function_call(exp, exp_idx, set, options);
7312 }
7313 LY_CHECK_RET(rc);
7314
7315 parent_pos_pred = 1;
7316 goto predicate;
7317
7318 case LYXP_TOKEN_OPERATOR_PATH:
7319 /* AbsoluteLocationPath */
7320 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7321 LY_CHECK_RET(rc);
7322 break;
7323
7324 case LYXP_TOKEN_LITERAL:
7325 /* Literal */
7326 if (!set || (options & LYXP_SCNODE_ALL)) {
7327 if (set) {
7328 set_scnode_clear_ctx(set);
7329 }
7330 eval_literal(exp, exp_idx, NULL);
7331 } else {
7332 eval_literal(exp, exp_idx, set);
7333 }
7334
7335 parent_pos_pred = 1;
7336 goto predicate;
7337
7338 case LYXP_TOKEN_NUMBER:
7339 /* Number */
7340 if (!set || (options & LYXP_SCNODE_ALL)) {
7341 if (set) {
7342 set_scnode_clear_ctx(set);
7343 }
Michal Vasko02a77382019-09-12 11:47:35 +02007344 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007345 } else {
7346 rc = eval_number(set->ctx, exp, exp_idx, set);
7347 }
7348 LY_CHECK_RET(rc);
7349
7350 parent_pos_pred = 1;
7351 goto predicate;
7352
7353 default:
7354 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7355 &exp->expr[exp->tok_pos[*exp_idx]]);
7356 return LY_EVALID;
7357 }
7358
7359 return LY_SUCCESS;
7360
7361predicate:
7362 /* Predicate* */
7363 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7364 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7365 LY_CHECK_RET(rc);
7366 }
7367
7368 /* ('/' or '//') RelativeLocationPath */
7369 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7370
7371 /* evaluate '/' or '//' */
7372 if (exp->tok_len[*exp_idx] == 1) {
7373 all_desc = 0;
7374 } else {
7375 assert(exp->tok_len[*exp_idx] == 2);
7376 all_desc = 1;
7377 }
7378
7379 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7380 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7381 ++(*exp_idx);
7382
7383 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7384 LY_CHECK_RET(rc);
7385 }
7386
7387 return LY_SUCCESS;
7388}
7389
7390/**
7391 * @brief Evaluate UnionExpr. Logs directly on error.
7392 *
7393 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7394 *
7395 * @param[in] exp Parsed XPath expression.
7396 * @param[in] exp_idx Position in the expression @p exp.
7397 * @param[in] repeat How many times this expression is repeated.
7398 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7399 * @param[in] options XPath options.
7400 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7401 */
7402static LY_ERR
7403eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7404{
7405 LY_ERR rc = LY_SUCCESS;
7406 struct lyxp_set orig_set, set2;
7407 uint16_t i;
7408
7409 assert(repeat);
7410
7411 set_init(&orig_set, set);
7412 set_init(&set2, set);
7413
7414 set_fill_set(&orig_set, set);
7415
7416 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7417 LY_CHECK_GOTO(rc, cleanup);
7418
7419 /* ('|' PathExpr)* */
7420 for (i = 0; i < repeat; ++i) {
7421 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7422 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7423 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7424 ++(*exp_idx);
7425
7426 if (!set) {
7427 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7428 LY_CHECK_GOTO(rc, cleanup);
7429 continue;
7430 }
7431
7432 set_fill_set(&set2, &orig_set);
7433 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7434 LY_CHECK_GOTO(rc, cleanup);
7435
7436 /* eval */
7437 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007438 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007439 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007440 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007441 LY_CHECK_GOTO(rc, cleanup);
7442 }
7443 }
7444
7445cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007446 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7447 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007448 return rc;
7449}
7450
7451/**
7452 * @brief Evaluate UnaryExpr. Logs directly on error.
7453 *
7454 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7455 *
7456 * @param[in] exp Parsed XPath expression.
7457 * @param[in] exp_idx Position in the expression @p exp.
7458 * @param[in] repeat How many times this expression is repeated.
7459 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7460 * @param[in] options XPath options.
7461 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7462 */
7463static LY_ERR
7464eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7465{
7466 LY_ERR rc;
7467 uint16_t this_op, i;
7468
7469 assert(repeat);
7470
7471 /* ('-')+ */
7472 this_op = *exp_idx;
7473 for (i = 0; i < repeat; ++i) {
7474 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7475
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
7481 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7482 LY_CHECK_RET(rc);
7483
7484 if (set && (repeat % 2)) {
7485 if (options & LYXP_SCNODE_ALL) {
7486 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7487 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007488 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007489 LY_CHECK_RET(rc);
7490 }
7491 }
7492
7493 return LY_SUCCESS;
7494}
7495
7496/**
7497 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7498 *
7499 * [16] MultiplicativeExpr ::= UnaryExpr
7500 * | MultiplicativeExpr '*' UnaryExpr
7501 * | MultiplicativeExpr 'div' UnaryExpr
7502 * | MultiplicativeExpr 'mod' UnaryExpr
7503 *
7504 * @param[in] exp Parsed XPath expression.
7505 * @param[in] exp_idx Position in the expression @p exp.
7506 * @param[in] repeat How many times this expression is repeated.
7507 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7508 * @param[in] options XPath options.
7509 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7510 */
7511static LY_ERR
7512eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7513{
7514 LY_ERR rc;
7515 uint16_t this_op;
7516 struct lyxp_set orig_set, set2;
7517 uint16_t i;
7518
7519 assert(repeat);
7520
7521 set_init(&orig_set, set);
7522 set_init(&set2, set);
7523
7524 set_fill_set(&orig_set, set);
7525
7526 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7527 LY_CHECK_GOTO(rc, cleanup);
7528
7529 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7530 for (i = 0; i < repeat; ++i) {
7531 this_op = *exp_idx;
7532
7533 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7534 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7535 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7536 ++(*exp_idx);
7537
7538 if (!set) {
7539 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7540 LY_CHECK_GOTO(rc, cleanup);
7541 continue;
7542 }
7543
7544 set_fill_set(&set2, &orig_set);
7545 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7546 LY_CHECK_GOTO(rc, cleanup);
7547
7548 /* eval */
7549 if (options & LYXP_SCNODE_ALL) {
7550 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007551 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007552 set_scnode_clear_ctx(set);
7553 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007554 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007555 LY_CHECK_GOTO(rc, cleanup);
7556 }
7557 }
7558
7559cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007560 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7561 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007562 return rc;
7563}
7564
7565/**
7566 * @brief Evaluate AdditiveExpr. Logs directly on error.
7567 *
7568 * [15] AdditiveExpr ::= MultiplicativeExpr
7569 * | AdditiveExpr '+' MultiplicativeExpr
7570 * | AdditiveExpr '-' MultiplicativeExpr
7571 *
7572 * @param[in] exp Parsed XPath expression.
7573 * @param[in] exp_idx Position in the expression @p exp.
7574 * @param[in] repeat How many times this expression is repeated.
7575 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7576 * @param[in] options XPath options.
7577 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7578 */
7579static LY_ERR
7580eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7581{
7582 LY_ERR rc;
7583 uint16_t this_op;
7584 struct lyxp_set orig_set, set2;
7585 uint16_t i;
7586
7587 assert(repeat);
7588
7589 set_init(&orig_set, set);
7590 set_init(&set2, set);
7591
7592 set_fill_set(&orig_set, set);
7593
7594 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7595 LY_CHECK_GOTO(rc, cleanup);
7596
7597 /* ('+' / '-' MultiplicativeExpr)* */
7598 for (i = 0; i < repeat; ++i) {
7599 this_op = *exp_idx;
7600
7601 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7602 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7603 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7604 ++(*exp_idx);
7605
7606 if (!set) {
7607 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7608 LY_CHECK_GOTO(rc, cleanup);
7609 continue;
7610 }
7611
7612 set_fill_set(&set2, &orig_set);
7613 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7614 LY_CHECK_GOTO(rc, cleanup);
7615
7616 /* eval */
7617 if (options & LYXP_SCNODE_ALL) {
7618 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007619 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007620 set_scnode_clear_ctx(set);
7621 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007622 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007623 LY_CHECK_GOTO(rc, cleanup);
7624 }
7625 }
7626
7627cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007628 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7629 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007630 return rc;
7631}
7632
7633/**
7634 * @brief Evaluate RelationalExpr. Logs directly on error.
7635 *
7636 * [14] RelationalExpr ::= AdditiveExpr
7637 * | RelationalExpr '<' AdditiveExpr
7638 * | RelationalExpr '>' AdditiveExpr
7639 * | RelationalExpr '<=' AdditiveExpr
7640 * | RelationalExpr '>=' AdditiveExpr
7641 *
7642 * @param[in] exp Parsed XPath expression.
7643 * @param[in] exp_idx Position in the expression @p exp.
7644 * @param[in] repeat How many times this expression is repeated.
7645 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7646 * @param[in] options XPath options.
7647 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7648 */
7649static LY_ERR
7650eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7651{
7652 LY_ERR rc;
7653 uint16_t this_op;
7654 struct lyxp_set orig_set, set2;
7655 uint16_t i;
7656
7657 assert(repeat);
7658
7659 set_init(&orig_set, set);
7660 set_init(&set2, set);
7661
7662 set_fill_set(&orig_set, set);
7663
7664 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7665 LY_CHECK_GOTO(rc, cleanup);
7666
7667 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7668 for (i = 0; i < repeat; ++i) {
7669 this_op = *exp_idx;
7670
7671 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7672 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7673 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7674 ++(*exp_idx);
7675
7676 if (!set) {
7677 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7678 LY_CHECK_GOTO(rc, cleanup);
7679 continue;
7680 }
7681
7682 set_fill_set(&set2, &orig_set);
7683 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7684 LY_CHECK_GOTO(rc, cleanup);
7685
7686 /* eval */
7687 if (options & LYXP_SCNODE_ALL) {
7688 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007689 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007690 set_scnode_clear_ctx(set);
7691 } else {
7692 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7693 LY_CHECK_GOTO(rc, cleanup);
7694 }
7695 }
7696
7697cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007698 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7699 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007700 return rc;
7701}
7702
7703/**
7704 * @brief Evaluate EqualityExpr. Logs directly on error.
7705 *
7706 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7707 * | EqualityExpr '!=' RelationalExpr
7708 *
7709 * @param[in] exp Parsed XPath expression.
7710 * @param[in] exp_idx Position in the expression @p exp.
7711 * @param[in] repeat How many times this expression is repeated.
7712 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7713 * @param[in] options XPath options.
7714 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7715 */
7716static LY_ERR
7717eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7718{
7719 LY_ERR rc;
7720 uint16_t this_op;
7721 struct lyxp_set orig_set, set2;
7722 uint16_t i;
7723
7724 assert(repeat);
7725
7726 set_init(&orig_set, set);
7727 set_init(&set2, set);
7728
7729 set_fill_set(&orig_set, set);
7730
7731 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7732 LY_CHECK_GOTO(rc, cleanup);
7733
7734 /* ('=' / '!=' RelationalExpr)* */
7735 for (i = 0; i < repeat; ++i) {
7736 this_op = *exp_idx;
7737
7738 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7739 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7740 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7741 ++(*exp_idx);
7742
7743 if (!set) {
7744 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7745 LY_CHECK_GOTO(rc, cleanup);
7746 continue;
7747 }
7748
7749 set_fill_set(&set2, &orig_set);
7750 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7751 LY_CHECK_GOTO(rc, cleanup);
7752
7753 /* eval */
7754 if (options & LYXP_SCNODE_ALL) {
7755 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7756 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7757 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007758 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007759 set_scnode_clear_ctx(set);
7760 } else {
7761 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7762 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7763 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7764 /* left operand is identityref */
7765 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7766 /* missing prefix in the right operand */
7767 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7768 if (!set2.val.str) {
7769 goto cleanup;
7770 }
7771
7772 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7773 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7774 set2.val.str[strlen(set->local_mod->name)] = ':';
7775 }
7776 }
7777
7778 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7779 LY_CHECK_GOTO(rc, cleanup);
7780 }
7781 }
7782
7783cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007784 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7785 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007786 return rc;
7787}
7788
7789/**
7790 * @brief Evaluate AndExpr. Logs directly on error.
7791 *
7792 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7793 *
7794 * @param[in] exp Parsed XPath expression.
7795 * @param[in] exp_idx Position in the expression @p exp.
7796 * @param[in] repeat How many times this expression is repeated.
7797 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7798 * @param[in] options XPath options.
7799 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7800 */
7801static LY_ERR
7802eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7803{
7804 LY_ERR rc;
7805 struct lyxp_set orig_set, set2;
7806 uint16_t i;
7807
7808 assert(repeat);
7809
7810 set_init(&orig_set, set);
7811 set_init(&set2, set);
7812
7813 set_fill_set(&orig_set, set);
7814
7815 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7816 LY_CHECK_GOTO(rc, cleanup);
7817
7818 /* cast to boolean, we know that will be the final result */
7819 if (set && (options & LYXP_SCNODE_ALL)) {
7820 set_scnode_clear_ctx(set);
7821 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007822 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007823 }
7824
7825 /* ('and' EqualityExpr)* */
7826 for (i = 0; i < repeat; ++i) {
7827 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7828 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7829 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7830 ++(*exp_idx);
7831
7832 /* lazy evaluation */
7833 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7834 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7835 LY_CHECK_GOTO(rc, cleanup);
7836 continue;
7837 }
7838
7839 set_fill_set(&set2, &orig_set);
7840 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7841 LY_CHECK_GOTO(rc, cleanup);
7842
7843 /* eval - just get boolean value actually */
7844 if (set->type == LYXP_SET_SCNODE_SET) {
7845 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007846 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007847 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007848 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007849 set_fill_set(set, &set2);
7850 }
7851 }
7852
7853cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007854 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7855 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007856 return rc;
7857}
7858
7859/**
7860 * @brief Evaluate OrExpr. Logs directly on error.
7861 *
7862 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7863 *
7864 * @param[in] exp Parsed XPath expression.
7865 * @param[in] exp_idx Position in the expression @p exp.
7866 * @param[in] repeat How many times this expression is repeated.
7867 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7868 * @param[in] options XPath options.
7869 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7870 */
7871static LY_ERR
7872eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7873{
7874 LY_ERR rc;
7875 struct lyxp_set orig_set, set2;
7876 uint16_t i;
7877
7878 assert(repeat);
7879
7880 set_init(&orig_set, set);
7881 set_init(&set2, set);
7882
7883 set_fill_set(&orig_set, set);
7884
7885 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7886 LY_CHECK_GOTO(rc, cleanup);
7887
7888 /* cast to boolean, we know that will be the final result */
7889 if (set && (options & LYXP_SCNODE_ALL)) {
7890 set_scnode_clear_ctx(set);
7891 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007892 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007893 }
7894
7895 /* ('or' AndExpr)* */
7896 for (i = 0; i < repeat; ++i) {
7897 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7898 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7899 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7900 ++(*exp_idx);
7901
7902 /* lazy evaluation */
7903 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7904 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7905 LY_CHECK_GOTO(rc, cleanup);
7906 continue;
7907 }
7908
7909 set_fill_set(&set2, &orig_set);
7910 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7911 * but it does not matter */
7912 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7913 LY_CHECK_GOTO(rc, cleanup);
7914
7915 /* eval - just get boolean value actually */
7916 if (set->type == LYXP_SET_SCNODE_SET) {
7917 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007918 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007919 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007920 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007921 set_fill_set(set, &set2);
7922 }
7923 }
7924
7925cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007926 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7927 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007928 return rc;
7929}
7930
7931/**
7932 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7933 *
7934 * @param[in] exp Parsed XPath expression.
7935 * @param[in] exp_idx Position in the expression @p exp.
7936 * @param[in] etype Expression type to evaluate.
7937 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7938 * @param[in] options XPath options.
7939 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7940 */
7941static LY_ERR
7942eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7943{
7944 uint16_t i, count;
7945 enum lyxp_expr_type next_etype;
7946 LY_ERR rc;
7947
7948 /* process operator repeats */
7949 if (!exp->repeat[*exp_idx]) {
7950 next_etype = LYXP_EXPR_NONE;
7951 } else {
7952 /* find etype repeat */
7953 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7954
7955 /* select one-priority lower because etype expression called us */
7956 if (i) {
7957 next_etype = exp->repeat[*exp_idx][i - 1];
7958 /* count repeats for that expression */
7959 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7960 } else {
7961 next_etype = LYXP_EXPR_NONE;
7962 }
7963 }
7964
7965 /* decide what expression are we parsing based on the repeat */
7966 switch (next_etype) {
7967 case LYXP_EXPR_OR:
7968 rc = eval_or_expr(exp, exp_idx, count, set, options);
7969 break;
7970 case LYXP_EXPR_AND:
7971 rc = eval_and_expr(exp, exp_idx, count, set, options);
7972 break;
7973 case LYXP_EXPR_EQUALITY:
7974 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7975 break;
7976 case LYXP_EXPR_RELATIONAL:
7977 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7978 break;
7979 case LYXP_EXPR_ADDITIVE:
7980 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7981 break;
7982 case LYXP_EXPR_MULTIPLICATIVE:
7983 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7984 break;
7985 case LYXP_EXPR_UNARY:
7986 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7987 break;
7988 case LYXP_EXPR_UNION:
7989 rc = eval_union_expr(exp, exp_idx, count, set, options);
7990 break;
7991 case LYXP_EXPR_NONE:
7992 rc = eval_path_expr(exp, exp_idx, set, options);
7993 break;
7994 default:
7995 LOGINT_RET(set->ctx);
7996 }
7997
7998 return rc;
7999}
8000
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008001/**
8002 * @brief Get root type.
8003 *
8004 * @param[in] ctx_node Context node.
8005 * @param[in] ctx_scnode Schema context node.
8006 * @param[in] options XPath options.
8007 * @return Root type.
8008 */
8009static enum lyxp_node_type
8010lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8011{
8012 if (options & LYXP_SCNODE_ALL) {
8013 if (options & LYXP_SCNODE) {
8014 /* general root that can access everything */
8015 return LYXP_NODE_ROOT;
8016 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8017 /* root context node can access only config data (because we said so, it is unspecified) */
8018 return LYXP_NODE_ROOT_CONFIG;
8019 } else {
8020 return LYXP_NODE_ROOT;
8021 }
8022 }
8023
8024 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8025 /* root context node can access only config data (because we said so, it is unspecified) */
8026 return LYXP_NODE_ROOT_CONFIG;
8027 }
8028
8029 return LYXP_NODE_ROOT;
8030}
8031
Michal Vasko03ff5a72019-09-11 13:49:33 +02008032LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008033lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
Michal Vaskof03ed032020-03-04 13:31:44 +01008034 enum lyxp_node_type ctx_node_type, const struct lyd_node *tree, struct lyxp_set *set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008035{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008036 uint16_t exp_idx = 0;
8037 LY_ERR rc;
8038
Michal Vaskoecd62de2019-11-13 12:35:11 +01008039 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008040
8041 /* prepare set for evaluation */
8042 exp_idx = 0;
8043 memset(set, 0, sizeof *set);
8044 set->type = LYXP_SET_EMPTY;
Michal Vasko9b368d32020-02-14 13:53:31 +01008045 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, 0);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008046 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008047 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008048 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008049 set->local_mod = local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +01008050 set->tree = tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008051 set->format = format;
8052
8053 /* evaluate */
8054 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8055 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008056 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008057 }
8058
Michal Vasko03ff5a72019-09-11 13:49:33 +02008059 return rc;
8060}
8061
8062#if 0
8063
8064/* full xml printing of set elements, not used currently */
8065
8066void
8067lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8068{
8069 uint32_t i;
8070 char *str_num;
8071 struct lyout out;
8072
8073 memset(&out, 0, sizeof out);
8074
8075 out.type = LYOUT_STREAM;
8076 out.method.f = f;
8077
8078 switch (set->type) {
8079 case LYXP_SET_EMPTY:
8080 ly_print(&out, "Empty XPath set\n\n");
8081 break;
8082 case LYXP_SET_BOOLEAN:
8083 ly_print(&out, "Boolean XPath set:\n");
8084 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8085 break;
8086 case LYXP_SET_STRING:
8087 ly_print(&out, "String XPath set:\n");
8088 ly_print(&out, "\"%s\"\n\n", set->value.str);
8089 break;
8090 case LYXP_SET_NUMBER:
8091 ly_print(&out, "Number XPath set:\n");
8092
8093 if (isnan(set->value.num)) {
8094 str_num = strdup("NaN");
8095 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8096 str_num = strdup("0");
8097 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8098 str_num = strdup("Infinity");
8099 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8100 str_num = strdup("-Infinity");
8101 } else if ((long long)set->value.num == set->value.num) {
8102 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8103 str_num = NULL;
8104 }
8105 } else {
8106 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8107 str_num = NULL;
8108 }
8109 }
8110 if (!str_num) {
8111 LOGMEM;
8112 return;
8113 }
8114 ly_print(&out, "%s\n\n", str_num);
8115 free(str_num);
8116 break;
8117 case LYXP_SET_NODE_SET:
8118 ly_print(&out, "Node XPath set:\n");
8119
8120 for (i = 0; i < set->used; ++i) {
8121 ly_print(&out, "%d. ", i + 1);
8122 switch (set->node_type[i]) {
8123 case LYXP_NODE_ROOT_ALL:
8124 ly_print(&out, "ROOT all\n\n");
8125 break;
8126 case LYXP_NODE_ROOT_CONFIG:
8127 ly_print(&out, "ROOT config\n\n");
8128 break;
8129 case LYXP_NODE_ROOT_STATE:
8130 ly_print(&out, "ROOT state\n\n");
8131 break;
8132 case LYXP_NODE_ROOT_NOTIF:
8133 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8134 break;
8135 case LYXP_NODE_ROOT_RPC:
8136 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8137 break;
8138 case LYXP_NODE_ROOT_OUTPUT:
8139 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8140 break;
8141 case LYXP_NODE_ELEM:
8142 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8143 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8144 ly_print(&out, "\n");
8145 break;
8146 case LYXP_NODE_TEXT:
8147 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8148 break;
8149 case LYXP_NODE_ATTR:
8150 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8151 break;
8152 }
8153 }
8154 break;
8155 }
8156}
8157
8158#endif
8159
8160LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008161lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008162{
8163 long double num;
8164 char *str;
8165 LY_ERR rc;
8166
8167 if (!set || (set->type == target)) {
8168 return LY_SUCCESS;
8169 }
8170
8171 /* it's not possible to convert anything into a node set */
8172 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8173
8174 if (set->type == LYXP_SET_SCNODE_SET) {
8175 set_free_content(set);
8176 return LY_EINVAL;
8177 }
8178
8179 /* to STRING */
8180 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8181 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8182 switch (set->type) {
8183 case LYXP_SET_NUMBER:
8184 if (isnan(set->val.num)) {
8185 set->val.str = strdup("NaN");
8186 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8187 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8188 set->val.str = strdup("0");
8189 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8190 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8191 set->val.str = strdup("Infinity");
8192 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8193 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8194 set->val.str = strdup("-Infinity");
8195 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8196 } else if ((long long)set->val.num == set->val.num) {
8197 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8198 LOGMEM_RET(set->ctx);
8199 }
8200 set->val.str = str;
8201 } else {
8202 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8203 LOGMEM_RET(set->ctx);
8204 }
8205 set->val.str = str;
8206 }
8207 break;
8208 case LYXP_SET_BOOLEAN:
8209 if (set->val.bool) {
8210 set->val.str = strdup("true");
8211 } else {
8212 set->val.str = strdup("false");
8213 }
8214 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8215 break;
8216 case LYXP_SET_NODE_SET:
8217 assert(set->used);
8218
8219 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008220 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008221
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008222 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008223 LY_CHECK_RET(rc);
8224 set_free_content(set);
8225 set->val.str = str;
8226 break;
8227 case LYXP_SET_EMPTY:
8228 set->val.str = strdup("");
8229 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8230 break;
8231 default:
8232 LOGINT_RET(set->ctx);
8233 }
8234 set->type = LYXP_SET_STRING;
8235 }
8236
8237 /* to NUMBER */
8238 if (target == LYXP_SET_NUMBER) {
8239 switch (set->type) {
8240 case LYXP_SET_STRING:
8241 num = cast_string_to_number(set->val.str);
8242 set_free_content(set);
8243 set->val.num = num;
8244 break;
8245 case LYXP_SET_BOOLEAN:
8246 if (set->val.bool) {
8247 set->val.num = 1;
8248 } else {
8249 set->val.num = 0;
8250 }
8251 break;
8252 default:
8253 LOGINT_RET(set->ctx);
8254 }
8255 set->type = LYXP_SET_NUMBER;
8256 }
8257
8258 /* to BOOLEAN */
8259 if (target == LYXP_SET_BOOLEAN) {
8260 switch (set->type) {
8261 case LYXP_SET_NUMBER:
8262 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8263 set->val.bool = 0;
8264 } else {
8265 set->val.bool = 1;
8266 }
8267 break;
8268 case LYXP_SET_STRING:
8269 if (set->val.str[0]) {
8270 set_free_content(set);
8271 set->val.bool = 1;
8272 } else {
8273 set_free_content(set);
8274 set->val.bool = 0;
8275 }
8276 break;
8277 case LYXP_SET_NODE_SET:
8278 set_free_content(set);
8279
8280 assert(set->used);
8281 set->val.bool = 1;
8282 break;
8283 case LYXP_SET_EMPTY:
8284 set->val.bool = 0;
8285 break;
8286 default:
8287 LOGINT_RET(set->ctx);
8288 }
8289 set->type = LYXP_SET_BOOLEAN;
8290 }
8291
8292 /* to EMPTY */
8293 if (target == LYXP_SET_EMPTY) {
8294 set_free_content(set);
8295 set->type = LYXP_SET_EMPTY;
8296 }
8297
8298 return LY_SUCCESS;
8299}
8300
8301LY_ERR
8302lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8303 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8304{
8305 struct ly_ctx *ctx;
8306 uint16_t exp_idx = 0;
8307
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008308 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008309
8310 ctx = local_mod->ctx;
8311
8312 /* prepare set for evaluation */
8313 exp_idx = 0;
8314 memset(set, 0, sizeof *set);
8315 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008316 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008317 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008318 set->ctx = ctx;
8319 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008320 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008321 set->local_mod = local_mod;
8322 set->format = format;
8323
8324 /* evaluate */
8325 return eval_expr_select(exp, &exp_idx, 0, set, options);
8326}