blob: 38489eead8ae6e713ec6f53dd359584575eae528 [file] [log] [blame]
Radek Krejcib1646a92018-11-02 16:08:26 +01001/**
2 * @file xpath.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief YANG XPath evaluation functions
5 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02006 * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
Radek Krejcib1646a92018-11-02 16:08:26 +01007 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Michal Vasko03ff5a72019-09-11 13:49:33 +020014#define _GNU_SOURCE
15
16/* needed by libmath functions isfinite(), isinf(), isnan(), signbit(), ... */
17#define _ISOC99_SOURCE
Radek Krejcib1646a92018-11-02 16:08:26 +010018
19#include "common.h"
20
Michal Vasko03ff5a72019-09-11 13:49:33 +020021#include <math.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010022#include <ctype.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <stdint.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010024#include <stdio.h>
25#include <stdlib.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010026#include <string.h>
Michal Vasko03ff5a72019-09-11 13:49:33 +020027#include <errno.h>
28#include <assert.h>
Radek Krejcib1646a92018-11-02 16:08:26 +010029
30#include "xpath.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "dict.h"
Radek Krejcib1646a92018-11-02 16:08:26 +010032#include "xml.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020033#include "printer_data.h"
34#include "tree_schema_internal.h"
35#include "plugins_types.h"
36
Michal Vasko03ff5a72019-09-11 13:49:33 +020037static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +020038static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
39
40/**
41 * @brief Print the type of an XPath \p set.
42 *
43 * @param[in] set Set to use.
44 * @return Set type string.
45 */
46static const char *
47print_set_type(struct lyxp_set *set)
48{
49 switch (set->type) {
50 case LYXP_SET_EMPTY:
51 return "empty";
52 case LYXP_SET_NODE_SET:
53 return "node set";
54 case LYXP_SET_SCNODE_SET:
55 return "schema node set";
56 case LYXP_SET_BOOLEAN:
57 return "boolean";
58 case LYXP_SET_NUMBER:
59 return "number";
60 case LYXP_SET_STRING:
61 return "string";
62 }
63
64 return NULL;
65}
66
67/**
68 * @brief Print an XPath token \p tok type.
69 *
70 * @param[in] tok Token to use.
71 * @return Token type string.
72 */
73static const char *
74print_token(enum lyxp_token tok)
75{
76 switch (tok) {
77 case LYXP_TOKEN_PAR1:
78 return "(";
79 case LYXP_TOKEN_PAR2:
80 return ")";
81 case LYXP_TOKEN_BRACK1:
82 return "[";
83 case LYXP_TOKEN_BRACK2:
84 return "]";
85 case LYXP_TOKEN_DOT:
86 return ".";
87 case LYXP_TOKEN_DDOT:
88 return "..";
89 case LYXP_TOKEN_AT:
90 return "@";
91 case LYXP_TOKEN_COMMA:
92 return ",";
93 case LYXP_TOKEN_NAMETEST:
94 return "NameTest";
95 case LYXP_TOKEN_NODETYPE:
96 return "NodeType";
97 case LYXP_TOKEN_FUNCNAME:
98 return "FunctionName";
99 case LYXP_TOKEN_OPERATOR_LOG:
100 return "Operator(Logic)";
101 case LYXP_TOKEN_OPERATOR_COMP:
102 return "Operator(Comparison)";
103 case LYXP_TOKEN_OPERATOR_MATH:
104 return "Operator(Math)";
105 case LYXP_TOKEN_OPERATOR_UNI:
106 return "Operator(Union)";
107 case LYXP_TOKEN_OPERATOR_PATH:
108 return "Operator(Path)";
109 case LYXP_TOKEN_LITERAL:
110 return "Literal";
111 case LYXP_TOKEN_NUMBER:
112 return "Number";
113 default:
114 LOGINT(NULL);
115 return "";
116 }
117}
118
119/**
120 * @brief Print the whole expression \p exp to debug output.
121 *
122 * @param[in] exp Expression to use.
123 */
124static void
125print_expr_struct_debug(struct lyxp_expr *exp)
126{
127 uint16_t i, j;
128 char tmp[128];
129
130 if (!exp || (ly_log_level < LY_LLDBG)) {
131 return;
132 }
133
134 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
135 for (i = 0; i < exp->used; ++i) {
136 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", print_token(exp->tokens[i]), exp->tok_len[i],
137 &exp->expr[exp->tok_pos[i]]);
138 if (exp->repeat[i]) {
139 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
140 for (j = 1; exp->repeat[i][j]; ++j) {
141 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
142 }
143 strcat(tmp, ")");
144 }
145 LOGDBG(LY_LDGXPATH, tmp);
146 }
147}
148
149#ifndef NDEBUG
150
151/**
152 * @brief Print XPath set content to debug output.
153 *
154 * @param[in] set Set to print.
155 */
156static void
157print_set_debug(struct lyxp_set *set)
158{
159 uint32_t i;
160 char *str;
161 int dynamic;
162 struct lyxp_set_node *item;
163 struct lyxp_set_scnode *sitem;
164
165 if (ly_log_level < LY_LLDBG) {
166 return;
167 }
168
169 switch (set->type) {
170 case LYXP_SET_NODE_SET:
171 LOGDBG(LY_LDGXPATH, "set NODE SET:");
172 for (i = 0; i < set->used; ++i) {
173 item = &set->val.nodes[i];
174
175 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100176 case LYXP_NODE_NONE:
177 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
178 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200179 case LYXP_NODE_ROOT:
180 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
181 break;
182 case LYXP_NODE_ROOT_CONFIG:
183 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
184 break;
185 case LYXP_NODE_ELEM:
186 if ((item->node->schema->nodetype == LYS_LIST)
187 && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
188 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
189 item->node->schema->name,
190 (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node), &dynamic)));
191 if (dynamic) {
192 free(str);
193 }
194 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
195 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
196 item->node->schema->name,
197 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
198 if (dynamic) {
199 free(str);
200 }
201 } else {
202 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
203 }
204 break;
205 case LYXP_NODE_TEXT:
206 if (item->node->schema->nodetype & LYS_ANYDATA) {
207 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
208 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
209 } else {
210 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
211 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
212 if (dynamic) {
213 free(str);
214 }
215 }
216 break;
217 case LYXP_NODE_ATTR:
218 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ATTR %s = %s", i + 1, item->pos, set->val.attrs[i].attr->name,
219 set->val.attrs[i].attr->value);
220 break;
221 }
222 }
223 break;
224
225 case LYXP_SET_SCNODE_SET:
226 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
227 for (i = 0; i < set->used; ++i) {
228 sitem = &set->val.scnodes[i];
229
230 switch (sitem->type) {
231 case LYXP_NODE_ROOT:
232 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
233 break;
234 case LYXP_NODE_ROOT_CONFIG:
235 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
236 break;
237 case LYXP_NODE_ELEM:
238 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
239 break;
240 default:
241 LOGINT(NULL);
242 break;
243 }
244 }
245 break;
246
247 case LYXP_SET_EMPTY:
248 LOGDBG(LY_LDGXPATH, "set EMPTY");
249 break;
250
251 case LYXP_SET_BOOLEAN:
252 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
253 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
254 break;
255
256 case LYXP_SET_STRING:
257 LOGDBG(LY_LDGXPATH, "set STRING");
258 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
259 break;
260
261 case LYXP_SET_NUMBER:
262 LOGDBG(LY_LDGXPATH, "set NUMBER");
263
264 if (isnan(set->val.num)) {
265 str = strdup("NaN");
266 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
267 str = strdup("0");
268 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
269 str = strdup("Infinity");
270 } else if (isinf(set->val.num) && signbit(set->val.num)) {
271 str = strdup("-Infinity");
272 } else if ((long long)set->val.num == set->val.num) {
273 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
274 str = NULL;
275 }
276 } else {
277 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
278 str = NULL;
279 }
280 }
281 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
282
283 LOGDBG(LY_LDGXPATH, "\t%s", str);
284 free(str);
285 }
286}
287
288#endif
289
290/**
291 * @brief Realloc the string \p str.
292 *
293 * @param[in] ctx libyang context for logging.
294 * @param[in] needed How much free space is required.
295 * @param[in,out] str Pointer to the string to use.
296 * @param[in,out] used Used bytes in \p str.
297 * @param[in,out] size Allocated bytes in \p str.
298 * @return LY_ERR
299 */
300static LY_ERR
301cast_string_realloc(struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
302{
303 if (*size - *used < needed) {
304 do {
305 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
306 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
307 return LY_EINVAL;
308 }
309 *size += LYXP_STRING_CAST_SIZE_STEP;
310 } while (*size - *used < needed);
311 *str = ly_realloc(*str, *size * sizeof(char));
312 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
313 }
314
315 return LY_SUCCESS;
316}
317
318/**
319 * @brief Cast nodes recursively to one string @p str.
320 *
321 * @param[in] node Node to cast.
322 * @param[in] fake_cont Whether to put the data into a "fake" container.
323 * @param[in] root_type Type of the XPath root.
324 * @param[in] indent Current indent.
325 * @param[in,out] str Resulting string.
326 * @param[in,out] used Used bytes in @p str.
327 * @param[in,out] size Allocated bytes in @p str.
328 * @return LY_ERR
329 */
330static LY_ERR
331cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
332 uint16_t *used, uint16_t *size)
333{
334 char *buf, *line, *ptr;
335 const char *value_str;
336 int dynamic;
337 const struct lyd_node *child;
338 struct lyd_node_any *any;
339 LY_ERR rc;
340
341 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
342 return LY_SUCCESS;
343 }
344
345 if (fake_cont) {
346 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
347 LY_CHECK_RET(rc);
348 strcpy(*str + (*used - 1), "\n");
349 ++(*used);
350
351 ++indent;
352 }
353
354 switch (node->schema->nodetype) {
355 case LYS_CONTAINER:
356 case LYS_LIST:
357 case LYS_RPC:
358 case LYS_NOTIF:
359 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
360 LY_CHECK_RET(rc);
361 strcpy(*str + (*used - 1), "\n");
362 ++(*used);
363
364 for (child = lyd_node_children(node); child; child = child->next) {
365 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
366 LY_CHECK_RET(rc);
367 }
368
369 break;
370
371 case LYS_LEAF:
372 case LYS_LEAFLIST:
373 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
374
375 /* print indent */
376 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
377 if (rc != LY_SUCCESS) {
378 if (dynamic) {
379 free((char *)value_str);
380 }
381 return rc;
382 }
383 memset(*str + (*used - 1), ' ', indent * 2);
384 *used += indent * 2;
385
386 /* print value */
387 if (*used == 1) {
388 sprintf(*str + (*used - 1), "%s", value_str);
389 *used += strlen(value_str);
390 } else {
391 sprintf(*str + (*used - 1), "%s\n", value_str);
392 *used += strlen(value_str) + 1;
393 }
394 if (dynamic) {
395 free((char *)value_str);
396 }
397
398 break;
399
400 case LYS_ANYXML:
401 case LYS_ANYDATA:
402 any = (struct lyd_node_any *)node;
403 if (!(void *)any->value.tree) {
404 /* no content */
405 buf = strdup("");
406 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
407 } else {
408 switch (any->value_type) {
409 case LYD_ANYDATA_STRING:
410 case LYD_ANYDATA_XML:
411 case LYD_ANYDATA_JSON:
412 buf = strdup(any->value.json);
413 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
414 break;
415 case LYD_ANYDATA_DATATREE:
416 rc = lyd_print_mem(&buf, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
417 LY_CHECK_RET(rc);
418 break;
419 /* TODO case LYD_ANYDATA_LYB:
420 LOGERR(LYD_NODE_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
421 return -1;*/
422 }
423 }
424
425 line = strtok_r(buf, "\n", &ptr);
426 do {
427 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
428 if (rc != LY_SUCCESS) {
429 free(buf);
430 return rc;
431 }
432 memset(*str + (*used - 1), ' ', indent * 2);
433 *used += indent * 2;
434
435 strcpy(*str + (*used - 1), line);
436 *used += strlen(line);
437
438 strcpy(*str + (*used - 1), "\n");
439 *used += 1;
440 } while ((line = strtok_r(NULL, "\n", &ptr)));
441
442 free(buf);
443 break;
444
445 default:
446 LOGINT_RET(LYD_NODE_CTX(node));
447 }
448
449 if (fake_cont) {
450 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
451 LY_CHECK_RET(rc);
452 strcpy(*str + (*used - 1), "\n");
453 ++(*used);
454
455 --indent;
456 }
457
458 return LY_SUCCESS;
459}
460
461/**
462 * @brief Cast an element into a string.
463 *
464 * @param[in] node Node to cast.
465 * @param[in] fake_cont Whether to put the data into a "fake" container.
466 * @param[in] root_type Type of the XPath root.
467 * @param[out] str Element cast to dynamically-allocated string.
468 * @return LY_ERR
469 */
470static LY_ERR
471cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, char **str)
472{
473 uint16_t used, size;
474 LY_ERR rc;
475
476 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
477 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
478 (*str)[0] = '\0';
479 used = 1;
480 size = LYXP_STRING_CAST_SIZE_START;
481
482 rc = cast_string_recursive(node, fake_cont, root_type, 0, str, &used, &size);
483 if (rc != LY_SUCCESS) {
484 free(*str);
485 return rc;
486 }
487
488 if (size > used) {
489 *str = ly_realloc(*str, used * sizeof(char));
490 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
491 }
492 return LY_SUCCESS;
493}
494
495/**
496 * @brief Cast a LYXP_SET_NODE_SET set into a string.
497 * Context position aware.
498 *
499 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200500 * @param[out] str Cast dynamically-allocated string.
501 * @return LY_ERR
502 */
503static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100504cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200505{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200506 int dynamic;
507
Michal Vasko03ff5a72019-09-11 13:49:33 +0200508 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100509 case LYXP_NODE_NONE:
510 /* invalid */
511 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200512 case LYXP_NODE_ROOT:
513 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100514 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200515 case LYXP_NODE_ELEM:
516 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100517 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200518 case LYXP_NODE_ATTR:
519 *str = (char *)lyd_attr2str(set->val.attrs[0].attr, &dynamic);
520 if (!dynamic) {
521 *str = strdup(*str);
522 if (!*str) {
523 LOGMEM_RET(set->ctx);
524 }
525 }
526 return LY_SUCCESS;
527 }
528
529 LOGINT_RET(set->ctx);
530}
531
532/**
533 * @brief Cast a string into an XPath number.
534 *
535 * @param[in] str String to use.
536 * @return Cast number.
537 */
538static long double
539cast_string_to_number(const char *str)
540{
541 long double num;
542 char *ptr;
543
544 errno = 0;
545 num = strtold(str, &ptr);
546 if (errno || *ptr) {
547 num = NAN;
548 }
549 return num;
550}
551
552/**
553 * @brief Callback for checking value equality.
554 *
555 * @param[in] val1_p First value.
556 * @param[in] val2_p Second value.
557 * @param[in] mod Whether hash table is being modified.
558 * @param[in] cb_data Callback data.
559 * @return 0 if not equal, non-zero if equal.
560 */
561static int
562set_values_equal_cb(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
563{
564 struct lyxp_set_hash_node *val1, *val2;
565
566 val1 = (struct lyxp_set_hash_node *)val1_p;
567 val2 = (struct lyxp_set_hash_node *)val2_p;
568
569 if ((val1->node == val2->node) && (val1->type == val2->type)) {
570 return 1;
571 }
572
573 return 0;
574}
575
576/**
577 * @brief Insert node and its hash into set.
578 *
579 * @param[in] set et to insert to.
580 * @param[in] node Node with hash.
581 * @param[in] type Node type.
582 */
583static void
584set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
585{
586 int r;
587 uint32_t i, hash;
588 struct lyxp_set_hash_node hnode;
589
590 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
591 /* create hash table and add all the nodes */
592 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
593 for (i = 0; i < set->used; ++i) {
594 hnode.node = set->val.nodes[i].node;
595 hnode.type = set->val.nodes[i].type;
596
597 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
598 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
599 hash = dict_hash_multi(hash, NULL, 0);
600
601 r = lyht_insert(set->ht, &hnode, hash, NULL);
602 assert(!r);
603 (void)r;
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;
754 new->trees = set->trees;
755 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);
920 trg->ht = lyht_dup(src->ht);
921 }
922 }
923}
924
925/**
926 * @brief Clear context of all schema nodes.
927 *
928 * @param[in] set Set to clear.
929 */
930static void
931set_scnode_clear_ctx(struct lyxp_set *set)
932{
933 uint32_t i;
934
935 for (i = 0; i < set->used; ++i) {
936 if (set->val.scnodes[i].in_ctx == 1) {
937 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100938 } else if (set->val.scnodes[i].in_ctx == -2) {
939 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200940 }
941 }
942}
943
944/**
945 * @brief Remove a node from a set. Removing last node changes
946 * set into LYXP_SET_EMPTY. Context position aware.
947 *
948 * @param[in] set Set to use.
949 * @param[in] idx Index from @p set of the node to be removed.
950 */
951static void
952set_remove_node(struct lyxp_set *set, uint32_t idx)
953{
954 assert(set && (set->type == LYXP_SET_NODE_SET));
955 assert(idx < set->used);
956
957 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
958
959 --set->used;
960 if (set->used) {
961 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
962 (set->used - idx) * sizeof *set->val.nodes);
963 } else {
964 set_free_content(set);
965 set->type = LYXP_SET_EMPTY;
966 }
967}
968
969/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100970 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200971 *
972 * @param[in] set Set to use.
973 * @param[in] idx Index from @p set of the node to be removed.
974 */
975static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100976set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200977{
978 assert(set && (set->type == LYXP_SET_NODE_SET));
979 assert(idx < set->used);
980
Michal Vasko2caefc12019-11-14 16:07:56 +0100981 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
982 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
983 }
984 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200985}
986
987/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100988 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200989 * set into LYXP_SET_EMPTY. Context position aware.
990 *
991 * @param[in] set Set to consolidate.
992 */
993static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100994set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200995{
996 uint16_t i, orig_used, end;
997 int32_t start;
998
Michal Vasko2caefc12019-11-14 16:07:56 +0100999 assert(set && (set->type != LYXP_SET_EMPTY));
Michal Vasko57eab132019-09-24 11:46:26 +02001000
1001 orig_used = set->used;
1002 set->used = 0;
1003 for (i = 0; i < orig_used;) {
1004 start = -1;
1005 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001006 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001007 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001008 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001009 end = i;
1010 ++i;
1011 break;
1012 }
1013
1014 ++i;
1015 if (i == orig_used) {
1016 end = i;
1017 }
1018 } while (i < orig_used);
1019
1020 if (start > -1) {
1021 /* move the whole chunk of valid nodes together */
1022 if (set->used != (unsigned)start) {
1023 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1024 }
1025 set->used += end - start;
1026 }
1027 }
1028
1029 if (!set->used) {
1030 set_free_content(set);
1031 /* this changes it to LYXP_SET_EMPTY */
1032 memset(set, 0, sizeof *set);
1033 }
1034}
1035
1036/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001037 * @brief Check for duplicates in a node set.
1038 *
1039 * @param[in] set Set to check.
1040 * @param[in] node Node to look for in @p set.
1041 * @param[in] node_type Type of @p node.
1042 * @param[in] skip_idx Index from @p set to skip.
1043 * @return LY_ERR
1044 */
1045static LY_ERR
1046set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1047{
1048 uint32_t i;
1049
Michal Vasko2caefc12019-11-14 16:07:56 +01001050 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001051 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1052 }
1053
1054 for (i = 0; i < set->used; ++i) {
1055 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1056 continue;
1057 }
1058
1059 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1060 return LY_EEXIST;
1061 }
1062 }
1063
1064 return LY_SUCCESS;
1065}
1066
Michal Vaskoecd62de2019-11-13 12:35:11 +01001067int
1068lyxp_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 +02001069{
1070 uint32_t i;
1071
1072 for (i = 0; i < set->used; ++i) {
1073 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1074 continue;
1075 }
1076
1077 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1078 return i;
1079 }
1080 }
1081
1082 return -1;
1083}
1084
Michal Vaskoecd62de2019-11-13 12:35:11 +01001085void
1086lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001087{
1088 uint32_t orig_used, i, j;
1089
1090 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1091 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1092
1093 if (set2->type == LYXP_SET_EMPTY) {
1094 return;
1095 }
1096
1097 if (set1->type == LYXP_SET_EMPTY) {
1098 memcpy(set1, set2, sizeof *set1);
1099 return;
1100 }
1101
1102 if (set1->used + set2->used > set1->size) {
1103 set1->size = set1->used + set2->used;
1104 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1105 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1106 }
1107
1108 orig_used = set1->used;
1109
1110 for (i = 0; i < set2->used; ++i) {
1111 for (j = 0; j < orig_used; ++j) {
1112 /* detect duplicities */
1113 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1114 break;
1115 }
1116 }
1117
1118 if (j == orig_used) {
1119 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1120 ++set1->used;
1121 }
1122 }
1123
1124 set_free_content(set2);
1125 set2->type = LYXP_SET_EMPTY;
1126}
1127
1128/**
1129 * @brief Insert a node into a set. Context position aware.
1130 *
1131 * @param[in] set Set to use.
1132 * @param[in] node Node to insert to @p set.
1133 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1134 * @param[in] node_type Node type of @p node.
1135 * @param[in] idx Index in @p set to insert into.
1136 */
1137static void
1138set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1139{
1140 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1141
1142 if (set->type == LYXP_SET_EMPTY) {
1143 /* first item */
1144 if (idx) {
1145 /* no real harm done, but it is a bug */
1146 LOGINT(set->ctx);
1147 idx = 0;
1148 }
1149 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1150 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1151 set->type = LYXP_SET_NODE_SET;
1152 set->used = 0;
1153 set->size = LYXP_SET_SIZE_START;
1154 set->ctx_pos = 1;
1155 set->ctx_size = 1;
1156 set->ht = NULL;
1157 } else {
1158 /* not an empty set */
1159 if (set->used == set->size) {
1160
1161 /* set is full */
1162 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1163 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1164 set->size += LYXP_SET_SIZE_STEP;
1165 }
1166
1167 if (idx > set->used) {
1168 LOGINT(set->ctx);
1169 idx = set->used;
1170 }
1171
1172 /* make space for the new node */
1173 if (idx < set->used) {
1174 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1175 }
1176 }
1177
1178 /* finally assign the value */
1179 set->val.nodes[idx].node = (struct lyd_node *)node;
1180 set->val.nodes[idx].type = node_type;
1181 set->val.nodes[idx].pos = pos;
1182 ++set->used;
1183
Michal Vasko2caefc12019-11-14 16:07:56 +01001184 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1185 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1186 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001187}
1188
Michal Vaskoecd62de2019-11-13 12:35:11 +01001189int
1190lyxp_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 +02001191{
1192 int ret;
1193
1194 assert(set->type == LYXP_SET_SCNODE_SET);
1195
Michal Vaskoecd62de2019-11-13 12:35:11 +01001196 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001197 if (ret > -1) {
1198 set->val.scnodes[ret].in_ctx = 1;
1199 } else {
1200 if (set->used == set->size) {
1201 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1202 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1203 set->size += LYXP_SET_SIZE_STEP;
1204 }
1205
1206 ret = set->used;
1207 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1208 set->val.scnodes[ret].type = node_type;
1209 set->val.scnodes[ret].in_ctx = 1;
1210 ++set->used;
1211 }
1212
1213 return ret;
1214}
1215
1216/**
1217 * @brief Replace a node in a set with another. Context position aware.
1218 *
1219 * @param[in] set Set to use.
1220 * @param[in] node Node to insert to @p set.
1221 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1222 * @param[in] node_type Node type of @p node.
1223 * @param[in] idx Index in @p set of the node to replace.
1224 */
1225static void
1226set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1227{
1228 assert(set && (idx < set->used));
1229
Michal Vasko2caefc12019-11-14 16:07:56 +01001230 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1231 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1232 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001233 set->val.nodes[idx].node = (struct lyd_node *)node;
1234 set->val.nodes[idx].type = node_type;
1235 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001236 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1237 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1238 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001239}
1240
1241/**
1242 * @brief Set all nodes with ctx 1 to a new unique context value.
1243 *
1244 * @param[in] set Set to modify.
1245 * @return New context value.
1246 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001247static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001248set_scnode_new_in_ctx(struct lyxp_set *set)
1249{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001250 uint32_t i;
1251 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001252
1253 assert(set->type == LYXP_SET_SCNODE_SET);
1254
1255 ret_ctx = 3;
1256retry:
1257 for (i = 0; i < set->used; ++i) {
1258 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1259 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1260 goto retry;
1261 }
1262 }
1263 for (i = 0; i < set->used; ++i) {
1264 if (set->val.scnodes[i].in_ctx == 1) {
1265 set->val.scnodes[i].in_ctx = ret_ctx;
1266 }
1267 }
1268
1269 return ret_ctx;
1270}
1271
1272/**
1273 * @brief Get unique @p node position in the data.
1274 *
1275 * @param[in] node Node to find.
1276 * @param[in] node_type Node type of @p node.
1277 * @param[in] root Root node.
1278 * @param[in] root_type Type of the XPath @p root node.
1279 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1280 * be used to increase efficiency and start the DFS from this node.
1281 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1282 * @return Node position.
1283 */
1284static uint32_t
1285get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1286 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1287{
1288 const struct lyd_node *next, *elem, *top_sibling;
1289 uint32_t pos = 1;
1290
1291 assert(prev && prev_pos && !root->prev->next);
1292
1293 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1294 return 0;
1295 }
1296
1297 if (*prev) {
1298 /* start from the previous element instead from the root */
1299 elem = next = *prev;
1300 pos = *prev_pos;
1301 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1302 goto dfs_search;
1303 }
1304
1305 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1306 /* TREE DFS */
1307 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1308dfs_search:
1309 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1310 goto skip_children;
1311 }
1312
1313 if (elem == node) {
1314 break;
1315 }
1316 ++pos;
1317
1318 /* TREE DFS END */
1319 /* select element for the next run - children first,
1320 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1321 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1322 next = NULL;
1323 } else {
1324 next = lyd_node_children(elem);
1325 }
1326 if (!next) {
1327skip_children:
1328 /* no children */
1329 if (elem == top_sibling) {
1330 /* we are done, root has no children */
1331 elem = NULL;
1332 break;
1333 }
1334 /* try siblings */
1335 next = elem->next;
1336 }
1337 while (!next) {
1338 /* no siblings, go back through parents */
1339 if (elem->parent == top_sibling->parent) {
1340 /* we are done, no next element to process */
1341 elem = NULL;
1342 break;
1343 }
1344 /* parent is already processed, go to its sibling */
1345 elem = (struct lyd_node *)elem->parent;
1346 next = elem->next;
1347 }
1348 }
1349
1350 /* node found */
1351 if (elem) {
1352 break;
1353 }
1354 }
1355
1356 if (!elem) {
1357 if (!(*prev)) {
1358 /* we went from root and failed to find it, cannot be */
1359 LOGINT(node->schema->module->ctx);
1360 return 0;
1361 } else {
1362 *prev = NULL;
1363 *prev_pos = 0;
1364
1365 elem = next = top_sibling = root;
1366 pos = 1;
1367 goto dfs_search;
1368 }
1369 }
1370
1371 /* remember the last found node for next time */
1372 *prev = node;
1373 *prev_pos = pos;
1374
1375 return pos;
1376}
1377
1378/**
1379 * @brief Assign (fill) missing node positions.
1380 *
1381 * @param[in] set Set to fill positions in.
1382 * @param[in] root Context root node.
1383 * @param[in] root_type Context root type.
1384 * @return LY_ERR
1385 */
1386static LY_ERR
1387set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1388{
1389 const struct lyd_node *prev = NULL, *tmp_node;
1390 uint32_t i, tmp_pos = 0;
1391
1392 for (i = 0; i < set->used; ++i) {
1393 if (!set->val.nodes[i].pos) {
1394 tmp_node = NULL;
1395 switch (set->val.nodes[i].type) {
1396 case LYXP_NODE_ATTR:
1397 tmp_node = set->val.attrs[i].attr->parent;
1398 if (!tmp_node) {
1399 LOGINT_RET(root->schema->module->ctx);
1400 }
1401 /* fallthrough */
1402 case LYXP_NODE_ELEM:
1403 case LYXP_NODE_TEXT:
1404 if (!tmp_node) {
1405 tmp_node = set->val.nodes[i].node;
1406 }
1407 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1408 break;
1409 default:
1410 /* all roots have position 0 */
1411 break;
1412 }
1413 }
1414 }
1415
1416 return LY_SUCCESS;
1417}
1418
1419/**
1420 * @brief Get unique @p attr position in the parent attributes.
1421 *
1422 * @param[in] attr Attr to use.
1423 * @return Attribute position.
1424 */
1425static uint16_t
1426get_attr_pos(struct lyd_attr *attr)
1427{
1428 uint16_t pos = 0;
1429 struct lyd_attr *attr2;
1430
1431 for (attr2 = attr->parent->attr; attr2 && (attr2 != attr); attr2 = attr2->next) {
1432 ++pos;
1433 }
1434
1435 assert(attr2);
1436 return pos;
1437}
1438
1439/**
1440 * @brief Compare 2 nodes in respect to XPath document order.
1441 *
1442 * @param[in] item1 1st node.
1443 * @param[in] item2 2nd node.
1444 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1445 */
1446static int
1447set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1448{
1449 uint32_t attr_pos1 = 0, attr_pos2 = 0;
1450
1451 if (item1->pos < item2->pos) {
1452 return -1;
1453 }
1454
1455 if (item1->pos > item2->pos) {
1456 return 1;
1457 }
1458
1459 /* node positions are equal, the fun case */
1460
1461 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1462 /* special case since text nodes are actually saved as their parents */
1463 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1464 if (item1->type == LYXP_NODE_ELEM) {
1465 assert(item2->type == LYXP_NODE_TEXT);
1466 return -1;
1467 } else {
1468 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1469 return 1;
1470 }
1471 }
1472
1473 /* we need attr positions now */
1474 if (item1->type == LYXP_NODE_ATTR) {
1475 attr_pos1 = get_attr_pos((struct lyd_attr *)item1->node);
1476 }
1477 if (item2->type == LYXP_NODE_ATTR) {
1478 attr_pos2 = get_attr_pos((struct lyd_attr *)item2->node);
1479 }
1480
1481 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st ATTR - =pos= - 2nd ATTR */
1482 /* check for duplicates */
1483 if (item1->node == item2->node) {
1484 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_ATTR) || (attr_pos1 == attr_pos2)));
1485 return 0;
1486 }
1487
1488 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd ATTR */
1489 /* elem is always first, 2nd node is after it */
1490 if (item1->type == LYXP_NODE_ELEM) {
1491 assert(item2->type != LYXP_NODE_ELEM);
1492 return -1;
1493 }
1494
1495 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd ATTR, 1st ATTR - any pos - 2nd ELEM, 1st ATTR - >pos> - 2nd ATTR */
1496 /* 2nd is before 1st */
1497 if (((item1->type == LYXP_NODE_TEXT)
1498 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_ATTR)))
1499 || ((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ELEM))
1500 || (((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ATTR))
1501 && (attr_pos1 > attr_pos2))) {
1502 return 1;
1503 }
1504
1505 /* 1st ATTR - any pos - 2nd TEXT, 1st ATTR <pos< - 2nd ATTR */
1506 /* 2nd is after 1st */
1507 return -1;
1508}
1509
1510/**
1511 * @brief Set cast for comparisons.
1512 *
1513 * @param[in] trg Target set to cast source into.
1514 * @param[in] src Source set.
1515 * @param[in] type Target set type.
1516 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001517 * @return LY_ERR
1518 */
1519static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001520set_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 +02001521{
1522 assert(src->type == LYXP_SET_NODE_SET);
1523
1524 set_init(trg, src);
1525
1526 /* insert node into target set */
1527 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1528
1529 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001530 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001531}
1532
1533#ifndef NDEBUG
1534
1535/**
1536 * @brief Bubble sort @p set into XPath document order.
1537 * Context position aware. Unused in the 'Release' build target.
1538 *
1539 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001540 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1541 */
1542static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001543set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001544{
1545 uint32_t i, j;
1546 int ret = 0, cmp, inverted, change;
1547 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001548 struct lyxp_set_node item;
1549 struct lyxp_set_hash_node hnode;
1550 uint64_t hash;
1551
1552 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1553 return 0;
1554 }
1555
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001556 /* find first top-level node to be used as anchor for positions */
1557 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1558 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001559
1560 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001561 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001562 return -1;
1563 }
1564
1565 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1566 print_set_debug(set);
1567
1568 for (i = 0; i < set->used; ++i) {
1569 inverted = 0;
1570 change = 0;
1571
1572 for (j = 1; j < set->used - i; ++j) {
1573 /* compare node positions */
1574 if (inverted) {
1575 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1576 } else {
1577 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1578 }
1579
1580 /* swap if needed */
1581 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1582 change = 1;
1583
1584 item = set->val.nodes[j - 1];
1585 set->val.nodes[j - 1] = set->val.nodes[j];
1586 set->val.nodes[j] = item;
1587 } else {
1588 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1589 inverted = !inverted;
1590 }
1591 }
1592
1593 ++ret;
1594
1595 if (!change) {
1596 break;
1597 }
1598 }
1599
1600 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1601 print_set_debug(set);
1602
1603 /* check node hashes */
1604 if (set->used >= LYD_HT_MIN_ITEMS) {
1605 assert(set->ht);
1606 for (i = 0; i < set->used; ++i) {
1607 hnode.node = set->val.nodes[i].node;
1608 hnode.type = set->val.nodes[i].type;
1609
1610 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1611 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1612 hash = dict_hash_multi(hash, NULL, 0);
1613
1614 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1615 }
1616 }
1617
1618 return ret - 1;
1619}
1620
1621/**
1622 * @brief Remove duplicate entries in a sorted node set.
1623 *
1624 * @param[in] set Sorted set to check.
1625 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1626 */
1627static LY_ERR
1628set_sorted_dup_node_clean(struct lyxp_set *set)
1629{
1630 uint32_t i = 0;
1631 LY_ERR ret = LY_SUCCESS;
1632
1633 if (set->used > 1) {
1634 while (i < set->used - 1) {
1635 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1636 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001637 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001638 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001639 }
Michal Vasko57eab132019-09-24 11:46:26 +02001640 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001641 }
1642 }
1643
Michal Vasko2caefc12019-11-14 16:07:56 +01001644 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001645 return ret;
1646}
1647
1648#endif
1649
1650/**
1651 * @brief Merge 2 sorted sets into one.
1652 *
1653 * @param[in,out] trg Set to merge into. Duplicates are removed.
1654 * @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 +02001655 * @return LY_ERR
1656 */
1657static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001658set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001659{
1660 uint32_t i, j, k, count, dup_count;
1661 int cmp;
1662 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001663
1664 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1665 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1666 return LY_EINVAL;
1667 }
1668
1669 if (src->type == LYXP_SET_EMPTY) {
1670 return LY_SUCCESS;
1671 } else if (trg->type == LYXP_SET_EMPTY) {
1672 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001673 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001674 return LY_SUCCESS;
1675 }
1676
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001677 /* find first top-level node to be used as anchor for positions */
1678 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1679 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001680
1681 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001682 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001683 return LY_EINT;
1684 }
1685
1686#ifndef NDEBUG
1687 LOGDBG(LY_LDGXPATH, "MERGE target");
1688 print_set_debug(trg);
1689 LOGDBG(LY_LDGXPATH, "MERGE source");
1690 print_set_debug(src);
1691#endif
1692
1693 /* make memory for the merge (duplicates are not detected yet, so space
1694 * will likely be wasted on them, too bad) */
1695 if (trg->size - trg->used < src->used) {
1696 trg->size = trg->used + src->used;
1697
1698 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1699 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1700 }
1701
1702 i = 0;
1703 j = 0;
1704 count = 0;
1705 dup_count = 0;
1706 do {
1707 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1708 if (!cmp) {
1709 if (!count) {
1710 /* duplicate, just skip it */
1711 ++i;
1712 ++j;
1713 } else {
1714 /* we are copying something already, so let's copy the duplicate too,
1715 * we are hoping that afterwards there are some more nodes to
1716 * copy and this way we can copy them all together */
1717 ++count;
1718 ++dup_count;
1719 ++i;
1720 ++j;
1721 }
1722 } else if (cmp < 0) {
1723 /* inserting src node into trg, just remember it for now */
1724 ++count;
1725 ++i;
1726
1727 /* insert the hash now */
1728 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1729 } else if (count) {
1730copy_nodes:
1731 /* time to actually copy the nodes, we have found the largest block of nodes */
1732 memmove(&trg->val.nodes[j + (count - dup_count)],
1733 &trg->val.nodes[j],
1734 (trg->used - j) * sizeof *trg->val.nodes);
1735 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1736
1737 trg->used += count - dup_count;
1738 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1739 j += count - dup_count;
1740
1741 count = 0;
1742 dup_count = 0;
1743 } else {
1744 ++j;
1745 }
1746 } while ((i < src->used) && (j < trg->used));
1747
1748 if ((i < src->used) || count) {
1749 /* insert all the hashes first */
1750 for (k = i; k < src->used; ++k) {
1751 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1752 }
1753
1754 /* loop ended, but we need to copy something at trg end */
1755 count += src->used - i;
1756 i = src->used;
1757 goto copy_nodes;
1758 }
1759
1760 /* we are inserting hashes before the actual node insert, which causes
1761 * situations when there were initially not enough items for a hash table,
1762 * but even after some were inserted, hash table was not created (during
1763 * insertion the number of items is not updated yet) */
1764 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1765 set_insert_node_hash(trg, NULL, 0);
1766 }
1767
1768#ifndef NDEBUG
1769 LOGDBG(LY_LDGXPATH, "MERGE result");
1770 print_set_debug(trg);
1771#endif
1772
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001773 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001774 return LY_SUCCESS;
1775}
1776
1777/*
1778 * (re)parse functions
1779 *
1780 * Parse functions parse the expression into
1781 * tokens (syntactic analysis).
1782 *
1783 * Reparse functions perform semantic analysis
1784 * (do not save the result, just a check) of
1785 * the expression and fill repeat indices.
1786 */
1787
1788/**
1789 * @brief Look at the next token and check its kind.
1790 *
1791 * @param[in] ctx Context for logging.
1792 * @param[in] exp Expression to use.
1793 * @param[in] exp_idx Position in the expression \p exp.
1794 * @param[in] want_tok Expected token.
1795 * @param[in] strict Whether the token is strictly required (print error if
1796 * not the next one) or we simply want to check whether it is the next or not.
1797 * @return LY_ERR
1798 */
1799static LY_ERR
1800exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1801{
1802 if (exp->used == exp_idx) {
1803 if (strict) {
1804 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1805 }
1806 return LY_EINVAL;
1807 }
1808
1809 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1810 if (strict) {
1811 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1812 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1813 }
1814 return LY_EINVAL;
1815 }
1816
1817 return LY_SUCCESS;
1818}
1819
1820/**
1821 * @brief Stack operation push on the repeat array.
1822 *
1823 * @param[in] exp Expression to use.
1824 * @param[in] exp_idx Position in the expresion \p exp.
1825 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1826 */
1827static void
1828exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1829{
1830 uint16_t i;
1831
1832 if (exp->repeat[exp_idx]) {
1833 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1834 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1835 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1836 exp->repeat[exp_idx][i] = repeat_op_idx;
1837 exp->repeat[exp_idx][i + 1] = 0;
1838 } else {
1839 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1840 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1841 exp->repeat[exp_idx][0] = repeat_op_idx;
1842 }
1843}
1844
1845/**
1846 * @brief Reparse Predicate. Logs directly on error.
1847 *
1848 * [7] Predicate ::= '[' Expr ']'
1849 *
1850 * @param[in] ctx Context for logging.
1851 * @param[in] exp Parsed XPath expression.
1852 * @param[in] exp_idx Position in the expression @p exp.
1853 * @return LY_ERR
1854 */
1855static LY_ERR
1856reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1857{
1858 LY_ERR rc;
1859
1860 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1861 LY_CHECK_RET(rc);
1862 ++(*exp_idx);
1863
1864 rc = reparse_or_expr(ctx, exp, exp_idx);
1865 LY_CHECK_RET(rc);
1866
1867 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1868 LY_CHECK_RET(rc);
1869 ++(*exp_idx);
1870
1871 return LY_SUCCESS;
1872}
1873
1874/**
1875 * @brief Reparse RelativeLocationPath. Logs directly on error.
1876 *
1877 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1878 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1879 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1880 *
1881 * @param[in] ctx Context for logging.
1882 * @param[in] exp Parsed XPath expression.
1883 * @param[in] exp_idx Position in the expression \p exp.
1884 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1885 */
1886static LY_ERR
1887reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1888{
1889 LY_ERR rc;
1890
1891 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1892 LY_CHECK_RET(rc);
1893
1894 goto step;
1895 do {
1896 /* '/' or '//' */
1897 ++(*exp_idx);
1898
1899 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1900 LY_CHECK_RET(rc);
1901step:
1902 /* Step */
1903 switch (exp->tokens[*exp_idx]) {
1904 case LYXP_TOKEN_DOT:
1905 ++(*exp_idx);
1906 break;
1907
1908 case LYXP_TOKEN_DDOT:
1909 ++(*exp_idx);
1910 break;
1911
1912 case LYXP_TOKEN_AT:
1913 ++(*exp_idx);
1914
1915 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1916 LY_CHECK_RET(rc);
1917 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1918 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1919 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1920 return LY_EVALID;
1921 }
1922 /* fall through */
1923 case LYXP_TOKEN_NAMETEST:
1924 ++(*exp_idx);
1925 goto reparse_predicate;
1926 break;
1927
1928 case LYXP_TOKEN_NODETYPE:
1929 ++(*exp_idx);
1930
1931 /* '(' */
1932 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1933 LY_CHECK_RET(rc);
1934 ++(*exp_idx);
1935
1936 /* ')' */
1937 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1938 LY_CHECK_RET(rc);
1939 ++(*exp_idx);
1940
1941reparse_predicate:
1942 /* Predicate* */
1943 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1944 rc = reparse_predicate(ctx, exp, exp_idx);
1945 LY_CHECK_RET(rc);
1946 }
1947 break;
1948 default:
1949 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1950 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1951 return LY_EVALID;
1952 }
1953 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1954
1955 return LY_SUCCESS;
1956}
1957
1958/**
1959 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1960 *
1961 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1962 *
1963 * @param[in] ctx Context for logging.
1964 * @param[in] exp Parsed XPath expression.
1965 * @param[in] exp_idx Position in the expression \p exp.
1966 * @return LY_ERR
1967 */
1968static LY_ERR
1969reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1970{
1971 LY_ERR rc;
1972
1973 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1974 LY_CHECK_RET(rc);
1975
1976 /* '/' RelativeLocationPath? */
1977 if (exp->tok_len[*exp_idx] == 1) {
1978 /* '/' */
1979 ++(*exp_idx);
1980
1981 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1982 return LY_SUCCESS;
1983 }
1984 switch (exp->tokens[*exp_idx]) {
1985 case LYXP_TOKEN_DOT:
1986 case LYXP_TOKEN_DDOT:
1987 case LYXP_TOKEN_AT:
1988 case LYXP_TOKEN_NAMETEST:
1989 case LYXP_TOKEN_NODETYPE:
1990 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1991 LY_CHECK_RET(rc);
1992 /* fall through */
1993 default:
1994 break;
1995 }
1996
1997 /* '//' RelativeLocationPath */
1998 } else {
1999 /* '//' */
2000 ++(*exp_idx);
2001
2002 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2003 LY_CHECK_RET(rc);
2004 }
2005
2006 return LY_SUCCESS;
2007}
2008
2009/**
2010 * @brief Reparse FunctionCall. Logs directly on error.
2011 *
2012 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2013 *
2014 * @param[in] ctx Context for logging.
2015 * @param[in] exp Parsed XPath expression.
2016 * @param[in] exp_idx Position in the expression @p exp.
2017 * @return LY_ERR
2018 */
2019static LY_ERR
2020reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2021{
2022 int min_arg_count = -1, max_arg_count, arg_count;
2023 uint16_t func_exp_idx;
2024 LY_ERR rc;
2025
2026 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2027 LY_CHECK_RET(rc);
2028 func_exp_idx = *exp_idx;
2029 switch (exp->tok_len[*exp_idx]) {
2030 case 3:
2031 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2032 min_arg_count = 1;
2033 max_arg_count = 1;
2034 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2035 min_arg_count = 1;
2036 max_arg_count = 1;
2037 }
2038 break;
2039 case 4:
2040 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2041 min_arg_count = 1;
2042 max_arg_count = 1;
2043 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2044 min_arg_count = 0;
2045 max_arg_count = 0;
2046 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2047 min_arg_count = 0;
2048 max_arg_count = 1;
2049 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2050 min_arg_count = 0;
2051 max_arg_count = 0;
2052 }
2053 break;
2054 case 5:
2055 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2056 min_arg_count = 1;
2057 max_arg_count = 1;
2058 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2059 min_arg_count = 0;
2060 max_arg_count = 0;
2061 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2062 min_arg_count = 1;
2063 max_arg_count = 1;
2064 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2065 min_arg_count = 1;
2066 max_arg_count = 1;
2067 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2068 min_arg_count = 1;
2069 max_arg_count = 1;
2070 }
2071 break;
2072 case 6:
2073 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2074 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002075 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002076 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2077 min_arg_count = 0;
2078 max_arg_count = 1;
2079 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2080 min_arg_count = 0;
2081 max_arg_count = 1;
2082 }
2083 break;
2084 case 7:
2085 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2086 min_arg_count = 1;
2087 max_arg_count = 1;
2088 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2089 min_arg_count = 1;
2090 max_arg_count = 1;
2091 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2092 min_arg_count = 0;
2093 max_arg_count = 0;
2094 }
2095 break;
2096 case 8:
2097 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2098 min_arg_count = 2;
2099 max_arg_count = 2;
2100 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2101 min_arg_count = 0;
2102 max_arg_count = 0;
2103 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2104 min_arg_count = 2;
2105 max_arg_count = 2;
2106 }
2107 break;
2108 case 9:
2109 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2110 min_arg_count = 2;
2111 max_arg_count = 3;
2112 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2113 min_arg_count = 3;
2114 max_arg_count = 3;
2115 }
2116 break;
2117 case 10:
2118 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2119 min_arg_count = 0;
2120 max_arg_count = 1;
2121 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2122 min_arg_count = 1;
2123 max_arg_count = 1;
2124 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2125 min_arg_count = 2;
2126 max_arg_count = 2;
2127 }
2128 break;
2129 case 11:
2130 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2131 min_arg_count = 2;
2132 max_arg_count = 2;
2133 }
2134 break;
2135 case 12:
2136 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2137 min_arg_count = 2;
2138 max_arg_count = 2;
2139 }
2140 break;
2141 case 13:
2142 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2143 min_arg_count = 0;
2144 max_arg_count = 1;
2145 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2146 min_arg_count = 0;
2147 max_arg_count = 1;
2148 }
2149 break;
2150 case 15:
2151 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2152 min_arg_count = 0;
2153 max_arg_count = 1;
2154 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2155 min_arg_count = 2;
2156 max_arg_count = 2;
2157 }
2158 break;
2159 case 16:
2160 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2161 min_arg_count = 2;
2162 max_arg_count = 2;
2163 }
2164 break;
2165 case 20:
2166 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2167 min_arg_count = 2;
2168 max_arg_count = 2;
2169 }
2170 break;
2171 }
2172 if (min_arg_count == -1) {
2173 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2174 return LY_EINVAL;
2175 }
2176 ++(*exp_idx);
2177
2178 /* '(' */
2179 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2180 LY_CHECK_RET(rc);
2181 ++(*exp_idx);
2182
2183 /* ( Expr ( ',' Expr )* )? */
2184 arg_count = 0;
2185 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2186 LY_CHECK_RET(rc);
2187 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2188 ++arg_count;
2189 rc = reparse_or_expr(ctx, exp, exp_idx);
2190 LY_CHECK_RET(rc);
2191 }
2192 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2193 ++(*exp_idx);
2194
2195 ++arg_count;
2196 rc = reparse_or_expr(ctx, exp, exp_idx);
2197 LY_CHECK_RET(rc);
2198 }
2199
2200 /* ')' */
2201 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2202 LY_CHECK_RET(rc);
2203 ++(*exp_idx);
2204
2205 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2206 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2207 &exp->expr[exp->tok_pos[func_exp_idx]]);
2208 return LY_EVALID;
2209 }
2210
2211 return LY_SUCCESS;
2212}
2213
2214/**
2215 * @brief Reparse PathExpr. Logs directly on error.
2216 *
2217 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2218 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2219 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2220 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2221 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2222 *
2223 * @param[in] ctx Context for logging.
2224 * @param[in] exp Parsed XPath expression.
2225 * @param[in] exp_idx Position in the expression @p exp.
2226 * @return LY_ERR
2227 */
2228static LY_ERR
2229reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2230{
2231 LY_ERR rc;
2232
2233 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2234 return -1;
2235 }
2236
2237 switch (exp->tokens[*exp_idx]) {
2238 case LYXP_TOKEN_PAR1:
2239 /* '(' Expr ')' Predicate* */
2240 ++(*exp_idx);
2241
2242 rc = reparse_or_expr(ctx, exp, exp_idx);
2243 LY_CHECK_RET(rc);
2244
2245 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2246 LY_CHECK_RET(rc);
2247 ++(*exp_idx);
2248 goto predicate;
2249 break;
2250 case LYXP_TOKEN_DOT:
2251 case LYXP_TOKEN_DDOT:
2252 case LYXP_TOKEN_AT:
2253 case LYXP_TOKEN_NAMETEST:
2254 case LYXP_TOKEN_NODETYPE:
2255 /* RelativeLocationPath */
2256 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2257 LY_CHECK_RET(rc);
2258 break;
2259 case LYXP_TOKEN_FUNCNAME:
2260 /* FunctionCall */
2261 rc = reparse_function_call(ctx, exp, exp_idx);
2262 LY_CHECK_RET(rc);
2263 goto predicate;
2264 break;
2265 case LYXP_TOKEN_OPERATOR_PATH:
2266 /* AbsoluteLocationPath */
2267 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2268 LY_CHECK_RET(rc);
2269 break;
2270 case LYXP_TOKEN_LITERAL:
2271 /* Literal */
2272 ++(*exp_idx);
2273 goto predicate;
2274 break;
2275 case LYXP_TOKEN_NUMBER:
2276 /* Number */
2277 ++(*exp_idx);
2278 goto predicate;
2279 break;
2280 default:
2281 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2282 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2283 return LY_EVALID;
2284 }
2285
2286 return LY_SUCCESS;
2287
2288predicate:
2289 /* Predicate* */
2290 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2291 rc = reparse_predicate(ctx, exp, exp_idx);
2292 LY_CHECK_RET(rc);
2293 }
2294
2295 /* ('/' or '//') RelativeLocationPath */
2296 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2297
2298 /* '/' or '//' */
2299 ++(*exp_idx);
2300
2301 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2302 LY_CHECK_RET(rc);
2303 }
2304
2305 return LY_SUCCESS;
2306}
2307
2308/**
2309 * @brief Reparse UnaryExpr. Logs directly on error.
2310 *
2311 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2312 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2313 *
2314 * @param[in] ctx Context for logging.
2315 * @param[in] exp Parsed XPath expression.
2316 * @param[in] exp_idx Position in the expression @p exp.
2317 * @return LY_ERR
2318 */
2319static LY_ERR
2320reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2321{
2322 uint16_t prev_exp;
2323 LY_ERR rc;
2324
2325 /* ('-')* */
2326 prev_exp = *exp_idx;
2327 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2328 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2329 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2330 ++(*exp_idx);
2331 }
2332
2333 /* PathExpr */
2334 prev_exp = *exp_idx;
2335 rc = reparse_path_expr(ctx, exp, exp_idx);
2336 LY_CHECK_RET(rc);
2337
2338 /* ('|' PathExpr)* */
2339 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2340 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2341 ++(*exp_idx);
2342
2343 rc = reparse_path_expr(ctx, exp, exp_idx);
2344 LY_CHECK_RET(rc);
2345 }
2346
2347 return LY_SUCCESS;
2348}
2349
2350/**
2351 * @brief Reparse AdditiveExpr. Logs directly on error.
2352 *
2353 * [15] AdditiveExpr ::= MultiplicativeExpr
2354 * | AdditiveExpr '+' MultiplicativeExpr
2355 * | AdditiveExpr '-' MultiplicativeExpr
2356 * [16] MultiplicativeExpr ::= UnaryExpr
2357 * | MultiplicativeExpr '*' UnaryExpr
2358 * | MultiplicativeExpr 'div' UnaryExpr
2359 * | MultiplicativeExpr 'mod' UnaryExpr
2360 *
2361 * @param[in] ctx Context for logging.
2362 * @param[in] exp Parsed XPath expression.
2363 * @param[in] exp_idx Position in the expression @p exp.
2364 * @return LY_ERR
2365 */
2366static LY_ERR
2367reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2368{
2369 uint16_t prev_add_exp, prev_mul_exp;
2370 LY_ERR rc;
2371
2372 prev_add_exp = *exp_idx;
2373 goto reparse_multiplicative_expr;
2374
2375 /* ('+' / '-' MultiplicativeExpr)* */
2376 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2377 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2378 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2379 ++(*exp_idx);
2380
2381reparse_multiplicative_expr:
2382 /* UnaryExpr */
2383 prev_mul_exp = *exp_idx;
2384 rc = reparse_unary_expr(ctx, exp, exp_idx);
2385 LY_CHECK_RET(rc);
2386
2387 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2388 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2389 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2390 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2391 ++(*exp_idx);
2392
2393 rc = reparse_unary_expr(ctx, exp, exp_idx);
2394 LY_CHECK_RET(rc);
2395 }
2396 }
2397
2398 return LY_SUCCESS;
2399}
2400
2401/**
2402 * @brief Reparse EqualityExpr. Logs directly on error.
2403 *
2404 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2405 * | EqualityExpr '!=' RelationalExpr
2406 * [14] RelationalExpr ::= AdditiveExpr
2407 * | RelationalExpr '<' AdditiveExpr
2408 * | RelationalExpr '>' AdditiveExpr
2409 * | RelationalExpr '<=' AdditiveExpr
2410 * | RelationalExpr '>=' AdditiveExpr
2411 *
2412 * @param[in] ctx Context for logging.
2413 * @param[in] exp Parsed XPath expression.
2414 * @param[in] exp_idx Position in the expression @p exp.
2415 * @return LY_ERR
2416 */
2417static LY_ERR
2418reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2419{
2420 uint16_t prev_eq_exp, prev_rel_exp;
2421 LY_ERR rc;
2422
2423 prev_eq_exp = *exp_idx;
2424 goto reparse_additive_expr;
2425
2426 /* ('=' / '!=' RelationalExpr)* */
2427 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2428 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2429 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2430 ++(*exp_idx);
2431
2432reparse_additive_expr:
2433 /* AdditiveExpr */
2434 prev_rel_exp = *exp_idx;
2435 rc = reparse_additive_expr(ctx, exp, exp_idx);
2436 LY_CHECK_RET(rc);
2437
2438 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2439 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2440 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2441 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2442 ++(*exp_idx);
2443
2444 rc = reparse_additive_expr(ctx, exp, exp_idx);
2445 LY_CHECK_RET(rc);
2446 }
2447 }
2448
2449 return LY_SUCCESS;
2450}
2451
2452/**
2453 * @brief Reparse OrExpr. Logs directly on error.
2454 *
2455 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2456 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2457 *
2458 * @param[in] ctx Context for logging.
2459 * @param[in] exp Parsed XPath expression.
2460 * @param[in] exp_idx Position in the expression @p exp.
2461 * @return LY_ERR
2462 */
2463static LY_ERR
2464reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2465{
2466 uint16_t prev_or_exp, prev_and_exp;
2467 LY_ERR rc;
2468
2469 prev_or_exp = *exp_idx;
2470 goto reparse_equality_expr;
2471
2472 /* ('or' AndExpr)* */
2473 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2474 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2475 ++(*exp_idx);
2476
2477reparse_equality_expr:
2478 /* EqualityExpr */
2479 prev_and_exp = *exp_idx;
2480 rc = reparse_equality_expr(ctx, exp, exp_idx);
2481 LY_CHECK_RET(rc);
2482
2483 /* ('and' EqualityExpr)* */
2484 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2485 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2486 ++(*exp_idx);
2487
2488 rc = reparse_equality_expr(ctx, exp, exp_idx);
2489 LY_CHECK_RET(rc);
2490 }
2491 }
2492
2493 return LY_SUCCESS;
2494}
Radek Krejcib1646a92018-11-02 16:08:26 +01002495
2496/**
2497 * @brief Parse NCName.
2498 *
2499 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002500 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002501 */
Radek Krejcid4270262019-01-07 15:07:25 +01002502static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002503parse_ncname(const char *ncname)
2504{
2505 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002506 size_t size;
2507 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002508
2509 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2510 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2511 return len;
2512 }
2513
2514 do {
2515 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002516 if (!*ncname) {
2517 break;
2518 }
Radek Krejcid4270262019-01-07 15:07:25 +01002519 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002520 } while (is_xmlqnamechar(uc) && (uc != ':'));
2521
2522 return len;
2523}
2524
2525/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002526 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002527 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002528 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002529 * @param[in] exp Expression to use.
2530 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002531 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002532 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002533 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002534 */
2535static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002536exp_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 +01002537{
2538 uint32_t prev;
2539
2540 if (exp->used == exp->size) {
2541 prev = exp->size;
2542 exp->size += LYXP_EXPR_SIZE_STEP;
2543 if (prev > exp->size) {
2544 LOGINT(ctx);
2545 return LY_EINT;
2546 }
2547
2548 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2549 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2550 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2551 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2552 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2553 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2554 }
2555
2556 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002557 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002558 exp->tok_len[exp->used] = tok_len;
2559 ++exp->used;
2560 return LY_SUCCESS;
2561}
2562
2563void
2564lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2565{
2566 uint16_t i;
2567
2568 if (!expr) {
2569 return;
2570 }
2571
2572 lydict_remove(ctx, expr->expr);
2573 free(expr->tokens);
2574 free(expr->tok_pos);
2575 free(expr->tok_len);
2576 if (expr->repeat) {
2577 for (i = 0; i < expr->used; ++i) {
2578 free(expr->repeat[i]);
2579 }
2580 }
2581 free(expr->repeat);
2582 free(expr);
2583}
2584
2585struct lyxp_expr *
2586lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2587{
2588 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002589 size_t parsed = 0, tok_len;
2590 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002591 enum lyxp_token tok_type;
2592 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002593 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002594
2595 if (strlen(expr) > UINT16_MAX) {
2596 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2597 return NULL;
2598 }
2599
2600 /* init lyxp_expr structure */
2601 ret = calloc(1, sizeof *ret);
2602 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2603 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2604 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2605 ret->used = 0;
2606 ret->size = LYXP_EXPR_SIZE_START;
2607 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2608 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2609
2610 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2611 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2612
2613 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2614 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2615
2616 while (is_xmlws(expr[parsed])) {
2617 ++parsed;
2618 }
2619
2620 do {
2621 if (expr[parsed] == '(') {
2622
2623 /* '(' */
2624 tok_len = 1;
2625 tok_type = LYXP_TOKEN_PAR1;
2626
2627 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2628 /* it is a NodeType/FunctionName after all */
2629 if (((ret->tok_len[ret->used - 1] == 4)
2630 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2631 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2632 ((ret->tok_len[ret->used - 1] == 7)
2633 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2634 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2635 } else {
2636 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2637 }
2638 prev_function_check = 0;
2639 }
2640
2641 } else if (expr[parsed] == ')') {
2642
2643 /* ')' */
2644 tok_len = 1;
2645 tok_type = LYXP_TOKEN_PAR2;
2646
2647 } else if (expr[parsed] == '[') {
2648
2649 /* '[' */
2650 tok_len = 1;
2651 tok_type = LYXP_TOKEN_BRACK1;
2652
2653 } else if (expr[parsed] == ']') {
2654
2655 /* ']' */
2656 tok_len = 1;
2657 tok_type = LYXP_TOKEN_BRACK2;
2658
2659 } else if (!strncmp(&expr[parsed], "..", 2)) {
2660
2661 /* '..' */
2662 tok_len = 2;
2663 tok_type = LYXP_TOKEN_DDOT;
2664
2665 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2666
2667 /* '.' */
2668 tok_len = 1;
2669 tok_type = LYXP_TOKEN_DOT;
2670
2671 } else if (expr[parsed] == '@') {
2672
2673 /* '@' */
2674 tok_len = 1;
2675 tok_type = LYXP_TOKEN_AT;
2676
2677 } else if (expr[parsed] == ',') {
2678
2679 /* ',' */
2680 tok_len = 1;
2681 tok_type = LYXP_TOKEN_COMMA;
2682
2683 } else if (expr[parsed] == '\'') {
2684
2685 /* Literal with ' */
2686 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2687 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2688 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2689 ++tok_len;
2690 tok_type = LYXP_TOKEN_LITERAL;
2691
2692 } else if (expr[parsed] == '\"') {
2693
2694 /* Literal with " */
2695 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2696 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2697 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2698 ++tok_len;
2699 tok_type = LYXP_TOKEN_LITERAL;
2700
2701 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2702
2703 /* Number */
2704 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2705 if (expr[parsed + tok_len] == '.') {
2706 ++tok_len;
2707 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2708 }
2709 tok_type = LYXP_TOKEN_NUMBER;
2710
2711 } else if (expr[parsed] == '/') {
2712
2713 /* Operator '/', '//' */
2714 if (!strncmp(&expr[parsed], "//", 2)) {
2715 tok_len = 2;
2716 } else {
2717 tok_len = 1;
2718 }
2719 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2720
2721 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2722 || !strncmp(&expr[parsed], ">=", 2)) {
2723
2724 /* Operator '!=', '<=', '>=' */
2725 tok_len = 2;
2726 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2727
2728 } else if (expr[parsed] == '|') {
2729
2730 /* Operator '|' */
2731 tok_len = 1;
2732 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2733
2734 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2735
2736 /* Operator '+', '-' */
2737 tok_len = 1;
2738 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2739
2740 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2741
2742 /* Operator '=', '<', '>' */
2743 tok_len = 1;
2744 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2745
2746 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2747 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2748 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2749 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2750 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2751 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2752 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2753 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2754 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2755
2756 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2757 if (expr[parsed] == '*') {
2758 tok_len = 1;
2759 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2760
2761 } else if (!strncmp(&expr[parsed], "or", 2)) {
2762 tok_len = 2;
2763 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2764
2765 } else if (!strncmp(&expr[parsed], "and", 3)) {
2766 tok_len = 3;
2767 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2768
2769 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2770 tok_len = 3;
2771 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2772
2773 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002774 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2775 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 +01002776 goto error;
2777 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002778 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002779 goto error;
2780 }
2781 } else if (expr[parsed] == '*') {
2782
2783 /* NameTest '*' */
2784 tok_len = 1;
2785 tok_type = LYXP_TOKEN_NAMETEST;
2786
2787 } else {
2788
2789 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2790 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002791 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002792 tok_len = ncname_len;
2793
2794 if (expr[parsed + tok_len] == ':') {
2795 ++tok_len;
2796 if (expr[parsed + tok_len] == '*') {
2797 ++tok_len;
2798 } else {
2799 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002800 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 +01002801 tok_len += ncname_len;
2802 }
2803 /* remove old flag to prevent ambiguities */
2804 prev_function_check = 0;
2805 tok_type = LYXP_TOKEN_NAMETEST;
2806 } else {
2807 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2808 prev_function_check = 1;
2809 tok_type = LYXP_TOKEN_NAMETEST;
2810 }
2811 }
2812
2813 /* store the token, move on to the next one */
2814 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2815 parsed += tok_len;
2816 while (is_xmlws(expr[parsed])) {
2817 ++parsed;
2818 }
2819
2820 } while (expr[parsed]);
2821
2822 /* prealloc repeat */
2823 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2824 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2825
Michal Vasko03ff5a72019-09-11 13:49:33 +02002826 /* fill repeat */
2827 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2828 if (ret->used > exp_idx) {
2829 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2830 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2831 &ret->expr[ret->tok_pos[exp_idx]]);
2832 goto error;
2833 }
2834
2835 print_expr_struct_debug(ret);
2836
Radek Krejcib1646a92018-11-02 16:08:26 +01002837 return ret;
2838
2839error:
2840 lyxp_expr_free(ctx, ret);
2841 return NULL;
2842}
2843
Michal Vasko03ff5a72019-09-11 13:49:33 +02002844/*
2845 * warn functions
2846 *
2847 * Warn functions check specific reasonable conditions for schema XPath
2848 * and print a warning if they are not satisfied.
2849 */
2850
2851/**
2852 * @brief Get the last-added schema node that is currently in the context.
2853 *
2854 * @param[in] set Set to search in.
2855 * @return Last-added schema context node, NULL if no node is in context.
2856 */
2857static struct lysc_node *
2858warn_get_scnode_in_ctx(struct lyxp_set *set)
2859{
2860 uint32_t i;
2861
2862 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2863 return NULL;
2864 }
2865
2866 i = set->used;
2867 do {
2868 --i;
2869 if (set->val.scnodes[i].in_ctx == 1) {
2870 /* if there are more, simply return the first found (last added) */
2871 return set->val.scnodes[i].scnode;
2872 }
2873 } while (i);
2874
2875 return NULL;
2876}
2877
2878/**
2879 * @brief Test whether a type is numeric - integer type or decimal64.
2880 *
2881 * @param[in] type Type to test.
2882 * @return 1 if numeric, 0 otherwise.
2883 */
2884static int
2885warn_is_numeric_type(struct lysc_type *type)
2886{
2887 struct lysc_type_union *uni;
2888 int ret;
2889 uint32_t i;
2890
2891 switch (type->basetype) {
2892 case LY_TYPE_DEC64:
2893 case LY_TYPE_INT8:
2894 case LY_TYPE_UINT8:
2895 case LY_TYPE_INT16:
2896 case LY_TYPE_UINT16:
2897 case LY_TYPE_INT32:
2898 case LY_TYPE_UINT32:
2899 case LY_TYPE_INT64:
2900 case LY_TYPE_UINT64:
2901 return 1;
2902 case LY_TYPE_UNION:
2903 uni = (struct lysc_type_union *)type;
2904 LY_ARRAY_FOR(uni->types, i) {
2905 ret = warn_is_numeric_type(uni->types[i]);
2906 if (ret) {
2907 /* found a suitable type */
2908 return 1;
2909 }
2910 }
2911 /* did not find any suitable type */
2912 return 0;
2913 case LY_TYPE_LEAFREF:
2914 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2915 default:
2916 return 0;
2917 }
2918}
2919
2920/**
2921 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2922 *
2923 * @param[in] type Type to test.
2924 * @return 1 if string, 0 otherwise.
2925 */
2926static int
2927warn_is_string_type(struct lysc_type *type)
2928{
2929 struct lysc_type_union *uni;
2930 int ret;
2931 uint32_t i;
2932
2933 switch (type->basetype) {
2934 case LY_TYPE_BITS:
2935 case LY_TYPE_ENUM:
2936 case LY_TYPE_IDENT:
2937 case LY_TYPE_INST:
2938 case LY_TYPE_STRING:
2939 return 1;
2940 case LY_TYPE_UNION:
2941 uni = (struct lysc_type_union *)type;
2942 LY_ARRAY_FOR(uni->types, i) {
2943 ret = warn_is_string_type(uni->types[i]);
2944 if (ret) {
2945 /* found a suitable type */
2946 return 1;
2947 }
2948 }
2949 /* did not find any suitable type */
2950 return 0;
2951 case LY_TYPE_LEAFREF:
2952 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2953 default:
2954 return 0;
2955 }
2956}
2957
2958/**
2959 * @brief Test whether a type is one specific type.
2960 *
2961 * @param[in] type Type to test.
2962 * @param[in] base Expected type.
2963 * @return 1 if it is, 0 otherwise.
2964 */
2965static int
2966warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2967{
2968 struct lysc_type_union *uni;
2969 int ret;
2970 uint32_t i;
2971
2972 if (type->basetype == base) {
2973 return 1;
2974 } else if (type->basetype == LY_TYPE_UNION) {
2975 uni = (struct lysc_type_union *)type;
2976 LY_ARRAY_FOR(uni->types, i) {
2977 ret = warn_is_specific_type(uni->types[i], base);
2978 if (ret) {
2979 /* found a suitable type */
2980 return 1;
2981 }
2982 }
2983 /* did not find any suitable type */
2984 return 0;
2985 } else if (type->basetype == LY_TYPE_LEAFREF) {
2986 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2987 }
2988
2989 return 0;
2990}
2991
2992/**
2993 * @brief Get next type of a (union) type.
2994 *
2995 * @param[in] type Base type.
2996 * @param[in] prev_type Previously returned type.
2997 * @return Next type or NULL.
2998 */
2999static struct lysc_type *
3000warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3001{
3002 struct lysc_type_union *uni;
3003 int found = 0;
3004 uint32_t i;
3005
3006 switch (type->basetype) {
3007 case LY_TYPE_UNION:
3008 uni = (struct lysc_type_union *)type;
3009 if (!prev_type) {
3010 return uni->types[0];
3011 }
3012 LY_ARRAY_FOR(uni->types, i) {
3013 if (found) {
3014 return uni->types[i];
3015 }
3016 if (prev_type == uni->types[i]) {
3017 found = 1;
3018 }
3019 }
3020 return NULL;
3021 default:
3022 if (prev_type) {
3023 assert(type == prev_type);
3024 return NULL;
3025 } else {
3026 return type;
3027 }
3028 }
3029}
3030
3031/**
3032 * @brief Test whether 2 types have a common type.
3033 *
3034 * @param[in] type1 First type.
3035 * @param[in] type2 Second type.
3036 * @return 1 if they do, 0 otherwise.
3037 */
3038static int
3039warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3040{
3041 struct lysc_type *t1, *rt1, *t2, *rt2;
3042
3043 t1 = NULL;
3044 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3045 if (t1->basetype == LY_TYPE_LEAFREF) {
3046 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3047 } else {
3048 rt1 = t1;
3049 }
3050
3051 t2 = NULL;
3052 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3053 if (t2->basetype == LY_TYPE_LEAFREF) {
3054 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3055 } else {
3056 rt2 = t2;
3057 }
3058
3059 if (rt2->basetype == rt1->basetype) {
3060 /* match found */
3061 return 1;
3062 }
3063 }
3064 }
3065
3066 return 0;
3067}
3068
3069/**
3070 * @brief Check both operands of comparison operators.
3071 *
3072 * @param[in] ctx Context for errors.
3073 * @param[in] set1 First operand set.
3074 * @param[in] set2 Second operand set.
3075 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3076 * @param[in] expr Start of the expression to print with the warning.
3077 * @param[in] tok_pos Token position.
3078 */
3079static void
3080warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3081{
3082 struct lysc_node_leaf *node1, *node2;
3083 int leaves = 1, warning = 0;
3084
3085 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3086 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3087
3088 if (!node1 && !node2) {
3089 /* no node-sets involved, nothing to do */
3090 return;
3091 }
3092
3093 if (node1) {
3094 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3095 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3096 warning = 1;
3097 leaves = 0;
3098 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3099 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3100 warning = 1;
3101 }
3102 }
3103
3104 if (node2) {
3105 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3106 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3107 warning = 1;
3108 leaves = 0;
3109 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3110 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3111 warning = 1;
3112 }
3113 }
3114
3115 if (node1 && node2 && leaves && !numbers_only) {
3116 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3117 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3118 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3119 && !warn_is_equal_type(node1->type, node2->type))) {
3120 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3121 warning = 1;
3122 }
3123 }
3124
3125 if (warning) {
3126 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3127 }
3128}
3129
3130/**
3131 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3132 *
3133 * @param[in] exp Parsed XPath expression.
3134 * @param[in] set Set with the leaf/leaf-list.
3135 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3136 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3137 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3138 */
3139static void
3140warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3141{
3142 struct lysc_node *scnode;
3143 struct lysc_type *type;
3144 char *value;
3145 LY_ERR rc;
3146 struct ly_err_item *err = NULL;
3147
3148 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3149 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3150 /* check that the node can have the specified value */
3151 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3152 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3153 } else {
3154 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3155 }
3156 if (!value) {
3157 LOGMEM(set->ctx);
3158 return;
3159 }
3160
3161 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3162 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3163 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3164 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3165 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3166 exp->expr + exp->tok_pos[equal_exp]);
3167 }
3168
3169 type = ((struct lysc_node_leaf *)scnode)->type;
3170 if (type->basetype != LY_TYPE_IDENT) {
3171 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3172 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3173
3174 if (err) {
3175 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3176 ly_err_free(err);
3177 } else if (rc != LY_SUCCESS) {
3178 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3179 }
3180 if (rc != LY_SUCCESS) {
3181 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3182 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3183 exp->expr + exp->tok_pos[equal_exp]);
3184 }
3185 }
3186 free(value);
3187 }
3188}
3189
3190/*
3191 * XPath functions
3192 */
3193
3194/**
3195 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3196 * depending on whether the first node bit value from the second argument is set.
3197 *
3198 * @param[in] args Array of arguments.
3199 * @param[in] arg_count Count of elements in @p args.
3200 * @param[in,out] set Context and result set at the same time.
3201 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003202 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003203 */
3204static LY_ERR
3205xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3206{
3207 struct lyd_node_term *leaf;
3208 struct lysc_node_leaf *sleaf;
3209 struct lysc_type_bits *bits;
3210 LY_ERR rc = LY_SUCCESS;
3211 uint32_t i;
3212
3213 if (options & LYXP_SCNODE_ALL) {
3214 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3215 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003216 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3217 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 +02003218 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3219 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003220 }
3221
3222 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3223 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3224 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 +02003225 } else if (!warn_is_string_type(sleaf->type)) {
3226 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003227 }
3228 }
3229 set_scnode_clear_ctx(set);
3230 return rc;
3231 }
3232
3233 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3234 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)");
3235 return LY_EVALID;
3236 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003237 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003238 LY_CHECK_RET(rc);
3239
3240 set_fill_boolean(set, 0);
3241 if (args[0]->type == LYXP_SET_NODE_SET) {
3242 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3243 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3244 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3245 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
3246 LY_ARRAY_FOR(bits->bits, i) {
3247 if (!strcmp(bits->bits[i].name, args[1]->val.str)) {
3248 set_fill_boolean(set, 1);
3249 break;
3250 }
3251 }
3252 }
3253 }
3254
3255 return LY_SUCCESS;
3256}
3257
3258/**
3259 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3260 * with the argument converted to boolean.
3261 *
3262 * @param[in] args Array of arguments.
3263 * @param[in] arg_count Count of elements in @p args.
3264 * @param[in,out] set Context and result set at the same time.
3265 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003266 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003267 */
3268static LY_ERR
3269xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3270{
3271 LY_ERR rc;
3272
3273 if (options & LYXP_SCNODE_ALL) {
3274 set_scnode_clear_ctx(set);
3275 return LY_SUCCESS;
3276 }
3277
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003278 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003279 LY_CHECK_RET(rc);
3280 set_fill_set(set, args[0]);
3281
3282 return LY_SUCCESS;
3283}
3284
3285/**
3286 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3287 * with the first argument rounded up to the nearest integer.
3288 *
3289 * @param[in] args Array of arguments.
3290 * @param[in] arg_count Count of elements in @p args.
3291 * @param[in,out] set Context and result set at the same time.
3292 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003293 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003294 */
3295static LY_ERR
3296xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3297{
3298 struct lysc_node_leaf *sleaf;
3299 LY_ERR rc = LY_SUCCESS;
3300
3301 if (options & LYXP_SCNODE_ALL) {
3302 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3303 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003304 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3305 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 +02003306 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3307 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003308 }
3309 set_scnode_clear_ctx(set);
3310 return rc;
3311 }
3312
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003313 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003314 LY_CHECK_RET(rc);
3315 if ((long long)args[0]->val.num != args[0]->val.num) {
3316 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3317 } else {
3318 set_fill_number(set, args[0]->val.num);
3319 }
3320
3321 return LY_SUCCESS;
3322}
3323
3324/**
3325 * @brief Execute the XPath concat(string, string, string*) function.
3326 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3327 *
3328 * @param[in] args Array of arguments.
3329 * @param[in] arg_count Count of elements in @p args.
3330 * @param[in,out] set Context and result set at the same time.
3331 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003332 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003333 */
3334static LY_ERR
3335xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3336{
3337 uint16_t i;
3338 char *str = NULL;
3339 size_t used = 1;
3340 LY_ERR rc = LY_SUCCESS;
3341 struct lysc_node_leaf *sleaf;
3342
3343 if (options & LYXP_SCNODE_ALL) {
3344 for (i = 0; i < arg_count; ++i) {
3345 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3346 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3347 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3348 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003349 } else if (!warn_is_string_type(sleaf->type)) {
3350 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", __func__, i + 1, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003351 }
3352 }
3353 }
3354 set_scnode_clear_ctx(set);
3355 return rc;
3356 }
3357
3358 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003359 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003360 if (rc != LY_SUCCESS) {
3361 free(str);
3362 return rc;
3363 }
3364
3365 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3366 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3367 strcpy(str + used - 1, args[i]->val.str);
3368 used += strlen(args[i]->val.str);
3369 }
3370
3371 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003372 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003373 set->type = LYXP_SET_STRING;
3374 set->val.str = str;
3375
3376 return LY_SUCCESS;
3377}
3378
3379/**
3380 * @brief Execute the XPath contains(string, string) function.
3381 * Returns LYXP_SET_BOOLEAN whether the second argument can
3382 * be found in the first or not.
3383 *
3384 * @param[in] args Array of arguments.
3385 * @param[in] arg_count Count of elements in @p args.
3386 * @param[in,out] set Context and result set at the same time.
3387 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003388 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003389 */
3390static LY_ERR
3391xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3392{
3393 struct lysc_node_leaf *sleaf;
3394 LY_ERR rc = LY_SUCCESS;
3395
3396 if (options & LYXP_SCNODE_ALL) {
3397 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3398 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3399 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 +02003400 } else if (!warn_is_string_type(sleaf->type)) {
3401 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003402 }
3403 }
3404
3405 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3406 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3407 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 +02003408 } else if (!warn_is_string_type(sleaf->type)) {
3409 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003410 }
3411 }
3412 set_scnode_clear_ctx(set);
3413 return rc;
3414 }
3415
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003416 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003417 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003418 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003419 LY_CHECK_RET(rc);
3420
3421 if (strstr(args[0]->val.str, args[1]->val.str)) {
3422 set_fill_boolean(set, 1);
3423 } else {
3424 set_fill_boolean(set, 0);
3425 }
3426
3427 return LY_SUCCESS;
3428}
3429
3430/**
3431 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3432 * with the size of the node-set from the argument.
3433 *
3434 * @param[in] args Array of arguments.
3435 * @param[in] arg_count Count of elements in @p args.
3436 * @param[in,out] set Context and result set at the same time.
3437 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003438 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003439 */
3440static LY_ERR
3441xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3442{
3443 struct lysc_node *scnode = NULL;
3444 LY_ERR rc = LY_SUCCESS;
3445
3446 if (options & LYXP_SCNODE_ALL) {
3447 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3448 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003449 }
3450 set_scnode_clear_ctx(set);
3451 return rc;
3452 }
3453
3454 if (args[0]->type == LYXP_SET_EMPTY) {
3455 set_fill_number(set, 0);
3456 return LY_SUCCESS;
3457 }
3458
3459 if (args[0]->type != LYXP_SET_NODE_SET) {
3460 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3461 return LY_EVALID;
3462 }
3463
3464 set_fill_number(set, args[0]->used);
3465 return LY_SUCCESS;
3466}
3467
3468/**
3469 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3470 * with the context with the intial node.
3471 *
3472 * @param[in] args Array of arguments.
3473 * @param[in] arg_count Count of elements in @p args.
3474 * @param[in,out] set Context and result set at the same time.
3475 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003476 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003477 */
3478static LY_ERR
3479xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3480{
3481 if (arg_count || args) {
3482 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3483 return LY_EVALID;
3484 }
3485
3486 if (options & LYXP_SCNODE_ALL) {
3487 set_scnode_clear_ctx(set);
3488
Michal Vaskoecd62de2019-11-13 12:35:11 +01003489 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003490 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003491 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003492
3493 /* position is filled later */
3494 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3495 }
3496
3497 return LY_SUCCESS;
3498}
3499
3500/**
3501 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3502 * leafref or instance-identifier target node(s).
3503 *
3504 * @param[in] args Array of arguments.
3505 * @param[in] arg_count Count of elements in @p args.
3506 * @param[in,out] set Context and result set at the same time.
3507 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003508 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003509 */
3510static LY_ERR
3511xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3512{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003513 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003514 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003515 struct lysc_node_leaf *sleaf = NULL;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003516 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003517 const struct lyd_node *node;
3518 char *errmsg = NULL;
3519 const char *val;
3520 int dynamic;
3521 LY_ERR rc = LY_SUCCESS;
3522
3523 if (options & LYXP_SCNODE_ALL) {
3524 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3525 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003526 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3527 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 +02003528 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3529 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3530 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003531 }
3532 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003533 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003534 cctx.ctx = set->ctx;
3535 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3536 /* it was already validated, it must succeed */
3537 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003538 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003539 }
3540 }
3541
Michal Vasko03ff5a72019-09-11 13:49:33 +02003542 return rc;
3543 }
3544
3545 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3546 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3547 return LY_EVALID;
3548 }
3549
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003550 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003551 if (args[0]->type != LYXP_SET_EMPTY) {
3552 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3553 sleaf = (struct lysc_node_leaf *)leaf->schema;
3554 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3555 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3556 /* find leafref target */
3557 val = lyd_value2str(leaf, &dynamic);
3558 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
3559 set->trees, &leaf->value, &errmsg);
3560 if (dynamic) {
3561 free((char *)val);
3562 }
3563 if (!node) {
3564 LOGERR(set->ctx, LY_EINVAL, errmsg);
3565 free(errmsg);
3566 return LY_EINVAL;
3567 }
3568
3569 /* insert it */
3570 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3571 } else {
3572 assert(sleaf->type->basetype == LY_TYPE_INST);
3573 node = (struct lyd_node *)lyd_target(leaf->value.target, set->trees);
3574 if (!node) {
3575 val = lyd_value2str(leaf, &dynamic);
3576 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3577 if (dynamic) {
3578 free((char *)val);
3579 }
3580 return LY_EVALID;
3581 }
3582 }
3583 }
3584 }
3585
3586 return LY_SUCCESS;
3587}
3588
3589/**
3590 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3591 * on whether the first argument nodes contain a node of an identity derived from the second
3592 * argument identity.
3593 *
3594 * @param[in] args Array of arguments.
3595 * @param[in] arg_count Count of elements in @p args.
3596 * @param[in,out] set Context and result set at the same time.
3597 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003598 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003599 */
3600static LY_ERR
3601xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3602{
3603 uint16_t i;
3604 struct lyd_node_term *leaf;
3605 struct lysc_node_leaf *sleaf;
3606 struct lyd_value data = {0};
3607 struct ly_err_item *err = NULL;
3608 LY_ERR rc = LY_SUCCESS;
3609 int found;
3610
3611 if (options & LYXP_SCNODE_ALL) {
3612 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3613 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003614 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3615 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 +02003616 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3617 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003618 }
3619
3620 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3621 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3622 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 +02003623 } else if (!warn_is_string_type(sleaf->type)) {
3624 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003625 }
3626 }
3627 set_scnode_clear_ctx(set);
3628 return rc;
3629 }
3630
3631 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3632 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3633 return LY_EVALID;
3634 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003635 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003636 LY_CHECK_RET(rc);
3637
3638 set_fill_boolean(set, 0);
3639 if (args[0]->type != LYXP_SET_EMPTY) {
3640 found = 0;
3641 for (i = 0; i < args[0]->used; ++i) {
3642 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3643 sleaf = (struct lysc_node_leaf *)leaf->schema;
3644 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3645 /* store args[1] into ident */
3646 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3647 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3648 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3649 if (err) {
3650 ly_err_print(err);
3651 ly_err_free(err);
3652 }
3653 LY_CHECK_RET(rc);
3654
3655 LY_ARRAY_FOR(data.ident->derived, i) {
3656 if (data.ident->derived[i] == leaf->value.ident) {
3657 set_fill_boolean(set, 1);
3658 found = 1;
3659 break;
3660 }
3661 }
3662 if (found) {
3663 break;
3664 }
3665 }
3666 }
3667 }
3668
3669 return LY_SUCCESS;
3670}
3671
3672/**
3673 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3674 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3675 * the second argument identity.
3676 *
3677 * @param[in] args Array of arguments.
3678 * @param[in] arg_count Count of elements in @p args.
3679 * @param[in,out] set Context and result set at the same time.
3680 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003681 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003682 */
3683static LY_ERR
3684xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3685{
3686 uint16_t i;
3687 struct lyd_node_term *leaf;
3688 struct lysc_node_leaf *sleaf;
3689 struct lyd_value data = {0};
3690 struct ly_err_item *err = NULL;
3691 LY_ERR rc = LY_SUCCESS;
3692 int found;
3693
3694 if (options & LYXP_SCNODE_ALL) {
3695 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3696 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003697 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3698 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003699 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3700 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003701 }
3702
3703 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3704 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3705 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 +02003706 } else if (!warn_is_string_type(sleaf->type)) {
3707 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003708 }
3709 }
3710 set_scnode_clear_ctx(set);
3711 return rc;
3712 }
3713
3714 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3715 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)");
3716 return LY_EVALID;
3717 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003718 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003719 LY_CHECK_RET(rc);
3720
3721 set_fill_boolean(set, 0);
3722 if (args[0]->type != LYXP_SET_EMPTY) {
3723 found = 0;
3724 for (i = 0; i < args[0]->used; ++i) {
3725 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3726 sleaf = (struct lysc_node_leaf *)leaf->schema;
3727 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3728 /* store args[1] into ident */
3729 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3730 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3731 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3732 if (err) {
3733 ly_err_print(err);
3734 ly_err_free(err);
3735 }
3736 LY_CHECK_RET(rc);
3737
3738 if (data.ident == leaf->value.ident) {
3739 set_fill_boolean(set, 1);
3740 break;
3741 }
3742 LY_ARRAY_FOR(data.ident->derived, i) {
3743 if (data.ident->derived[i] == leaf->value.ident) {
3744 set_fill_boolean(set, 1);
3745 found = 1;
3746 break;
3747 }
3748 }
3749 if (found) {
3750 break;
3751 }
3752 }
3753 }
3754 }
3755
3756 return LY_SUCCESS;
3757}
3758
3759/**
3760 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3761 * with the integer value of the first node's enum value, otherwise NaN.
3762 *
3763 * @param[in] args Array of arguments.
3764 * @param[in] arg_count Count of elements in @p args.
3765 * @param[in,out] set Context and result set at the same time.
3766 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003767 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003768 */
3769static LY_ERR
3770xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3771{
3772 struct lyd_node_term *leaf;
3773 struct lysc_node_leaf *sleaf;
3774 LY_ERR rc = LY_SUCCESS;
3775
3776 if (options & LYXP_SCNODE_ALL) {
3777 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3778 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003779 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3780 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 +02003781 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3782 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003783 }
3784 set_scnode_clear_ctx(set);
3785 return rc;
3786 }
3787
3788 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3789 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3790 return LY_EVALID;
3791 }
3792
3793 set_fill_number(set, NAN);
3794 if (args[0]->type == LYXP_SET_NODE_SET) {
3795 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3796 sleaf = (struct lysc_node_leaf *)leaf->schema;
3797 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3798 set_fill_number(set, leaf->value.enum_item->value);
3799 }
3800 }
3801
3802 return LY_SUCCESS;
3803}
3804
3805/**
3806 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3807 * with false value.
3808 *
3809 * @param[in] args Array of arguments.
3810 * @param[in] arg_count Count of elements in @p args.
3811 * @param[in,out] set Context and result set at the same time.
3812 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003813 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003814 */
3815static LY_ERR
3816xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3817{
3818 if (options & LYXP_SCNODE_ALL) {
3819 set_scnode_clear_ctx(set);
3820 return LY_SUCCESS;
3821 }
3822
3823 set_fill_boolean(set, 0);
3824 return LY_SUCCESS;
3825}
3826
3827/**
3828 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3829 * with the first argument floored (truncated).
3830 *
3831 * @param[in] args Array of arguments.
3832 * @param[in] arg_count Count of elements in @p args.
3833 * @param[in,out] set Context and result set at the same time.
3834 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003835 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003836 */
3837static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003838xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003839{
3840 LY_ERR rc;
3841
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003842 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003843 LY_CHECK_RET(rc);
3844 if (isfinite(args[0]->val.num)) {
3845 set_fill_number(set, (long long)args[0]->val.num);
3846 }
3847
3848 return LY_SUCCESS;
3849}
3850
3851/**
3852 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3853 * whether the language of the text matches the one from the argument.
3854 *
3855 * @param[in] args Array of arguments.
3856 * @param[in] arg_count Count of elements in @p args.
3857 * @param[in,out] set Context and result set at the same time.
3858 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003859 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003860 */
3861static LY_ERR
3862xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3863{
3864 const struct lyd_node *node;
3865 struct lysc_node_leaf *sleaf;
3866 struct lyd_attr *attr = NULL;
3867 const char *val;
3868 int i, dynamic;
3869 LY_ERR rc = LY_SUCCESS;
3870
3871 if (options & LYXP_SCNODE_ALL) {
3872 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3873 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3874 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 +02003875 } else if (!warn_is_string_type(sleaf->type)) {
3876 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003877 }
3878 }
3879 set_scnode_clear_ctx(set);
3880 return rc;
3881 }
3882
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003883 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003884 LY_CHECK_RET(rc);
3885
3886 if (set->type == LYXP_SET_EMPTY) {
3887 set_fill_boolean(set, 0);
3888 return LY_SUCCESS;
3889 }
3890 if (set->type != LYXP_SET_NODE_SET) {
3891 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3892 return LY_EVALID;
3893 }
3894
3895 switch (set->val.nodes[0].type) {
3896 case LYXP_NODE_ELEM:
3897 case LYXP_NODE_TEXT:
3898 node = set->val.nodes[0].node;
3899 break;
3900 case LYXP_NODE_ATTR:
3901 node = set->val.attrs[0].attr->parent;
3902 break;
3903 default:
3904 /* nothing to do with roots */
3905 set_fill_boolean(set, 0);
3906 return LY_SUCCESS;
3907 }
3908
3909 /* find lang attribute */
3910 for (; node; node = (struct lyd_node *)node->parent) {
3911 for (attr = node->attr; attr; attr = attr->next) {
3912 /* annotations */
3913 if (attr->name && !strcmp(attr->name, "lang") && !strcmp(attr->annotation->module->name, "xml")) {
3914 break;
3915 }
3916 }
3917
3918 if (attr) {
3919 break;
3920 }
3921 }
3922
3923 /* compare languages */
3924 if (!attr) {
3925 set_fill_boolean(set, 0);
3926 } else {
3927 val = lyd_attr2str(attr, &dynamic);
3928 for (i = 0; args[0]->val.str[i]; ++i) {
3929 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3930 set_fill_boolean(set, 0);
3931 break;
3932 }
3933 }
3934 if (!args[0]->val.str[i]) {
3935 if (!val[i] || (val[i] == '-')) {
3936 set_fill_boolean(set, 1);
3937 } else {
3938 set_fill_boolean(set, 0);
3939 }
3940 }
3941 if (dynamic) {
3942 free((char *)val);
3943 }
3944 }
3945
3946 return LY_SUCCESS;
3947}
3948
3949/**
3950 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3951 * with the context size.
3952 *
3953 * @param[in] args Array of arguments.
3954 * @param[in] arg_count Count of elements in @p args.
3955 * @param[in,out] set Context and result set at the same time.
3956 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003957 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003958 */
3959static LY_ERR
3960xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3961{
3962 if (options & LYXP_SCNODE_ALL) {
3963 set_scnode_clear_ctx(set);
3964 return LY_SUCCESS;
3965 }
3966
3967 if (set->type == LYXP_SET_EMPTY) {
3968 set_fill_number(set, 0);
3969 return LY_SUCCESS;
3970 }
3971 if (set->type != LYXP_SET_NODE_SET) {
3972 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3973 return LY_EVALID;
3974 }
3975
3976 set_fill_number(set, set->ctx_size);
3977 return LY_SUCCESS;
3978}
3979
3980/**
3981 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3982 * with the node name without namespace from the argument or the context.
3983 *
3984 * @param[in] args Array of arguments.
3985 * @param[in] arg_count Count of elements in @p args.
3986 * @param[in,out] set Context and result set at the same time.
3987 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003988 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003989 */
3990static LY_ERR
3991xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3992{
3993 struct lyxp_set_node *item;
3994 /* suppress unused variable warning */
3995 (void)options;
3996
3997 if (options & LYXP_SCNODE_ALL) {
3998 set_scnode_clear_ctx(set);
3999 return LY_SUCCESS;
4000 }
4001
4002 if (arg_count) {
4003 if (args[0]->type == LYXP_SET_EMPTY) {
4004 set_fill_string(set, "", 0);
4005 return LY_SUCCESS;
4006 }
4007 if (args[0]->type != LYXP_SET_NODE_SET) {
4008 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4009 return LY_EVALID;
4010 }
4011
4012 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004013 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004014
4015 item = &args[0]->val.nodes[0];
4016 } else {
4017 if (set->type == LYXP_SET_EMPTY) {
4018 set_fill_string(set, "", 0);
4019 return LY_SUCCESS;
4020 }
4021 if (set->type != LYXP_SET_NODE_SET) {
4022 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4023 return LY_EVALID;
4024 }
4025
4026 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004027 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004028
4029 item = &set->val.nodes[0];
4030 }
4031
4032 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004033 case LYXP_NODE_NONE:
4034 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004035 case LYXP_NODE_ROOT:
4036 case LYXP_NODE_ROOT_CONFIG:
4037 case LYXP_NODE_TEXT:
4038 set_fill_string(set, "", 0);
4039 break;
4040 case LYXP_NODE_ELEM:
4041 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4042 break;
4043 case LYXP_NODE_ATTR:
4044 set_fill_string(set, ((struct lyd_attr *)item->node)->name, strlen(((struct lyd_attr *)item->node)->name));
4045 break;
4046 }
4047
4048 return LY_SUCCESS;
4049}
4050
4051/**
4052 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4053 * with the node name fully qualified (with namespace) from the argument or the context.
4054 *
4055 * @param[in] args Array of arguments.
4056 * @param[in] arg_count Count of elements in @p args.
4057 * @param[in,out] set Context and result set at the same time.
4058 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004059 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004060 */
4061static LY_ERR
4062xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4063{
4064 struct lyxp_set_node *item;
4065 struct lys_module *mod;
4066 char *str;
4067 const char *name;
4068 int rc;
4069
4070 if (options & LYXP_SCNODE_ALL) {
4071 set_scnode_clear_ctx(set);
4072 return LY_SUCCESS;
4073 }
4074
4075 if (arg_count) {
4076 if (args[0]->type == LYXP_SET_EMPTY) {
4077 set_fill_string(set, "", 0);
4078 return LY_SUCCESS;
4079 }
4080 if (args[0]->type != LYXP_SET_NODE_SET) {
4081 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4082 return LY_EVALID;
4083 }
4084
4085 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004086 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004087
4088 item = &args[0]->val.nodes[0];
4089 } else {
4090 if (set->type == LYXP_SET_EMPTY) {
4091 set_fill_string(set, "", 0);
4092 return LY_SUCCESS;
4093 }
4094 if (set->type != LYXP_SET_NODE_SET) {
4095 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4096 return LY_EVALID;
4097 }
4098
4099 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004100 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004101
4102 item = &set->val.nodes[0];
4103 }
4104
4105 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004106 case LYXP_NODE_NONE:
4107 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004108 case LYXP_NODE_ROOT:
4109 case LYXP_NODE_ROOT_CONFIG:
4110 case LYXP_NODE_TEXT:
4111 mod = NULL;
4112 name = NULL;
4113 break;
4114 case LYXP_NODE_ELEM:
4115 mod = item->node->schema->module;
4116 name = item->node->schema->name;
4117 break;
4118 case LYXP_NODE_ATTR:
4119 mod = ((struct lyd_attr *)item->node)->annotation->module;
4120 name = ((struct lyd_attr *)item->node)->name;
4121 break;
4122 }
4123
4124 if (mod && name) {
4125 switch (set->format) {
4126 case LYD_UNKNOWN:
4127 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4128 break;
4129 case LYD_JSON:
4130 rc = asprintf(&str, "%s:%s", mod->name, name);
4131 break;
Michal Vasko9409ef62019-09-12 11:47:17 +02004132 default:
4133 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004134 }
4135 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4136 set_fill_string(set, str, strlen(str));
4137 free(str);
4138 } else {
4139 set_fill_string(set, "", 0);
4140 }
4141
4142 return LY_SUCCESS;
4143}
4144
4145/**
4146 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4147 * with the namespace of the node from the argument or the context.
4148 *
4149 * @param[in] args Array of arguments.
4150 * @param[in] arg_count Count of elements in @p args.
4151 * @param[in,out] set Context and result set at the same time.
4152 * @param[in] options XPath options.
4153 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4154 */
4155static LY_ERR
4156xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4157{
4158 struct lyxp_set_node *item;
4159 struct lys_module *mod;
4160 /* suppress unused variable warning */
4161 (void)options;
4162
4163 if (options & LYXP_SCNODE_ALL) {
4164 set_scnode_clear_ctx(set);
4165 return LY_SUCCESS;
4166 }
4167
4168 if (arg_count) {
4169 if (args[0]->type == LYXP_SET_EMPTY) {
4170 set_fill_string(set, "", 0);
4171 return LY_SUCCESS;
4172 }
4173 if (args[0]->type != LYXP_SET_NODE_SET) {
4174 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4175 return LY_EVALID;
4176 }
4177
4178 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004179 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004180
4181 item = &args[0]->val.nodes[0];
4182 } else {
4183 if (set->type == LYXP_SET_EMPTY) {
4184 set_fill_string(set, "", 0);
4185 return LY_SUCCESS;
4186 }
4187 if (set->type != LYXP_SET_NODE_SET) {
4188 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4189 return LY_EVALID;
4190 }
4191
4192 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004193 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004194
4195 item = &set->val.nodes[0];
4196 }
4197
4198 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004199 case LYXP_NODE_NONE:
4200 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004201 case LYXP_NODE_ROOT:
4202 case LYXP_NODE_ROOT_CONFIG:
4203 case LYXP_NODE_TEXT:
4204 set_fill_string(set, "", 0);
4205 break;
4206 case LYXP_NODE_ELEM:
4207 case LYXP_NODE_ATTR:
4208 if (item->type == LYXP_NODE_ELEM) {
4209 mod = item->node->schema->module;
4210 } else { /* LYXP_NODE_ATTR */
4211 /* annotations */
4212 mod = ((struct lyd_attr *)item->node)->annotation->module;
4213 }
4214
4215 set_fill_string(set, mod->ns, strlen(mod->ns));
4216 break;
4217 }
4218
4219 return LY_SUCCESS;
4220}
4221
4222/**
4223 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4224 * with only nodes from the context. In practice it either leaves the context
4225 * as it is or returns an empty node set.
4226 *
4227 * @param[in] args Array of arguments.
4228 * @param[in] arg_count Count of elements in @p args.
4229 * @param[in,out] set Context and result set at the same time.
4230 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004231 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004232 */
4233static LY_ERR
4234xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4235{
4236 if (options & LYXP_SCNODE_ALL) {
4237 set_scnode_clear_ctx(set);
4238 return LY_SUCCESS;
4239 }
4240
4241 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004242 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004243 }
4244 return LY_SUCCESS;
4245}
4246
4247/**
4248 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4249 * with normalized value (no leading, trailing, double white spaces) of the node
4250 * from the argument or the context.
4251 *
4252 * @param[in] args Array of arguments.
4253 * @param[in] arg_count Count of elements in @p args.
4254 * @param[in,out] set Context and result set at the same time.
4255 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004256 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004257 */
4258static LY_ERR
4259xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4260{
4261 uint16_t i, new_used;
4262 char *new;
4263 int have_spaces = 0, space_before = 0;
4264 struct lysc_node_leaf *sleaf;
4265 LY_ERR rc = LY_SUCCESS;
4266
4267 if (options & LYXP_SCNODE_ALL) {
4268 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4269 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4270 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 +02004271 } else if (!warn_is_string_type(sleaf->type)) {
4272 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004273 }
4274 }
4275 set_scnode_clear_ctx(set);
4276 return rc;
4277 }
4278
4279 if (arg_count) {
4280 set_fill_set(set, args[0]);
4281 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004282 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004283 LY_CHECK_RET(rc);
4284
4285 /* is there any normalization necessary? */
4286 for (i = 0; set->val.str[i]; ++i) {
4287 if (is_xmlws(set->val.str[i])) {
4288 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4289 have_spaces = 1;
4290 break;
4291 }
4292 space_before = 1;
4293 } else {
4294 space_before = 0;
4295 }
4296 }
4297
4298 /* yep, there is */
4299 if (have_spaces) {
4300 /* it's enough, at least one character will go, makes space for ending '\0' */
4301 new = malloc(strlen(set->val.str) * sizeof(char));
4302 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4303 new_used = 0;
4304
4305 space_before = 0;
4306 for (i = 0; set->val.str[i]; ++i) {
4307 if (is_xmlws(set->val.str[i])) {
4308 if ((i == 0) || space_before) {
4309 space_before = 1;
4310 continue;
4311 } else {
4312 space_before = 1;
4313 }
4314 } else {
4315 space_before = 0;
4316 }
4317
4318 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4319 ++new_used;
4320 }
4321
4322 /* at worst there is one trailing space now */
4323 if (new_used && is_xmlws(new[new_used - 1])) {
4324 --new_used;
4325 }
4326
4327 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4328 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4329 new[new_used] = '\0';
4330
4331 free(set->val.str);
4332 set->val.str = new;
4333 }
4334
4335 return LY_SUCCESS;
4336}
4337
4338/**
4339 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4340 * with the argument converted to boolean and logically inverted.
4341 *
4342 * @param[in] args Array of arguments.
4343 * @param[in] arg_count Count of elements in @p args.
4344 * @param[in,out] set Context and result set at the same time.
4345 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004346 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004347 */
4348static LY_ERR
4349xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4350{
4351 if (options & LYXP_SCNODE_ALL) {
4352 set_scnode_clear_ctx(set);
4353 return LY_SUCCESS;
4354 }
4355
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004356 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004357 if (args[0]->val.bool) {
4358 set_fill_boolean(set, 0);
4359 } else {
4360 set_fill_boolean(set, 1);
4361 }
4362
4363 return LY_SUCCESS;
4364}
4365
4366/**
4367 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4368 * with the number representation of either the argument or the context.
4369 *
4370 * @param[in] args Array of arguments.
4371 * @param[in] arg_count Count of elements in @p args.
4372 * @param[in,out] set Context and result set at the same time.
4373 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004374 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004375 */
4376static LY_ERR
4377xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4378{
4379 LY_ERR rc;
4380
4381 if (options & LYXP_SCNODE_ALL) {
4382 set_scnode_clear_ctx(set);
4383 return LY_SUCCESS;
4384 }
4385
4386 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004387 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004388 LY_CHECK_RET(rc);
4389 set_fill_set(set, args[0]);
4390 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004391 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004392 LY_CHECK_RET(rc);
4393 }
4394
4395 return LY_SUCCESS;
4396}
4397
4398/**
4399 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4400 * with the context position.
4401 *
4402 * @param[in] args Array of arguments.
4403 * @param[in] arg_count Count of elements in @p args.
4404 * @param[in,out] set Context and result set at the same time.
4405 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004406 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004407 */
4408static LY_ERR
4409xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4410{
4411 if (options & LYXP_SCNODE_ALL) {
4412 set_scnode_clear_ctx(set);
4413 return LY_SUCCESS;
4414 }
4415
4416 if (set->type == LYXP_SET_EMPTY) {
4417 set_fill_number(set, 0);
4418 return LY_SUCCESS;
4419 }
4420 if (set->type != LYXP_SET_NODE_SET) {
4421 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4422 return LY_EVALID;
4423 }
4424
4425 set_fill_number(set, set->ctx_pos);
4426
4427 /* UNUSED in 'Release' build type */
4428 (void)options;
4429 return LY_SUCCESS;
4430}
4431
4432/**
4433 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4434 * depending on whether the second argument regex matches the first argument string. For details refer to
4435 * YANG 1.1 RFC section 10.2.1.
4436 *
4437 * @param[in] args Array of arguments.
4438 * @param[in] arg_count Count of elements in @p args.
4439 * @param[in,out] set Context and result set at the same time.
4440 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004441 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004442 */
4443static LY_ERR
4444xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4445{
4446 struct lysc_pattern **patterns = NULL, **pattern;
4447 struct lysc_node_leaf *sleaf;
4448 char *path;
4449 LY_ERR rc = LY_SUCCESS;
4450 struct ly_err_item *err;
4451
4452 if (options & LYXP_SCNODE_ALL) {
4453 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4454 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4455 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 +02004456 } else if (!warn_is_string_type(sleaf->type)) {
4457 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004458 }
4459 }
4460
4461 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4462 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4463 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 +02004464 } else if (!warn_is_string_type(sleaf->type)) {
4465 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004466 }
4467 }
4468 set_scnode_clear_ctx(set);
4469 return rc;
4470 }
4471
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004472 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004473 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004474 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004475 LY_CHECK_RET(rc);
4476
4477 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4478 *pattern = malloc(sizeof **pattern);
4479 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4480 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4481 free(path);
4482 if (rc != LY_SUCCESS) {
4483 LY_ARRAY_FREE(patterns);
4484 return rc;
4485 }
4486
4487 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4488 pcre2_code_free((*pattern)->code);
4489 free(*pattern);
4490 LY_ARRAY_FREE(patterns);
4491 if (rc && (rc != LY_EVALID)) {
4492 ly_err_print(err);
4493 ly_err_free(err);
4494 return rc;
4495 }
4496
4497 if (rc == LY_EVALID) {
4498 ly_err_free(err);
4499 set_fill_boolean(set, 0);
4500 } else {
4501 set_fill_boolean(set, 1);
4502 }
4503
4504 return LY_SUCCESS;
4505}
4506
4507/**
4508 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4509 * with the rounded first argument. For details refer to
4510 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4511 *
4512 * @param[in] args Array of arguments.
4513 * @param[in] arg_count Count of elements in @p args.
4514 * @param[in,out] set Context and result set at the same time.
4515 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004516 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004517 */
4518static LY_ERR
4519xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4520{
4521 struct lysc_node_leaf *sleaf;
4522 LY_ERR rc = LY_SUCCESS;
4523
4524 if (options & LYXP_SCNODE_ALL) {
4525 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4526 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004527 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4528 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 +02004529 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4530 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004531 }
4532 set_scnode_clear_ctx(set);
4533 return rc;
4534 }
4535
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004536 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004537 LY_CHECK_RET(rc);
4538
4539 /* cover only the cases where floor can't be used */
4540 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4541 set_fill_number(set, -0.0f);
4542 } else {
4543 args[0]->val.num += 0.5;
4544 rc = xpath_floor(args, 1, args[0], options);
4545 LY_CHECK_RET(rc);
4546 set_fill_number(set, args[0]->val.num);
4547 }
4548
4549 return LY_SUCCESS;
4550}
4551
4552/**
4553 * @brief Execute the XPath starts-with(string, string) function.
4554 * Returns LYXP_SET_BOOLEAN whether the second argument is
4555 * the prefix of the first or not.
4556 *
4557 * @param[in] args Array of arguments.
4558 * @param[in] arg_count Count of elements in @p args.
4559 * @param[in,out] set Context and result set at the same time.
4560 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004561 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004562 */
4563static LY_ERR
4564xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4565{
4566 struct lysc_node_leaf *sleaf;
4567 LY_ERR rc = LY_SUCCESS;
4568
4569 if (options & LYXP_SCNODE_ALL) {
4570 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4571 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4572 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 +02004573 } else if (!warn_is_string_type(sleaf->type)) {
4574 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004575 }
4576 }
4577
4578 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4579 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4580 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 +02004581 } else if (!warn_is_string_type(sleaf->type)) {
4582 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004583 }
4584 }
4585 set_scnode_clear_ctx(set);
4586 return rc;
4587 }
4588
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004589 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004590 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004591 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004592 LY_CHECK_RET(rc);
4593
4594 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4595 set_fill_boolean(set, 0);
4596 } else {
4597 set_fill_boolean(set, 1);
4598 }
4599
4600 return LY_SUCCESS;
4601}
4602
4603/**
4604 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4605 * with the string representation of either the argument or the context.
4606 *
4607 * @param[in] args Array of arguments.
4608 * @param[in] arg_count Count of elements in @p args.
4609 * @param[in,out] set Context and result set at the same time.
4610 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004611 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004612 */
4613static LY_ERR
4614xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4615{
4616 LY_ERR rc;
4617
4618 if (options & LYXP_SCNODE_ALL) {
4619 set_scnode_clear_ctx(set);
4620 return LY_SUCCESS;
4621 }
4622
4623 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004624 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004625 LY_CHECK_RET(rc);
4626 set_fill_set(set, args[0]);
4627 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004628 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004629 LY_CHECK_RET(rc);
4630 }
4631
4632 return LY_SUCCESS;
4633}
4634
4635/**
4636 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4637 * with the length of the string in either the argument or the context.
4638 *
4639 * @param[in] args Array of arguments.
4640 * @param[in] arg_count Count of elements in @p args.
4641 * @param[in,out] set Context and result set at the same time.
4642 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004643 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004644 */
4645static LY_ERR
4646xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4647{
4648 struct lysc_node_leaf *sleaf;
4649 LY_ERR rc = LY_SUCCESS;
4650
4651 if (options & LYXP_SCNODE_ALL) {
4652 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4653 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4654 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 +02004655 } else if (!warn_is_string_type(sleaf->type)) {
4656 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004657 }
4658 }
4659 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4660 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4661 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 +02004662 } else if (!warn_is_string_type(sleaf->type)) {
4663 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004664 }
4665 }
4666 set_scnode_clear_ctx(set);
4667 return rc;
4668 }
4669
4670 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004671 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004672 LY_CHECK_RET(rc);
4673 set_fill_number(set, strlen(args[0]->val.str));
4674 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004675 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004676 LY_CHECK_RET(rc);
4677 set_fill_number(set, strlen(set->val.str));
4678 }
4679
4680 return LY_SUCCESS;
4681}
4682
4683/**
4684 * @brief Execute the XPath substring(string, number, number?) function.
4685 * Returns LYXP_SET_STRING substring of the first argument starting
4686 * on the second argument index ending on the third argument index,
4687 * indexed from 1. For exact definition refer to
4688 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4689 *
4690 * @param[in] args Array of arguments.
4691 * @param[in] arg_count Count of elements in @p args.
4692 * @param[in,out] set Context and result set at the same time.
4693 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004694 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004695 */
4696static LY_ERR
4697xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4698{
4699 int start, len;
4700 uint16_t str_start, str_len, pos;
4701 struct lysc_node_leaf *sleaf;
4702 LY_ERR rc = LY_SUCCESS;
4703
4704 if (options & LYXP_SCNODE_ALL) {
4705 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4706 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4707 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 +02004708 } else if (!warn_is_string_type(sleaf->type)) {
4709 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004710 }
4711 }
4712
4713 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4714 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4715 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 +02004716 } else if (!warn_is_numeric_type(sleaf->type)) {
4717 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004718 }
4719 }
4720
4721 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4722 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4723 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4724 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 +02004725 } else if (!warn_is_numeric_type(sleaf->type)) {
4726 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004727 }
4728 }
4729 set_scnode_clear_ctx(set);
4730 return rc;
4731 }
4732
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004733 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004734 LY_CHECK_RET(rc);
4735
4736 /* start */
4737 if (xpath_round(&args[1], 1, args[1], options)) {
4738 return -1;
4739 }
4740 if (isfinite(args[1]->val.num)) {
4741 start = args[1]->val.num - 1;
4742 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4743 start = INT_MIN;
4744 } else {
4745 start = INT_MAX;
4746 }
4747
4748 /* len */
4749 if (arg_count == 3) {
4750 rc = xpath_round(&args[2], 1, args[2], options);
4751 LY_CHECK_RET(rc);
4752 if (isfinite(args[2]->val.num)) {
4753 len = args[2]->val.num;
4754 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4755 len = 0;
4756 } else {
4757 len = INT_MAX;
4758 }
4759 } else {
4760 len = INT_MAX;
4761 }
4762
4763 /* find matching character positions */
4764 str_start = 0;
4765 str_len = 0;
4766 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4767 if (pos < start) {
4768 ++str_start;
4769 } else if (pos < start + len) {
4770 ++str_len;
4771 } else {
4772 break;
4773 }
4774 }
4775
4776 set_fill_string(set, args[0]->val.str + str_start, str_len);
4777 return LY_SUCCESS;
4778}
4779
4780/**
4781 * @brief Execute the XPath substring-after(string, string) function.
4782 * Returns LYXP_SET_STRING with the string succeeding the occurance
4783 * of the second argument in the first or an empty string.
4784 *
4785 * @param[in] args Array of arguments.
4786 * @param[in] arg_count Count of elements in @p args.
4787 * @param[in,out] set Context and result set at the same time.
4788 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004789 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004790 */
4791static LY_ERR
4792xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4793{
4794 char *ptr;
4795 struct lysc_node_leaf *sleaf;
4796 LY_ERR rc = LY_SUCCESS;
4797
4798 if (options & LYXP_SCNODE_ALL) {
4799 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4800 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4801 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 +02004802 } else if (!warn_is_string_type(sleaf->type)) {
4803 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004804 }
4805 }
4806
4807 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4808 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4809 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 +02004810 } else if (!warn_is_string_type(sleaf->type)) {
4811 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004812 }
4813 }
4814 set_scnode_clear_ctx(set);
4815 return rc;
4816 }
4817
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004818 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004819 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004820 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004821 LY_CHECK_RET(rc);
4822
4823 ptr = strstr(args[0]->val.str, args[1]->val.str);
4824 if (ptr) {
4825 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4826 } else {
4827 set_fill_string(set, "", 0);
4828 }
4829
4830 return LY_SUCCESS;
4831}
4832
4833/**
4834 * @brief Execute the XPath substring-before(string, string) function.
4835 * Returns LYXP_SET_STRING with the string preceding the occurance
4836 * of the second argument in the first or an empty string.
4837 *
4838 * @param[in] args Array of arguments.
4839 * @param[in] arg_count Count of elements in @p args.
4840 * @param[in,out] set Context and result set at the same time.
4841 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004842 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004843 */
4844static LY_ERR
4845xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4846{
4847 char *ptr;
4848 struct lysc_node_leaf *sleaf;
4849 LY_ERR rc = LY_SUCCESS;
4850
4851 if (options & LYXP_SCNODE_ALL) {
4852 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4853 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4854 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 +02004855 } else if (!warn_is_string_type(sleaf->type)) {
4856 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004857 }
4858 }
4859
4860 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4861 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4862 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 +02004863 } else if (!warn_is_string_type(sleaf->type)) {
4864 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004865 }
4866 }
4867 set_scnode_clear_ctx(set);
4868 return rc;
4869 }
4870
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004871 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004872 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004873 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004874 LY_CHECK_RET(rc);
4875
4876 ptr = strstr(args[0]->val.str, args[1]->val.str);
4877 if (ptr) {
4878 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4879 } else {
4880 set_fill_string(set, "", 0);
4881 }
4882
4883 return LY_SUCCESS;
4884}
4885
4886/**
4887 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4888 * with the sum of all the nodes in the context.
4889 *
4890 * @param[in] args Array of arguments.
4891 * @param[in] arg_count Count of elements in @p args.
4892 * @param[in,out] set Context and result set at the same time.
4893 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004894 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004895 */
4896static LY_ERR
4897xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4898{
4899 long double num;
4900 char *str;
4901 uint16_t i;
4902 struct lyxp_set set_item;
4903 struct lysc_node_leaf *sleaf;
4904 LY_ERR rc = LY_SUCCESS;
4905
4906 if (options & LYXP_SCNODE_ALL) {
4907 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4908 for (i = 0; i < args[0]->used; ++i) {
4909 if (args[0]->val.scnodes[i].in_ctx == 1) {
4910 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4911 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4912 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4913 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004914 } else if (!warn_is_numeric_type(sleaf->type)) {
4915 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004916 }
4917 }
4918 }
4919 }
4920 set_scnode_clear_ctx(set);
4921 return rc;
4922 }
4923
4924 set_fill_number(set, 0);
4925 if (args[0]->type == LYXP_SET_EMPTY) {
4926 return LY_SUCCESS;
4927 }
4928
4929 if (args[0]->type != LYXP_SET_NODE_SET) {
4930 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4931 return LY_EVALID;
4932 }
4933
Michal Vasko5c4e5892019-11-14 12:31:38 +01004934 set_init(&set_item, set);
4935
Michal Vasko03ff5a72019-09-11 13:49:33 +02004936 set_item.type = LYXP_SET_NODE_SET;
4937 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4938 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4939
4940 set_item.used = 1;
4941 set_item.size = 1;
4942
4943 for (i = 0; i < args[0]->used; ++i) {
4944 set_item.val.nodes[0] = args[0]->val.nodes[i];
4945
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004946 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004947 LY_CHECK_RET(rc);
4948 num = cast_string_to_number(str);
4949 free(str);
4950 set->val.num += num;
4951 }
4952
4953 free(set_item.val.nodes);
4954
4955 return LY_SUCCESS;
4956}
4957
4958/**
4959 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4960 * with the text content of the nodes in the context.
4961 *
4962 * @param[in] args Array of arguments.
4963 * @param[in] arg_count Count of elements in @p args.
4964 * @param[in,out] set Context and result set at the same time.
4965 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004966 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004967 */
4968static LY_ERR
4969xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4970{
4971 uint32_t i;
4972
4973 if (options & LYXP_SCNODE_ALL) {
4974 set_scnode_clear_ctx(set);
4975 return LY_SUCCESS;
4976 }
4977
4978 if (set->type == LYXP_SET_EMPTY) {
4979 return LY_SUCCESS;
4980 }
4981 if (set->type != LYXP_SET_NODE_SET) {
4982 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4983 return LY_EVALID;
4984 }
4985
4986 for (i = 0; i < set->used;) {
4987 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004988 case LYXP_NODE_NONE:
4989 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004990 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004991 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4992 set->val.nodes[i].type = LYXP_NODE_TEXT;
4993 ++i;
4994 break;
4995 }
4996 /* fall through */
4997 case LYXP_NODE_ROOT:
4998 case LYXP_NODE_ROOT_CONFIG:
4999 case LYXP_NODE_TEXT:
5000 case LYXP_NODE_ATTR:
5001 set_remove_node(set, i);
5002 break;
5003 }
5004 }
5005
5006 return LY_SUCCESS;
5007}
5008
5009/**
5010 * @brief Execute the XPath translate(string, string, string) function.
5011 * Returns LYXP_SET_STRING with the first argument with the characters
5012 * from the second argument replaced by those on the corresponding
5013 * positions in the third argument.
5014 *
5015 * @param[in] args Array of arguments.
5016 * @param[in] arg_count Count of elements in @p args.
5017 * @param[in,out] set Context and result set at the same time.
5018 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005019 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005020 */
5021static LY_ERR
5022xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5023{
5024 uint16_t i, j, new_used;
5025 char *new;
5026 int found, have_removed;
5027 struct lysc_node_leaf *sleaf;
5028 LY_ERR rc = LY_SUCCESS;
5029
5030 if (options & LYXP_SCNODE_ALL) {
5031 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5032 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5033 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 +02005034 } else if (!warn_is_string_type(sleaf->type)) {
5035 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005036 }
5037 }
5038
5039 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5040 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5041 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 +02005042 } else if (!warn_is_string_type(sleaf->type)) {
5043 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005044 }
5045 }
5046
5047 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5048 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5049 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 +02005050 } else if (!warn_is_string_type(sleaf->type)) {
5051 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005052 }
5053 }
5054 set_scnode_clear_ctx(set);
5055 return rc;
5056 }
5057
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005058 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005059 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005060 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005061 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005062 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005063 LY_CHECK_RET(rc);
5064
5065 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5066 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5067 new_used = 0;
5068
5069 have_removed = 0;
5070 for (i = 0; args[0]->val.str[i]; ++i) {
5071 found = 0;
5072
5073 for (j = 0; args[1]->val.str[j]; ++j) {
5074 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5075 /* removing this char */
5076 if (j >= strlen(args[2]->val.str)) {
5077 have_removed = 1;
5078 found = 1;
5079 break;
5080 }
5081 /* replacing this char */
5082 new[new_used] = args[2]->val.str[j];
5083 ++new_used;
5084 found = 1;
5085 break;
5086 }
5087 }
5088
5089 /* copying this char */
5090 if (!found) {
5091 new[new_used] = args[0]->val.str[i];
5092 ++new_used;
5093 }
5094 }
5095
5096 if (have_removed) {
5097 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5098 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5099 }
5100 new[new_used] = '\0';
5101
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005102 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005103 set->type = LYXP_SET_STRING;
5104 set->val.str = new;
5105
5106 return LY_SUCCESS;
5107}
5108
5109/**
5110 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5111 * with true value.
5112 *
5113 * @param[in] args Array of arguments.
5114 * @param[in] arg_count Count of elements in @p args.
5115 * @param[in,out] set Context and result set at the same time.
5116 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005117 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005118 */
5119static LY_ERR
5120xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5121{
5122 if (options & LYXP_SCNODE_ALL) {
5123 set_scnode_clear_ctx(set);
5124 return LY_SUCCESS;
5125 }
5126
5127 set_fill_boolean(set, 1);
5128 return LY_SUCCESS;
5129}
5130
5131/*
5132 * moveto functions
5133 *
5134 * They and only they actually change the context (set).
5135 */
5136
5137/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005138 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005139 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005140 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5141 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5142 * @param[in] set Set with XPath context.
5143 * @param[out] moveto_mod Expected module of a matching node.
5144 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005145 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005146static LY_ERR
5147moveto_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 +02005148{
Michal Vasko6346ece2019-09-24 13:12:53 +02005149 const struct lys_module *mod;
5150 const char *ptr;
5151 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005152 char *str;
5153
Michal Vasko6346ece2019-09-24 13:12:53 +02005154 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5155 /* specific module */
5156 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005157
Michal Vasko6346ece2019-09-24 13:12:53 +02005158 switch (set->format) {
5159 case LYD_UNKNOWN:
5160 /* schema, search all local module imports */
5161 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5162 break;
5163 case LYD_JSON:
5164 /* JSON data, search in context */
5165 str = strndup(*qname, pref_len);
5166 mod = ly_ctx_get_module(set->ctx, str, NULL);
5167 free(str);
5168 break;
5169 default:
5170 LOGINT_RET(set->ctx);
5171 }
5172
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005173 /* Check for errors and non-implemented modules, as they are not valid */
5174 if (!mod || !mod->implemented) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005175 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5176 return LY_EVALID;
5177 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005178
Michal Vasko6346ece2019-09-24 13:12:53 +02005179 *qname += pref_len + 1;
5180 *qname_len -= pref_len + 1;
5181 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5182 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005183 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005184 } else {
5185 /* local module */
5186 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005187 }
5188
Michal Vasko6346ece2019-09-24 13:12:53 +02005189 *moveto_mod = mod;
5190 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005191}
5192
5193/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005194 * @brief Move context @p set to the root. Handles absolute path.
5195 * Result is LYXP_SET_NODE_SET.
5196 *
5197 * @param[in,out] set Set to use.
5198 * @param[in] options Xpath options.
5199 */
5200static void
5201moveto_root(struct lyxp_set *set, int options)
5202{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005203 if (!set) {
5204 return;
5205 }
5206
5207 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005208 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005209 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005210 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005211 lyxp_set_cast(set, LYXP_SET_EMPTY);
5212 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005213 }
5214}
5215
5216/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005217 * @brief Check whether a node has some unresolved "when".
5218 *
5219 * @param[in] node Node to check.
5220 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5221 */
5222static LY_ERR
5223moveto_when_check(const struct lyd_node *node)
5224{
5225 const struct lysc_node *schema;
5226
5227 if (!node) {
5228 return LY_SUCCESS;
5229 }
5230
5231 schema = node->schema;
5232 do {
5233 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5234 return LY_EINCOMPLETE;
5235 }
5236 schema = schema->parent;
5237 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5238
5239 return LY_SUCCESS;
5240}
5241
5242/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005243 * @brief Check @p node as a part of NameTest processing.
5244 *
5245 * @param[in] node Node to check.
5246 * @param[in] root_type XPath root node type.
5247 * @param[in] node_name Node name to move to. Must be in the dictionary!
5248 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005249 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5250 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005251 */
5252static LY_ERR
5253moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5254 const struct lys_module *moveto_mod)
5255{
5256 /* module check */
5257 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005258 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005259 }
5260
Michal Vasko5c4e5892019-11-14 12:31:38 +01005261 /* context check */
5262 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005263 return LY_EINVAL;
5264 }
5265
5266 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005267 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005268 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005269 }
5270
Michal Vaskoa1424542019-11-14 16:08:52 +01005271 /* when check */
5272 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005273 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005274 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005275
5276 /* match */
5277 return LY_SUCCESS;
5278}
5279
5280/**
5281 * @brief Check @p node as a part of schema NameTest processing.
5282 *
5283 * @param[in] node Schema node to check.
5284 * @param[in] root_type XPath root node type.
5285 * @param[in] node_name Node name to move to. Must be in the dictionary!
5286 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005287 * @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 +02005288 */
5289static LY_ERR
5290moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005291 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005292{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005293 /* module check */
5294 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005295 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005296 }
5297
5298 /* context check */
5299 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5300 return LY_EINVAL;
5301 }
5302
5303 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005304 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005305 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005306 }
5307
5308 /* match */
5309 return LY_SUCCESS;
5310}
5311
5312/**
5313 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5314 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5315 *
5316 * @param[in,out] set Set to use.
5317 * @param[in] qname Qualified node name to move to.
5318 * @param[in] qname_len Length of @p qname.
5319 * @param[in] options XPath options.
5320 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5321 */
5322static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005323moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005324{
Michal Vasko79bebfd2019-11-14 16:09:19 +01005325 uint32_t i, j;
Michal Vasko6346ece2019-09-24 13:12:53 +02005326 int replaced;
5327 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005328 const struct lys_module *moveto_mod;
5329 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005330 LY_ERR rc;
5331
5332 if (!set || (set->type == LYXP_SET_EMPTY)) {
5333 return LY_SUCCESS;
5334 }
5335
5336 if (set->type != LYXP_SET_NODE_SET) {
5337 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5338 return LY_EVALID;
5339 }
5340
Michal Vasko6346ece2019-09-24 13:12:53 +02005341 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5342 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005343
5344 /* name */
5345 name_dict = lydict_insert(set->ctx, qname, qname_len);
5346
5347 for (i = 0; i < set->used; ) {
5348 replaced = 0;
5349
5350 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 +01005351 assert(!set->val.nodes[i].node);
5352 /* search in all the trees */
Michal Vasko79bebfd2019-11-14 16:09:19 +01005353 LY_ARRAY_FOR(set->trees, j) {
5354 for (sub = set->trees[j]; sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005355 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005356 if (rc == LY_SUCCESS) {
5357 /* pos filled later */
5358 if (!replaced) {
5359 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5360 replaced = 1;
5361 } else {
5362 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5363 }
5364 ++i;
5365 } else if (rc == LY_EINCOMPLETE) {
5366 lydict_remove(set->ctx, name_dict);
5367 return rc;
5368 }
5369 }
5370 }
5371
Michal Vasko5c4e5892019-11-14 12:31:38 +01005372 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5373 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005374
5375 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005376 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005377 if (rc == LY_SUCCESS) {
5378 if (!replaced) {
5379 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5380 replaced = 1;
5381 } else {
5382 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5383 }
5384 ++i;
5385 } else if (rc == LY_EINCOMPLETE) {
5386 lydict_remove(set->ctx, name_dict);
5387 return rc;
5388 }
5389 }
5390 }
5391
5392 if (!replaced) {
5393 /* no match */
5394 set_remove_node(set, i);
5395 }
5396 }
5397 lydict_remove(set->ctx, name_dict);
5398
5399 return LY_SUCCESS;
5400}
5401
5402/**
5403 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5404 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5405 *
5406 * @param[in,out] set Set to use.
5407 * @param[in] qname Qualified node name to move to.
5408 * @param[in] qname_len Length of @p qname.
5409 * @param[in] options XPath options.
5410 * @return LY_ERR
5411 */
5412static LY_ERR
5413moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5414{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005415 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005416 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005417 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005418 const struct lys_module *moveto_mod;
5419 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005420 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005421
5422 if (!set || (set->type == LYXP_SET_EMPTY)) {
5423 return LY_SUCCESS;
5424 }
5425
5426 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005427 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 +02005428 return LY_EVALID;
5429 }
5430
Michal Vasko6346ece2019-09-24 13:12:53 +02005431 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5432 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005433
5434 /* name */
5435 name_dict = lydict_insert(set->ctx, qname, qname_len);
5436
Michal Vaskocafad9d2019-11-07 15:20:03 +01005437 /* getnext opts */
5438 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5439 if (options & LYXP_SCNODE_OUTPUT) {
5440 getnext_opts |= LYS_GETNEXT_OUTPUT;
5441 }
5442
Michal Vasko03ff5a72019-09-11 13:49:33 +02005443 orig_used = set->used;
5444 for (i = 0; i < orig_used; ++i) {
5445 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005446 if (set->val.scnodes[i].in_ctx != -2) {
5447 continue;
5448 }
5449
5450 /* remember context node */
5451 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005452 } else {
5453 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005454 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005455
5456 start_parent = set->val.scnodes[i].scnode;
5457
5458 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5459 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5460 * so use it directly (root node itself is useless in this case) */
5461 mod_idx = 0;
5462 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5463 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005464 /* module may not be implemented */
5465 while (moveto_mod->implemented && (sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
Michal Vaskocafad9d2019-11-07 15:20:03 +01005466 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005467 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005468 /* we need to prevent these nodes from being considered in this moveto */
5469 if ((idx < orig_used) && (idx > i)) {
5470 set->val.scnodes[idx].in_ctx = 2;
5471 temp_ctx = 1;
5472 }
5473 }
5474 }
5475
5476 if (!mod_idx) {
5477 /* moveto_mod was specified, we are not going through the whole context */
5478 break;
5479 }
5480 /* next iteration */
5481 moveto_mod = NULL;
5482 }
5483
5484 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5485 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5486 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005487 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5488 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005489 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005490 if ((idx < orig_used) && (idx > i)) {
5491 set->val.scnodes[idx].in_ctx = 2;
5492 temp_ctx = 1;
5493 }
5494 }
5495 }
5496 }
5497 }
5498 lydict_remove(set->ctx, name_dict);
5499
5500 /* correct temporary in_ctx values */
5501 if (temp_ctx) {
5502 for (i = 0; i < orig_used; ++i) {
5503 if (set->val.scnodes[i].in_ctx == 2) {
5504 set->val.scnodes[i].in_ctx = 1;
5505 }
5506 }
5507 }
5508
5509 return LY_SUCCESS;
5510}
5511
5512/**
5513 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5514 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5515 * Context position aware.
5516 *
5517 * @param[in] set Set to use.
5518 * @param[in] qname Qualified node name to move to.
5519 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005520 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5521 */
5522static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005523moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005524{
5525 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005526 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005527 const struct lyd_node *next, *elem, *start;
5528 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005529 struct lyxp_set ret_set;
5530 LY_ERR rc;
5531
5532 if (!set || (set->type == LYXP_SET_EMPTY)) {
5533 return LY_SUCCESS;
5534 }
5535
5536 if (set->type != LYXP_SET_NODE_SET) {
5537 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5538 return LY_EVALID;
5539 }
5540
Michal Vasko6346ece2019-09-24 13:12:53 +02005541 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5542 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005543
5544 /* replace the original nodes (and throws away all text and attr nodes, root is replaced by a child) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005545 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005546 LY_CHECK_RET(rc);
5547
Michal Vasko6346ece2019-09-24 13:12:53 +02005548 /* name */
5549 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005550
Michal Vasko6346ece2019-09-24 13:12:53 +02005551 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005552 set_init(&ret_set, set);
5553 for (i = 0; i < set->used; ++i) {
5554
5555 /* TREE DFS */
5556 start = set->val.nodes[i].node;
5557 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005558 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005559 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005560 /* add matching node into result set */
5561 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5562 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5563 /* the node is a duplicate, we'll process it later in the set */
5564 goto skip_children;
5565 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005566 } else if (rc == LY_EINCOMPLETE) {
5567 lydict_remove(set->ctx, name_dict);
5568 return rc;
5569 } else if (rc == LY_EINVAL) {
5570 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005571 }
5572
5573 /* TREE DFS NEXT ELEM */
5574 /* select element for the next run - children first */
5575 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5576 next = NULL;
5577 } else {
5578 next = lyd_node_children(elem);
5579 }
5580 if (!next) {
5581skip_children:
5582 /* no children, so try siblings, but only if it's not the start,
5583 * that is considered to be the root and it's siblings are not traversed */
5584 if (elem != start) {
5585 next = elem->next;
5586 } else {
5587 break;
5588 }
5589 }
5590 while (!next) {
5591 /* no siblings, go back through the parents */
5592 if ((struct lyd_node *)elem->parent == start) {
5593 /* we are done, no next element to process */
5594 break;
5595 }
5596 /* parent is already processed, go to its sibling */
5597 elem = (struct lyd_node *)elem->parent;
5598 next = elem->next;
5599 }
5600 }
5601 }
5602
5603 /* make the temporary set the current one */
5604 ret_set.ctx_pos = set->ctx_pos;
5605 ret_set.ctx_size = set->ctx_size;
5606 set_free_content(set);
5607 memcpy(set, &ret_set, sizeof *set);
5608
Michal Vasko6346ece2019-09-24 13:12:53 +02005609 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005610 return LY_SUCCESS;
5611}
5612
5613/**
5614 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5615 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5616 *
5617 * @param[in] set Set to use.
5618 * @param[in] qname Qualified node name to move to.
5619 * @param[in] qname_len Length of @p qname.
5620 * @param[in] options XPath options.
5621 * @return LY_ERR
5622 */
5623static LY_ERR
5624moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5625{
Michal Vasko6346ece2019-09-24 13:12:53 +02005626 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005627 const struct lysc_node *next, *elem, *start;
5628 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005629 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005630
5631 if (!set || (set->type == LYXP_SET_EMPTY)) {
5632 return LY_SUCCESS;
5633 }
5634
5635 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005636 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 +02005637 return LY_EVALID;
5638 }
5639
Michal Vasko6346ece2019-09-24 13:12:53 +02005640 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5641 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005642
5643 orig_used = set->used;
5644 for (i = 0; i < orig_used; ++i) {
5645 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005646 if (set->val.scnodes[i].in_ctx != -2) {
5647 continue;
5648 }
5649
5650 /* remember context node */
5651 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005652 } else {
5653 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005654 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005655
5656 /* TREE DFS */
5657 start = set->val.scnodes[i].scnode;
5658 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005659 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5660 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005661 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005662 }
5663
Michal Vaskocafad9d2019-11-07 15:20:03 +01005664 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005665 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005666 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005667 set->val.scnodes[idx].in_ctx = 1;
5668 if (idx > i) {
5669 /* we will process it later in the set */
5670 goto skip_children;
5671 }
5672 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005673 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005674 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005675 } else if (rc == LY_EINVAL) {
5676 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005677 }
5678
5679next_iter:
5680 /* TREE DFS NEXT ELEM */
5681 /* select element for the next run - children first */
5682 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5683 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5684 next = NULL;
5685 }
5686 if (!next) {
5687skip_children:
5688 /* no children, so try siblings, but only if it's not the start,
5689 * that is considered to be the root and it's siblings are not traversed */
5690 if (elem != start) {
5691 next = elem->next;
5692 } else {
5693 break;
5694 }
5695 }
5696 while (!next) {
5697 /* no siblings, go back through the parents */
5698 if (elem->parent == start) {
5699 /* we are done, no next element to process */
5700 break;
5701 }
5702 /* parent is already processed, go to its sibling */
5703 elem = elem->parent;
5704 next = elem->next;
5705 }
5706 }
5707 }
5708
5709 return LY_SUCCESS;
5710}
5711
5712/**
5713 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5714 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5715 * Indirectly context position aware.
5716 *
5717 * @param[in,out] set Set to use.
5718 * @param[in] qname Qualified node name to move to.
5719 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005720 * @return LY_ERR
5721 */
5722static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005723moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005724{
5725 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005726 int replaced, all = 0;
5727 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005728 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005729 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005730
5731 if (!set || (set->type == LYXP_SET_EMPTY)) {
5732 return LY_SUCCESS;
5733 }
5734
5735 if (set->type != LYXP_SET_NODE_SET) {
5736 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5737 return LY_EVALID;
5738 }
5739
Michal Vasko6346ece2019-09-24 13:12:53 +02005740 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5741 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005742
5743 if ((qname_len == 1) && (qname[0] == '*')) {
5744 all = 1;
5745 }
5746
5747 for (i = 0; i < set->used; ) {
5748 replaced = 0;
5749
5750 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5751 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005752 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005753 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5754
5755 /* check "namespace" */
5756 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5757 continue;
5758 }
5759
5760 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5761 /* match */
5762 if (!replaced) {
5763 set->val.attrs[i].attr = sub;
5764 set->val.attrs[i].type = LYXP_NODE_ATTR;
5765 /* pos does not change */
5766 replaced = 1;
5767 } else {
5768 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_ATTR, i + 1);
5769 }
5770 ++i;
5771 }
5772 }
5773 }
5774
5775 if (!replaced) {
5776 /* no match */
5777 set_remove_node(set, i);
5778 }
5779 }
5780
5781 return LY_SUCCESS;
5782}
5783
5784/**
5785 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
5786 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5787 *
5788 * @param[in,out] set1 Set to use for the result.
5789 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005790 * @return LY_ERR
5791 */
5792static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005793moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005794{
5795 LY_ERR rc;
5796
5797 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5798 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5799 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5800 return LY_EVALID;
5801 }
5802
5803 /* set2 is empty or both set1 and set2 */
5804 if (set2->type == LYXP_SET_EMPTY) {
5805 return LY_SUCCESS;
5806 }
5807
5808 if (set1->type == LYXP_SET_EMPTY) {
5809 memcpy(set1, set2, sizeof *set1);
5810 /* dynamic memory belongs to set1 now, do not free */
5811 set2->type = LYXP_SET_EMPTY;
5812 return LY_SUCCESS;
5813 }
5814
5815 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005816 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005817
5818 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005819 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005820 LY_CHECK_RET(rc);
5821
5822 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005823 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005824
5825 return LY_SUCCESS;
5826}
5827
5828/**
5829 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5830 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5831 * Context position aware.
5832 *
5833 * @param[in,out] set Set to use.
5834 * @param[in] qname Qualified node name to move to.
5835 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005836 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5837 */
5838static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005839moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005840{
5841 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005842 int replaced, all = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005843 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005844 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005845 struct lyxp_set *set_all_desc = NULL;
5846 LY_ERR rc;
5847
5848 if (!set || (set->type == LYXP_SET_EMPTY)) {
5849 return LY_SUCCESS;
5850 }
5851
5852 if (set->type != LYXP_SET_NODE_SET) {
5853 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5854 return LY_EVALID;
5855 }
5856
Michal Vasko6346ece2019-09-24 13:12:53 +02005857 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5858 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005859
5860 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5861 * but it likely won't be used much, so it's a waste of time */
5862 /* copy the context */
5863 set_all_desc = set_copy(set);
5864 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005865 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005866 if (rc != LY_SUCCESS) {
5867 lyxp_set_free(set_all_desc);
5868 return rc;
5869 }
5870 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005871 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005872 if (rc != LY_SUCCESS) {
5873 lyxp_set_free(set_all_desc);
5874 return rc;
5875 }
5876 lyxp_set_free(set_all_desc);
5877
5878 if ((qname_len == 1) && (qname[0] == '*')) {
5879 all = 1;
5880 }
5881
5882 for (i = 0; i < set->used; ) {
5883 replaced = 0;
5884
5885 /* only attributes of an elem can be in the result, skip all the rest,
5886 * we have all attributes qualified in lyd tree */
5887 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5888 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5889 /* check "namespace" */
5890 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5891 continue;
5892 }
5893
5894 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5895 /* match */
5896 if (!replaced) {
5897 set->val.attrs[i].attr = sub;
5898 set->val.attrs[i].type = LYXP_NODE_ATTR;
5899 /* pos does not change */
5900 replaced = 1;
5901 } else {
5902 set_insert_node(set, (struct lyd_node *)sub, set->val.attrs[i].pos, LYXP_NODE_ATTR, i + 1);
5903 }
5904 ++i;
5905 }
5906 }
5907 }
5908
5909 if (!replaced) {
5910 /* no match */
5911 set_remove_node(set, i);
5912 }
5913 }
5914
5915 return LY_SUCCESS;
5916}
5917
5918/**
5919 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5920 * (or LYXP_SET_EMPTY). Context position aware.
5921 *
5922 * @param[in] parent Current parent.
5923 * @param[in] parent_pos Position of @p parent.
5924 * @param[in] parent_type Node type of @p parent.
5925 * @param[in,out] to_set Set to use.
5926 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005927 * @param[in] options XPath options.
5928 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5929 */
5930static LY_ERR
5931moveto_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 +01005932 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005933{
5934 const struct lyd_node *sub;
5935 LY_ERR rc;
5936
5937 switch (parent_type) {
5938 case LYXP_NODE_ROOT:
5939 case LYXP_NODE_ROOT_CONFIG:
5940 /* add the same node but as an element */
5941 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5942 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5943
5944 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005945 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005946 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005947 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005948 LY_CHECK_RET(rc);
5949 }
5950 }
5951 break;
5952 case LYXP_NODE_ELEM:
5953 /* add all the children ... */
5954 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5955 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5956 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005957 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005958 continue;
5959 }
5960
Michal Vaskoa1424542019-11-14 16:08:52 +01005961 /* when check */
5962 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005963 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005964 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005965
5966 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5967 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5968
Michal Vasko5c4e5892019-11-14 12:31:38 +01005969 /* skip anydata/anyxml nodes */
5970 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005971 continue;
5972 }
5973
5974 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005975 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005976 LY_CHECK_RET(rc);
5977 }
5978 }
5979
5980 /* ... or add their text node, ... */
5981 } else {
5982 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5983 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5984 }
5985 }
5986 break;
5987 default:
5988 LOGINT_RET(parent->schema->module->ctx);
5989 }
5990
5991 return LY_SUCCESS;
5992}
5993
5994/**
5995 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5996 * (or LYXP_SET_EMPTY). Context position aware.
5997 *
5998 * @param[in,out] set Set to use.
5999 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6000 * @param[in] options XPath options.
6001 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6002 */
6003static LY_ERR
6004moveto_self(struct lyxp_set *set, int all_desc, int options)
6005{
6006 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006007 struct lyxp_set ret_set;
6008 LY_ERR rc;
6009
6010 if (!set || (set->type == LYXP_SET_EMPTY)) {
6011 return LY_SUCCESS;
6012 }
6013
6014 if (set->type != LYXP_SET_NODE_SET) {
6015 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6016 return LY_EVALID;
6017 }
6018
6019 /* nothing to do */
6020 if (!all_desc) {
6021 return LY_SUCCESS;
6022 }
6023
Michal Vasko03ff5a72019-09-11 13:49:33 +02006024 /* add all the children, they get added recursively */
6025 set_init(&ret_set, set);
6026 for (i = 0; i < set->used; ++i) {
6027 /* copy the current node to tmp */
6028 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6029
6030 /* do not touch attributes and text nodes */
6031 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_ATTR)) {
6032 continue;
6033 }
6034
Michal Vasko5c4e5892019-11-14 12:31:38 +01006035 /* skip anydata/anyxml nodes */
6036 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006037 continue;
6038 }
6039
6040 /* add all the children */
6041 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 +01006042 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006043 if (rc != LY_SUCCESS) {
6044 set_free_content(&ret_set);
6045 return rc;
6046 }
6047 }
6048
6049 /* use the temporary set as the current one */
6050 ret_set.ctx_pos = set->ctx_pos;
6051 ret_set.ctx_size = set->ctx_size;
6052 set_free_content(set);
6053 memcpy(set, &ret_set, sizeof *set);
6054
6055 return LY_SUCCESS;
6056}
6057
6058/**
6059 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6060 * (or LYXP_SET_EMPTY).
6061 *
6062 * @param[in,out] set Set to use.
6063 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6064 * @param[in] options XPath options.
6065 * @return LY_ERR
6066 */
6067static LY_ERR
6068moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6069{
6070 const struct lysc_node *sub;
6071 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006072
6073 if (!set || (set->type == LYXP_SET_EMPTY)) {
6074 return LY_SUCCESS;
6075 }
6076
6077 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006078 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 +02006079 return LY_EVALID;
6080 }
6081
6082 /* nothing to do */
6083 if (!all_desc) {
6084 return LY_SUCCESS;
6085 }
6086
Michal Vasko03ff5a72019-09-11 13:49:33 +02006087 /* add all the children, they get added recursively */
6088 for (i = 0; i < set->used; ++i) {
6089 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006090 if (set->val.scnodes[i].in_ctx != -2) {
6091 continue;
6092 }
6093
6094 /* remember context node (it was traversed again so it changes to a normal node) */
6095 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006096 }
6097
6098 /* add all the children */
6099 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6100 sub = NULL;
6101 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6102 /* RPC input/output check */
6103 if (options & LYXP_SCNODE_OUTPUT) {
6104 if (sub->parent->nodetype == LYS_INPUT) {
6105 continue;
6106 }
6107 } else {
6108 if (sub->parent->nodetype == LYS_OUTPUT) {
6109 continue;
6110 }
6111 }
6112
6113 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006114 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006115 continue;
6116 }
6117
Michal Vaskoecd62de2019-11-13 12:35:11 +01006118 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006119 /* throw away the insert index, we want to consider that node again, recursively */
6120 }
6121 }
6122 }
6123
6124 return LY_SUCCESS;
6125}
6126
6127/**
6128 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6129 * (or LYXP_SET_EMPTY). Context position aware.
6130 *
6131 * @param[in] set Set to use.
6132 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6133 * @param[in] options XPath options.
6134 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6135 */
6136static LY_ERR
6137moveto_parent(struct lyxp_set *set, int all_desc, int options)
6138{
6139 LY_ERR rc;
6140 uint32_t i;
6141 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006142 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006143
6144 if (!set || (set->type == LYXP_SET_EMPTY)) {
6145 return LY_SUCCESS;
6146 }
6147
6148 if (set->type != LYXP_SET_NODE_SET) {
6149 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6150 return LY_EVALID;
6151 }
6152
6153 if (all_desc) {
6154 /* <path>//.. == <path>//./.. */
6155 rc = moveto_self(set, 1, options);
6156 LY_CHECK_RET(rc);
6157 }
6158
Michal Vasko57eab132019-09-24 11:46:26 +02006159 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006160 node = set->val.nodes[i].node;
6161
6162 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6163 new_node = (struct lyd_node *)node->parent;
6164 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6165 new_node = node;
6166 } else if (set->val.nodes[i].type == LYXP_NODE_ATTR) {
6167 new_node = set->val.attrs[i].attr->parent;
6168 if (!new_node) {
6169 LOGINT_RET(set->ctx);
6170 }
6171 } else {
6172 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006173 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006174 continue;
6175 }
6176
Michal Vaskoa1424542019-11-14 16:08:52 +01006177 /* when check */
6178 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006179 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006180 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006181
6182 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006183 if (!new_node) {
6184 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006185
6186 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6187 } else {
6188 new_type = LYXP_NODE_ELEM;
6189 }
6190
Michal Vasko03ff5a72019-09-11 13:49:33 +02006191 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006192 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006193 } else {
6194 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006195 }
6196 }
6197
Michal Vasko2caefc12019-11-14 16:07:56 +01006198 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006199 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006200
6201 return LY_SUCCESS;
6202}
6203
6204/**
6205 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6206 * (or LYXP_SET_EMPTY).
6207 *
6208 * @param[in] set Set to use.
6209 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6210 * @param[in] options XPath options.
6211 * @return LY_ERR
6212 */
6213static LY_ERR
6214moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6215{
6216 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006217 const struct lysc_node *node, *new_node;
6218 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006219 LY_ERR rc;
6220
6221 if (!set || (set->type == LYXP_SET_EMPTY)) {
6222 return LY_SUCCESS;
6223 }
6224
6225 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006226 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 +02006227 return LY_EVALID;
6228 }
6229
6230 if (all_desc) {
6231 /* <path>//.. == <path>//./.. */
6232 rc = moveto_scnode_self(set, 1, options);
6233 LY_CHECK_RET(rc);
6234 }
6235
Michal Vasko03ff5a72019-09-11 13:49:33 +02006236 orig_used = set->used;
6237 for (i = 0; i < orig_used; ++i) {
6238 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006239 if (set->val.scnodes[i].in_ctx != -2) {
6240 continue;
6241 }
6242
6243 /* remember context node */
6244 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006245 } else {
6246 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006247 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006248
6249 node = set->val.scnodes[i].scnode;
6250
6251 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6252 for (new_node = node->parent;
6253 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6254 new_node = new_node->parent);
6255 } else {
6256 /* root does not have a parent */
6257 continue;
6258 }
6259
Michal Vasko03ff5a72019-09-11 13:49:33 +02006260 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006261 if (!new_node) {
6262 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006263
6264 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6265 } else {
6266 new_type = LYXP_NODE_ELEM;
6267 }
6268
Michal Vaskoecd62de2019-11-13 12:35:11 +01006269 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006270 if ((idx < orig_used) && (idx > i)) {
6271 set->val.scnodes[idx].in_ctx = 2;
6272 temp_ctx = 1;
6273 }
6274 }
6275
6276 if (temp_ctx) {
6277 for (i = 0; i < orig_used; ++i) {
6278 if (set->val.scnodes[i].in_ctx == 2) {
6279 set->val.scnodes[i].in_ctx = 1;
6280 }
6281 }
6282 }
6283
6284 return LY_SUCCESS;
6285}
6286
6287/**
6288 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6289 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6290 *
6291 * @param[in,out] set1 Set to use for the result.
6292 * @param[in] set2 Set acting as the second operand for @p op.
6293 * @param[in] op Comparison operator to process.
6294 * @param[in] options XPath options.
6295 * @return LY_ERR
6296 */
6297static LY_ERR
6298moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6299{
6300 /*
6301 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6302 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6303 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6304 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6305 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6306 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6307 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6308 *
6309 * '=' or '!='
6310 * BOOLEAN + BOOLEAN
6311 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6312 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6313 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6314 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6315 * NUMBER + NUMBER
6316 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6317 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6318 * STRING + STRING
6319 *
6320 * '<=', '<', '>=', '>'
6321 * NUMBER + NUMBER
6322 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6323 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6324 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6325 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6326 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6327 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6328 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6329 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6330 */
6331 struct lyxp_set iter1, iter2;
6332 int result;
6333 int64_t i;
6334 LY_ERR rc;
6335
6336 iter1.type = LYXP_SET_EMPTY;
6337
6338 /* empty node-sets are always false */
6339 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6340 set_fill_boolean(set1, 0);
6341 return LY_SUCCESS;
6342 }
6343
6344 /* iterative evaluation with node-sets */
6345 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6346 if (set1->type == LYXP_SET_NODE_SET) {
6347 for (i = 0; i < set1->used; ++i) {
6348 switch (set2->type) {
6349 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006350 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006351 break;
6352 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006353 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006354 break;
6355 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006356 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006357 break;
6358 }
6359 LY_CHECK_RET(rc);
6360
6361 rc = moveto_op_comp(&iter1, set2, op, options);
6362 if (rc != LY_SUCCESS) {
6363 set_free_content(&iter1);
6364 return rc;
6365 }
6366
6367 /* lazy evaluation until true */
6368 if (iter1.val.bool) {
6369 set_fill_boolean(set1, 1);
6370 return LY_SUCCESS;
6371 }
6372 }
6373 } else {
6374 for (i = 0; i < set2->used; ++i) {
6375 switch (set1->type) {
6376 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006377 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006378 break;
6379 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006380 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006381 break;
6382 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006383 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006384 break;
6385 }
6386 LY_CHECK_RET(rc);
6387
6388 set_fill_set(&iter1, set1);
6389
6390 rc = moveto_op_comp(&iter1, &iter2, op, options);
6391 if (rc != LY_SUCCESS) {
6392 set_free_content(&iter1);
6393 set_free_content(&iter2);
6394 return rc;
6395 }
6396 set_free_content(&iter2);
6397
6398 /* lazy evaluation until true */
6399 if (iter1.val.bool) {
6400 set_fill_boolean(set1, 1);
6401 return LY_SUCCESS;
6402 }
6403 }
6404 }
6405
6406 /* false for all nodes */
6407 set_fill_boolean(set1, 0);
6408 return LY_SUCCESS;
6409 }
6410
6411 /* first convert properly */
6412 if ((op[0] == '=') || (op[0] == '!')) {
6413 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006414 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6415 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006416 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006417 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006418 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006419 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006420 LY_CHECK_RET(rc);
6421 } /* else we have 2 strings */
6422 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006423 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006424 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006425 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006426 LY_CHECK_RET(rc);
6427 }
6428
6429 assert(set1->type == set2->type);
6430
6431 /* compute result */
6432 if (op[0] == '=') {
6433 if (set1->type == LYXP_SET_BOOLEAN) {
6434 result = (set1->val.bool == set2->val.bool);
6435 } else if (set1->type == LYXP_SET_NUMBER) {
6436 result = (set1->val.num == set2->val.num);
6437 } else {
6438 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006439 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006440 }
6441 } else if (op[0] == '!') {
6442 if (set1->type == LYXP_SET_BOOLEAN) {
6443 result = (set1->val.bool != set2->val.bool);
6444 } else if (set1->type == LYXP_SET_NUMBER) {
6445 result = (set1->val.num != set2->val.num);
6446 } else {
6447 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006448 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006449 }
6450 } else {
6451 assert(set1->type == LYXP_SET_NUMBER);
6452 if (op[0] == '<') {
6453 if (op[1] == '=') {
6454 result = (set1->val.num <= set2->val.num);
6455 } else {
6456 result = (set1->val.num < set2->val.num);
6457 }
6458 } else {
6459 if (op[1] == '=') {
6460 result = (set1->val.num >= set2->val.num);
6461 } else {
6462 result = (set1->val.num > set2->val.num);
6463 }
6464 }
6465 }
6466
6467 /* assign result */
6468 if (result) {
6469 set_fill_boolean(set1, 1);
6470 } else {
6471 set_fill_boolean(set1, 0);
6472 }
6473
6474 return LY_SUCCESS;
6475}
6476
6477/**
6478 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6479 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6480 *
6481 * @param[in,out] set1 Set to use for the result.
6482 * @param[in] set2 Set acting as the second operand for @p op.
6483 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006484 * @return LY_ERR
6485 */
6486static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006487moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006488{
6489 LY_ERR rc;
6490
6491 /* unary '-' */
6492 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006493 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006494 LY_CHECK_RET(rc);
6495 set1->val.num *= -1;
6496 lyxp_set_free(set2);
6497 return LY_SUCCESS;
6498 }
6499
6500 assert(set1 && set2);
6501
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006502 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006503 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006504 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006505 LY_CHECK_RET(rc);
6506
6507 switch (op[0]) {
6508 /* '+' */
6509 case '+':
6510 set1->val.num += set2->val.num;
6511 break;
6512
6513 /* '-' */
6514 case '-':
6515 set1->val.num -= set2->val.num;
6516 break;
6517
6518 /* '*' */
6519 case '*':
6520 set1->val.num *= set2->val.num;
6521 break;
6522
6523 /* 'div' */
6524 case 'd':
6525 set1->val.num /= set2->val.num;
6526 break;
6527
6528 /* 'mod' */
6529 case 'm':
6530 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6531 break;
6532
6533 default:
6534 LOGINT_RET(set1->ctx);
6535 }
6536
6537 return LY_SUCCESS;
6538}
6539
6540/*
6541 * eval functions
6542 *
6543 * They execute a parsed XPath expression on some data subtree.
6544 */
6545
6546/**
6547 * @brief Evaluate Literal. Logs directly on error.
6548 *
6549 * @param[in] exp Parsed XPath expression.
6550 * @param[in] exp_idx Position in the expression @p exp.
6551 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6552 */
6553static void
6554eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6555{
6556 if (set) {
6557 if (exp->tok_len[*exp_idx] == 2) {
6558 set_fill_string(set, "", 0);
6559 } else {
6560 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6561 }
6562 }
6563 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6564 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6565 ++(*exp_idx);
6566}
6567
6568/**
6569 * @brief Evaluate NodeTest. Logs directly on error.
6570 *
6571 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6572 *
6573 * @param[in] exp Parsed XPath expression.
6574 * @param[in] exp_idx Position in the expression @p exp.
6575 * @param[in] attr_axis Whether to search attributes or standard nodes.
6576 * @param[in] all_desc Whether to search all the descendants or children only.
6577 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6578 * @param[in] options XPath options.
6579 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6580 */
6581static int
6582eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6583 struct lyxp_set *set, int options)
6584{
6585 int i;
6586 char *path;
6587 LY_ERR rc;
6588
6589 switch (exp->tokens[*exp_idx]) {
6590 case LYXP_TOKEN_NAMETEST:
6591 if (attr_axis) {
6592 if (set && (options & LYXP_SCNODE_ALL)) {
6593 set_scnode_clear_ctx(set);
6594 rc = LY_SUCCESS;
6595 } else {
6596 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006597 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006598 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006599 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006600 }
6601 }
6602 } else {
6603 if (all_desc) {
6604 if (set && (options & LYXP_SCNODE_ALL)) {
6605 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6606 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006607 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006608 }
6609 } else {
6610 if (set && (options & LYXP_SCNODE_ALL)) {
6611 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6612 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006613 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006614 }
6615 }
6616
6617 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6618 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006619 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006620 break;
6621 }
6622 }
6623 if (i == -1) {
6624 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6625 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6626 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6627 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6628 free(path);
6629 }
6630 }
6631 }
6632 LY_CHECK_RET(rc);
6633
6634 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6635 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6636 ++(*exp_idx);
6637 break;
6638
6639 case LYXP_TOKEN_NODETYPE:
6640 if (set) {
6641 assert(exp->tok_len[*exp_idx] == 4);
6642 if (set->type == LYXP_SET_SCNODE_SET) {
6643 set_scnode_clear_ctx(set);
6644 /* just for the debug message underneath */
6645 set = NULL;
6646 } else {
6647 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6648 rc = xpath_node(NULL, 0, set, options);
6649 LY_CHECK_RET(rc);
6650 } else {
6651 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6652 rc = xpath_text(NULL, 0, set, options);
6653 LY_CHECK_RET(rc);
6654 }
6655 }
6656 }
6657 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6658 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6659 ++(*exp_idx);
6660
6661 /* '(' */
6662 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6663 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6664 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6665 ++(*exp_idx);
6666
6667 /* ')' */
6668 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6669 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6670 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6671 ++(*exp_idx);
6672 break;
6673
6674 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006675 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006676 }
6677
6678 return LY_SUCCESS;
6679}
6680
6681/**
6682 * @brief Evaluate Predicate. Logs directly on error.
6683 *
6684 * [7] Predicate ::= '[' Expr ']'
6685 *
6686 * @param[in] exp Parsed XPath expression.
6687 * @param[in] exp_idx Position in the expression @p exp.
6688 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6689 * @param[in] options XPath options.
6690 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6691 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6692 */
6693static LY_ERR
6694eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6695{
6696 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006697 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006698 uint32_t orig_pos, orig_size;
6699 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006700 struct lyxp_set set2;
6701 struct lyd_node *orig_parent;
6702
6703 /* '[' */
6704 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6705 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6706 ++(*exp_idx);
6707
6708 if (!set) {
6709only_parse:
6710 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6711 LY_CHECK_RET(rc);
6712 } else if (set->type == LYXP_SET_NODE_SET) {
6713 /* 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 +01006714 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006715
6716 /* empty set, nothing to evaluate */
6717 if (!set->used) {
6718 goto only_parse;
6719 }
6720
6721 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006722 orig_pos = 0;
6723 orig_size = set->used;
6724 orig_parent = NULL;
6725 for (i = 0; i < set->used; ) {
6726 set_init(&set2, set);
6727 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6728 /* remember the node context position for position() and context size for last(),
6729 * predicates should always be evaluated with respect to the child axis (since we do
6730 * not support explicit axes) so we assign positions based on their parents */
6731 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6732 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6733 orig_pos = 1;
6734 } else {
6735 ++orig_pos;
6736 }
6737
6738 set2.ctx_pos = orig_pos;
6739 set2.ctx_size = orig_size;
6740 *exp_idx = orig_exp;
6741
6742 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6743 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006744 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006745 return rc;
6746 }
6747
6748 /* number is a position */
6749 if (set2.type == LYXP_SET_NUMBER) {
6750 if ((long long)set2.val.num == orig_pos) {
6751 set2.val.num = 1;
6752 } else {
6753 set2.val.num = 0;
6754 }
6755 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006756 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006757
6758 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006759 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006760 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006761 }
6762 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006763 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006764
6765 } else if (set->type == LYXP_SET_SCNODE_SET) {
6766 for (i = 0; i < set->used; ++i) {
6767 if (set->val.scnodes[i].in_ctx == 1) {
6768 /* there is a currently-valid node */
6769 break;
6770 }
6771 }
6772 /* empty set, nothing to evaluate */
6773 if (i == set->used) {
6774 goto only_parse;
6775 }
6776
6777 orig_exp = *exp_idx;
6778
Michal Vasko03ff5a72019-09-11 13:49:33 +02006779 /* set special in_ctx to all the valid snodes */
6780 pred_in_ctx = set_scnode_new_in_ctx(set);
6781
6782 /* use the valid snodes one-by-one */
6783 for (i = 0; i < set->used; ++i) {
6784 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6785 continue;
6786 }
6787 set->val.scnodes[i].in_ctx = 1;
6788
6789 *exp_idx = orig_exp;
6790
6791 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6792 LY_CHECK_RET(rc);
6793
6794 set->val.scnodes[i].in_ctx = pred_in_ctx;
6795 }
6796
6797 /* restore the state as it was before the predicate */
6798 for (i = 0; i < set->used; ++i) {
6799 if (set->val.scnodes[i].in_ctx == 1) {
6800 set->val.scnodes[i].in_ctx = 0;
6801 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6802 set->val.scnodes[i].in_ctx = 1;
6803 }
6804 }
6805
6806 } else {
6807 set2.type = LYXP_SET_EMPTY;
6808 set_fill_set(&set2, set);
6809
6810 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6811 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006812 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006813 return rc;
6814 }
6815
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006816 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006817 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006818 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006819 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006820 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006821 }
6822
6823 /* ']' */
6824 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6825 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6826 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6827 ++(*exp_idx);
6828
6829 return LY_SUCCESS;
6830}
6831
6832/**
6833 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6834 *
6835 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6836 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6837 *
6838 * @param[in] exp Parsed XPath expression.
6839 * @param[in] exp_idx Position in the expression @p exp.
6840 * @param[in] all_desc Whether to search all the descendants or children only.
6841 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6842 * @param[in] options XPath options.
6843 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6844 */
6845static LY_ERR
6846eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6847{
6848 int attr_axis;
6849 LY_ERR rc;
6850
6851 goto step;
6852 do {
6853 /* evaluate '/' or '//' */
6854 if (exp->tok_len[*exp_idx] == 1) {
6855 all_desc = 0;
6856 } else {
6857 assert(exp->tok_len[*exp_idx] == 2);
6858 all_desc = 1;
6859 }
6860 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6861 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6862 ++(*exp_idx);
6863
6864step:
6865 /* Step */
6866 attr_axis = 0;
6867 switch (exp->tokens[*exp_idx]) {
6868 case LYXP_TOKEN_DOT:
6869 /* evaluate '.' */
6870 if (set && (options & LYXP_SCNODE_ALL)) {
6871 rc = moveto_scnode_self(set, all_desc, options);
6872 } else {
6873 rc = moveto_self(set, all_desc, options);
6874 }
6875 LY_CHECK_RET(rc);
6876 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6877 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6878 ++(*exp_idx);
6879 break;
6880
6881 case LYXP_TOKEN_DDOT:
6882 /* evaluate '..' */
6883 if (set && (options & LYXP_SCNODE_ALL)) {
6884 rc = moveto_scnode_parent(set, all_desc, options);
6885 } else {
6886 rc = moveto_parent(set, all_desc, options);
6887 }
6888 LY_CHECK_RET(rc);
6889 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6890 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6891 ++(*exp_idx);
6892 break;
6893
6894 case LYXP_TOKEN_AT:
6895 /* evaluate '@' */
6896 attr_axis = 1;
6897 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6898 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6899 ++(*exp_idx);
6900
6901 /* fall through */
6902 case LYXP_TOKEN_NAMETEST:
6903 case LYXP_TOKEN_NODETYPE:
6904 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6905 LY_CHECK_RET(rc);
6906
6907 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6908 rc = eval_predicate(exp, exp_idx, set, options, 1);
6909 LY_CHECK_RET(rc);
6910 }
6911 break;
6912
6913 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006914 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006915 }
6916 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6917
6918 return LY_SUCCESS;
6919}
6920
6921/**
6922 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6923 *
6924 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6925 *
6926 * @param[in] exp Parsed XPath expression.
6927 * @param[in] exp_idx Position in the expression @p exp.
6928 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6929 * @param[in] options XPath options.
6930 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6931 */
6932static LY_ERR
6933eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6934{
6935 int all_desc;
6936 LY_ERR rc;
6937
6938 if (set) {
6939 /* no matter what tokens follow, we need to be at the root */
6940 moveto_root(set, options);
6941 }
6942
6943 /* '/' RelativeLocationPath? */
6944 if (exp->tok_len[*exp_idx] == 1) {
6945 /* evaluate '/' - deferred */
6946 all_desc = 0;
6947 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6948 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6949 ++(*exp_idx);
6950
Michal Vasko4b9e1052019-09-13 11:25:37 +02006951 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006952 return LY_SUCCESS;
6953 }
6954 switch (exp->tokens[*exp_idx]) {
6955 case LYXP_TOKEN_DOT:
6956 case LYXP_TOKEN_DDOT:
6957 case LYXP_TOKEN_AT:
6958 case LYXP_TOKEN_NAMETEST:
6959 case LYXP_TOKEN_NODETYPE:
6960 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6961 LY_CHECK_RET(rc);
6962 break;
6963 default:
6964 break;
6965 }
6966
6967 /* '//' RelativeLocationPath */
6968 } else {
6969 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6970 all_desc = 1;
6971 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6972 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6973 ++(*exp_idx);
6974
6975 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6976 LY_CHECK_RET(rc);
6977 }
6978
6979 return LY_SUCCESS;
6980}
6981
6982/**
6983 * @brief Evaluate FunctionCall. Logs directly on error.
6984 *
6985 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6986 *
6987 * @param[in] exp Parsed XPath expression.
6988 * @param[in] exp_idx Position in the expression @p exp.
6989 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6990 * @param[in] options XPath options.
6991 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6992 */
6993static LY_ERR
6994eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6995{
6996 LY_ERR rc;
6997 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01006998 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006999 struct lyxp_set **args = NULL, **args_aux;
7000
7001 if (set) {
7002 /* FunctionName */
7003 switch (exp->tok_len[*exp_idx]) {
7004 case 3:
7005 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7006 xpath_func = &xpath_not;
7007 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7008 xpath_func = &xpath_sum;
7009 }
7010 break;
7011 case 4:
7012 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7013 xpath_func = &xpath_lang;
7014 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7015 xpath_func = &xpath_last;
7016 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7017 xpath_func = &xpath_name;
7018 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7019 xpath_func = &xpath_true;
7020 }
7021 break;
7022 case 5:
7023 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7024 xpath_func = &xpath_count;
7025 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7026 xpath_func = &xpath_false;
7027 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7028 xpath_func = &xpath_floor;
7029 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7030 xpath_func = &xpath_round;
7031 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7032 xpath_func = &xpath_deref;
7033 }
7034 break;
7035 case 6:
7036 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7037 xpath_func = &xpath_concat;
7038 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7039 xpath_func = &xpath_number;
7040 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7041 xpath_func = &xpath_string;
7042 }
7043 break;
7044 case 7:
7045 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7046 xpath_func = &xpath_boolean;
7047 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7048 xpath_func = &xpath_ceiling;
7049 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7050 xpath_func = &xpath_current;
7051 }
7052 break;
7053 case 8:
7054 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7055 xpath_func = &xpath_contains;
7056 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7057 xpath_func = &xpath_position;
7058 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7059 xpath_func = &xpath_re_match;
7060 }
7061 break;
7062 case 9:
7063 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7064 xpath_func = &xpath_substring;
7065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7066 xpath_func = &xpath_translate;
7067 }
7068 break;
7069 case 10:
7070 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7071 xpath_func = &xpath_local_name;
7072 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7073 xpath_func = &xpath_enum_value;
7074 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7075 xpath_func = &xpath_bit_is_set;
7076 }
7077 break;
7078 case 11:
7079 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7080 xpath_func = &xpath_starts_with;
7081 }
7082 break;
7083 case 12:
7084 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7085 xpath_func = &xpath_derived_from;
7086 }
7087 break;
7088 case 13:
7089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7090 xpath_func = &xpath_namespace_uri;
7091 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7092 xpath_func = &xpath_string_length;
7093 }
7094 break;
7095 case 15:
7096 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7097 xpath_func = &xpath_normalize_space;
7098 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7099 xpath_func = &xpath_substring_after;
7100 }
7101 break;
7102 case 16:
7103 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7104 xpath_func = &xpath_substring_before;
7105 }
7106 break;
7107 case 20:
7108 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7109 xpath_func = &xpath_derived_from_or_self;
7110 }
7111 break;
7112 }
7113
7114 if (!xpath_func) {
7115 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7116 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]]);
7117 return LY_EVALID;
7118 }
7119 }
7120
7121 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7122 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7123 ++(*exp_idx);
7124
7125 /* '(' */
7126 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7127 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7128 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7129 ++(*exp_idx);
7130
7131 /* ( Expr ( ',' Expr )* )? */
7132 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7133 if (set) {
7134 args = malloc(sizeof *args);
7135 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7136 arg_count = 1;
7137 args[0] = set_copy(set);
7138 if (!args[0]) {
7139 rc = LY_EMEM;
7140 goto cleanup;
7141 }
7142
7143 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7144 LY_CHECK_GOTO(rc, cleanup);
7145 } else {
7146 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7147 LY_CHECK_GOTO(rc, cleanup);
7148 }
7149 }
7150 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7151 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7152 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7153 ++(*exp_idx);
7154
7155 if (set) {
7156 ++arg_count;
7157 args_aux = realloc(args, arg_count * sizeof *args);
7158 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7159 args = args_aux;
7160 args[arg_count - 1] = set_copy(set);
7161 if (!args[arg_count - 1]) {
7162 rc = LY_EMEM;
7163 goto cleanup;
7164 }
7165
7166 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7167 LY_CHECK_GOTO(rc, cleanup);
7168 } else {
7169 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7170 LY_CHECK_GOTO(rc, cleanup);
7171 }
7172 }
7173
7174 /* ')' */
7175 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7176 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7177 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7178 ++(*exp_idx);
7179
7180 if (set) {
7181 /* evaluate function */
7182 rc = xpath_func(args, arg_count, set, options);
7183
7184 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007185 /* merge all nodes from arg evaluations */
7186 for (i = 0; i < arg_count; ++i) {
7187 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007188 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007189 }
7190 }
7191 } else {
7192 rc = LY_SUCCESS;
7193 }
7194
7195cleanup:
7196 for (i = 0; i < arg_count; ++i) {
7197 lyxp_set_free(args[i]);
7198 }
7199 free(args);
7200
7201 return rc;
7202}
7203
7204/**
7205 * @brief Evaluate Number. Logs directly on error.
7206 *
7207 * @param[in] ctx Context for errors.
7208 * @param[in] exp Parsed XPath expression.
7209 * @param[in] exp_idx Position in the expression @p exp.
7210 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7211 * @return LY_ERR
7212 */
7213static LY_ERR
7214eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7215{
7216 long double num;
7217 char *endptr;
7218
7219 if (set) {
7220 errno = 0;
7221 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7222 if (errno) {
7223 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7224 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7225 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7226 return LY_EVALID;
7227 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7228 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7229 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7230 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7231 return LY_EVALID;
7232 }
7233
7234 set_fill_number(set, num);
7235 }
7236
7237 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7238 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7239 ++(*exp_idx);
7240 return LY_SUCCESS;
7241}
7242
7243/**
7244 * @brief Evaluate PathExpr. Logs directly on error.
7245 *
7246 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7247 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7248 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7249 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7250 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7251 *
7252 * @param[in] exp Parsed XPath expression.
7253 * @param[in] exp_idx Position in the expression @p exp.
7254 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7255 * @param[in] options XPath options.
7256 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7257 */
7258static LY_ERR
7259eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7260{
7261 int all_desc, parent_pos_pred;
7262 LY_ERR rc;
7263
7264 switch (exp->tokens[*exp_idx]) {
7265 case LYXP_TOKEN_PAR1:
7266 /* '(' Expr ')' */
7267
7268 /* '(' */
7269 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7270 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7271 ++(*exp_idx);
7272
7273 /* Expr */
7274 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7275 LY_CHECK_RET(rc);
7276
7277 /* ')' */
7278 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
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 parent_pos_pred = 0;
7284 goto predicate;
7285
7286 case LYXP_TOKEN_DOT:
7287 case LYXP_TOKEN_DDOT:
7288 case LYXP_TOKEN_AT:
7289 case LYXP_TOKEN_NAMETEST:
7290 case LYXP_TOKEN_NODETYPE:
7291 /* RelativeLocationPath */
7292 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7293 LY_CHECK_RET(rc);
7294 break;
7295
7296 case LYXP_TOKEN_FUNCNAME:
7297 /* FunctionCall */
7298 if (!set) {
7299 rc = eval_function_call(exp, exp_idx, NULL, options);
7300 } else {
7301 rc = eval_function_call(exp, exp_idx, set, options);
7302 }
7303 LY_CHECK_RET(rc);
7304
7305 parent_pos_pred = 1;
7306 goto predicate;
7307
7308 case LYXP_TOKEN_OPERATOR_PATH:
7309 /* AbsoluteLocationPath */
7310 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7311 LY_CHECK_RET(rc);
7312 break;
7313
7314 case LYXP_TOKEN_LITERAL:
7315 /* Literal */
7316 if (!set || (options & LYXP_SCNODE_ALL)) {
7317 if (set) {
7318 set_scnode_clear_ctx(set);
7319 }
7320 eval_literal(exp, exp_idx, NULL);
7321 } else {
7322 eval_literal(exp, exp_idx, set);
7323 }
7324
7325 parent_pos_pred = 1;
7326 goto predicate;
7327
7328 case LYXP_TOKEN_NUMBER:
7329 /* Number */
7330 if (!set || (options & LYXP_SCNODE_ALL)) {
7331 if (set) {
7332 set_scnode_clear_ctx(set);
7333 }
Michal Vasko02a77382019-09-12 11:47:35 +02007334 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007335 } else {
7336 rc = eval_number(set->ctx, exp, exp_idx, set);
7337 }
7338 LY_CHECK_RET(rc);
7339
7340 parent_pos_pred = 1;
7341 goto predicate;
7342
7343 default:
7344 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7345 &exp->expr[exp->tok_pos[*exp_idx]]);
7346 return LY_EVALID;
7347 }
7348
7349 return LY_SUCCESS;
7350
7351predicate:
7352 /* Predicate* */
7353 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7354 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7355 LY_CHECK_RET(rc);
7356 }
7357
7358 /* ('/' or '//') RelativeLocationPath */
7359 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7360
7361 /* evaluate '/' or '//' */
7362 if (exp->tok_len[*exp_idx] == 1) {
7363 all_desc = 0;
7364 } else {
7365 assert(exp->tok_len[*exp_idx] == 2);
7366 all_desc = 1;
7367 }
7368
7369 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7370 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7371 ++(*exp_idx);
7372
7373 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7374 LY_CHECK_RET(rc);
7375 }
7376
7377 return LY_SUCCESS;
7378}
7379
7380/**
7381 * @brief Evaluate UnionExpr. Logs directly on error.
7382 *
7383 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7384 *
7385 * @param[in] exp Parsed XPath expression.
7386 * @param[in] exp_idx Position in the expression @p exp.
7387 * @param[in] repeat How many times this expression is repeated.
7388 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7389 * @param[in] options XPath options.
7390 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7391 */
7392static LY_ERR
7393eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7394{
7395 LY_ERR rc = LY_SUCCESS;
7396 struct lyxp_set orig_set, set2;
7397 uint16_t i;
7398
7399 assert(repeat);
7400
7401 set_init(&orig_set, set);
7402 set_init(&set2, set);
7403
7404 set_fill_set(&orig_set, set);
7405
7406 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7407 LY_CHECK_GOTO(rc, cleanup);
7408
7409 /* ('|' PathExpr)* */
7410 for (i = 0; i < repeat; ++i) {
7411 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7412 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7413 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7414 ++(*exp_idx);
7415
7416 if (!set) {
7417 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7418 LY_CHECK_GOTO(rc, cleanup);
7419 continue;
7420 }
7421
7422 set_fill_set(&set2, &orig_set);
7423 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7424 LY_CHECK_GOTO(rc, cleanup);
7425
7426 /* eval */
7427 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007428 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007429 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007430 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007431 LY_CHECK_GOTO(rc, cleanup);
7432 }
7433 }
7434
7435cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007436 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7437 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007438 return rc;
7439}
7440
7441/**
7442 * @brief Evaluate UnaryExpr. Logs directly on error.
7443 *
7444 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7445 *
7446 * @param[in] exp Parsed XPath expression.
7447 * @param[in] exp_idx Position in the expression @p exp.
7448 * @param[in] repeat How many times this expression is repeated.
7449 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7450 * @param[in] options XPath options.
7451 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7452 */
7453static LY_ERR
7454eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7455{
7456 LY_ERR rc;
7457 uint16_t this_op, i;
7458
7459 assert(repeat);
7460
7461 /* ('-')+ */
7462 this_op = *exp_idx;
7463 for (i = 0; i < repeat; ++i) {
7464 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7465
7466 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7467 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7468 ++(*exp_idx);
7469 }
7470
7471 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7472 LY_CHECK_RET(rc);
7473
7474 if (set && (repeat % 2)) {
7475 if (options & LYXP_SCNODE_ALL) {
7476 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7477 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007478 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007479 LY_CHECK_RET(rc);
7480 }
7481 }
7482
7483 return LY_SUCCESS;
7484}
7485
7486/**
7487 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7488 *
7489 * [16] MultiplicativeExpr ::= UnaryExpr
7490 * | MultiplicativeExpr '*' UnaryExpr
7491 * | MultiplicativeExpr 'div' UnaryExpr
7492 * | MultiplicativeExpr 'mod' UnaryExpr
7493 *
7494 * @param[in] exp Parsed XPath expression.
7495 * @param[in] exp_idx Position in the expression @p exp.
7496 * @param[in] repeat How many times this expression is repeated.
7497 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7498 * @param[in] options XPath options.
7499 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7500 */
7501static LY_ERR
7502eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7503{
7504 LY_ERR rc;
7505 uint16_t this_op;
7506 struct lyxp_set orig_set, set2;
7507 uint16_t i;
7508
7509 assert(repeat);
7510
7511 set_init(&orig_set, set);
7512 set_init(&set2, set);
7513
7514 set_fill_set(&orig_set, set);
7515
7516 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7517 LY_CHECK_GOTO(rc, cleanup);
7518
7519 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7520 for (i = 0; i < repeat; ++i) {
7521 this_op = *exp_idx;
7522
7523 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7524 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7525 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7526 ++(*exp_idx);
7527
7528 if (!set) {
7529 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7530 LY_CHECK_GOTO(rc, cleanup);
7531 continue;
7532 }
7533
7534 set_fill_set(&set2, &orig_set);
7535 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7536 LY_CHECK_GOTO(rc, cleanup);
7537
7538 /* eval */
7539 if (options & LYXP_SCNODE_ALL) {
7540 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007541 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007542 set_scnode_clear_ctx(set);
7543 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007544 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007545 LY_CHECK_GOTO(rc, cleanup);
7546 }
7547 }
7548
7549cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007550 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7551 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007552 return rc;
7553}
7554
7555/**
7556 * @brief Evaluate AdditiveExpr. Logs directly on error.
7557 *
7558 * [15] AdditiveExpr ::= MultiplicativeExpr
7559 * | AdditiveExpr '+' MultiplicativeExpr
7560 * | AdditiveExpr '-' MultiplicativeExpr
7561 *
7562 * @param[in] exp Parsed XPath expression.
7563 * @param[in] exp_idx Position in the expression @p exp.
7564 * @param[in] repeat How many times this expression is repeated.
7565 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7566 * @param[in] options XPath options.
7567 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7568 */
7569static LY_ERR
7570eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7571{
7572 LY_ERR rc;
7573 uint16_t this_op;
7574 struct lyxp_set orig_set, set2;
7575 uint16_t i;
7576
7577 assert(repeat);
7578
7579 set_init(&orig_set, set);
7580 set_init(&set2, set);
7581
7582 set_fill_set(&orig_set, set);
7583
7584 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7585 LY_CHECK_GOTO(rc, cleanup);
7586
7587 /* ('+' / '-' MultiplicativeExpr)* */
7588 for (i = 0; i < repeat; ++i) {
7589 this_op = *exp_idx;
7590
7591 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7592 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7593 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7594 ++(*exp_idx);
7595
7596 if (!set) {
7597 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7598 LY_CHECK_GOTO(rc, cleanup);
7599 continue;
7600 }
7601
7602 set_fill_set(&set2, &orig_set);
7603 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7604 LY_CHECK_GOTO(rc, cleanup);
7605
7606 /* eval */
7607 if (options & LYXP_SCNODE_ALL) {
7608 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007609 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007610 set_scnode_clear_ctx(set);
7611 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007612 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007613 LY_CHECK_GOTO(rc, cleanup);
7614 }
7615 }
7616
7617cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007618 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7619 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007620 return rc;
7621}
7622
7623/**
7624 * @brief Evaluate RelationalExpr. Logs directly on error.
7625 *
7626 * [14] RelationalExpr ::= AdditiveExpr
7627 * | RelationalExpr '<' AdditiveExpr
7628 * | RelationalExpr '>' AdditiveExpr
7629 * | RelationalExpr '<=' AdditiveExpr
7630 * | RelationalExpr '>=' AdditiveExpr
7631 *
7632 * @param[in] exp Parsed XPath expression.
7633 * @param[in] exp_idx Position in the expression @p exp.
7634 * @param[in] repeat How many times this expression is repeated.
7635 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7636 * @param[in] options XPath options.
7637 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7638 */
7639static LY_ERR
7640eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7641{
7642 LY_ERR rc;
7643 uint16_t this_op;
7644 struct lyxp_set orig_set, set2;
7645 uint16_t i;
7646
7647 assert(repeat);
7648
7649 set_init(&orig_set, set);
7650 set_init(&set2, set);
7651
7652 set_fill_set(&orig_set, set);
7653
7654 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7655 LY_CHECK_GOTO(rc, cleanup);
7656
7657 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7658 for (i = 0; i < repeat; ++i) {
7659 this_op = *exp_idx;
7660
7661 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7662 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7663 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7664 ++(*exp_idx);
7665
7666 if (!set) {
7667 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7668 LY_CHECK_GOTO(rc, cleanup);
7669 continue;
7670 }
7671
7672 set_fill_set(&set2, &orig_set);
7673 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7674 LY_CHECK_GOTO(rc, cleanup);
7675
7676 /* eval */
7677 if (options & LYXP_SCNODE_ALL) {
7678 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007679 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007680 set_scnode_clear_ctx(set);
7681 } else {
7682 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7683 LY_CHECK_GOTO(rc, cleanup);
7684 }
7685 }
7686
7687cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007688 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7689 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007690 return rc;
7691}
7692
7693/**
7694 * @brief Evaluate EqualityExpr. Logs directly on error.
7695 *
7696 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7697 * | EqualityExpr '!=' RelationalExpr
7698 *
7699 * @param[in] exp Parsed XPath expression.
7700 * @param[in] exp_idx Position in the expression @p exp.
7701 * @param[in] repeat How many times this expression is repeated.
7702 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7703 * @param[in] options XPath options.
7704 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7705 */
7706static LY_ERR
7707eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7708{
7709 LY_ERR rc;
7710 uint16_t this_op;
7711 struct lyxp_set orig_set, set2;
7712 uint16_t i;
7713
7714 assert(repeat);
7715
7716 set_init(&orig_set, set);
7717 set_init(&set2, set);
7718
7719 set_fill_set(&orig_set, set);
7720
7721 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7722 LY_CHECK_GOTO(rc, cleanup);
7723
7724 /* ('=' / '!=' RelationalExpr)* */
7725 for (i = 0; i < repeat; ++i) {
7726 this_op = *exp_idx;
7727
7728 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7729 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7730 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7731 ++(*exp_idx);
7732
7733 if (!set) {
7734 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7735 LY_CHECK_GOTO(rc, cleanup);
7736 continue;
7737 }
7738
7739 set_fill_set(&set2, &orig_set);
7740 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7741 LY_CHECK_GOTO(rc, cleanup);
7742
7743 /* eval */
7744 if (options & LYXP_SCNODE_ALL) {
7745 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7746 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7747 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007748 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007749 set_scnode_clear_ctx(set);
7750 } else {
7751 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7752 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7753 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7754 /* left operand is identityref */
7755 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7756 /* missing prefix in the right operand */
7757 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7758 if (!set2.val.str) {
7759 goto cleanup;
7760 }
7761
7762 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7763 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7764 set2.val.str[strlen(set->local_mod->name)] = ':';
7765 }
7766 }
7767
7768 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7769 LY_CHECK_GOTO(rc, cleanup);
7770 }
7771 }
7772
7773cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007774 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7775 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007776 return rc;
7777}
7778
7779/**
7780 * @brief Evaluate AndExpr. Logs directly on error.
7781 *
7782 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7783 *
7784 * @param[in] exp Parsed XPath expression.
7785 * @param[in] exp_idx Position in the expression @p exp.
7786 * @param[in] repeat How many times this expression is repeated.
7787 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7788 * @param[in] options XPath options.
7789 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7790 */
7791static LY_ERR
7792eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7793{
7794 LY_ERR rc;
7795 struct lyxp_set orig_set, set2;
7796 uint16_t i;
7797
7798 assert(repeat);
7799
7800 set_init(&orig_set, set);
7801 set_init(&set2, set);
7802
7803 set_fill_set(&orig_set, set);
7804
7805 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7806 LY_CHECK_GOTO(rc, cleanup);
7807
7808 /* cast to boolean, we know that will be the final result */
7809 if (set && (options & LYXP_SCNODE_ALL)) {
7810 set_scnode_clear_ctx(set);
7811 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007812 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007813 }
7814
7815 /* ('and' EqualityExpr)* */
7816 for (i = 0; i < repeat; ++i) {
7817 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7818 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7819 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7820 ++(*exp_idx);
7821
7822 /* lazy evaluation */
7823 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7824 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7825 LY_CHECK_GOTO(rc, cleanup);
7826 continue;
7827 }
7828
7829 set_fill_set(&set2, &orig_set);
7830 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7831 LY_CHECK_GOTO(rc, cleanup);
7832
7833 /* eval - just get boolean value actually */
7834 if (set->type == LYXP_SET_SCNODE_SET) {
7835 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007836 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007837 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007838 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007839 set_fill_set(set, &set2);
7840 }
7841 }
7842
7843cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007844 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7845 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007846 return rc;
7847}
7848
7849/**
7850 * @brief Evaluate OrExpr. Logs directly on error.
7851 *
7852 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7853 *
7854 * @param[in] exp Parsed XPath expression.
7855 * @param[in] exp_idx Position in the expression @p exp.
7856 * @param[in] repeat How many times this expression is repeated.
7857 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7858 * @param[in] options XPath options.
7859 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7860 */
7861static LY_ERR
7862eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7863{
7864 LY_ERR rc;
7865 struct lyxp_set orig_set, set2;
7866 uint16_t i;
7867
7868 assert(repeat);
7869
7870 set_init(&orig_set, set);
7871 set_init(&set2, set);
7872
7873 set_fill_set(&orig_set, set);
7874
7875 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7876 LY_CHECK_GOTO(rc, cleanup);
7877
7878 /* cast to boolean, we know that will be the final result */
7879 if (set && (options & LYXP_SCNODE_ALL)) {
7880 set_scnode_clear_ctx(set);
7881 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007882 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007883 }
7884
7885 /* ('or' AndExpr)* */
7886 for (i = 0; i < repeat; ++i) {
7887 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7888 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7889 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7890 ++(*exp_idx);
7891
7892 /* lazy evaluation */
7893 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7894 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7895 LY_CHECK_GOTO(rc, cleanup);
7896 continue;
7897 }
7898
7899 set_fill_set(&set2, &orig_set);
7900 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7901 * but it does not matter */
7902 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7903 LY_CHECK_GOTO(rc, cleanup);
7904
7905 /* eval - just get boolean value actually */
7906 if (set->type == LYXP_SET_SCNODE_SET) {
7907 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007908 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007909 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007910 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007911 set_fill_set(set, &set2);
7912 }
7913 }
7914
7915cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007916 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7917 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007918 return rc;
7919}
7920
7921/**
7922 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7923 *
7924 * @param[in] exp Parsed XPath expression.
7925 * @param[in] exp_idx Position in the expression @p exp.
7926 * @param[in] etype Expression type to evaluate.
7927 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7928 * @param[in] options XPath options.
7929 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7930 */
7931static LY_ERR
7932eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7933{
7934 uint16_t i, count;
7935 enum lyxp_expr_type next_etype;
7936 LY_ERR rc;
7937
7938 /* process operator repeats */
7939 if (!exp->repeat[*exp_idx]) {
7940 next_etype = LYXP_EXPR_NONE;
7941 } else {
7942 /* find etype repeat */
7943 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7944
7945 /* select one-priority lower because etype expression called us */
7946 if (i) {
7947 next_etype = exp->repeat[*exp_idx][i - 1];
7948 /* count repeats for that expression */
7949 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7950 } else {
7951 next_etype = LYXP_EXPR_NONE;
7952 }
7953 }
7954
7955 /* decide what expression are we parsing based on the repeat */
7956 switch (next_etype) {
7957 case LYXP_EXPR_OR:
7958 rc = eval_or_expr(exp, exp_idx, count, set, options);
7959 break;
7960 case LYXP_EXPR_AND:
7961 rc = eval_and_expr(exp, exp_idx, count, set, options);
7962 break;
7963 case LYXP_EXPR_EQUALITY:
7964 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7965 break;
7966 case LYXP_EXPR_RELATIONAL:
7967 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7968 break;
7969 case LYXP_EXPR_ADDITIVE:
7970 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7971 break;
7972 case LYXP_EXPR_MULTIPLICATIVE:
7973 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7974 break;
7975 case LYXP_EXPR_UNARY:
7976 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7977 break;
7978 case LYXP_EXPR_UNION:
7979 rc = eval_union_expr(exp, exp_idx, count, set, options);
7980 break;
7981 case LYXP_EXPR_NONE:
7982 rc = eval_path_expr(exp, exp_idx, set, options);
7983 break;
7984 default:
7985 LOGINT_RET(set->ctx);
7986 }
7987
7988 return rc;
7989}
7990
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007991/**
7992 * @brief Get root type.
7993 *
7994 * @param[in] ctx_node Context node.
7995 * @param[in] ctx_scnode Schema context node.
7996 * @param[in] options XPath options.
7997 * @return Root type.
7998 */
7999static enum lyxp_node_type
8000lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8001{
8002 if (options & LYXP_SCNODE_ALL) {
8003 if (options & LYXP_SCNODE) {
8004 /* general root that can access everything */
8005 return LYXP_NODE_ROOT;
8006 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8007 /* root context node can access only config data (because we said so, it is unspecified) */
8008 return LYXP_NODE_ROOT_CONFIG;
8009 } else {
8010 return LYXP_NODE_ROOT;
8011 }
8012 }
8013
8014 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8015 /* root context node can access only config data (because we said so, it is unspecified) */
8016 return LYXP_NODE_ROOT_CONFIG;
8017 }
8018
8019 return LYXP_NODE_ROOT;
8020}
8021
Michal Vasko03ff5a72019-09-11 13:49:33 +02008022LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008023lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
Michal Vasko03ff5a72019-09-11 13:49:33 +02008024 enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
8025{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008026 uint16_t exp_idx = 0;
8027 LY_ERR rc;
8028
Michal Vaskoecd62de2019-11-13 12:35:11 +01008029 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008030
8031 /* prepare set for evaluation */
8032 exp_idx = 0;
8033 memset(set, 0, sizeof *set);
8034 set->type = LYXP_SET_EMPTY;
8035 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, options);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008036 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008037 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008038 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008039 set->local_mod = local_mod;
8040 set->trees = trees;
8041 set->format = format;
8042
8043 /* evaluate */
8044 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8045 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008046 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008047 }
8048
Michal Vasko03ff5a72019-09-11 13:49:33 +02008049 return rc;
8050}
8051
8052#if 0
8053
8054/* full xml printing of set elements, not used currently */
8055
8056void
8057lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8058{
8059 uint32_t i;
8060 char *str_num;
8061 struct lyout out;
8062
8063 memset(&out, 0, sizeof out);
8064
8065 out.type = LYOUT_STREAM;
8066 out.method.f = f;
8067
8068 switch (set->type) {
8069 case LYXP_SET_EMPTY:
8070 ly_print(&out, "Empty XPath set\n\n");
8071 break;
8072 case LYXP_SET_BOOLEAN:
8073 ly_print(&out, "Boolean XPath set:\n");
8074 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8075 break;
8076 case LYXP_SET_STRING:
8077 ly_print(&out, "String XPath set:\n");
8078 ly_print(&out, "\"%s\"\n\n", set->value.str);
8079 break;
8080 case LYXP_SET_NUMBER:
8081 ly_print(&out, "Number XPath set:\n");
8082
8083 if (isnan(set->value.num)) {
8084 str_num = strdup("NaN");
8085 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8086 str_num = strdup("0");
8087 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8088 str_num = strdup("Infinity");
8089 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8090 str_num = strdup("-Infinity");
8091 } else if ((long long)set->value.num == set->value.num) {
8092 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8093 str_num = NULL;
8094 }
8095 } else {
8096 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8097 str_num = NULL;
8098 }
8099 }
8100 if (!str_num) {
8101 LOGMEM;
8102 return;
8103 }
8104 ly_print(&out, "%s\n\n", str_num);
8105 free(str_num);
8106 break;
8107 case LYXP_SET_NODE_SET:
8108 ly_print(&out, "Node XPath set:\n");
8109
8110 for (i = 0; i < set->used; ++i) {
8111 ly_print(&out, "%d. ", i + 1);
8112 switch (set->node_type[i]) {
8113 case LYXP_NODE_ROOT_ALL:
8114 ly_print(&out, "ROOT all\n\n");
8115 break;
8116 case LYXP_NODE_ROOT_CONFIG:
8117 ly_print(&out, "ROOT config\n\n");
8118 break;
8119 case LYXP_NODE_ROOT_STATE:
8120 ly_print(&out, "ROOT state\n\n");
8121 break;
8122 case LYXP_NODE_ROOT_NOTIF:
8123 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8124 break;
8125 case LYXP_NODE_ROOT_RPC:
8126 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8127 break;
8128 case LYXP_NODE_ROOT_OUTPUT:
8129 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8130 break;
8131 case LYXP_NODE_ELEM:
8132 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8133 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8134 ly_print(&out, "\n");
8135 break;
8136 case LYXP_NODE_TEXT:
8137 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8138 break;
8139 case LYXP_NODE_ATTR:
8140 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8141 break;
8142 }
8143 }
8144 break;
8145 }
8146}
8147
8148#endif
8149
8150LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008151lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008152{
8153 long double num;
8154 char *str;
8155 LY_ERR rc;
8156
8157 if (!set || (set->type == target)) {
8158 return LY_SUCCESS;
8159 }
8160
8161 /* it's not possible to convert anything into a node set */
8162 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8163
8164 if (set->type == LYXP_SET_SCNODE_SET) {
8165 set_free_content(set);
8166 return LY_EINVAL;
8167 }
8168
8169 /* to STRING */
8170 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8171 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8172 switch (set->type) {
8173 case LYXP_SET_NUMBER:
8174 if (isnan(set->val.num)) {
8175 set->val.str = strdup("NaN");
8176 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8177 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8178 set->val.str = strdup("0");
8179 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8180 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8181 set->val.str = strdup("Infinity");
8182 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8183 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8184 set->val.str = strdup("-Infinity");
8185 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8186 } else if ((long long)set->val.num == set->val.num) {
8187 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8188 LOGMEM_RET(set->ctx);
8189 }
8190 set->val.str = str;
8191 } else {
8192 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8193 LOGMEM_RET(set->ctx);
8194 }
8195 set->val.str = str;
8196 }
8197 break;
8198 case LYXP_SET_BOOLEAN:
8199 if (set->val.bool) {
8200 set->val.str = strdup("true");
8201 } else {
8202 set->val.str = strdup("false");
8203 }
8204 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8205 break;
8206 case LYXP_SET_NODE_SET:
8207 assert(set->used);
8208
8209 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008210 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008211
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008212 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008213 LY_CHECK_RET(rc);
8214 set_free_content(set);
8215 set->val.str = str;
8216 break;
8217 case LYXP_SET_EMPTY:
8218 set->val.str = strdup("");
8219 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8220 break;
8221 default:
8222 LOGINT_RET(set->ctx);
8223 }
8224 set->type = LYXP_SET_STRING;
8225 }
8226
8227 /* to NUMBER */
8228 if (target == LYXP_SET_NUMBER) {
8229 switch (set->type) {
8230 case LYXP_SET_STRING:
8231 num = cast_string_to_number(set->val.str);
8232 set_free_content(set);
8233 set->val.num = num;
8234 break;
8235 case LYXP_SET_BOOLEAN:
8236 if (set->val.bool) {
8237 set->val.num = 1;
8238 } else {
8239 set->val.num = 0;
8240 }
8241 break;
8242 default:
8243 LOGINT_RET(set->ctx);
8244 }
8245 set->type = LYXP_SET_NUMBER;
8246 }
8247
8248 /* to BOOLEAN */
8249 if (target == LYXP_SET_BOOLEAN) {
8250 switch (set->type) {
8251 case LYXP_SET_NUMBER:
8252 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8253 set->val.bool = 0;
8254 } else {
8255 set->val.bool = 1;
8256 }
8257 break;
8258 case LYXP_SET_STRING:
8259 if (set->val.str[0]) {
8260 set_free_content(set);
8261 set->val.bool = 1;
8262 } else {
8263 set_free_content(set);
8264 set->val.bool = 0;
8265 }
8266 break;
8267 case LYXP_SET_NODE_SET:
8268 set_free_content(set);
8269
8270 assert(set->used);
8271 set->val.bool = 1;
8272 break;
8273 case LYXP_SET_EMPTY:
8274 set->val.bool = 0;
8275 break;
8276 default:
8277 LOGINT_RET(set->ctx);
8278 }
8279 set->type = LYXP_SET_BOOLEAN;
8280 }
8281
8282 /* to EMPTY */
8283 if (target == LYXP_SET_EMPTY) {
8284 set_free_content(set);
8285 set->type = LYXP_SET_EMPTY;
8286 }
8287
8288 return LY_SUCCESS;
8289}
8290
8291LY_ERR
8292lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8293 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8294{
8295 struct ly_ctx *ctx;
8296 uint16_t exp_idx = 0;
8297
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008298 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008299
8300 ctx = local_mod->ctx;
8301
8302 /* prepare set for evaluation */
8303 exp_idx = 0;
8304 memset(set, 0, sizeof *set);
8305 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008306 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008307 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008308 set->ctx = ctx;
8309 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008310 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008311 set->local_mod = local_mod;
8312 set->format = format;
8313
8314 /* evaluate */
8315 return eval_expr_select(exp, &exp_idx, 0, set, options);
8316}