blob: c5e3259bff5d39c811ecacf0c67c3cba312c7558 [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);
Michal Vasko9b368d32020-02-14 13:53:31 +0100920 if (src->ht) {
921 trg->ht = lyht_dup(src->ht);
922 } else {
923 trg->ht = NULL;
924 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200925 }
926 }
927}
928
929/**
930 * @brief Clear context of all schema nodes.
931 *
932 * @param[in] set Set to clear.
933 */
934static void
935set_scnode_clear_ctx(struct lyxp_set *set)
936{
937 uint32_t i;
938
939 for (i = 0; i < set->used; ++i) {
940 if (set->val.scnodes[i].in_ctx == 1) {
941 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100942 } else if (set->val.scnodes[i].in_ctx == -2) {
943 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200944 }
945 }
946}
947
948/**
949 * @brief Remove a node from a set. Removing last node changes
950 * set into LYXP_SET_EMPTY. Context position aware.
951 *
952 * @param[in] set Set to use.
953 * @param[in] idx Index from @p set of the node to be removed.
954 */
955static void
956set_remove_node(struct lyxp_set *set, uint32_t idx)
957{
958 assert(set && (set->type == LYXP_SET_NODE_SET));
959 assert(idx < set->used);
960
961 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
962
963 --set->used;
964 if (set->used) {
965 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
966 (set->used - idx) * sizeof *set->val.nodes);
967 } else {
968 set_free_content(set);
969 set->type = LYXP_SET_EMPTY;
970 }
971}
972
973/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100974 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200975 *
976 * @param[in] set Set to use.
977 * @param[in] idx Index from @p set of the node to be removed.
978 */
979static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100980set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200981{
982 assert(set && (set->type == LYXP_SET_NODE_SET));
983 assert(idx < set->used);
984
Michal Vasko2caefc12019-11-14 16:07:56 +0100985 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
986 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
987 }
988 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200989}
990
991/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100992 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200993 * set into LYXP_SET_EMPTY. Context position aware.
994 *
995 * @param[in] set Set to consolidate.
996 */
997static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100998set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200999{
1000 uint16_t i, orig_used, end;
1001 int32_t start;
1002
Michal Vasko2caefc12019-11-14 16:07:56 +01001003 assert(set && (set->type != LYXP_SET_EMPTY));
Michal Vasko57eab132019-09-24 11:46:26 +02001004
1005 orig_used = set->used;
1006 set->used = 0;
1007 for (i = 0; i < orig_used;) {
1008 start = -1;
1009 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001010 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001011 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001012 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001013 end = i;
1014 ++i;
1015 break;
1016 }
1017
1018 ++i;
1019 if (i == orig_used) {
1020 end = i;
1021 }
1022 } while (i < orig_used);
1023
1024 if (start > -1) {
1025 /* move the whole chunk of valid nodes together */
1026 if (set->used != (unsigned)start) {
1027 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1028 }
1029 set->used += end - start;
1030 }
1031 }
1032
1033 if (!set->used) {
1034 set_free_content(set);
1035 /* this changes it to LYXP_SET_EMPTY */
1036 memset(set, 0, sizeof *set);
1037 }
1038}
1039
1040/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001041 * @brief Check for duplicates in a node set.
1042 *
1043 * @param[in] set Set to check.
1044 * @param[in] node Node to look for in @p set.
1045 * @param[in] node_type Type of @p node.
1046 * @param[in] skip_idx Index from @p set to skip.
1047 * @return LY_ERR
1048 */
1049static LY_ERR
1050set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1051{
1052 uint32_t i;
1053
Michal Vasko2caefc12019-11-14 16:07:56 +01001054 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001055 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1056 }
1057
1058 for (i = 0; i < set->used; ++i) {
1059 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1060 continue;
1061 }
1062
1063 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1064 return LY_EEXIST;
1065 }
1066 }
1067
1068 return LY_SUCCESS;
1069}
1070
Michal Vaskoecd62de2019-11-13 12:35:11 +01001071int
1072lyxp_set_scnode_dup_node_check(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type, int skip_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001073{
1074 uint32_t i;
1075
1076 for (i = 0; i < set->used; ++i) {
1077 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1078 continue;
1079 }
1080
1081 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1082 return i;
1083 }
1084 }
1085
1086 return -1;
1087}
1088
Michal Vaskoecd62de2019-11-13 12:35:11 +01001089void
1090lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001091{
1092 uint32_t orig_used, i, j;
1093
1094 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1095 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1096
1097 if (set2->type == LYXP_SET_EMPTY) {
1098 return;
1099 }
1100
1101 if (set1->type == LYXP_SET_EMPTY) {
1102 memcpy(set1, set2, sizeof *set1);
1103 return;
1104 }
1105
1106 if (set1->used + set2->used > set1->size) {
1107 set1->size = set1->used + set2->used;
1108 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1109 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1110 }
1111
1112 orig_used = set1->used;
1113
1114 for (i = 0; i < set2->used; ++i) {
1115 for (j = 0; j < orig_used; ++j) {
1116 /* detect duplicities */
1117 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1118 break;
1119 }
1120 }
1121
1122 if (j == orig_used) {
1123 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1124 ++set1->used;
1125 }
1126 }
1127
1128 set_free_content(set2);
1129 set2->type = LYXP_SET_EMPTY;
1130}
1131
1132/**
1133 * @brief Insert a node into a set. Context position aware.
1134 *
1135 * @param[in] set Set to use.
1136 * @param[in] node Node to insert to @p set.
1137 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1138 * @param[in] node_type Node type of @p node.
1139 * @param[in] idx Index in @p set to insert into.
1140 */
1141static void
1142set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1143{
1144 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1145
1146 if (set->type == LYXP_SET_EMPTY) {
1147 /* first item */
1148 if (idx) {
1149 /* no real harm done, but it is a bug */
1150 LOGINT(set->ctx);
1151 idx = 0;
1152 }
1153 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1154 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1155 set->type = LYXP_SET_NODE_SET;
1156 set->used = 0;
1157 set->size = LYXP_SET_SIZE_START;
1158 set->ctx_pos = 1;
1159 set->ctx_size = 1;
1160 set->ht = NULL;
1161 } else {
1162 /* not an empty set */
1163 if (set->used == set->size) {
1164
1165 /* set is full */
1166 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1167 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1168 set->size += LYXP_SET_SIZE_STEP;
1169 }
1170
1171 if (idx > set->used) {
1172 LOGINT(set->ctx);
1173 idx = set->used;
1174 }
1175
1176 /* make space for the new node */
1177 if (idx < set->used) {
1178 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1179 }
1180 }
1181
1182 /* finally assign the value */
1183 set->val.nodes[idx].node = (struct lyd_node *)node;
1184 set->val.nodes[idx].type = node_type;
1185 set->val.nodes[idx].pos = pos;
1186 ++set->used;
1187
Michal Vasko2caefc12019-11-14 16:07:56 +01001188 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1189 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1190 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001191}
1192
Michal Vaskoecd62de2019-11-13 12:35:11 +01001193int
1194lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001195{
1196 int ret;
1197
1198 assert(set->type == LYXP_SET_SCNODE_SET);
1199
Michal Vaskoecd62de2019-11-13 12:35:11 +01001200 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001201 if (ret > -1) {
1202 set->val.scnodes[ret].in_ctx = 1;
1203 } else {
1204 if (set->used == set->size) {
1205 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1206 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1207 set->size += LYXP_SET_SIZE_STEP;
1208 }
1209
1210 ret = set->used;
1211 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1212 set->val.scnodes[ret].type = node_type;
1213 set->val.scnodes[ret].in_ctx = 1;
1214 ++set->used;
1215 }
1216
1217 return ret;
1218}
1219
1220/**
1221 * @brief Replace a node in a set with another. Context position aware.
1222 *
1223 * @param[in] set Set to use.
1224 * @param[in] node Node to insert to @p set.
1225 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1226 * @param[in] node_type Node type of @p node.
1227 * @param[in] idx Index in @p set of the node to replace.
1228 */
1229static void
1230set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1231{
1232 assert(set && (idx < set->used));
1233
Michal Vasko2caefc12019-11-14 16:07:56 +01001234 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1235 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1236 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001237 set->val.nodes[idx].node = (struct lyd_node *)node;
1238 set->val.nodes[idx].type = node_type;
1239 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001240 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1241 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1242 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001243}
1244
1245/**
1246 * @brief Set all nodes with ctx 1 to a new unique context value.
1247 *
1248 * @param[in] set Set to modify.
1249 * @return New context value.
1250 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001251static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001252set_scnode_new_in_ctx(struct lyxp_set *set)
1253{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001254 uint32_t i;
1255 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001256
1257 assert(set->type == LYXP_SET_SCNODE_SET);
1258
1259 ret_ctx = 3;
1260retry:
1261 for (i = 0; i < set->used; ++i) {
1262 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1263 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1264 goto retry;
1265 }
1266 }
1267 for (i = 0; i < set->used; ++i) {
1268 if (set->val.scnodes[i].in_ctx == 1) {
1269 set->val.scnodes[i].in_ctx = ret_ctx;
1270 }
1271 }
1272
1273 return ret_ctx;
1274}
1275
1276/**
1277 * @brief Get unique @p node position in the data.
1278 *
1279 * @param[in] node Node to find.
1280 * @param[in] node_type Node type of @p node.
1281 * @param[in] root Root node.
1282 * @param[in] root_type Type of the XPath @p root node.
1283 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1284 * be used to increase efficiency and start the DFS from this node.
1285 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1286 * @return Node position.
1287 */
1288static uint32_t
1289get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1290 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1291{
1292 const struct lyd_node *next, *elem, *top_sibling;
1293 uint32_t pos = 1;
1294
1295 assert(prev && prev_pos && !root->prev->next);
1296
1297 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1298 return 0;
1299 }
1300
1301 if (*prev) {
1302 /* start from the previous element instead from the root */
1303 elem = next = *prev;
1304 pos = *prev_pos;
1305 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1306 goto dfs_search;
1307 }
1308
1309 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1310 /* TREE DFS */
1311 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1312dfs_search:
1313 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1314 goto skip_children;
1315 }
1316
1317 if (elem == node) {
1318 break;
1319 }
1320 ++pos;
1321
1322 /* TREE DFS END */
1323 /* select element for the next run - children first,
1324 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1325 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1326 next = NULL;
1327 } else {
1328 next = lyd_node_children(elem);
1329 }
1330 if (!next) {
1331skip_children:
1332 /* no children */
1333 if (elem == top_sibling) {
1334 /* we are done, root has no children */
1335 elem = NULL;
1336 break;
1337 }
1338 /* try siblings */
1339 next = elem->next;
1340 }
1341 while (!next) {
1342 /* no siblings, go back through parents */
1343 if (elem->parent == top_sibling->parent) {
1344 /* we are done, no next element to process */
1345 elem = NULL;
1346 break;
1347 }
1348 /* parent is already processed, go to its sibling */
1349 elem = (struct lyd_node *)elem->parent;
1350 next = elem->next;
1351 }
1352 }
1353
1354 /* node found */
1355 if (elem) {
1356 break;
1357 }
1358 }
1359
1360 if (!elem) {
1361 if (!(*prev)) {
1362 /* we went from root and failed to find it, cannot be */
1363 LOGINT(node->schema->module->ctx);
1364 return 0;
1365 } else {
1366 *prev = NULL;
1367 *prev_pos = 0;
1368
1369 elem = next = top_sibling = root;
1370 pos = 1;
1371 goto dfs_search;
1372 }
1373 }
1374
1375 /* remember the last found node for next time */
1376 *prev = node;
1377 *prev_pos = pos;
1378
1379 return pos;
1380}
1381
1382/**
1383 * @brief Assign (fill) missing node positions.
1384 *
1385 * @param[in] set Set to fill positions in.
1386 * @param[in] root Context root node.
1387 * @param[in] root_type Context root type.
1388 * @return LY_ERR
1389 */
1390static LY_ERR
1391set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1392{
1393 const struct lyd_node *prev = NULL, *tmp_node;
1394 uint32_t i, tmp_pos = 0;
1395
1396 for (i = 0; i < set->used; ++i) {
1397 if (!set->val.nodes[i].pos) {
1398 tmp_node = NULL;
1399 switch (set->val.nodes[i].type) {
1400 case LYXP_NODE_ATTR:
1401 tmp_node = set->val.attrs[i].attr->parent;
1402 if (!tmp_node) {
1403 LOGINT_RET(root->schema->module->ctx);
1404 }
1405 /* fallthrough */
1406 case LYXP_NODE_ELEM:
1407 case LYXP_NODE_TEXT:
1408 if (!tmp_node) {
1409 tmp_node = set->val.nodes[i].node;
1410 }
1411 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1412 break;
1413 default:
1414 /* all roots have position 0 */
1415 break;
1416 }
1417 }
1418 }
1419
1420 return LY_SUCCESS;
1421}
1422
1423/**
1424 * @brief Get unique @p attr position in the parent attributes.
1425 *
1426 * @param[in] attr Attr to use.
1427 * @return Attribute position.
1428 */
1429static uint16_t
1430get_attr_pos(struct lyd_attr *attr)
1431{
1432 uint16_t pos = 0;
1433 struct lyd_attr *attr2;
1434
1435 for (attr2 = attr->parent->attr; attr2 && (attr2 != attr); attr2 = attr2->next) {
1436 ++pos;
1437 }
1438
1439 assert(attr2);
1440 return pos;
1441}
1442
1443/**
1444 * @brief Compare 2 nodes in respect to XPath document order.
1445 *
1446 * @param[in] item1 1st node.
1447 * @param[in] item2 2nd node.
1448 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1449 */
1450static int
1451set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1452{
1453 uint32_t attr_pos1 = 0, attr_pos2 = 0;
1454
1455 if (item1->pos < item2->pos) {
1456 return -1;
1457 }
1458
1459 if (item1->pos > item2->pos) {
1460 return 1;
1461 }
1462
1463 /* node positions are equal, the fun case */
1464
1465 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1466 /* special case since text nodes are actually saved as their parents */
1467 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1468 if (item1->type == LYXP_NODE_ELEM) {
1469 assert(item2->type == LYXP_NODE_TEXT);
1470 return -1;
1471 } else {
1472 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1473 return 1;
1474 }
1475 }
1476
1477 /* we need attr positions now */
1478 if (item1->type == LYXP_NODE_ATTR) {
1479 attr_pos1 = get_attr_pos((struct lyd_attr *)item1->node);
1480 }
1481 if (item2->type == LYXP_NODE_ATTR) {
1482 attr_pos2 = get_attr_pos((struct lyd_attr *)item2->node);
1483 }
1484
1485 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st ATTR - =pos= - 2nd ATTR */
1486 /* check for duplicates */
1487 if (item1->node == item2->node) {
1488 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_ATTR) || (attr_pos1 == attr_pos2)));
1489 return 0;
1490 }
1491
1492 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd ATTR */
1493 /* elem is always first, 2nd node is after it */
1494 if (item1->type == LYXP_NODE_ELEM) {
1495 assert(item2->type != LYXP_NODE_ELEM);
1496 return -1;
1497 }
1498
1499 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd ATTR, 1st ATTR - any pos - 2nd ELEM, 1st ATTR - >pos> - 2nd ATTR */
1500 /* 2nd is before 1st */
1501 if (((item1->type == LYXP_NODE_TEXT)
1502 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_ATTR)))
1503 || ((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ELEM))
1504 || (((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ATTR))
1505 && (attr_pos1 > attr_pos2))) {
1506 return 1;
1507 }
1508
1509 /* 1st ATTR - any pos - 2nd TEXT, 1st ATTR <pos< - 2nd ATTR */
1510 /* 2nd is after 1st */
1511 return -1;
1512}
1513
1514/**
1515 * @brief Set cast for comparisons.
1516 *
1517 * @param[in] trg Target set to cast source into.
1518 * @param[in] src Source set.
1519 * @param[in] type Target set type.
1520 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001521 * @return LY_ERR
1522 */
1523static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001524set_comp_cast(struct lyxp_set *trg, struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001525{
1526 assert(src->type == LYXP_SET_NODE_SET);
1527
1528 set_init(trg, src);
1529
1530 /* insert node into target set */
1531 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1532
1533 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001534 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001535}
1536
1537#ifndef NDEBUG
1538
1539/**
1540 * @brief Bubble sort @p set into XPath document order.
1541 * Context position aware. Unused in the 'Release' build target.
1542 *
1543 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001544 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1545 */
1546static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001547set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001548{
1549 uint32_t i, j;
1550 int ret = 0, cmp, inverted, change;
1551 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001552 struct lyxp_set_node item;
1553 struct lyxp_set_hash_node hnode;
1554 uint64_t hash;
1555
1556 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1557 return 0;
1558 }
1559
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001560 /* find first top-level node to be used as anchor for positions */
1561 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1562 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001563
1564 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001565 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001566 return -1;
1567 }
1568
1569 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1570 print_set_debug(set);
1571
1572 for (i = 0; i < set->used; ++i) {
1573 inverted = 0;
1574 change = 0;
1575
1576 for (j = 1; j < set->used - i; ++j) {
1577 /* compare node positions */
1578 if (inverted) {
1579 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1580 } else {
1581 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1582 }
1583
1584 /* swap if needed */
1585 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1586 change = 1;
1587
1588 item = set->val.nodes[j - 1];
1589 set->val.nodes[j - 1] = set->val.nodes[j];
1590 set->val.nodes[j] = item;
1591 } else {
1592 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1593 inverted = !inverted;
1594 }
1595 }
1596
1597 ++ret;
1598
1599 if (!change) {
1600 break;
1601 }
1602 }
1603
1604 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1605 print_set_debug(set);
1606
1607 /* check node hashes */
1608 if (set->used >= LYD_HT_MIN_ITEMS) {
1609 assert(set->ht);
1610 for (i = 0; i < set->used; ++i) {
1611 hnode.node = set->val.nodes[i].node;
1612 hnode.type = set->val.nodes[i].type;
1613
1614 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1615 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1616 hash = dict_hash_multi(hash, NULL, 0);
1617
1618 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1619 }
1620 }
1621
1622 return ret - 1;
1623}
1624
1625/**
1626 * @brief Remove duplicate entries in a sorted node set.
1627 *
1628 * @param[in] set Sorted set to check.
1629 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1630 */
1631static LY_ERR
1632set_sorted_dup_node_clean(struct lyxp_set *set)
1633{
1634 uint32_t i = 0;
1635 LY_ERR ret = LY_SUCCESS;
1636
1637 if (set->used > 1) {
1638 while (i < set->used - 1) {
1639 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1640 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001641 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001642 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001643 }
Michal Vasko57eab132019-09-24 11:46:26 +02001644 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001645 }
1646 }
1647
Michal Vasko2caefc12019-11-14 16:07:56 +01001648 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001649 return ret;
1650}
1651
1652#endif
1653
1654/**
1655 * @brief Merge 2 sorted sets into one.
1656 *
1657 * @param[in,out] trg Set to merge into. Duplicates are removed.
1658 * @param[in] src Set to be merged into @p trg. It is cast to #LYXP_SET_EMPTY on success.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001659 * @return LY_ERR
1660 */
1661static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001662set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001663{
1664 uint32_t i, j, k, count, dup_count;
1665 int cmp;
1666 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001667
1668 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1669 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1670 return LY_EINVAL;
1671 }
1672
1673 if (src->type == LYXP_SET_EMPTY) {
1674 return LY_SUCCESS;
1675 } else if (trg->type == LYXP_SET_EMPTY) {
1676 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001677 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001678 return LY_SUCCESS;
1679 }
1680
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001681 /* find first top-level node to be used as anchor for positions */
1682 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1683 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001684
1685 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001686 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001687 return LY_EINT;
1688 }
1689
1690#ifndef NDEBUG
1691 LOGDBG(LY_LDGXPATH, "MERGE target");
1692 print_set_debug(trg);
1693 LOGDBG(LY_LDGXPATH, "MERGE source");
1694 print_set_debug(src);
1695#endif
1696
1697 /* make memory for the merge (duplicates are not detected yet, so space
1698 * will likely be wasted on them, too bad) */
1699 if (trg->size - trg->used < src->used) {
1700 trg->size = trg->used + src->used;
1701
1702 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1703 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1704 }
1705
1706 i = 0;
1707 j = 0;
1708 count = 0;
1709 dup_count = 0;
1710 do {
1711 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1712 if (!cmp) {
1713 if (!count) {
1714 /* duplicate, just skip it */
1715 ++i;
1716 ++j;
1717 } else {
1718 /* we are copying something already, so let's copy the duplicate too,
1719 * we are hoping that afterwards there are some more nodes to
1720 * copy and this way we can copy them all together */
1721 ++count;
1722 ++dup_count;
1723 ++i;
1724 ++j;
1725 }
1726 } else if (cmp < 0) {
1727 /* inserting src node into trg, just remember it for now */
1728 ++count;
1729 ++i;
1730
1731 /* insert the hash now */
1732 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1733 } else if (count) {
1734copy_nodes:
1735 /* time to actually copy the nodes, we have found the largest block of nodes */
1736 memmove(&trg->val.nodes[j + (count - dup_count)],
1737 &trg->val.nodes[j],
1738 (trg->used - j) * sizeof *trg->val.nodes);
1739 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1740
1741 trg->used += count - dup_count;
1742 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1743 j += count - dup_count;
1744
1745 count = 0;
1746 dup_count = 0;
1747 } else {
1748 ++j;
1749 }
1750 } while ((i < src->used) && (j < trg->used));
1751
1752 if ((i < src->used) || count) {
1753 /* insert all the hashes first */
1754 for (k = i; k < src->used; ++k) {
1755 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1756 }
1757
1758 /* loop ended, but we need to copy something at trg end */
1759 count += src->used - i;
1760 i = src->used;
1761 goto copy_nodes;
1762 }
1763
1764 /* we are inserting hashes before the actual node insert, which causes
1765 * situations when there were initially not enough items for a hash table,
1766 * but even after some were inserted, hash table was not created (during
1767 * insertion the number of items is not updated yet) */
1768 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1769 set_insert_node_hash(trg, NULL, 0);
1770 }
1771
1772#ifndef NDEBUG
1773 LOGDBG(LY_LDGXPATH, "MERGE result");
1774 print_set_debug(trg);
1775#endif
1776
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001777 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001778 return LY_SUCCESS;
1779}
1780
1781/*
1782 * (re)parse functions
1783 *
1784 * Parse functions parse the expression into
1785 * tokens (syntactic analysis).
1786 *
1787 * Reparse functions perform semantic analysis
1788 * (do not save the result, just a check) of
1789 * the expression and fill repeat indices.
1790 */
1791
1792/**
1793 * @brief Look at the next token and check its kind.
1794 *
1795 * @param[in] ctx Context for logging.
1796 * @param[in] exp Expression to use.
1797 * @param[in] exp_idx Position in the expression \p exp.
1798 * @param[in] want_tok Expected token.
1799 * @param[in] strict Whether the token is strictly required (print error if
1800 * not the next one) or we simply want to check whether it is the next or not.
1801 * @return LY_ERR
1802 */
1803static LY_ERR
1804exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1805{
1806 if (exp->used == exp_idx) {
1807 if (strict) {
1808 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1809 }
1810 return LY_EINVAL;
1811 }
1812
1813 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1814 if (strict) {
1815 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1816 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1817 }
1818 return LY_EINVAL;
1819 }
1820
1821 return LY_SUCCESS;
1822}
1823
1824/**
1825 * @brief Stack operation push on the repeat array.
1826 *
1827 * @param[in] exp Expression to use.
1828 * @param[in] exp_idx Position in the expresion \p exp.
1829 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1830 */
1831static void
1832exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1833{
1834 uint16_t i;
1835
1836 if (exp->repeat[exp_idx]) {
1837 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1838 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1839 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1840 exp->repeat[exp_idx][i] = repeat_op_idx;
1841 exp->repeat[exp_idx][i + 1] = 0;
1842 } else {
1843 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1844 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1845 exp->repeat[exp_idx][0] = repeat_op_idx;
1846 }
1847}
1848
1849/**
1850 * @brief Reparse Predicate. Logs directly on error.
1851 *
1852 * [7] Predicate ::= '[' Expr ']'
1853 *
1854 * @param[in] ctx Context for logging.
1855 * @param[in] exp Parsed XPath expression.
1856 * @param[in] exp_idx Position in the expression @p exp.
1857 * @return LY_ERR
1858 */
1859static LY_ERR
1860reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1861{
1862 LY_ERR rc;
1863
1864 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1865 LY_CHECK_RET(rc);
1866 ++(*exp_idx);
1867
1868 rc = reparse_or_expr(ctx, exp, exp_idx);
1869 LY_CHECK_RET(rc);
1870
1871 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1872 LY_CHECK_RET(rc);
1873 ++(*exp_idx);
1874
1875 return LY_SUCCESS;
1876}
1877
1878/**
1879 * @brief Reparse RelativeLocationPath. Logs directly on error.
1880 *
1881 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1882 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1883 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1884 *
1885 * @param[in] ctx Context for logging.
1886 * @param[in] exp Parsed XPath expression.
1887 * @param[in] exp_idx Position in the expression \p exp.
1888 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1889 */
1890static LY_ERR
1891reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1892{
1893 LY_ERR rc;
1894
1895 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1896 LY_CHECK_RET(rc);
1897
1898 goto step;
1899 do {
1900 /* '/' or '//' */
1901 ++(*exp_idx);
1902
1903 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1904 LY_CHECK_RET(rc);
1905step:
1906 /* Step */
1907 switch (exp->tokens[*exp_idx]) {
1908 case LYXP_TOKEN_DOT:
1909 ++(*exp_idx);
1910 break;
1911
1912 case LYXP_TOKEN_DDOT:
1913 ++(*exp_idx);
1914 break;
1915
1916 case LYXP_TOKEN_AT:
1917 ++(*exp_idx);
1918
1919 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1920 LY_CHECK_RET(rc);
1921 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1922 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1923 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1924 return LY_EVALID;
1925 }
1926 /* fall through */
1927 case LYXP_TOKEN_NAMETEST:
1928 ++(*exp_idx);
1929 goto reparse_predicate;
1930 break;
1931
1932 case LYXP_TOKEN_NODETYPE:
1933 ++(*exp_idx);
1934
1935 /* '(' */
1936 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1937 LY_CHECK_RET(rc);
1938 ++(*exp_idx);
1939
1940 /* ')' */
1941 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1942 LY_CHECK_RET(rc);
1943 ++(*exp_idx);
1944
1945reparse_predicate:
1946 /* Predicate* */
1947 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1948 rc = reparse_predicate(ctx, exp, exp_idx);
1949 LY_CHECK_RET(rc);
1950 }
1951 break;
1952 default:
1953 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1954 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1955 return LY_EVALID;
1956 }
1957 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1958
1959 return LY_SUCCESS;
1960}
1961
1962/**
1963 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1964 *
1965 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1966 *
1967 * @param[in] ctx Context for logging.
1968 * @param[in] exp Parsed XPath expression.
1969 * @param[in] exp_idx Position in the expression \p exp.
1970 * @return LY_ERR
1971 */
1972static LY_ERR
1973reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1974{
1975 LY_ERR rc;
1976
1977 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1978 LY_CHECK_RET(rc);
1979
1980 /* '/' RelativeLocationPath? */
1981 if (exp->tok_len[*exp_idx] == 1) {
1982 /* '/' */
1983 ++(*exp_idx);
1984
1985 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1986 return LY_SUCCESS;
1987 }
1988 switch (exp->tokens[*exp_idx]) {
1989 case LYXP_TOKEN_DOT:
1990 case LYXP_TOKEN_DDOT:
1991 case LYXP_TOKEN_AT:
1992 case LYXP_TOKEN_NAMETEST:
1993 case LYXP_TOKEN_NODETYPE:
1994 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1995 LY_CHECK_RET(rc);
1996 /* fall through */
1997 default:
1998 break;
1999 }
2000
2001 /* '//' RelativeLocationPath */
2002 } else {
2003 /* '//' */
2004 ++(*exp_idx);
2005
2006 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2007 LY_CHECK_RET(rc);
2008 }
2009
2010 return LY_SUCCESS;
2011}
2012
2013/**
2014 * @brief Reparse FunctionCall. Logs directly on error.
2015 *
2016 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2017 *
2018 * @param[in] ctx Context for logging.
2019 * @param[in] exp Parsed XPath expression.
2020 * @param[in] exp_idx Position in the expression @p exp.
2021 * @return LY_ERR
2022 */
2023static LY_ERR
2024reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2025{
2026 int min_arg_count = -1, max_arg_count, arg_count;
2027 uint16_t func_exp_idx;
2028 LY_ERR rc;
2029
2030 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2031 LY_CHECK_RET(rc);
2032 func_exp_idx = *exp_idx;
2033 switch (exp->tok_len[*exp_idx]) {
2034 case 3:
2035 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2036 min_arg_count = 1;
2037 max_arg_count = 1;
2038 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2039 min_arg_count = 1;
2040 max_arg_count = 1;
2041 }
2042 break;
2043 case 4:
2044 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2045 min_arg_count = 1;
2046 max_arg_count = 1;
2047 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2048 min_arg_count = 0;
2049 max_arg_count = 0;
2050 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2051 min_arg_count = 0;
2052 max_arg_count = 1;
2053 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2054 min_arg_count = 0;
2055 max_arg_count = 0;
2056 }
2057 break;
2058 case 5:
2059 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2060 min_arg_count = 1;
2061 max_arg_count = 1;
2062 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2063 min_arg_count = 0;
2064 max_arg_count = 0;
2065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2066 min_arg_count = 1;
2067 max_arg_count = 1;
2068 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2069 min_arg_count = 1;
2070 max_arg_count = 1;
2071 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2072 min_arg_count = 1;
2073 max_arg_count = 1;
2074 }
2075 break;
2076 case 6:
2077 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2078 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002079 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002080 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2081 min_arg_count = 0;
2082 max_arg_count = 1;
2083 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2084 min_arg_count = 0;
2085 max_arg_count = 1;
2086 }
2087 break;
2088 case 7:
2089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2090 min_arg_count = 1;
2091 max_arg_count = 1;
2092 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2093 min_arg_count = 1;
2094 max_arg_count = 1;
2095 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2096 min_arg_count = 0;
2097 max_arg_count = 0;
2098 }
2099 break;
2100 case 8:
2101 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2102 min_arg_count = 2;
2103 max_arg_count = 2;
2104 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2105 min_arg_count = 0;
2106 max_arg_count = 0;
2107 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2108 min_arg_count = 2;
2109 max_arg_count = 2;
2110 }
2111 break;
2112 case 9:
2113 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2114 min_arg_count = 2;
2115 max_arg_count = 3;
2116 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2117 min_arg_count = 3;
2118 max_arg_count = 3;
2119 }
2120 break;
2121 case 10:
2122 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2123 min_arg_count = 0;
2124 max_arg_count = 1;
2125 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2126 min_arg_count = 1;
2127 max_arg_count = 1;
2128 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2129 min_arg_count = 2;
2130 max_arg_count = 2;
2131 }
2132 break;
2133 case 11:
2134 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2135 min_arg_count = 2;
2136 max_arg_count = 2;
2137 }
2138 break;
2139 case 12:
2140 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2141 min_arg_count = 2;
2142 max_arg_count = 2;
2143 }
2144 break;
2145 case 13:
2146 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2147 min_arg_count = 0;
2148 max_arg_count = 1;
2149 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2150 min_arg_count = 0;
2151 max_arg_count = 1;
2152 }
2153 break;
2154 case 15:
2155 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2156 min_arg_count = 0;
2157 max_arg_count = 1;
2158 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2159 min_arg_count = 2;
2160 max_arg_count = 2;
2161 }
2162 break;
2163 case 16:
2164 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2165 min_arg_count = 2;
2166 max_arg_count = 2;
2167 }
2168 break;
2169 case 20:
2170 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2171 min_arg_count = 2;
2172 max_arg_count = 2;
2173 }
2174 break;
2175 }
2176 if (min_arg_count == -1) {
2177 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2178 return LY_EINVAL;
2179 }
2180 ++(*exp_idx);
2181
2182 /* '(' */
2183 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2184 LY_CHECK_RET(rc);
2185 ++(*exp_idx);
2186
2187 /* ( Expr ( ',' Expr )* )? */
2188 arg_count = 0;
2189 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2190 LY_CHECK_RET(rc);
2191 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2192 ++arg_count;
2193 rc = reparse_or_expr(ctx, exp, exp_idx);
2194 LY_CHECK_RET(rc);
2195 }
2196 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2197 ++(*exp_idx);
2198
2199 ++arg_count;
2200 rc = reparse_or_expr(ctx, exp, exp_idx);
2201 LY_CHECK_RET(rc);
2202 }
2203
2204 /* ')' */
2205 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2206 LY_CHECK_RET(rc);
2207 ++(*exp_idx);
2208
2209 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2210 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2211 &exp->expr[exp->tok_pos[func_exp_idx]]);
2212 return LY_EVALID;
2213 }
2214
2215 return LY_SUCCESS;
2216}
2217
2218/**
2219 * @brief Reparse PathExpr. Logs directly on error.
2220 *
2221 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2222 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2223 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2224 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2225 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2226 *
2227 * @param[in] ctx Context for logging.
2228 * @param[in] exp Parsed XPath expression.
2229 * @param[in] exp_idx Position in the expression @p exp.
2230 * @return LY_ERR
2231 */
2232static LY_ERR
2233reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2234{
2235 LY_ERR rc;
2236
2237 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2238 return -1;
2239 }
2240
2241 switch (exp->tokens[*exp_idx]) {
2242 case LYXP_TOKEN_PAR1:
2243 /* '(' Expr ')' Predicate* */
2244 ++(*exp_idx);
2245
2246 rc = reparse_or_expr(ctx, exp, exp_idx);
2247 LY_CHECK_RET(rc);
2248
2249 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2250 LY_CHECK_RET(rc);
2251 ++(*exp_idx);
2252 goto predicate;
2253 break;
2254 case LYXP_TOKEN_DOT:
2255 case LYXP_TOKEN_DDOT:
2256 case LYXP_TOKEN_AT:
2257 case LYXP_TOKEN_NAMETEST:
2258 case LYXP_TOKEN_NODETYPE:
2259 /* RelativeLocationPath */
2260 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2261 LY_CHECK_RET(rc);
2262 break;
2263 case LYXP_TOKEN_FUNCNAME:
2264 /* FunctionCall */
2265 rc = reparse_function_call(ctx, exp, exp_idx);
2266 LY_CHECK_RET(rc);
2267 goto predicate;
2268 break;
2269 case LYXP_TOKEN_OPERATOR_PATH:
2270 /* AbsoluteLocationPath */
2271 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2272 LY_CHECK_RET(rc);
2273 break;
2274 case LYXP_TOKEN_LITERAL:
2275 /* Literal */
2276 ++(*exp_idx);
2277 goto predicate;
2278 break;
2279 case LYXP_TOKEN_NUMBER:
2280 /* Number */
2281 ++(*exp_idx);
2282 goto predicate;
2283 break;
2284 default:
2285 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2286 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2287 return LY_EVALID;
2288 }
2289
2290 return LY_SUCCESS;
2291
2292predicate:
2293 /* Predicate* */
2294 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2295 rc = reparse_predicate(ctx, exp, exp_idx);
2296 LY_CHECK_RET(rc);
2297 }
2298
2299 /* ('/' or '//') RelativeLocationPath */
2300 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2301
2302 /* '/' or '//' */
2303 ++(*exp_idx);
2304
2305 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2306 LY_CHECK_RET(rc);
2307 }
2308
2309 return LY_SUCCESS;
2310}
2311
2312/**
2313 * @brief Reparse UnaryExpr. Logs directly on error.
2314 *
2315 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2316 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2317 *
2318 * @param[in] ctx Context for logging.
2319 * @param[in] exp Parsed XPath expression.
2320 * @param[in] exp_idx Position in the expression @p exp.
2321 * @return LY_ERR
2322 */
2323static LY_ERR
2324reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2325{
2326 uint16_t prev_exp;
2327 LY_ERR rc;
2328
2329 /* ('-')* */
2330 prev_exp = *exp_idx;
2331 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2332 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2333 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2334 ++(*exp_idx);
2335 }
2336
2337 /* PathExpr */
2338 prev_exp = *exp_idx;
2339 rc = reparse_path_expr(ctx, exp, exp_idx);
2340 LY_CHECK_RET(rc);
2341
2342 /* ('|' PathExpr)* */
2343 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2344 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2345 ++(*exp_idx);
2346
2347 rc = reparse_path_expr(ctx, exp, exp_idx);
2348 LY_CHECK_RET(rc);
2349 }
2350
2351 return LY_SUCCESS;
2352}
2353
2354/**
2355 * @brief Reparse AdditiveExpr. Logs directly on error.
2356 *
2357 * [15] AdditiveExpr ::= MultiplicativeExpr
2358 * | AdditiveExpr '+' MultiplicativeExpr
2359 * | AdditiveExpr '-' MultiplicativeExpr
2360 * [16] MultiplicativeExpr ::= UnaryExpr
2361 * | MultiplicativeExpr '*' UnaryExpr
2362 * | MultiplicativeExpr 'div' UnaryExpr
2363 * | MultiplicativeExpr 'mod' UnaryExpr
2364 *
2365 * @param[in] ctx Context for logging.
2366 * @param[in] exp Parsed XPath expression.
2367 * @param[in] exp_idx Position in the expression @p exp.
2368 * @return LY_ERR
2369 */
2370static LY_ERR
2371reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2372{
2373 uint16_t prev_add_exp, prev_mul_exp;
2374 LY_ERR rc;
2375
2376 prev_add_exp = *exp_idx;
2377 goto reparse_multiplicative_expr;
2378
2379 /* ('+' / '-' MultiplicativeExpr)* */
2380 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2381 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2382 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2383 ++(*exp_idx);
2384
2385reparse_multiplicative_expr:
2386 /* UnaryExpr */
2387 prev_mul_exp = *exp_idx;
2388 rc = reparse_unary_expr(ctx, exp, exp_idx);
2389 LY_CHECK_RET(rc);
2390
2391 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2392 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2393 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2394 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2395 ++(*exp_idx);
2396
2397 rc = reparse_unary_expr(ctx, exp, exp_idx);
2398 LY_CHECK_RET(rc);
2399 }
2400 }
2401
2402 return LY_SUCCESS;
2403}
2404
2405/**
2406 * @brief Reparse EqualityExpr. Logs directly on error.
2407 *
2408 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2409 * | EqualityExpr '!=' RelationalExpr
2410 * [14] RelationalExpr ::= AdditiveExpr
2411 * | RelationalExpr '<' AdditiveExpr
2412 * | RelationalExpr '>' AdditiveExpr
2413 * | RelationalExpr '<=' AdditiveExpr
2414 * | RelationalExpr '>=' AdditiveExpr
2415 *
2416 * @param[in] ctx Context for logging.
2417 * @param[in] exp Parsed XPath expression.
2418 * @param[in] exp_idx Position in the expression @p exp.
2419 * @return LY_ERR
2420 */
2421static LY_ERR
2422reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2423{
2424 uint16_t prev_eq_exp, prev_rel_exp;
2425 LY_ERR rc;
2426
2427 prev_eq_exp = *exp_idx;
2428 goto reparse_additive_expr;
2429
2430 /* ('=' / '!=' RelationalExpr)* */
2431 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2432 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2433 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2434 ++(*exp_idx);
2435
2436reparse_additive_expr:
2437 /* AdditiveExpr */
2438 prev_rel_exp = *exp_idx;
2439 rc = reparse_additive_expr(ctx, exp, exp_idx);
2440 LY_CHECK_RET(rc);
2441
2442 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2443 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2444 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2445 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2446 ++(*exp_idx);
2447
2448 rc = reparse_additive_expr(ctx, exp, exp_idx);
2449 LY_CHECK_RET(rc);
2450 }
2451 }
2452
2453 return LY_SUCCESS;
2454}
2455
2456/**
2457 * @brief Reparse OrExpr. Logs directly on error.
2458 *
2459 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2460 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2461 *
2462 * @param[in] ctx Context for logging.
2463 * @param[in] exp Parsed XPath expression.
2464 * @param[in] exp_idx Position in the expression @p exp.
2465 * @return LY_ERR
2466 */
2467static LY_ERR
2468reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2469{
2470 uint16_t prev_or_exp, prev_and_exp;
2471 LY_ERR rc;
2472
2473 prev_or_exp = *exp_idx;
2474 goto reparse_equality_expr;
2475
2476 /* ('or' AndExpr)* */
2477 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2478 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2479 ++(*exp_idx);
2480
2481reparse_equality_expr:
2482 /* EqualityExpr */
2483 prev_and_exp = *exp_idx;
2484 rc = reparse_equality_expr(ctx, exp, exp_idx);
2485 LY_CHECK_RET(rc);
2486
2487 /* ('and' EqualityExpr)* */
2488 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2489 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2490 ++(*exp_idx);
2491
2492 rc = reparse_equality_expr(ctx, exp, exp_idx);
2493 LY_CHECK_RET(rc);
2494 }
2495 }
2496
2497 return LY_SUCCESS;
2498}
Radek Krejcib1646a92018-11-02 16:08:26 +01002499
2500/**
2501 * @brief Parse NCName.
2502 *
2503 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002504 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002505 */
Radek Krejcid4270262019-01-07 15:07:25 +01002506static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002507parse_ncname(const char *ncname)
2508{
2509 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002510 size_t size;
2511 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002512
2513 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2514 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2515 return len;
2516 }
2517
2518 do {
2519 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002520 if (!*ncname) {
2521 break;
2522 }
Radek Krejcid4270262019-01-07 15:07:25 +01002523 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002524 } while (is_xmlqnamechar(uc) && (uc != ':'));
2525
2526 return len;
2527}
2528
2529/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002530 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002531 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002532 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002533 * @param[in] exp Expression to use.
2534 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002535 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002536 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002537 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002538 */
2539static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002540exp_add_token(struct ly_ctx *ctx, struct lyxp_expr *exp, enum lyxp_token token, uint16_t tok_pos, uint16_t tok_len)
Radek Krejcib1646a92018-11-02 16:08:26 +01002541{
2542 uint32_t prev;
2543
2544 if (exp->used == exp->size) {
2545 prev = exp->size;
2546 exp->size += LYXP_EXPR_SIZE_STEP;
2547 if (prev > exp->size) {
2548 LOGINT(ctx);
2549 return LY_EINT;
2550 }
2551
2552 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2553 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2554 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2555 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2556 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2557 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2558 }
2559
2560 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002561 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002562 exp->tok_len[exp->used] = tok_len;
2563 ++exp->used;
2564 return LY_SUCCESS;
2565}
2566
2567void
2568lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2569{
2570 uint16_t i;
2571
2572 if (!expr) {
2573 return;
2574 }
2575
2576 lydict_remove(ctx, expr->expr);
2577 free(expr->tokens);
2578 free(expr->tok_pos);
2579 free(expr->tok_len);
2580 if (expr->repeat) {
2581 for (i = 0; i < expr->used; ++i) {
2582 free(expr->repeat[i]);
2583 }
2584 }
2585 free(expr->repeat);
2586 free(expr);
2587}
2588
2589struct lyxp_expr *
2590lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2591{
2592 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002593 size_t parsed = 0, tok_len;
2594 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002595 enum lyxp_token tok_type;
2596 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002597 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002598
2599 if (strlen(expr) > UINT16_MAX) {
2600 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2601 return NULL;
2602 }
2603
2604 /* init lyxp_expr structure */
2605 ret = calloc(1, sizeof *ret);
2606 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2607 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2608 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2609 ret->used = 0;
2610 ret->size = LYXP_EXPR_SIZE_START;
2611 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2612 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2613
2614 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2615 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2616
2617 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2618 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2619
2620 while (is_xmlws(expr[parsed])) {
2621 ++parsed;
2622 }
2623
2624 do {
2625 if (expr[parsed] == '(') {
2626
2627 /* '(' */
2628 tok_len = 1;
2629 tok_type = LYXP_TOKEN_PAR1;
2630
2631 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2632 /* it is a NodeType/FunctionName after all */
2633 if (((ret->tok_len[ret->used - 1] == 4)
2634 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2635 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2636 ((ret->tok_len[ret->used - 1] == 7)
2637 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2638 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2639 } else {
2640 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2641 }
2642 prev_function_check = 0;
2643 }
2644
2645 } else if (expr[parsed] == ')') {
2646
2647 /* ')' */
2648 tok_len = 1;
2649 tok_type = LYXP_TOKEN_PAR2;
2650
2651 } else if (expr[parsed] == '[') {
2652
2653 /* '[' */
2654 tok_len = 1;
2655 tok_type = LYXP_TOKEN_BRACK1;
2656
2657 } else if (expr[parsed] == ']') {
2658
2659 /* ']' */
2660 tok_len = 1;
2661 tok_type = LYXP_TOKEN_BRACK2;
2662
2663 } else if (!strncmp(&expr[parsed], "..", 2)) {
2664
2665 /* '..' */
2666 tok_len = 2;
2667 tok_type = LYXP_TOKEN_DDOT;
2668
2669 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2670
2671 /* '.' */
2672 tok_len = 1;
2673 tok_type = LYXP_TOKEN_DOT;
2674
2675 } else if (expr[parsed] == '@') {
2676
2677 /* '@' */
2678 tok_len = 1;
2679 tok_type = LYXP_TOKEN_AT;
2680
2681 } else if (expr[parsed] == ',') {
2682
2683 /* ',' */
2684 tok_len = 1;
2685 tok_type = LYXP_TOKEN_COMMA;
2686
2687 } else if (expr[parsed] == '\'') {
2688
2689 /* Literal with ' */
2690 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2691 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2692 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2693 ++tok_len;
2694 tok_type = LYXP_TOKEN_LITERAL;
2695
2696 } else if (expr[parsed] == '\"') {
2697
2698 /* Literal with " */
2699 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2700 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2701 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2702 ++tok_len;
2703 tok_type = LYXP_TOKEN_LITERAL;
2704
2705 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2706
2707 /* Number */
2708 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2709 if (expr[parsed + tok_len] == '.') {
2710 ++tok_len;
2711 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2712 }
2713 tok_type = LYXP_TOKEN_NUMBER;
2714
2715 } else if (expr[parsed] == '/') {
2716
2717 /* Operator '/', '//' */
2718 if (!strncmp(&expr[parsed], "//", 2)) {
2719 tok_len = 2;
2720 } else {
2721 tok_len = 1;
2722 }
2723 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2724
2725 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2726 || !strncmp(&expr[parsed], ">=", 2)) {
2727
2728 /* Operator '!=', '<=', '>=' */
2729 tok_len = 2;
2730 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2731
2732 } else if (expr[parsed] == '|') {
2733
2734 /* Operator '|' */
2735 tok_len = 1;
2736 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2737
2738 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2739
2740 /* Operator '+', '-' */
2741 tok_len = 1;
2742 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2743
2744 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2745
2746 /* Operator '=', '<', '>' */
2747 tok_len = 1;
2748 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2749
2750 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2751 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2752 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2753 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2754 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2755 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2756 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2757 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2758 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2759
2760 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2761 if (expr[parsed] == '*') {
2762 tok_len = 1;
2763 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2764
2765 } else if (!strncmp(&expr[parsed], "or", 2)) {
2766 tok_len = 2;
2767 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2768
2769 } else if (!strncmp(&expr[parsed], "and", 3)) {
2770 tok_len = 3;
2771 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2772
2773 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2774 tok_len = 3;
2775 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2776
2777 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002778 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2779 expr[parsed], expr[parsed], ret->tok_len[ret->used - 1], &ret->expr[ret->tok_pos[ret->used - 1]]);
Radek Krejcib1646a92018-11-02 16:08:26 +01002780 goto error;
2781 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002782 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002783 goto error;
2784 }
2785 } else if (expr[parsed] == '*') {
2786
2787 /* NameTest '*' */
2788 tok_len = 1;
2789 tok_type = LYXP_TOKEN_NAMETEST;
2790
2791 } else {
2792
2793 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2794 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002795 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002796 tok_len = ncname_len;
2797
2798 if (expr[parsed + tok_len] == ':') {
2799 ++tok_len;
2800 if (expr[parsed + tok_len] == '*') {
2801 ++tok_len;
2802 } else {
2803 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002804 LY_CHECK_ERR_GOTO(ncname_len < 0, LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed - ncname_len + 1, expr), error);
Radek Krejcib1646a92018-11-02 16:08:26 +01002805 tok_len += ncname_len;
2806 }
2807 /* remove old flag to prevent ambiguities */
2808 prev_function_check = 0;
2809 tok_type = LYXP_TOKEN_NAMETEST;
2810 } else {
2811 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2812 prev_function_check = 1;
2813 tok_type = LYXP_TOKEN_NAMETEST;
2814 }
2815 }
2816
2817 /* store the token, move on to the next one */
2818 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2819 parsed += tok_len;
2820 while (is_xmlws(expr[parsed])) {
2821 ++parsed;
2822 }
2823
2824 } while (expr[parsed]);
2825
2826 /* prealloc repeat */
2827 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2828 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2829
Michal Vasko03ff5a72019-09-11 13:49:33 +02002830 /* fill repeat */
2831 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2832 if (ret->used > exp_idx) {
2833 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2834 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2835 &ret->expr[ret->tok_pos[exp_idx]]);
2836 goto error;
2837 }
2838
2839 print_expr_struct_debug(ret);
2840
Radek Krejcib1646a92018-11-02 16:08:26 +01002841 return ret;
2842
2843error:
2844 lyxp_expr_free(ctx, ret);
2845 return NULL;
2846}
2847
Michal Vasko03ff5a72019-09-11 13:49:33 +02002848/*
2849 * warn functions
2850 *
2851 * Warn functions check specific reasonable conditions for schema XPath
2852 * and print a warning if they are not satisfied.
2853 */
2854
2855/**
2856 * @brief Get the last-added schema node that is currently in the context.
2857 *
2858 * @param[in] set Set to search in.
2859 * @return Last-added schema context node, NULL if no node is in context.
2860 */
2861static struct lysc_node *
2862warn_get_scnode_in_ctx(struct lyxp_set *set)
2863{
2864 uint32_t i;
2865
2866 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2867 return NULL;
2868 }
2869
2870 i = set->used;
2871 do {
2872 --i;
2873 if (set->val.scnodes[i].in_ctx == 1) {
2874 /* if there are more, simply return the first found (last added) */
2875 return set->val.scnodes[i].scnode;
2876 }
2877 } while (i);
2878
2879 return NULL;
2880}
2881
2882/**
2883 * @brief Test whether a type is numeric - integer type or decimal64.
2884 *
2885 * @param[in] type Type to test.
2886 * @return 1 if numeric, 0 otherwise.
2887 */
2888static int
2889warn_is_numeric_type(struct lysc_type *type)
2890{
2891 struct lysc_type_union *uni;
2892 int ret;
2893 uint32_t i;
2894
2895 switch (type->basetype) {
2896 case LY_TYPE_DEC64:
2897 case LY_TYPE_INT8:
2898 case LY_TYPE_UINT8:
2899 case LY_TYPE_INT16:
2900 case LY_TYPE_UINT16:
2901 case LY_TYPE_INT32:
2902 case LY_TYPE_UINT32:
2903 case LY_TYPE_INT64:
2904 case LY_TYPE_UINT64:
2905 return 1;
2906 case LY_TYPE_UNION:
2907 uni = (struct lysc_type_union *)type;
2908 LY_ARRAY_FOR(uni->types, i) {
2909 ret = warn_is_numeric_type(uni->types[i]);
2910 if (ret) {
2911 /* found a suitable type */
2912 return 1;
2913 }
2914 }
2915 /* did not find any suitable type */
2916 return 0;
2917 case LY_TYPE_LEAFREF:
2918 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2919 default:
2920 return 0;
2921 }
2922}
2923
2924/**
2925 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2926 *
2927 * @param[in] type Type to test.
2928 * @return 1 if string, 0 otherwise.
2929 */
2930static int
2931warn_is_string_type(struct lysc_type *type)
2932{
2933 struct lysc_type_union *uni;
2934 int ret;
2935 uint32_t i;
2936
2937 switch (type->basetype) {
2938 case LY_TYPE_BITS:
2939 case LY_TYPE_ENUM:
2940 case LY_TYPE_IDENT:
2941 case LY_TYPE_INST:
2942 case LY_TYPE_STRING:
2943 return 1;
2944 case LY_TYPE_UNION:
2945 uni = (struct lysc_type_union *)type;
2946 LY_ARRAY_FOR(uni->types, i) {
2947 ret = warn_is_string_type(uni->types[i]);
2948 if (ret) {
2949 /* found a suitable type */
2950 return 1;
2951 }
2952 }
2953 /* did not find any suitable type */
2954 return 0;
2955 case LY_TYPE_LEAFREF:
2956 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2957 default:
2958 return 0;
2959 }
2960}
2961
2962/**
2963 * @brief Test whether a type is one specific type.
2964 *
2965 * @param[in] type Type to test.
2966 * @param[in] base Expected type.
2967 * @return 1 if it is, 0 otherwise.
2968 */
2969static int
2970warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2971{
2972 struct lysc_type_union *uni;
2973 int ret;
2974 uint32_t i;
2975
2976 if (type->basetype == base) {
2977 return 1;
2978 } else if (type->basetype == LY_TYPE_UNION) {
2979 uni = (struct lysc_type_union *)type;
2980 LY_ARRAY_FOR(uni->types, i) {
2981 ret = warn_is_specific_type(uni->types[i], base);
2982 if (ret) {
2983 /* found a suitable type */
2984 return 1;
2985 }
2986 }
2987 /* did not find any suitable type */
2988 return 0;
2989 } else if (type->basetype == LY_TYPE_LEAFREF) {
2990 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2991 }
2992
2993 return 0;
2994}
2995
2996/**
2997 * @brief Get next type of a (union) type.
2998 *
2999 * @param[in] type Base type.
3000 * @param[in] prev_type Previously returned type.
3001 * @return Next type or NULL.
3002 */
3003static struct lysc_type *
3004warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3005{
3006 struct lysc_type_union *uni;
3007 int found = 0;
3008 uint32_t i;
3009
3010 switch (type->basetype) {
3011 case LY_TYPE_UNION:
3012 uni = (struct lysc_type_union *)type;
3013 if (!prev_type) {
3014 return uni->types[0];
3015 }
3016 LY_ARRAY_FOR(uni->types, i) {
3017 if (found) {
3018 return uni->types[i];
3019 }
3020 if (prev_type == uni->types[i]) {
3021 found = 1;
3022 }
3023 }
3024 return NULL;
3025 default:
3026 if (prev_type) {
3027 assert(type == prev_type);
3028 return NULL;
3029 } else {
3030 return type;
3031 }
3032 }
3033}
3034
3035/**
3036 * @brief Test whether 2 types have a common type.
3037 *
3038 * @param[in] type1 First type.
3039 * @param[in] type2 Second type.
3040 * @return 1 if they do, 0 otherwise.
3041 */
3042static int
3043warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3044{
3045 struct lysc_type *t1, *rt1, *t2, *rt2;
3046
3047 t1 = NULL;
3048 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3049 if (t1->basetype == LY_TYPE_LEAFREF) {
3050 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3051 } else {
3052 rt1 = t1;
3053 }
3054
3055 t2 = NULL;
3056 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3057 if (t2->basetype == LY_TYPE_LEAFREF) {
3058 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3059 } else {
3060 rt2 = t2;
3061 }
3062
3063 if (rt2->basetype == rt1->basetype) {
3064 /* match found */
3065 return 1;
3066 }
3067 }
3068 }
3069
3070 return 0;
3071}
3072
3073/**
3074 * @brief Check both operands of comparison operators.
3075 *
3076 * @param[in] ctx Context for errors.
3077 * @param[in] set1 First operand set.
3078 * @param[in] set2 Second operand set.
3079 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3080 * @param[in] expr Start of the expression to print with the warning.
3081 * @param[in] tok_pos Token position.
3082 */
3083static void
3084warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3085{
3086 struct lysc_node_leaf *node1, *node2;
3087 int leaves = 1, warning = 0;
3088
3089 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3090 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3091
3092 if (!node1 && !node2) {
3093 /* no node-sets involved, nothing to do */
3094 return;
3095 }
3096
3097 if (node1) {
3098 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3099 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3100 warning = 1;
3101 leaves = 0;
3102 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3103 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3104 warning = 1;
3105 }
3106 }
3107
3108 if (node2) {
3109 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3110 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3111 warning = 1;
3112 leaves = 0;
3113 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3114 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3115 warning = 1;
3116 }
3117 }
3118
3119 if (node1 && node2 && leaves && !numbers_only) {
3120 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3121 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3122 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3123 && !warn_is_equal_type(node1->type, node2->type))) {
3124 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3125 warning = 1;
3126 }
3127 }
3128
3129 if (warning) {
3130 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3131 }
3132}
3133
3134/**
3135 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3136 *
3137 * @param[in] exp Parsed XPath expression.
3138 * @param[in] set Set with the leaf/leaf-list.
3139 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3140 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3141 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3142 */
3143static void
3144warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3145{
3146 struct lysc_node *scnode;
3147 struct lysc_type *type;
3148 char *value;
3149 LY_ERR rc;
3150 struct ly_err_item *err = NULL;
3151
3152 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3153 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3154 /* check that the node can have the specified value */
3155 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3156 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3157 } else {
3158 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3159 }
3160 if (!value) {
3161 LOGMEM(set->ctx);
3162 return;
3163 }
3164
3165 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3166 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3167 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3168 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3169 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3170 exp->expr + exp->tok_pos[equal_exp]);
3171 }
3172
3173 type = ((struct lysc_node_leaf *)scnode)->type;
3174 if (type->basetype != LY_TYPE_IDENT) {
3175 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3176 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3177
3178 if (err) {
3179 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3180 ly_err_free(err);
3181 } else if (rc != LY_SUCCESS) {
3182 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3183 }
3184 if (rc != LY_SUCCESS) {
3185 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3186 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3187 exp->expr + exp->tok_pos[equal_exp]);
3188 }
3189 }
3190 free(value);
3191 }
3192}
3193
3194/*
3195 * XPath functions
3196 */
3197
3198/**
3199 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3200 * depending on whether the first node bit value from the second argument is set.
3201 *
3202 * @param[in] args Array of arguments.
3203 * @param[in] arg_count Count of elements in @p args.
3204 * @param[in,out] set Context and result set at the same time.
3205 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003206 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003207 */
3208static LY_ERR
3209xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3210{
3211 struct lyd_node_term *leaf;
3212 struct lysc_node_leaf *sleaf;
3213 struct lysc_type_bits *bits;
3214 LY_ERR rc = LY_SUCCESS;
3215 uint32_t i;
3216
3217 if (options & LYXP_SCNODE_ALL) {
3218 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3219 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003220 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3221 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003222 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3223 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003224 }
3225
3226 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3227 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3228 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003229 } else if (!warn_is_string_type(sleaf->type)) {
3230 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003231 }
3232 }
3233 set_scnode_clear_ctx(set);
3234 return rc;
3235 }
3236
3237 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3238 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "bit-is-set(node-set, string)");
3239 return LY_EVALID;
3240 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003241 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003242 LY_CHECK_RET(rc);
3243
3244 set_fill_boolean(set, 0);
3245 if (args[0]->type == LYXP_SET_NODE_SET) {
3246 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3247 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3248 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3249 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
3250 LY_ARRAY_FOR(bits->bits, i) {
3251 if (!strcmp(bits->bits[i].name, args[1]->val.str)) {
3252 set_fill_boolean(set, 1);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258
3259 return LY_SUCCESS;
3260}
3261
3262/**
3263 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3264 * with the argument converted to boolean.
3265 *
3266 * @param[in] args Array of arguments.
3267 * @param[in] arg_count Count of elements in @p args.
3268 * @param[in,out] set Context and result set at the same time.
3269 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003270 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003271 */
3272static LY_ERR
3273xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3274{
3275 LY_ERR rc;
3276
3277 if (options & LYXP_SCNODE_ALL) {
3278 set_scnode_clear_ctx(set);
3279 return LY_SUCCESS;
3280 }
3281
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003282 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003283 LY_CHECK_RET(rc);
3284 set_fill_set(set, args[0]);
3285
3286 return LY_SUCCESS;
3287}
3288
3289/**
3290 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3291 * with the first argument rounded up to the nearest integer.
3292 *
3293 * @param[in] args Array of arguments.
3294 * @param[in] arg_count Count of elements in @p args.
3295 * @param[in,out] set Context and result set at the same time.
3296 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003297 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003298 */
3299static LY_ERR
3300xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3301{
3302 struct lysc_node_leaf *sleaf;
3303 LY_ERR rc = LY_SUCCESS;
3304
3305 if (options & LYXP_SCNODE_ALL) {
3306 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3307 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003308 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3309 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003310 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3311 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003312 }
3313 set_scnode_clear_ctx(set);
3314 return rc;
3315 }
3316
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003317 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003318 LY_CHECK_RET(rc);
3319 if ((long long)args[0]->val.num != args[0]->val.num) {
3320 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3321 } else {
3322 set_fill_number(set, args[0]->val.num);
3323 }
3324
3325 return LY_SUCCESS;
3326}
3327
3328/**
3329 * @brief Execute the XPath concat(string, string, string*) function.
3330 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3331 *
3332 * @param[in] args Array of arguments.
3333 * @param[in] arg_count Count of elements in @p args.
3334 * @param[in,out] set Context and result set at the same time.
3335 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003336 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003337 */
3338static LY_ERR
3339xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3340{
3341 uint16_t i;
3342 char *str = NULL;
3343 size_t used = 1;
3344 LY_ERR rc = LY_SUCCESS;
3345 struct lysc_node_leaf *sleaf;
3346
3347 if (options & LYXP_SCNODE_ALL) {
3348 for (i = 0; i < arg_count; ++i) {
3349 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3350 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3351 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3352 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003353 } else if (!warn_is_string_type(sleaf->type)) {
3354 LOGWRN(set->ctx, "Argument #%u of %s is node \"%s\", not of string-type.", __func__, i + 1, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003355 }
3356 }
3357 }
3358 set_scnode_clear_ctx(set);
3359 return rc;
3360 }
3361
3362 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003363 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003364 if (rc != LY_SUCCESS) {
3365 free(str);
3366 return rc;
3367 }
3368
3369 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3370 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3371 strcpy(str + used - 1, args[i]->val.str);
3372 used += strlen(args[i]->val.str);
3373 }
3374
3375 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003376 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003377 set->type = LYXP_SET_STRING;
3378 set->val.str = str;
3379
3380 return LY_SUCCESS;
3381}
3382
3383/**
3384 * @brief Execute the XPath contains(string, string) function.
3385 * Returns LYXP_SET_BOOLEAN whether the second argument can
3386 * be found in the first or not.
3387 *
3388 * @param[in] args Array of arguments.
3389 * @param[in] arg_count Count of elements in @p args.
3390 * @param[in,out] set Context and result set at the same time.
3391 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003392 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003393 */
3394static LY_ERR
3395xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3396{
3397 struct lysc_node_leaf *sleaf;
3398 LY_ERR rc = LY_SUCCESS;
3399
3400 if (options & LYXP_SCNODE_ALL) {
3401 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3402 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3403 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003404 } else if (!warn_is_string_type(sleaf->type)) {
3405 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003406 }
3407 }
3408
3409 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3410 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3411 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003412 } else if (!warn_is_string_type(sleaf->type)) {
3413 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003414 }
3415 }
3416 set_scnode_clear_ctx(set);
3417 return rc;
3418 }
3419
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003420 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003421 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003422 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003423 LY_CHECK_RET(rc);
3424
3425 if (strstr(args[0]->val.str, args[1]->val.str)) {
3426 set_fill_boolean(set, 1);
3427 } else {
3428 set_fill_boolean(set, 0);
3429 }
3430
3431 return LY_SUCCESS;
3432}
3433
3434/**
3435 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3436 * with the size of the node-set from the argument.
3437 *
3438 * @param[in] args Array of arguments.
3439 * @param[in] arg_count Count of elements in @p args.
3440 * @param[in,out] set Context and result set at the same time.
3441 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003442 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003443 */
3444static LY_ERR
3445xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3446{
3447 struct lysc_node *scnode = NULL;
3448 LY_ERR rc = LY_SUCCESS;
3449
3450 if (options & LYXP_SCNODE_ALL) {
3451 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3452 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003453 }
3454 set_scnode_clear_ctx(set);
3455 return rc;
3456 }
3457
3458 if (args[0]->type == LYXP_SET_EMPTY) {
3459 set_fill_number(set, 0);
3460 return LY_SUCCESS;
3461 }
3462
3463 if (args[0]->type != LYXP_SET_NODE_SET) {
3464 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3465 return LY_EVALID;
3466 }
3467
3468 set_fill_number(set, args[0]->used);
3469 return LY_SUCCESS;
3470}
3471
3472/**
3473 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3474 * with the context with the intial node.
3475 *
3476 * @param[in] args Array of arguments.
3477 * @param[in] arg_count Count of elements in @p args.
3478 * @param[in,out] set Context and result set at the same time.
3479 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003480 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003481 */
3482static LY_ERR
3483xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3484{
3485 if (arg_count || args) {
3486 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3487 return LY_EVALID;
3488 }
3489
3490 if (options & LYXP_SCNODE_ALL) {
3491 set_scnode_clear_ctx(set);
3492
Michal Vaskoecd62de2019-11-13 12:35:11 +01003493 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003494 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003495 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003496
3497 /* position is filled later */
3498 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3499 }
3500
3501 return LY_SUCCESS;
3502}
3503
3504/**
3505 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3506 * leafref or instance-identifier target node(s).
3507 *
3508 * @param[in] args Array of arguments.
3509 * @param[in] arg_count Count of elements in @p args.
3510 * @param[in,out] set Context and result set at the same time.
3511 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003512 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003513 */
3514static LY_ERR
3515xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3516{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003517 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003518 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003519 struct lysc_node_leaf *sleaf = NULL;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003520 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003521 const struct lyd_node *node;
3522 char *errmsg = NULL;
3523 const char *val;
3524 int dynamic;
3525 LY_ERR rc = LY_SUCCESS;
3526
3527 if (options & LYXP_SCNODE_ALL) {
3528 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3529 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003530 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3531 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003532 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3533 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3534 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003535 }
3536 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003537 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003538 cctx.ctx = set->ctx;
3539 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3540 /* it was already validated, it must succeed */
3541 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003542 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003543 }
3544 }
3545
Michal Vasko03ff5a72019-09-11 13:49:33 +02003546 return rc;
3547 }
3548
3549 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3550 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3551 return LY_EVALID;
3552 }
3553
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003554 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003555 if (args[0]->type != LYXP_SET_EMPTY) {
3556 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3557 sleaf = (struct lysc_node_leaf *)leaf->schema;
3558 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3559 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3560 /* find leafref target */
3561 val = lyd_value2str(leaf, &dynamic);
3562 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
3563 set->trees, &leaf->value, &errmsg);
3564 if (dynamic) {
3565 free((char *)val);
3566 }
3567 if (!node) {
3568 LOGERR(set->ctx, LY_EINVAL, errmsg);
3569 free(errmsg);
3570 return LY_EINVAL;
3571 }
3572
3573 /* insert it */
3574 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3575 } else {
3576 assert(sleaf->type->basetype == LY_TYPE_INST);
3577 node = (struct lyd_node *)lyd_target(leaf->value.target, set->trees);
3578 if (!node) {
3579 val = lyd_value2str(leaf, &dynamic);
3580 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3581 if (dynamic) {
3582 free((char *)val);
3583 }
3584 return LY_EVALID;
3585 }
3586 }
3587 }
3588 }
3589
3590 return LY_SUCCESS;
3591}
3592
3593/**
3594 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3595 * on whether the first argument nodes contain a node of an identity derived from the second
3596 * argument identity.
3597 *
3598 * @param[in] args Array of arguments.
3599 * @param[in] arg_count Count of elements in @p args.
3600 * @param[in,out] set Context and result set at the same time.
3601 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003602 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003603 */
3604static LY_ERR
3605xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3606{
3607 uint16_t i;
3608 struct lyd_node_term *leaf;
3609 struct lysc_node_leaf *sleaf;
3610 struct lyd_value data = {0};
3611 struct ly_err_item *err = NULL;
3612 LY_ERR rc = LY_SUCCESS;
3613 int found;
3614
3615 if (options & LYXP_SCNODE_ALL) {
3616 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3617 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003618 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3619 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003620 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3621 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003622 }
3623
3624 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3625 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3626 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003627 } else if (!warn_is_string_type(sleaf->type)) {
3628 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003629 }
3630 }
3631 set_scnode_clear_ctx(set);
3632 return rc;
3633 }
3634
3635 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3636 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3637 return LY_EVALID;
3638 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003639 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003640 LY_CHECK_RET(rc);
3641
3642 set_fill_boolean(set, 0);
3643 if (args[0]->type != LYXP_SET_EMPTY) {
3644 found = 0;
3645 for (i = 0; i < args[0]->used; ++i) {
3646 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3647 sleaf = (struct lysc_node_leaf *)leaf->schema;
3648 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3649 /* store args[1] into ident */
3650 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3651 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3652 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3653 if (err) {
3654 ly_err_print(err);
3655 ly_err_free(err);
3656 }
3657 LY_CHECK_RET(rc);
3658
3659 LY_ARRAY_FOR(data.ident->derived, i) {
3660 if (data.ident->derived[i] == leaf->value.ident) {
3661 set_fill_boolean(set, 1);
3662 found = 1;
3663 break;
3664 }
3665 }
3666 if (found) {
3667 break;
3668 }
3669 }
3670 }
3671 }
3672
3673 return LY_SUCCESS;
3674}
3675
3676/**
3677 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3678 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3679 * the second argument identity.
3680 *
3681 * @param[in] args Array of arguments.
3682 * @param[in] arg_count Count of elements in @p args.
3683 * @param[in,out] set Context and result set at the same time.
3684 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003685 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003686 */
3687static LY_ERR
3688xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3689{
3690 uint16_t i;
3691 struct lyd_node_term *leaf;
3692 struct lysc_node_leaf *sleaf;
3693 struct lyd_value data = {0};
3694 struct ly_err_item *err = NULL;
3695 LY_ERR rc = LY_SUCCESS;
3696 int found;
3697
3698 if (options & LYXP_SCNODE_ALL) {
3699 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3700 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003701 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3702 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003703 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3704 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003705 }
3706
3707 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3708 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3709 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003710 } else if (!warn_is_string_type(sleaf->type)) {
3711 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003712 }
3713 }
3714 set_scnode_clear_ctx(set);
3715 return rc;
3716 }
3717
3718 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3719 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from-or-self(node-set, string)");
3720 return LY_EVALID;
3721 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003722 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003723 LY_CHECK_RET(rc);
3724
3725 set_fill_boolean(set, 0);
3726 if (args[0]->type != LYXP_SET_EMPTY) {
3727 found = 0;
3728 for (i = 0; i < args[0]->used; ++i) {
3729 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3730 sleaf = (struct lysc_node_leaf *)leaf->schema;
3731 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3732 /* store args[1] into ident */
3733 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3734 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3735 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3736 if (err) {
3737 ly_err_print(err);
3738 ly_err_free(err);
3739 }
3740 LY_CHECK_RET(rc);
3741
3742 if (data.ident == leaf->value.ident) {
3743 set_fill_boolean(set, 1);
3744 break;
3745 }
3746 LY_ARRAY_FOR(data.ident->derived, i) {
3747 if (data.ident->derived[i] == leaf->value.ident) {
3748 set_fill_boolean(set, 1);
3749 found = 1;
3750 break;
3751 }
3752 }
3753 if (found) {
3754 break;
3755 }
3756 }
3757 }
3758 }
3759
3760 return LY_SUCCESS;
3761}
3762
3763/**
3764 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3765 * with the integer value of the first node's enum value, otherwise NaN.
3766 *
3767 * @param[in] args Array of arguments.
3768 * @param[in] arg_count Count of elements in @p args.
3769 * @param[in,out] set Context and result set at the same time.
3770 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003771 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003772 */
3773static LY_ERR
3774xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3775{
3776 struct lyd_node_term *leaf;
3777 struct lysc_node_leaf *sleaf;
3778 LY_ERR rc = LY_SUCCESS;
3779
3780 if (options & LYXP_SCNODE_ALL) {
3781 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3782 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003783 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3784 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003785 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3786 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003787 }
3788 set_scnode_clear_ctx(set);
3789 return rc;
3790 }
3791
3792 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3793 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3794 return LY_EVALID;
3795 }
3796
3797 set_fill_number(set, NAN);
3798 if (args[0]->type == LYXP_SET_NODE_SET) {
3799 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3800 sleaf = (struct lysc_node_leaf *)leaf->schema;
3801 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3802 set_fill_number(set, leaf->value.enum_item->value);
3803 }
3804 }
3805
3806 return LY_SUCCESS;
3807}
3808
3809/**
3810 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3811 * with false value.
3812 *
3813 * @param[in] args Array of arguments.
3814 * @param[in] arg_count Count of elements in @p args.
3815 * @param[in,out] set Context and result set at the same time.
3816 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003817 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003818 */
3819static LY_ERR
3820xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3821{
3822 if (options & LYXP_SCNODE_ALL) {
3823 set_scnode_clear_ctx(set);
3824 return LY_SUCCESS;
3825 }
3826
3827 set_fill_boolean(set, 0);
3828 return LY_SUCCESS;
3829}
3830
3831/**
3832 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3833 * with the first argument floored (truncated).
3834 *
3835 * @param[in] args Array of arguments.
3836 * @param[in] arg_count Count of elements in @p args.
3837 * @param[in,out] set Context and result set at the same time.
3838 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003839 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003840 */
3841static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003842xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003843{
3844 LY_ERR rc;
3845
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003846 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003847 LY_CHECK_RET(rc);
3848 if (isfinite(args[0]->val.num)) {
3849 set_fill_number(set, (long long)args[0]->val.num);
3850 }
3851
3852 return LY_SUCCESS;
3853}
3854
3855/**
3856 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3857 * whether the language of the text matches the one from the argument.
3858 *
3859 * @param[in] args Array of arguments.
3860 * @param[in] arg_count Count of elements in @p args.
3861 * @param[in,out] set Context and result set at the same time.
3862 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003863 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003864 */
3865static LY_ERR
3866xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3867{
3868 const struct lyd_node *node;
3869 struct lysc_node_leaf *sleaf;
3870 struct lyd_attr *attr = NULL;
3871 const char *val;
3872 int i, dynamic;
3873 LY_ERR rc = LY_SUCCESS;
3874
3875 if (options & LYXP_SCNODE_ALL) {
3876 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3877 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3878 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003879 } else if (!warn_is_string_type(sleaf->type)) {
3880 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003881 }
3882 }
3883 set_scnode_clear_ctx(set);
3884 return rc;
3885 }
3886
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003887 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003888 LY_CHECK_RET(rc);
3889
3890 if (set->type == LYXP_SET_EMPTY) {
3891 set_fill_boolean(set, 0);
3892 return LY_SUCCESS;
3893 }
3894 if (set->type != LYXP_SET_NODE_SET) {
3895 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3896 return LY_EVALID;
3897 }
3898
3899 switch (set->val.nodes[0].type) {
3900 case LYXP_NODE_ELEM:
3901 case LYXP_NODE_TEXT:
3902 node = set->val.nodes[0].node;
3903 break;
3904 case LYXP_NODE_ATTR:
3905 node = set->val.attrs[0].attr->parent;
3906 break;
3907 default:
3908 /* nothing to do with roots */
3909 set_fill_boolean(set, 0);
3910 return LY_SUCCESS;
3911 }
3912
3913 /* find lang attribute */
3914 for (; node; node = (struct lyd_node *)node->parent) {
3915 for (attr = node->attr; attr; attr = attr->next) {
3916 /* annotations */
3917 if (attr->name && !strcmp(attr->name, "lang") && !strcmp(attr->annotation->module->name, "xml")) {
3918 break;
3919 }
3920 }
3921
3922 if (attr) {
3923 break;
3924 }
3925 }
3926
3927 /* compare languages */
3928 if (!attr) {
3929 set_fill_boolean(set, 0);
3930 } else {
3931 val = lyd_attr2str(attr, &dynamic);
3932 for (i = 0; args[0]->val.str[i]; ++i) {
3933 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3934 set_fill_boolean(set, 0);
3935 break;
3936 }
3937 }
3938 if (!args[0]->val.str[i]) {
3939 if (!val[i] || (val[i] == '-')) {
3940 set_fill_boolean(set, 1);
3941 } else {
3942 set_fill_boolean(set, 0);
3943 }
3944 }
3945 if (dynamic) {
3946 free((char *)val);
3947 }
3948 }
3949
3950 return LY_SUCCESS;
3951}
3952
3953/**
3954 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3955 * with the context size.
3956 *
3957 * @param[in] args Array of arguments.
3958 * @param[in] arg_count Count of elements in @p args.
3959 * @param[in,out] set Context and result set at the same time.
3960 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003961 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003962 */
3963static LY_ERR
3964xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3965{
3966 if (options & LYXP_SCNODE_ALL) {
3967 set_scnode_clear_ctx(set);
3968 return LY_SUCCESS;
3969 }
3970
3971 if (set->type == LYXP_SET_EMPTY) {
3972 set_fill_number(set, 0);
3973 return LY_SUCCESS;
3974 }
3975 if (set->type != LYXP_SET_NODE_SET) {
3976 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3977 return LY_EVALID;
3978 }
3979
3980 set_fill_number(set, set->ctx_size);
3981 return LY_SUCCESS;
3982}
3983
3984/**
3985 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3986 * with the node name without namespace from the argument or the context.
3987 *
3988 * @param[in] args Array of arguments.
3989 * @param[in] arg_count Count of elements in @p args.
3990 * @param[in,out] set Context and result set at the same time.
3991 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003992 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003993 */
3994static LY_ERR
3995xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3996{
3997 struct lyxp_set_node *item;
3998 /* suppress unused variable warning */
3999 (void)options;
4000
4001 if (options & LYXP_SCNODE_ALL) {
4002 set_scnode_clear_ctx(set);
4003 return LY_SUCCESS;
4004 }
4005
4006 if (arg_count) {
4007 if (args[0]->type == LYXP_SET_EMPTY) {
4008 set_fill_string(set, "", 0);
4009 return LY_SUCCESS;
4010 }
4011 if (args[0]->type != LYXP_SET_NODE_SET) {
4012 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4013 return LY_EVALID;
4014 }
4015
4016 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004017 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004018
4019 item = &args[0]->val.nodes[0];
4020 } else {
4021 if (set->type == LYXP_SET_EMPTY) {
4022 set_fill_string(set, "", 0);
4023 return LY_SUCCESS;
4024 }
4025 if (set->type != LYXP_SET_NODE_SET) {
4026 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4027 return LY_EVALID;
4028 }
4029
4030 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004031 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004032
4033 item = &set->val.nodes[0];
4034 }
4035
4036 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004037 case LYXP_NODE_NONE:
4038 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004039 case LYXP_NODE_ROOT:
4040 case LYXP_NODE_ROOT_CONFIG:
4041 case LYXP_NODE_TEXT:
4042 set_fill_string(set, "", 0);
4043 break;
4044 case LYXP_NODE_ELEM:
4045 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4046 break;
4047 case LYXP_NODE_ATTR:
4048 set_fill_string(set, ((struct lyd_attr *)item->node)->name, strlen(((struct lyd_attr *)item->node)->name));
4049 break;
4050 }
4051
4052 return LY_SUCCESS;
4053}
4054
4055/**
4056 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4057 * with the node name fully qualified (with namespace) from the argument or the context.
4058 *
4059 * @param[in] args Array of arguments.
4060 * @param[in] arg_count Count of elements in @p args.
4061 * @param[in,out] set Context and result set at the same time.
4062 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004063 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004064 */
4065static LY_ERR
4066xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4067{
4068 struct lyxp_set_node *item;
4069 struct lys_module *mod;
4070 char *str;
4071 const char *name;
4072 int rc;
4073
4074 if (options & LYXP_SCNODE_ALL) {
4075 set_scnode_clear_ctx(set);
4076 return LY_SUCCESS;
4077 }
4078
4079 if (arg_count) {
4080 if (args[0]->type == LYXP_SET_EMPTY) {
4081 set_fill_string(set, "", 0);
4082 return LY_SUCCESS;
4083 }
4084 if (args[0]->type != LYXP_SET_NODE_SET) {
4085 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4086 return LY_EVALID;
4087 }
4088
4089 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004090 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004091
4092 item = &args[0]->val.nodes[0];
4093 } else {
4094 if (set->type == LYXP_SET_EMPTY) {
4095 set_fill_string(set, "", 0);
4096 return LY_SUCCESS;
4097 }
4098 if (set->type != LYXP_SET_NODE_SET) {
4099 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4100 return LY_EVALID;
4101 }
4102
4103 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004104 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004105
4106 item = &set->val.nodes[0];
4107 }
4108
4109 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004110 case LYXP_NODE_NONE:
4111 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004112 case LYXP_NODE_ROOT:
4113 case LYXP_NODE_ROOT_CONFIG:
4114 case LYXP_NODE_TEXT:
4115 mod = NULL;
4116 name = NULL;
4117 break;
4118 case LYXP_NODE_ELEM:
4119 mod = item->node->schema->module;
4120 name = item->node->schema->name;
4121 break;
4122 case LYXP_NODE_ATTR:
4123 mod = ((struct lyd_attr *)item->node)->annotation->module;
4124 name = ((struct lyd_attr *)item->node)->name;
4125 break;
4126 }
4127
4128 if (mod && name) {
4129 switch (set->format) {
4130 case LYD_UNKNOWN:
4131 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4132 break;
4133 case LYD_JSON:
4134 rc = asprintf(&str, "%s:%s", mod->name, name);
4135 break;
Michal Vasko9409ef62019-09-12 11:47:17 +02004136 default:
4137 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004138 }
4139 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4140 set_fill_string(set, str, strlen(str));
4141 free(str);
4142 } else {
4143 set_fill_string(set, "", 0);
4144 }
4145
4146 return LY_SUCCESS;
4147}
4148
4149/**
4150 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4151 * with the namespace of the node from the argument or the context.
4152 *
4153 * @param[in] args Array of arguments.
4154 * @param[in] arg_count Count of elements in @p args.
4155 * @param[in,out] set Context and result set at the same time.
4156 * @param[in] options XPath options.
4157 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4158 */
4159static LY_ERR
4160xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4161{
4162 struct lyxp_set_node *item;
4163 struct lys_module *mod;
4164 /* suppress unused variable warning */
4165 (void)options;
4166
4167 if (options & LYXP_SCNODE_ALL) {
4168 set_scnode_clear_ctx(set);
4169 return LY_SUCCESS;
4170 }
4171
4172 if (arg_count) {
4173 if (args[0]->type == LYXP_SET_EMPTY) {
4174 set_fill_string(set, "", 0);
4175 return LY_SUCCESS;
4176 }
4177 if (args[0]->type != LYXP_SET_NODE_SET) {
4178 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4179 return LY_EVALID;
4180 }
4181
4182 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004183 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004184
4185 item = &args[0]->val.nodes[0];
4186 } else {
4187 if (set->type == LYXP_SET_EMPTY) {
4188 set_fill_string(set, "", 0);
4189 return LY_SUCCESS;
4190 }
4191 if (set->type != LYXP_SET_NODE_SET) {
4192 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4193 return LY_EVALID;
4194 }
4195
4196 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004197 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004198
4199 item = &set->val.nodes[0];
4200 }
4201
4202 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004203 case LYXP_NODE_NONE:
4204 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004205 case LYXP_NODE_ROOT:
4206 case LYXP_NODE_ROOT_CONFIG:
4207 case LYXP_NODE_TEXT:
4208 set_fill_string(set, "", 0);
4209 break;
4210 case LYXP_NODE_ELEM:
4211 case LYXP_NODE_ATTR:
4212 if (item->type == LYXP_NODE_ELEM) {
4213 mod = item->node->schema->module;
4214 } else { /* LYXP_NODE_ATTR */
4215 /* annotations */
4216 mod = ((struct lyd_attr *)item->node)->annotation->module;
4217 }
4218
4219 set_fill_string(set, mod->ns, strlen(mod->ns));
4220 break;
4221 }
4222
4223 return LY_SUCCESS;
4224}
4225
4226/**
4227 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4228 * with only nodes from the context. In practice it either leaves the context
4229 * as it is or returns an empty node set.
4230 *
4231 * @param[in] args Array of arguments.
4232 * @param[in] arg_count Count of elements in @p args.
4233 * @param[in,out] set Context and result set at the same time.
4234 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004235 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004236 */
4237static LY_ERR
4238xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4239{
4240 if (options & LYXP_SCNODE_ALL) {
4241 set_scnode_clear_ctx(set);
4242 return LY_SUCCESS;
4243 }
4244
4245 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004246 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004247 }
4248 return LY_SUCCESS;
4249}
4250
4251/**
4252 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4253 * with normalized value (no leading, trailing, double white spaces) of the node
4254 * from the argument or the context.
4255 *
4256 * @param[in] args Array of arguments.
4257 * @param[in] arg_count Count of elements in @p args.
4258 * @param[in,out] set Context and result set at the same time.
4259 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004260 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004261 */
4262static LY_ERR
4263xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4264{
4265 uint16_t i, new_used;
4266 char *new;
4267 int have_spaces = 0, space_before = 0;
4268 struct lysc_node_leaf *sleaf;
4269 LY_ERR rc = LY_SUCCESS;
4270
4271 if (options & LYXP_SCNODE_ALL) {
4272 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4273 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4274 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004275 } else if (!warn_is_string_type(sleaf->type)) {
4276 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004277 }
4278 }
4279 set_scnode_clear_ctx(set);
4280 return rc;
4281 }
4282
4283 if (arg_count) {
4284 set_fill_set(set, args[0]);
4285 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004286 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004287 LY_CHECK_RET(rc);
4288
4289 /* is there any normalization necessary? */
4290 for (i = 0; set->val.str[i]; ++i) {
4291 if (is_xmlws(set->val.str[i])) {
4292 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4293 have_spaces = 1;
4294 break;
4295 }
4296 space_before = 1;
4297 } else {
4298 space_before = 0;
4299 }
4300 }
4301
4302 /* yep, there is */
4303 if (have_spaces) {
4304 /* it's enough, at least one character will go, makes space for ending '\0' */
4305 new = malloc(strlen(set->val.str) * sizeof(char));
4306 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4307 new_used = 0;
4308
4309 space_before = 0;
4310 for (i = 0; set->val.str[i]; ++i) {
4311 if (is_xmlws(set->val.str[i])) {
4312 if ((i == 0) || space_before) {
4313 space_before = 1;
4314 continue;
4315 } else {
4316 space_before = 1;
4317 }
4318 } else {
4319 space_before = 0;
4320 }
4321
4322 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4323 ++new_used;
4324 }
4325
4326 /* at worst there is one trailing space now */
4327 if (new_used && is_xmlws(new[new_used - 1])) {
4328 --new_used;
4329 }
4330
4331 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4332 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4333 new[new_used] = '\0';
4334
4335 free(set->val.str);
4336 set->val.str = new;
4337 }
4338
4339 return LY_SUCCESS;
4340}
4341
4342/**
4343 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4344 * with the argument converted to boolean and logically inverted.
4345 *
4346 * @param[in] args Array of arguments.
4347 * @param[in] arg_count Count of elements in @p args.
4348 * @param[in,out] set Context and result set at the same time.
4349 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004350 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004351 */
4352static LY_ERR
4353xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4354{
4355 if (options & LYXP_SCNODE_ALL) {
4356 set_scnode_clear_ctx(set);
4357 return LY_SUCCESS;
4358 }
4359
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004360 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004361 if (args[0]->val.bool) {
4362 set_fill_boolean(set, 0);
4363 } else {
4364 set_fill_boolean(set, 1);
4365 }
4366
4367 return LY_SUCCESS;
4368}
4369
4370/**
4371 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4372 * with the number representation of either the argument or the context.
4373 *
4374 * @param[in] args Array of arguments.
4375 * @param[in] arg_count Count of elements in @p args.
4376 * @param[in,out] set Context and result set at the same time.
4377 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004378 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004379 */
4380static LY_ERR
4381xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4382{
4383 LY_ERR rc;
4384
4385 if (options & LYXP_SCNODE_ALL) {
4386 set_scnode_clear_ctx(set);
4387 return LY_SUCCESS;
4388 }
4389
4390 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004391 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004392 LY_CHECK_RET(rc);
4393 set_fill_set(set, args[0]);
4394 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004395 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004396 LY_CHECK_RET(rc);
4397 }
4398
4399 return LY_SUCCESS;
4400}
4401
4402/**
4403 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4404 * with the context position.
4405 *
4406 * @param[in] args Array of arguments.
4407 * @param[in] arg_count Count of elements in @p args.
4408 * @param[in,out] set Context and result set at the same time.
4409 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004410 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004411 */
4412static LY_ERR
4413xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4414{
4415 if (options & LYXP_SCNODE_ALL) {
4416 set_scnode_clear_ctx(set);
4417 return LY_SUCCESS;
4418 }
4419
4420 if (set->type == LYXP_SET_EMPTY) {
4421 set_fill_number(set, 0);
4422 return LY_SUCCESS;
4423 }
4424 if (set->type != LYXP_SET_NODE_SET) {
4425 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4426 return LY_EVALID;
4427 }
4428
4429 set_fill_number(set, set->ctx_pos);
4430
4431 /* UNUSED in 'Release' build type */
4432 (void)options;
4433 return LY_SUCCESS;
4434}
4435
4436/**
4437 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4438 * depending on whether the second argument regex matches the first argument string. For details refer to
4439 * YANG 1.1 RFC section 10.2.1.
4440 *
4441 * @param[in] args Array of arguments.
4442 * @param[in] arg_count Count of elements in @p args.
4443 * @param[in,out] set Context and result set at the same time.
4444 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004445 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004446 */
4447static LY_ERR
4448xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4449{
4450 struct lysc_pattern **patterns = NULL, **pattern;
4451 struct lysc_node_leaf *sleaf;
4452 char *path;
4453 LY_ERR rc = LY_SUCCESS;
4454 struct ly_err_item *err;
4455
4456 if (options & LYXP_SCNODE_ALL) {
4457 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4458 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4459 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004460 } else if (!warn_is_string_type(sleaf->type)) {
4461 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004462 }
4463 }
4464
4465 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4466 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4467 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004468 } else if (!warn_is_string_type(sleaf->type)) {
4469 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004470 }
4471 }
4472 set_scnode_clear_ctx(set);
4473 return rc;
4474 }
4475
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004476 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004477 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004478 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004479 LY_CHECK_RET(rc);
4480
4481 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4482 *pattern = malloc(sizeof **pattern);
4483 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4484 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4485 free(path);
4486 if (rc != LY_SUCCESS) {
4487 LY_ARRAY_FREE(patterns);
4488 return rc;
4489 }
4490
4491 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4492 pcre2_code_free((*pattern)->code);
4493 free(*pattern);
4494 LY_ARRAY_FREE(patterns);
4495 if (rc && (rc != LY_EVALID)) {
4496 ly_err_print(err);
4497 ly_err_free(err);
4498 return rc;
4499 }
4500
4501 if (rc == LY_EVALID) {
4502 ly_err_free(err);
4503 set_fill_boolean(set, 0);
4504 } else {
4505 set_fill_boolean(set, 1);
4506 }
4507
4508 return LY_SUCCESS;
4509}
4510
4511/**
4512 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4513 * with the rounded first argument. For details refer to
4514 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4515 *
4516 * @param[in] args Array of arguments.
4517 * @param[in] arg_count Count of elements in @p args.
4518 * @param[in,out] set Context and result set at the same time.
4519 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004520 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004521 */
4522static LY_ERR
4523xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4524{
4525 struct lysc_node_leaf *sleaf;
4526 LY_ERR rc = LY_SUCCESS;
4527
4528 if (options & LYXP_SCNODE_ALL) {
4529 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4530 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004531 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4532 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004533 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4534 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004535 }
4536 set_scnode_clear_ctx(set);
4537 return rc;
4538 }
4539
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004540 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004541 LY_CHECK_RET(rc);
4542
4543 /* cover only the cases where floor can't be used */
4544 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4545 set_fill_number(set, -0.0f);
4546 } else {
4547 args[0]->val.num += 0.5;
4548 rc = xpath_floor(args, 1, args[0], options);
4549 LY_CHECK_RET(rc);
4550 set_fill_number(set, args[0]->val.num);
4551 }
4552
4553 return LY_SUCCESS;
4554}
4555
4556/**
4557 * @brief Execute the XPath starts-with(string, string) function.
4558 * Returns LYXP_SET_BOOLEAN whether the second argument is
4559 * the prefix of the first or not.
4560 *
4561 * @param[in] args Array of arguments.
4562 * @param[in] arg_count Count of elements in @p args.
4563 * @param[in,out] set Context and result set at the same time.
4564 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004565 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004566 */
4567static LY_ERR
4568xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4569{
4570 struct lysc_node_leaf *sleaf;
4571 LY_ERR rc = LY_SUCCESS;
4572
4573 if (options & LYXP_SCNODE_ALL) {
4574 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4575 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4576 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004577 } else if (!warn_is_string_type(sleaf->type)) {
4578 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004579 }
4580 }
4581
4582 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4583 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4584 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004585 } else if (!warn_is_string_type(sleaf->type)) {
4586 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004587 }
4588 }
4589 set_scnode_clear_ctx(set);
4590 return rc;
4591 }
4592
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004593 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004594 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004595 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004596 LY_CHECK_RET(rc);
4597
4598 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4599 set_fill_boolean(set, 0);
4600 } else {
4601 set_fill_boolean(set, 1);
4602 }
4603
4604 return LY_SUCCESS;
4605}
4606
4607/**
4608 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4609 * with the string representation of either the argument or the context.
4610 *
4611 * @param[in] args Array of arguments.
4612 * @param[in] arg_count Count of elements in @p args.
4613 * @param[in,out] set Context and result set at the same time.
4614 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004615 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004616 */
4617static LY_ERR
4618xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4619{
4620 LY_ERR rc;
4621
4622 if (options & LYXP_SCNODE_ALL) {
4623 set_scnode_clear_ctx(set);
4624 return LY_SUCCESS;
4625 }
4626
4627 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004628 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004629 LY_CHECK_RET(rc);
4630 set_fill_set(set, args[0]);
4631 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004632 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004633 LY_CHECK_RET(rc);
4634 }
4635
4636 return LY_SUCCESS;
4637}
4638
4639/**
4640 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4641 * with the length of the string in either the argument or the context.
4642 *
4643 * @param[in] args Array of arguments.
4644 * @param[in] arg_count Count of elements in @p args.
4645 * @param[in,out] set Context and result set at the same time.
4646 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004647 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004648 */
4649static LY_ERR
4650xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4651{
4652 struct lysc_node_leaf *sleaf;
4653 LY_ERR rc = LY_SUCCESS;
4654
4655 if (options & LYXP_SCNODE_ALL) {
4656 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4657 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4658 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004659 } else if (!warn_is_string_type(sleaf->type)) {
4660 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004661 }
4662 }
4663 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4664 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4665 LOGWRN(set->ctx, "Argument #0 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004666 } else if (!warn_is_string_type(sleaf->type)) {
4667 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004668 }
4669 }
4670 set_scnode_clear_ctx(set);
4671 return rc;
4672 }
4673
4674 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004675 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004676 LY_CHECK_RET(rc);
4677 set_fill_number(set, strlen(args[0]->val.str));
4678 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004679 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004680 LY_CHECK_RET(rc);
4681 set_fill_number(set, strlen(set->val.str));
4682 }
4683
4684 return LY_SUCCESS;
4685}
4686
4687/**
4688 * @brief Execute the XPath substring(string, number, number?) function.
4689 * Returns LYXP_SET_STRING substring of the first argument starting
4690 * on the second argument index ending on the third argument index,
4691 * indexed from 1. For exact definition refer to
4692 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4693 *
4694 * @param[in] args Array of arguments.
4695 * @param[in] arg_count Count of elements in @p args.
4696 * @param[in,out] set Context and result set at the same time.
4697 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004698 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004699 */
4700static LY_ERR
4701xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4702{
4703 int start, len;
4704 uint16_t str_start, str_len, pos;
4705 struct lysc_node_leaf *sleaf;
4706 LY_ERR rc = LY_SUCCESS;
4707
4708 if (options & LYXP_SCNODE_ALL) {
4709 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4710 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4711 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004712 } else if (!warn_is_string_type(sleaf->type)) {
4713 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004714 }
4715 }
4716
4717 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4718 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4719 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004720 } else if (!warn_is_numeric_type(sleaf->type)) {
4721 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004722 }
4723 }
4724
4725 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4726 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4727 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4728 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004729 } else if (!warn_is_numeric_type(sleaf->type)) {
4730 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004731 }
4732 }
4733 set_scnode_clear_ctx(set);
4734 return rc;
4735 }
4736
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004737 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004738 LY_CHECK_RET(rc);
4739
4740 /* start */
4741 if (xpath_round(&args[1], 1, args[1], options)) {
4742 return -1;
4743 }
4744 if (isfinite(args[1]->val.num)) {
4745 start = args[1]->val.num - 1;
4746 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4747 start = INT_MIN;
4748 } else {
4749 start = INT_MAX;
4750 }
4751
4752 /* len */
4753 if (arg_count == 3) {
4754 rc = xpath_round(&args[2], 1, args[2], options);
4755 LY_CHECK_RET(rc);
4756 if (isfinite(args[2]->val.num)) {
4757 len = args[2]->val.num;
4758 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4759 len = 0;
4760 } else {
4761 len = INT_MAX;
4762 }
4763 } else {
4764 len = INT_MAX;
4765 }
4766
4767 /* find matching character positions */
4768 str_start = 0;
4769 str_len = 0;
4770 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4771 if (pos < start) {
4772 ++str_start;
4773 } else if (pos < start + len) {
4774 ++str_len;
4775 } else {
4776 break;
4777 }
4778 }
4779
4780 set_fill_string(set, args[0]->val.str + str_start, str_len);
4781 return LY_SUCCESS;
4782}
4783
4784/**
4785 * @brief Execute the XPath substring-after(string, string) function.
4786 * Returns LYXP_SET_STRING with the string succeeding the occurance
4787 * of the second argument in the first or an empty string.
4788 *
4789 * @param[in] args Array of arguments.
4790 * @param[in] arg_count Count of elements in @p args.
4791 * @param[in,out] set Context and result set at the same time.
4792 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004793 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004794 */
4795static LY_ERR
4796xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4797{
4798 char *ptr;
4799 struct lysc_node_leaf *sleaf;
4800 LY_ERR rc = LY_SUCCESS;
4801
4802 if (options & LYXP_SCNODE_ALL) {
4803 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4804 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4805 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004806 } else if (!warn_is_string_type(sleaf->type)) {
4807 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004808 }
4809 }
4810
4811 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4812 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4813 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004814 } else if (!warn_is_string_type(sleaf->type)) {
4815 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004816 }
4817 }
4818 set_scnode_clear_ctx(set);
4819 return rc;
4820 }
4821
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004822 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004823 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004824 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004825 LY_CHECK_RET(rc);
4826
4827 ptr = strstr(args[0]->val.str, args[1]->val.str);
4828 if (ptr) {
4829 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4830 } else {
4831 set_fill_string(set, "", 0);
4832 }
4833
4834 return LY_SUCCESS;
4835}
4836
4837/**
4838 * @brief Execute the XPath substring-before(string, string) function.
4839 * Returns LYXP_SET_STRING with the string preceding the occurance
4840 * of the second argument in the first or an empty string.
4841 *
4842 * @param[in] args Array of arguments.
4843 * @param[in] arg_count Count of elements in @p args.
4844 * @param[in,out] set Context and result set at the same time.
4845 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004846 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004847 */
4848static LY_ERR
4849xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4850{
4851 char *ptr;
4852 struct lysc_node_leaf *sleaf;
4853 LY_ERR rc = LY_SUCCESS;
4854
4855 if (options & LYXP_SCNODE_ALL) {
4856 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4857 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4858 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004859 } else if (!warn_is_string_type(sleaf->type)) {
4860 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004861 }
4862 }
4863
4864 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4865 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4866 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004867 } else if (!warn_is_string_type(sleaf->type)) {
4868 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004869 }
4870 }
4871 set_scnode_clear_ctx(set);
4872 return rc;
4873 }
4874
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004875 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004876 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004877 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004878 LY_CHECK_RET(rc);
4879
4880 ptr = strstr(args[0]->val.str, args[1]->val.str);
4881 if (ptr) {
4882 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4883 } else {
4884 set_fill_string(set, "", 0);
4885 }
4886
4887 return LY_SUCCESS;
4888}
4889
4890/**
4891 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4892 * with the sum of all the nodes in the context.
4893 *
4894 * @param[in] args Array of arguments.
4895 * @param[in] arg_count Count of elements in @p args.
4896 * @param[in,out] set Context and result set at the same time.
4897 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004898 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004899 */
4900static LY_ERR
4901xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4902{
4903 long double num;
4904 char *str;
4905 uint16_t i;
4906 struct lyxp_set set_item;
4907 struct lysc_node_leaf *sleaf;
4908 LY_ERR rc = LY_SUCCESS;
4909
4910 if (options & LYXP_SCNODE_ALL) {
4911 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4912 for (i = 0; i < args[0]->used; ++i) {
4913 if (args[0]->val.scnodes[i].in_ctx == 1) {
4914 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4915 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4916 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4917 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004918 } else if (!warn_is_numeric_type(sleaf->type)) {
4919 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004920 }
4921 }
4922 }
4923 }
4924 set_scnode_clear_ctx(set);
4925 return rc;
4926 }
4927
4928 set_fill_number(set, 0);
4929 if (args[0]->type == LYXP_SET_EMPTY) {
4930 return LY_SUCCESS;
4931 }
4932
4933 if (args[0]->type != LYXP_SET_NODE_SET) {
4934 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4935 return LY_EVALID;
4936 }
4937
Michal Vasko5c4e5892019-11-14 12:31:38 +01004938 set_init(&set_item, set);
4939
Michal Vasko03ff5a72019-09-11 13:49:33 +02004940 set_item.type = LYXP_SET_NODE_SET;
4941 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4942 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4943
4944 set_item.used = 1;
4945 set_item.size = 1;
4946
4947 for (i = 0; i < args[0]->used; ++i) {
4948 set_item.val.nodes[0] = args[0]->val.nodes[i];
4949
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004950 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004951 LY_CHECK_RET(rc);
4952 num = cast_string_to_number(str);
4953 free(str);
4954 set->val.num += num;
4955 }
4956
4957 free(set_item.val.nodes);
4958
4959 return LY_SUCCESS;
4960}
4961
4962/**
4963 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4964 * with the text content of the nodes in the context.
4965 *
4966 * @param[in] args Array of arguments.
4967 * @param[in] arg_count Count of elements in @p args.
4968 * @param[in,out] set Context and result set at the same time.
4969 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004970 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004971 */
4972static LY_ERR
4973xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4974{
4975 uint32_t i;
4976
4977 if (options & LYXP_SCNODE_ALL) {
4978 set_scnode_clear_ctx(set);
4979 return LY_SUCCESS;
4980 }
4981
4982 if (set->type == LYXP_SET_EMPTY) {
4983 return LY_SUCCESS;
4984 }
4985 if (set->type != LYXP_SET_NODE_SET) {
4986 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4987 return LY_EVALID;
4988 }
4989
4990 for (i = 0; i < set->used;) {
4991 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004992 case LYXP_NODE_NONE:
4993 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004994 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004995 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4996 set->val.nodes[i].type = LYXP_NODE_TEXT;
4997 ++i;
4998 break;
4999 }
5000 /* fall through */
5001 case LYXP_NODE_ROOT:
5002 case LYXP_NODE_ROOT_CONFIG:
5003 case LYXP_NODE_TEXT:
5004 case LYXP_NODE_ATTR:
5005 set_remove_node(set, i);
5006 break;
5007 }
5008 }
5009
5010 return LY_SUCCESS;
5011}
5012
5013/**
5014 * @brief Execute the XPath translate(string, string, string) function.
5015 * Returns LYXP_SET_STRING with the first argument with the characters
5016 * from the second argument replaced by those on the corresponding
5017 * positions in the third argument.
5018 *
5019 * @param[in] args Array of arguments.
5020 * @param[in] arg_count Count of elements in @p args.
5021 * @param[in,out] set Context and result set at the same time.
5022 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005023 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005024 */
5025static LY_ERR
5026xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5027{
5028 uint16_t i, j, new_used;
5029 char *new;
5030 int found, have_removed;
5031 struct lysc_node_leaf *sleaf;
5032 LY_ERR rc = LY_SUCCESS;
5033
5034 if (options & LYXP_SCNODE_ALL) {
5035 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5036 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5037 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005038 } else if (!warn_is_string_type(sleaf->type)) {
5039 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005040 }
5041 }
5042
5043 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5044 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5045 LOGWRN(set->ctx, "Argument #2 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005046 } else if (!warn_is_string_type(sleaf->type)) {
5047 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005048 }
5049 }
5050
5051 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5052 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5053 LOGWRN(set->ctx, "Argument #3 of %s is a %s node \"%s\".", __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005054 } else if (!warn_is_string_type(sleaf->type)) {
5055 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005056 }
5057 }
5058 set_scnode_clear_ctx(set);
5059 return rc;
5060 }
5061
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005062 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005063 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005064 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005065 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005066 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005067 LY_CHECK_RET(rc);
5068
5069 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5070 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5071 new_used = 0;
5072
5073 have_removed = 0;
5074 for (i = 0; args[0]->val.str[i]; ++i) {
5075 found = 0;
5076
5077 for (j = 0; args[1]->val.str[j]; ++j) {
5078 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5079 /* removing this char */
5080 if (j >= strlen(args[2]->val.str)) {
5081 have_removed = 1;
5082 found = 1;
5083 break;
5084 }
5085 /* replacing this char */
5086 new[new_used] = args[2]->val.str[j];
5087 ++new_used;
5088 found = 1;
5089 break;
5090 }
5091 }
5092
5093 /* copying this char */
5094 if (!found) {
5095 new[new_used] = args[0]->val.str[i];
5096 ++new_used;
5097 }
5098 }
5099
5100 if (have_removed) {
5101 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5102 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5103 }
5104 new[new_used] = '\0';
5105
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005106 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005107 set->type = LYXP_SET_STRING;
5108 set->val.str = new;
5109
5110 return LY_SUCCESS;
5111}
5112
5113/**
5114 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5115 * with true value.
5116 *
5117 * @param[in] args Array of arguments.
5118 * @param[in] arg_count Count of elements in @p args.
5119 * @param[in,out] set Context and result set at the same time.
5120 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005121 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005122 */
5123static LY_ERR
5124xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5125{
5126 if (options & LYXP_SCNODE_ALL) {
5127 set_scnode_clear_ctx(set);
5128 return LY_SUCCESS;
5129 }
5130
5131 set_fill_boolean(set, 1);
5132 return LY_SUCCESS;
5133}
5134
5135/*
5136 * moveto functions
5137 *
5138 * They and only they actually change the context (set).
5139 */
5140
5141/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005142 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005143 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005144 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5145 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5146 * @param[in] set Set with XPath context.
5147 * @param[out] moveto_mod Expected module of a matching node.
5148 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005149 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005150static LY_ERR
5151moveto_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 +02005152{
Michal Vasko6346ece2019-09-24 13:12:53 +02005153 const struct lys_module *mod;
5154 const char *ptr;
5155 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005156 char *str;
5157
Michal Vasko6346ece2019-09-24 13:12:53 +02005158 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5159 /* specific module */
5160 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005161
Michal Vasko6346ece2019-09-24 13:12:53 +02005162 switch (set->format) {
5163 case LYD_UNKNOWN:
5164 /* schema, search all local module imports */
5165 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5166 break;
5167 case LYD_JSON:
5168 /* JSON data, search in context */
5169 str = strndup(*qname, pref_len);
5170 mod = ly_ctx_get_module(set->ctx, str, NULL);
5171 free(str);
5172 break;
5173 default:
5174 LOGINT_RET(set->ctx);
5175 }
5176
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005177 /* Check for errors and non-implemented modules, as they are not valid */
5178 if (!mod || !mod->implemented) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005179 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5180 return LY_EVALID;
5181 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005182
Michal Vasko6346ece2019-09-24 13:12:53 +02005183 *qname += pref_len + 1;
5184 *qname_len -= pref_len + 1;
5185 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5186 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005187 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005188 } else {
5189 /* local module */
5190 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005191 }
5192
Michal Vasko6346ece2019-09-24 13:12:53 +02005193 *moveto_mod = mod;
5194 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005195}
5196
5197/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005198 * @brief Move context @p set to the root. Handles absolute path.
5199 * Result is LYXP_SET_NODE_SET.
5200 *
5201 * @param[in,out] set Set to use.
5202 * @param[in] options Xpath options.
5203 */
5204static void
5205moveto_root(struct lyxp_set *set, int options)
5206{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005207 if (!set) {
5208 return;
5209 }
5210
5211 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005212 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005213 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005214 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005215 lyxp_set_cast(set, LYXP_SET_EMPTY);
5216 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005217 }
5218}
5219
5220/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005221 * @brief Check whether a node has some unresolved "when".
5222 *
5223 * @param[in] node Node to check.
5224 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5225 */
5226static LY_ERR
5227moveto_when_check(const struct lyd_node *node)
5228{
5229 const struct lysc_node *schema;
5230
5231 if (!node) {
5232 return LY_SUCCESS;
5233 }
5234
5235 schema = node->schema;
5236 do {
5237 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5238 return LY_EINCOMPLETE;
5239 }
5240 schema = schema->parent;
5241 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5242
5243 return LY_SUCCESS;
5244}
5245
5246/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005247 * @brief Check @p node as a part of NameTest processing.
5248 *
5249 * @param[in] node Node to check.
5250 * @param[in] root_type XPath root node type.
5251 * @param[in] node_name Node name to move to. Must be in the dictionary!
5252 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005253 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5254 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005255 */
5256static LY_ERR
5257moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5258 const struct lys_module *moveto_mod)
5259{
5260 /* module check */
5261 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005262 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005263 }
5264
Michal Vasko5c4e5892019-11-14 12:31:38 +01005265 /* context check */
5266 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005267 return LY_EINVAL;
5268 }
5269
5270 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005271 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005272 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005273 }
5274
Michal Vaskoa1424542019-11-14 16:08:52 +01005275 /* when check */
5276 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005277 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005278 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005279
5280 /* match */
5281 return LY_SUCCESS;
5282}
5283
5284/**
5285 * @brief Check @p node as a part of schema NameTest processing.
5286 *
5287 * @param[in] node Schema node to check.
5288 * @param[in] root_type XPath root node type.
5289 * @param[in] node_name Node name to move to. Must be in the dictionary!
5290 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005291 * @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 +02005292 */
5293static LY_ERR
5294moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005295 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005296{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005297 /* module check */
5298 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005299 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005300 }
5301
5302 /* context check */
5303 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5304 return LY_EINVAL;
5305 }
5306
5307 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005308 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005309 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005310 }
5311
5312 /* match */
5313 return LY_SUCCESS;
5314}
5315
5316/**
5317 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5318 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5319 *
5320 * @param[in,out] set Set to use.
5321 * @param[in] qname Qualified node name to move to.
5322 * @param[in] qname_len Length of @p qname.
5323 * @param[in] options XPath options.
5324 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5325 */
5326static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005327moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005328{
Michal Vasko79bebfd2019-11-14 16:09:19 +01005329 uint32_t i, j;
Michal Vasko6346ece2019-09-24 13:12:53 +02005330 int replaced;
5331 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005332 const struct lys_module *moveto_mod;
5333 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005334 LY_ERR rc;
5335
5336 if (!set || (set->type == LYXP_SET_EMPTY)) {
5337 return LY_SUCCESS;
5338 }
5339
5340 if (set->type != LYXP_SET_NODE_SET) {
5341 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5342 return LY_EVALID;
5343 }
5344
Michal Vasko6346ece2019-09-24 13:12:53 +02005345 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5346 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005347
5348 /* name */
5349 name_dict = lydict_insert(set->ctx, qname, qname_len);
5350
5351 for (i = 0; i < set->used; ) {
5352 replaced = 0;
5353
5354 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 +01005355 assert(!set->val.nodes[i].node);
5356 /* search in all the trees */
Michal Vasko79bebfd2019-11-14 16:09:19 +01005357 LY_ARRAY_FOR(set->trees, j) {
5358 for (sub = set->trees[j]; sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005359 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005360 if (rc == LY_SUCCESS) {
5361 /* pos filled later */
5362 if (!replaced) {
5363 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5364 replaced = 1;
5365 } else {
5366 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5367 }
5368 ++i;
5369 } else if (rc == LY_EINCOMPLETE) {
5370 lydict_remove(set->ctx, name_dict);
5371 return rc;
5372 }
5373 }
5374 }
5375
Michal Vasko5c4e5892019-11-14 12:31:38 +01005376 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5377 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005378
5379 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005380 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005381 if (rc == LY_SUCCESS) {
5382 if (!replaced) {
5383 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5384 replaced = 1;
5385 } else {
5386 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5387 }
5388 ++i;
5389 } else if (rc == LY_EINCOMPLETE) {
5390 lydict_remove(set->ctx, name_dict);
5391 return rc;
5392 }
5393 }
5394 }
5395
5396 if (!replaced) {
5397 /* no match */
5398 set_remove_node(set, i);
5399 }
5400 }
5401 lydict_remove(set->ctx, name_dict);
5402
5403 return LY_SUCCESS;
5404}
5405
5406/**
5407 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5408 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5409 *
5410 * @param[in,out] set Set to use.
5411 * @param[in] qname Qualified node name to move to.
5412 * @param[in] qname_len Length of @p qname.
5413 * @param[in] options XPath options.
5414 * @return LY_ERR
5415 */
5416static LY_ERR
5417moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5418{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005419 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005420 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005421 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005422 const struct lys_module *moveto_mod;
5423 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005424 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005425
5426 if (!set || (set->type == LYXP_SET_EMPTY)) {
5427 return LY_SUCCESS;
5428 }
5429
5430 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005431 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 +02005432 return LY_EVALID;
5433 }
5434
Michal Vasko6346ece2019-09-24 13:12:53 +02005435 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5436 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005437
5438 /* name */
5439 name_dict = lydict_insert(set->ctx, qname, qname_len);
5440
Michal Vaskocafad9d2019-11-07 15:20:03 +01005441 /* getnext opts */
5442 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5443 if (options & LYXP_SCNODE_OUTPUT) {
5444 getnext_opts |= LYS_GETNEXT_OUTPUT;
5445 }
5446
Michal Vasko03ff5a72019-09-11 13:49:33 +02005447 orig_used = set->used;
5448 for (i = 0; i < orig_used; ++i) {
5449 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005450 if (set->val.scnodes[i].in_ctx != -2) {
5451 continue;
5452 }
5453
5454 /* remember context node */
5455 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005456 } else {
5457 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005458 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005459
5460 start_parent = set->val.scnodes[i].scnode;
5461
5462 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5463 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5464 * so use it directly (root node itself is useless in this case) */
5465 mod_idx = 0;
5466 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5467 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005468 /* module may not be implemented */
5469 while (moveto_mod->implemented && (sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
Michal Vaskocafad9d2019-11-07 15:20:03 +01005470 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005471 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005472 /* we need to prevent these nodes from being considered in this moveto */
5473 if ((idx < orig_used) && (idx > i)) {
5474 set->val.scnodes[idx].in_ctx = 2;
5475 temp_ctx = 1;
5476 }
5477 }
5478 }
5479
5480 if (!mod_idx) {
5481 /* moveto_mod was specified, we are not going through the whole context */
5482 break;
5483 }
5484 /* next iteration */
5485 moveto_mod = NULL;
5486 }
5487
5488 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5489 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5490 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005491 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5492 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005493 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005494 if ((idx < orig_used) && (idx > i)) {
5495 set->val.scnodes[idx].in_ctx = 2;
5496 temp_ctx = 1;
5497 }
5498 }
5499 }
5500 }
5501 }
5502 lydict_remove(set->ctx, name_dict);
5503
5504 /* correct temporary in_ctx values */
5505 if (temp_ctx) {
5506 for (i = 0; i < orig_used; ++i) {
5507 if (set->val.scnodes[i].in_ctx == 2) {
5508 set->val.scnodes[i].in_ctx = 1;
5509 }
5510 }
5511 }
5512
5513 return LY_SUCCESS;
5514}
5515
5516/**
5517 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5518 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5519 * Context position aware.
5520 *
5521 * @param[in] set Set to use.
5522 * @param[in] qname Qualified node name to move to.
5523 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005524 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5525 */
5526static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005527moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005528{
5529 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005530 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005531 const struct lyd_node *next, *elem, *start;
5532 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005533 struct lyxp_set ret_set;
5534 LY_ERR rc;
5535
5536 if (!set || (set->type == LYXP_SET_EMPTY)) {
5537 return LY_SUCCESS;
5538 }
5539
5540 if (set->type != LYXP_SET_NODE_SET) {
5541 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5542 return LY_EVALID;
5543 }
5544
Michal Vasko6346ece2019-09-24 13:12:53 +02005545 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5546 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005547
5548 /* 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 +01005549 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005550 LY_CHECK_RET(rc);
5551
Michal Vasko6346ece2019-09-24 13:12:53 +02005552 /* name */
5553 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005554
Michal Vasko6346ece2019-09-24 13:12:53 +02005555 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005556 set_init(&ret_set, set);
5557 for (i = 0; i < set->used; ++i) {
5558
5559 /* TREE DFS */
5560 start = set->val.nodes[i].node;
5561 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005562 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005563 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005564 /* add matching node into result set */
5565 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5566 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5567 /* the node is a duplicate, we'll process it later in the set */
5568 goto skip_children;
5569 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005570 } else if (rc == LY_EINCOMPLETE) {
5571 lydict_remove(set->ctx, name_dict);
5572 return rc;
5573 } else if (rc == LY_EINVAL) {
5574 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005575 }
5576
5577 /* TREE DFS NEXT ELEM */
5578 /* select element for the next run - children first */
5579 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5580 next = NULL;
5581 } else {
5582 next = lyd_node_children(elem);
5583 }
5584 if (!next) {
5585skip_children:
5586 /* no children, so try siblings, but only if it's not the start,
5587 * that is considered to be the root and it's siblings are not traversed */
5588 if (elem != start) {
5589 next = elem->next;
5590 } else {
5591 break;
5592 }
5593 }
5594 while (!next) {
5595 /* no siblings, go back through the parents */
5596 if ((struct lyd_node *)elem->parent == start) {
5597 /* we are done, no next element to process */
5598 break;
5599 }
5600 /* parent is already processed, go to its sibling */
5601 elem = (struct lyd_node *)elem->parent;
5602 next = elem->next;
5603 }
5604 }
5605 }
5606
5607 /* make the temporary set the current one */
5608 ret_set.ctx_pos = set->ctx_pos;
5609 ret_set.ctx_size = set->ctx_size;
5610 set_free_content(set);
5611 memcpy(set, &ret_set, sizeof *set);
5612
Michal Vasko6346ece2019-09-24 13:12:53 +02005613 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005614 return LY_SUCCESS;
5615}
5616
5617/**
5618 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5619 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5620 *
5621 * @param[in] set Set to use.
5622 * @param[in] qname Qualified node name to move to.
5623 * @param[in] qname_len Length of @p qname.
5624 * @param[in] options XPath options.
5625 * @return LY_ERR
5626 */
5627static LY_ERR
5628moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5629{
Michal Vasko6346ece2019-09-24 13:12:53 +02005630 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005631 const struct lysc_node *next, *elem, *start;
5632 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005633 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005634
5635 if (!set || (set->type == LYXP_SET_EMPTY)) {
5636 return LY_SUCCESS;
5637 }
5638
5639 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005640 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 +02005641 return LY_EVALID;
5642 }
5643
Michal Vasko6346ece2019-09-24 13:12:53 +02005644 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5645 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005646
5647 orig_used = set->used;
5648 for (i = 0; i < orig_used; ++i) {
5649 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005650 if (set->val.scnodes[i].in_ctx != -2) {
5651 continue;
5652 }
5653
5654 /* remember context node */
5655 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005656 } else {
5657 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005658 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005659
5660 /* TREE DFS */
5661 start = set->val.scnodes[i].scnode;
5662 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005663 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5664 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005665 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005666 }
5667
Michal Vaskocafad9d2019-11-07 15:20:03 +01005668 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005669 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005670 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005671 set->val.scnodes[idx].in_ctx = 1;
5672 if (idx > i) {
5673 /* we will process it later in the set */
5674 goto skip_children;
5675 }
5676 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005677 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005678 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005679 } else if (rc == LY_EINVAL) {
5680 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005681 }
5682
5683next_iter:
5684 /* TREE DFS NEXT ELEM */
5685 /* select element for the next run - children first */
5686 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5687 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5688 next = NULL;
5689 }
5690 if (!next) {
5691skip_children:
5692 /* no children, so try siblings, but only if it's not the start,
5693 * that is considered to be the root and it's siblings are not traversed */
5694 if (elem != start) {
5695 next = elem->next;
5696 } else {
5697 break;
5698 }
5699 }
5700 while (!next) {
5701 /* no siblings, go back through the parents */
5702 if (elem->parent == start) {
5703 /* we are done, no next element to process */
5704 break;
5705 }
5706 /* parent is already processed, go to its sibling */
5707 elem = elem->parent;
5708 next = elem->next;
5709 }
5710 }
5711 }
5712
5713 return LY_SUCCESS;
5714}
5715
5716/**
5717 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5718 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5719 * Indirectly context position aware.
5720 *
5721 * @param[in,out] set Set to use.
5722 * @param[in] qname Qualified node name to move to.
5723 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005724 * @return LY_ERR
5725 */
5726static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005727moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005728{
5729 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005730 int replaced, all = 0;
5731 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005732 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005733 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005734
5735 if (!set || (set->type == LYXP_SET_EMPTY)) {
5736 return LY_SUCCESS;
5737 }
5738
5739 if (set->type != LYXP_SET_NODE_SET) {
5740 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5741 return LY_EVALID;
5742 }
5743
Michal Vasko6346ece2019-09-24 13:12:53 +02005744 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5745 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005746
5747 if ((qname_len == 1) && (qname[0] == '*')) {
5748 all = 1;
5749 }
5750
5751 for (i = 0; i < set->used; ) {
5752 replaced = 0;
5753
5754 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5755 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005756 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005757 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5758
5759 /* check "namespace" */
5760 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5761 continue;
5762 }
5763
5764 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5765 /* match */
5766 if (!replaced) {
5767 set->val.attrs[i].attr = sub;
5768 set->val.attrs[i].type = LYXP_NODE_ATTR;
5769 /* pos does not change */
5770 replaced = 1;
5771 } else {
5772 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_ATTR, i + 1);
5773 }
5774 ++i;
5775 }
5776 }
5777 }
5778
5779 if (!replaced) {
5780 /* no match */
5781 set_remove_node(set, i);
5782 }
5783 }
5784
5785 return LY_SUCCESS;
5786}
5787
5788/**
5789 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
5790 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5791 *
5792 * @param[in,out] set1 Set to use for the result.
5793 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005794 * @return LY_ERR
5795 */
5796static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005797moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005798{
5799 LY_ERR rc;
5800
5801 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5802 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5803 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5804 return LY_EVALID;
5805 }
5806
5807 /* set2 is empty or both set1 and set2 */
5808 if (set2->type == LYXP_SET_EMPTY) {
5809 return LY_SUCCESS;
5810 }
5811
5812 if (set1->type == LYXP_SET_EMPTY) {
5813 memcpy(set1, set2, sizeof *set1);
5814 /* dynamic memory belongs to set1 now, do not free */
5815 set2->type = LYXP_SET_EMPTY;
5816 return LY_SUCCESS;
5817 }
5818
5819 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005820 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005821
5822 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005823 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005824 LY_CHECK_RET(rc);
5825
5826 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005827 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005828
5829 return LY_SUCCESS;
5830}
5831
5832/**
5833 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5834 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5835 * Context position aware.
5836 *
5837 * @param[in,out] set Set to use.
5838 * @param[in] qname Qualified node name to move to.
5839 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005840 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5841 */
5842static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005843moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005844{
5845 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005846 int replaced, all = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005847 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005848 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005849 struct lyxp_set *set_all_desc = NULL;
5850 LY_ERR rc;
5851
5852 if (!set || (set->type == LYXP_SET_EMPTY)) {
5853 return LY_SUCCESS;
5854 }
5855
5856 if (set->type != LYXP_SET_NODE_SET) {
5857 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5858 return LY_EVALID;
5859 }
5860
Michal Vasko6346ece2019-09-24 13:12:53 +02005861 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5862 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005863
5864 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5865 * but it likely won't be used much, so it's a waste of time */
5866 /* copy the context */
5867 set_all_desc = set_copy(set);
5868 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005869 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005870 if (rc != LY_SUCCESS) {
5871 lyxp_set_free(set_all_desc);
5872 return rc;
5873 }
5874 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005875 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005876 if (rc != LY_SUCCESS) {
5877 lyxp_set_free(set_all_desc);
5878 return rc;
5879 }
5880 lyxp_set_free(set_all_desc);
5881
5882 if ((qname_len == 1) && (qname[0] == '*')) {
5883 all = 1;
5884 }
5885
5886 for (i = 0; i < set->used; ) {
5887 replaced = 0;
5888
5889 /* only attributes of an elem can be in the result, skip all the rest,
5890 * we have all attributes qualified in lyd tree */
5891 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5892 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5893 /* check "namespace" */
5894 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5895 continue;
5896 }
5897
5898 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5899 /* match */
5900 if (!replaced) {
5901 set->val.attrs[i].attr = sub;
5902 set->val.attrs[i].type = LYXP_NODE_ATTR;
5903 /* pos does not change */
5904 replaced = 1;
5905 } else {
5906 set_insert_node(set, (struct lyd_node *)sub, set->val.attrs[i].pos, LYXP_NODE_ATTR, i + 1);
5907 }
5908 ++i;
5909 }
5910 }
5911 }
5912
5913 if (!replaced) {
5914 /* no match */
5915 set_remove_node(set, i);
5916 }
5917 }
5918
5919 return LY_SUCCESS;
5920}
5921
5922/**
5923 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5924 * (or LYXP_SET_EMPTY). Context position aware.
5925 *
5926 * @param[in] parent Current parent.
5927 * @param[in] parent_pos Position of @p parent.
5928 * @param[in] parent_type Node type of @p parent.
5929 * @param[in,out] to_set Set to use.
5930 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005931 * @param[in] options XPath options.
5932 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5933 */
5934static LY_ERR
5935moveto_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 +01005936 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005937{
5938 const struct lyd_node *sub;
5939 LY_ERR rc;
5940
5941 switch (parent_type) {
5942 case LYXP_NODE_ROOT:
5943 case LYXP_NODE_ROOT_CONFIG:
5944 /* add the same node but as an element */
5945 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5946 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5947
5948 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005949 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005950 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005951 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005952 LY_CHECK_RET(rc);
5953 }
5954 }
5955 break;
5956 case LYXP_NODE_ELEM:
5957 /* add all the children ... */
5958 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5959 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5960 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005961 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005962 continue;
5963 }
5964
Michal Vaskoa1424542019-11-14 16:08:52 +01005965 /* when check */
5966 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005967 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005968 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005969
5970 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5971 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5972
Michal Vasko5c4e5892019-11-14 12:31:38 +01005973 /* skip anydata/anyxml nodes */
5974 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005975 continue;
5976 }
5977
5978 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005979 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005980 LY_CHECK_RET(rc);
5981 }
5982 }
5983
5984 /* ... or add their text node, ... */
5985 } else {
5986 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5987 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5988 }
5989 }
5990 break;
5991 default:
5992 LOGINT_RET(parent->schema->module->ctx);
5993 }
5994
5995 return LY_SUCCESS;
5996}
5997
5998/**
5999 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
6000 * (or LYXP_SET_EMPTY). Context position aware.
6001 *
6002 * @param[in,out] set Set to use.
6003 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6004 * @param[in] options XPath options.
6005 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6006 */
6007static LY_ERR
6008moveto_self(struct lyxp_set *set, int all_desc, int options)
6009{
6010 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006011 struct lyxp_set ret_set;
6012 LY_ERR rc;
6013
6014 if (!set || (set->type == LYXP_SET_EMPTY)) {
6015 return LY_SUCCESS;
6016 }
6017
6018 if (set->type != LYXP_SET_NODE_SET) {
6019 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6020 return LY_EVALID;
6021 }
6022
6023 /* nothing to do */
6024 if (!all_desc) {
6025 return LY_SUCCESS;
6026 }
6027
Michal Vasko03ff5a72019-09-11 13:49:33 +02006028 /* add all the children, they get added recursively */
6029 set_init(&ret_set, set);
6030 for (i = 0; i < set->used; ++i) {
6031 /* copy the current node to tmp */
6032 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6033
6034 /* do not touch attributes and text nodes */
6035 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_ATTR)) {
6036 continue;
6037 }
6038
Michal Vasko5c4e5892019-11-14 12:31:38 +01006039 /* skip anydata/anyxml nodes */
6040 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006041 continue;
6042 }
6043
6044 /* add all the children */
6045 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 +01006046 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006047 if (rc != LY_SUCCESS) {
6048 set_free_content(&ret_set);
6049 return rc;
6050 }
6051 }
6052
6053 /* use the temporary set as the current one */
6054 ret_set.ctx_pos = set->ctx_pos;
6055 ret_set.ctx_size = set->ctx_size;
6056 set_free_content(set);
6057 memcpy(set, &ret_set, sizeof *set);
6058
6059 return LY_SUCCESS;
6060}
6061
6062/**
6063 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6064 * (or LYXP_SET_EMPTY).
6065 *
6066 * @param[in,out] set Set to use.
6067 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6068 * @param[in] options XPath options.
6069 * @return LY_ERR
6070 */
6071static LY_ERR
6072moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6073{
6074 const struct lysc_node *sub;
6075 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006076
6077 if (!set || (set->type == LYXP_SET_EMPTY)) {
6078 return LY_SUCCESS;
6079 }
6080
6081 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006082 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 +02006083 return LY_EVALID;
6084 }
6085
6086 /* nothing to do */
6087 if (!all_desc) {
6088 return LY_SUCCESS;
6089 }
6090
Michal Vasko03ff5a72019-09-11 13:49:33 +02006091 /* add all the children, they get added recursively */
6092 for (i = 0; i < set->used; ++i) {
6093 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006094 if (set->val.scnodes[i].in_ctx != -2) {
6095 continue;
6096 }
6097
6098 /* remember context node (it was traversed again so it changes to a normal node) */
6099 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006100 }
6101
6102 /* add all the children */
6103 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6104 sub = NULL;
6105 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6106 /* RPC input/output check */
6107 if (options & LYXP_SCNODE_OUTPUT) {
6108 if (sub->parent->nodetype == LYS_INPUT) {
6109 continue;
6110 }
6111 } else {
6112 if (sub->parent->nodetype == LYS_OUTPUT) {
6113 continue;
6114 }
6115 }
6116
6117 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006118 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006119 continue;
6120 }
6121
Michal Vaskoecd62de2019-11-13 12:35:11 +01006122 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006123 /* throw away the insert index, we want to consider that node again, recursively */
6124 }
6125 }
6126 }
6127
6128 return LY_SUCCESS;
6129}
6130
6131/**
6132 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6133 * (or LYXP_SET_EMPTY). Context position aware.
6134 *
6135 * @param[in] set Set to use.
6136 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6137 * @param[in] options XPath options.
6138 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6139 */
6140static LY_ERR
6141moveto_parent(struct lyxp_set *set, int all_desc, int options)
6142{
6143 LY_ERR rc;
6144 uint32_t i;
6145 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006146 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006147
6148 if (!set || (set->type == LYXP_SET_EMPTY)) {
6149 return LY_SUCCESS;
6150 }
6151
6152 if (set->type != LYXP_SET_NODE_SET) {
6153 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6154 return LY_EVALID;
6155 }
6156
6157 if (all_desc) {
6158 /* <path>//.. == <path>//./.. */
6159 rc = moveto_self(set, 1, options);
6160 LY_CHECK_RET(rc);
6161 }
6162
Michal Vasko57eab132019-09-24 11:46:26 +02006163 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006164 node = set->val.nodes[i].node;
6165
6166 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6167 new_node = (struct lyd_node *)node->parent;
6168 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6169 new_node = node;
6170 } else if (set->val.nodes[i].type == LYXP_NODE_ATTR) {
6171 new_node = set->val.attrs[i].attr->parent;
6172 if (!new_node) {
6173 LOGINT_RET(set->ctx);
6174 }
6175 } else {
6176 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006177 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006178 continue;
6179 }
6180
Michal Vaskoa1424542019-11-14 16:08:52 +01006181 /* when check */
6182 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006183 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006184 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006185
6186 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006187 if (!new_node) {
6188 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006189
6190 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6191 } else {
6192 new_type = LYXP_NODE_ELEM;
6193 }
6194
Michal Vasko03ff5a72019-09-11 13:49:33 +02006195 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006196 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006197 } else {
6198 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006199 }
6200 }
6201
Michal Vasko2caefc12019-11-14 16:07:56 +01006202 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006203 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006204
6205 return LY_SUCCESS;
6206}
6207
6208/**
6209 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6210 * (or LYXP_SET_EMPTY).
6211 *
6212 * @param[in] set Set to use.
6213 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6214 * @param[in] options XPath options.
6215 * @return LY_ERR
6216 */
6217static LY_ERR
6218moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6219{
6220 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006221 const struct lysc_node *node, *new_node;
6222 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006223 LY_ERR rc;
6224
6225 if (!set || (set->type == LYXP_SET_EMPTY)) {
6226 return LY_SUCCESS;
6227 }
6228
6229 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006230 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 +02006231 return LY_EVALID;
6232 }
6233
6234 if (all_desc) {
6235 /* <path>//.. == <path>//./.. */
6236 rc = moveto_scnode_self(set, 1, options);
6237 LY_CHECK_RET(rc);
6238 }
6239
Michal Vasko03ff5a72019-09-11 13:49:33 +02006240 orig_used = set->used;
6241 for (i = 0; i < orig_used; ++i) {
6242 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006243 if (set->val.scnodes[i].in_ctx != -2) {
6244 continue;
6245 }
6246
6247 /* remember context node */
6248 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006249 } else {
6250 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006251 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006252
6253 node = set->val.scnodes[i].scnode;
6254
6255 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6256 for (new_node = node->parent;
6257 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6258 new_node = new_node->parent);
6259 } else {
6260 /* root does not have a parent */
6261 continue;
6262 }
6263
Michal Vasko03ff5a72019-09-11 13:49:33 +02006264 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006265 if (!new_node) {
6266 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006267
6268 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6269 } else {
6270 new_type = LYXP_NODE_ELEM;
6271 }
6272
Michal Vaskoecd62de2019-11-13 12:35:11 +01006273 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006274 if ((idx < orig_used) && (idx > i)) {
6275 set->val.scnodes[idx].in_ctx = 2;
6276 temp_ctx = 1;
6277 }
6278 }
6279
6280 if (temp_ctx) {
6281 for (i = 0; i < orig_used; ++i) {
6282 if (set->val.scnodes[i].in_ctx == 2) {
6283 set->val.scnodes[i].in_ctx = 1;
6284 }
6285 }
6286 }
6287
6288 return LY_SUCCESS;
6289}
6290
6291/**
6292 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6293 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6294 *
6295 * @param[in,out] set1 Set to use for the result.
6296 * @param[in] set2 Set acting as the second operand for @p op.
6297 * @param[in] op Comparison operator to process.
6298 * @param[in] options XPath options.
6299 * @return LY_ERR
6300 */
6301static LY_ERR
6302moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6303{
6304 /*
6305 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6306 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6307 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6308 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6309 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6310 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6311 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6312 *
6313 * '=' or '!='
6314 * BOOLEAN + BOOLEAN
6315 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6316 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6317 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6318 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6319 * NUMBER + NUMBER
6320 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6321 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6322 * STRING + STRING
6323 *
6324 * '<=', '<', '>=', '>'
6325 * NUMBER + NUMBER
6326 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6327 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6328 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6329 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6330 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6331 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6332 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6333 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6334 */
6335 struct lyxp_set iter1, iter2;
6336 int result;
6337 int64_t i;
6338 LY_ERR rc;
6339
6340 iter1.type = LYXP_SET_EMPTY;
6341
6342 /* empty node-sets are always false */
6343 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6344 set_fill_boolean(set1, 0);
6345 return LY_SUCCESS;
6346 }
6347
6348 /* iterative evaluation with node-sets */
6349 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6350 if (set1->type == LYXP_SET_NODE_SET) {
6351 for (i = 0; i < set1->used; ++i) {
6352 switch (set2->type) {
6353 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006354 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006355 break;
6356 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006357 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006358 break;
6359 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006360 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006361 break;
6362 }
6363 LY_CHECK_RET(rc);
6364
6365 rc = moveto_op_comp(&iter1, set2, op, options);
6366 if (rc != LY_SUCCESS) {
6367 set_free_content(&iter1);
6368 return rc;
6369 }
6370
6371 /* lazy evaluation until true */
6372 if (iter1.val.bool) {
6373 set_fill_boolean(set1, 1);
6374 return LY_SUCCESS;
6375 }
6376 }
6377 } else {
6378 for (i = 0; i < set2->used; ++i) {
6379 switch (set1->type) {
6380 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006381 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006382 break;
6383 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006384 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006385 break;
6386 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006387 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006388 break;
6389 }
6390 LY_CHECK_RET(rc);
6391
6392 set_fill_set(&iter1, set1);
6393
6394 rc = moveto_op_comp(&iter1, &iter2, op, options);
6395 if (rc != LY_SUCCESS) {
6396 set_free_content(&iter1);
6397 set_free_content(&iter2);
6398 return rc;
6399 }
6400 set_free_content(&iter2);
6401
6402 /* lazy evaluation until true */
6403 if (iter1.val.bool) {
6404 set_fill_boolean(set1, 1);
6405 return LY_SUCCESS;
6406 }
6407 }
6408 }
6409
6410 /* false for all nodes */
6411 set_fill_boolean(set1, 0);
6412 return LY_SUCCESS;
6413 }
6414
6415 /* first convert properly */
6416 if ((op[0] == '=') || (op[0] == '!')) {
6417 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006418 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6419 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006420 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006421 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006422 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006423 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006424 LY_CHECK_RET(rc);
6425 } /* else we have 2 strings */
6426 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006427 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006428 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006429 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006430 LY_CHECK_RET(rc);
6431 }
6432
6433 assert(set1->type == set2->type);
6434
6435 /* compute result */
6436 if (op[0] == '=') {
6437 if (set1->type == LYXP_SET_BOOLEAN) {
6438 result = (set1->val.bool == set2->val.bool);
6439 } else if (set1->type == LYXP_SET_NUMBER) {
6440 result = (set1->val.num == set2->val.num);
6441 } else {
6442 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006443 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006444 }
6445 } else if (op[0] == '!') {
6446 if (set1->type == LYXP_SET_BOOLEAN) {
6447 result = (set1->val.bool != set2->val.bool);
6448 } else if (set1->type == LYXP_SET_NUMBER) {
6449 result = (set1->val.num != set2->val.num);
6450 } else {
6451 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006452 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006453 }
6454 } else {
6455 assert(set1->type == LYXP_SET_NUMBER);
6456 if (op[0] == '<') {
6457 if (op[1] == '=') {
6458 result = (set1->val.num <= set2->val.num);
6459 } else {
6460 result = (set1->val.num < set2->val.num);
6461 }
6462 } else {
6463 if (op[1] == '=') {
6464 result = (set1->val.num >= set2->val.num);
6465 } else {
6466 result = (set1->val.num > set2->val.num);
6467 }
6468 }
6469 }
6470
6471 /* assign result */
6472 if (result) {
6473 set_fill_boolean(set1, 1);
6474 } else {
6475 set_fill_boolean(set1, 0);
6476 }
6477
6478 return LY_SUCCESS;
6479}
6480
6481/**
6482 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6483 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6484 *
6485 * @param[in,out] set1 Set to use for the result.
6486 * @param[in] set2 Set acting as the second operand for @p op.
6487 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006488 * @return LY_ERR
6489 */
6490static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006491moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006492{
6493 LY_ERR rc;
6494
6495 /* unary '-' */
6496 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006497 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006498 LY_CHECK_RET(rc);
6499 set1->val.num *= -1;
6500 lyxp_set_free(set2);
6501 return LY_SUCCESS;
6502 }
6503
6504 assert(set1 && set2);
6505
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006506 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006507 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006508 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006509 LY_CHECK_RET(rc);
6510
6511 switch (op[0]) {
6512 /* '+' */
6513 case '+':
6514 set1->val.num += set2->val.num;
6515 break;
6516
6517 /* '-' */
6518 case '-':
6519 set1->val.num -= set2->val.num;
6520 break;
6521
6522 /* '*' */
6523 case '*':
6524 set1->val.num *= set2->val.num;
6525 break;
6526
6527 /* 'div' */
6528 case 'd':
6529 set1->val.num /= set2->val.num;
6530 break;
6531
6532 /* 'mod' */
6533 case 'm':
6534 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6535 break;
6536
6537 default:
6538 LOGINT_RET(set1->ctx);
6539 }
6540
6541 return LY_SUCCESS;
6542}
6543
6544/*
6545 * eval functions
6546 *
6547 * They execute a parsed XPath expression on some data subtree.
6548 */
6549
6550/**
6551 * @brief Evaluate Literal. Logs directly on error.
6552 *
6553 * @param[in] exp Parsed XPath expression.
6554 * @param[in] exp_idx Position in the expression @p exp.
6555 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6556 */
6557static void
6558eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6559{
6560 if (set) {
6561 if (exp->tok_len[*exp_idx] == 2) {
6562 set_fill_string(set, "", 0);
6563 } else {
6564 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6565 }
6566 }
6567 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6568 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6569 ++(*exp_idx);
6570}
6571
6572/**
6573 * @brief Evaluate NodeTest. Logs directly on error.
6574 *
6575 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6576 *
6577 * @param[in] exp Parsed XPath expression.
6578 * @param[in] exp_idx Position in the expression @p exp.
6579 * @param[in] attr_axis Whether to search attributes or standard nodes.
6580 * @param[in] all_desc Whether to search all the descendants or children only.
6581 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6582 * @param[in] options XPath options.
6583 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6584 */
6585static int
6586eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6587 struct lyxp_set *set, int options)
6588{
6589 int i;
6590 char *path;
6591 LY_ERR rc;
6592
6593 switch (exp->tokens[*exp_idx]) {
6594 case LYXP_TOKEN_NAMETEST:
6595 if (attr_axis) {
6596 if (set && (options & LYXP_SCNODE_ALL)) {
6597 set_scnode_clear_ctx(set);
6598 rc = LY_SUCCESS;
6599 } else {
6600 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006601 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006602 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006603 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006604 }
6605 }
6606 } else {
6607 if (all_desc) {
6608 if (set && (options & LYXP_SCNODE_ALL)) {
6609 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6610 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006611 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006612 }
6613 } else {
6614 if (set && (options & LYXP_SCNODE_ALL)) {
6615 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6616 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006617 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006618 }
6619 }
6620
6621 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6622 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006623 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006624 break;
6625 }
6626 }
6627 if (i == -1) {
6628 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6629 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6630 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6631 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6632 free(path);
6633 }
6634 }
6635 }
6636 LY_CHECK_RET(rc);
6637
6638 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6639 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6640 ++(*exp_idx);
6641 break;
6642
6643 case LYXP_TOKEN_NODETYPE:
6644 if (set) {
6645 assert(exp->tok_len[*exp_idx] == 4);
6646 if (set->type == LYXP_SET_SCNODE_SET) {
6647 set_scnode_clear_ctx(set);
6648 /* just for the debug message underneath */
6649 set = NULL;
6650 } else {
6651 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6652 rc = xpath_node(NULL, 0, set, options);
6653 LY_CHECK_RET(rc);
6654 } else {
6655 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6656 rc = xpath_text(NULL, 0, set, options);
6657 LY_CHECK_RET(rc);
6658 }
6659 }
6660 }
6661 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6662 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6663 ++(*exp_idx);
6664
6665 /* '(' */
6666 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6667 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6668 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6669 ++(*exp_idx);
6670
6671 /* ')' */
6672 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6673 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6674 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6675 ++(*exp_idx);
6676 break;
6677
6678 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006679 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006680 }
6681
6682 return LY_SUCCESS;
6683}
6684
6685/**
6686 * @brief Evaluate Predicate. Logs directly on error.
6687 *
6688 * [7] Predicate ::= '[' Expr ']'
6689 *
6690 * @param[in] exp Parsed XPath expression.
6691 * @param[in] exp_idx Position in the expression @p exp.
6692 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6693 * @param[in] options XPath options.
6694 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6695 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6696 */
6697static LY_ERR
6698eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6699{
6700 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006701 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006702 uint32_t orig_pos, orig_size;
6703 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006704 struct lyxp_set set2;
6705 struct lyd_node *orig_parent;
6706
6707 /* '[' */
6708 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6709 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6710 ++(*exp_idx);
6711
6712 if (!set) {
6713only_parse:
6714 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6715 LY_CHECK_RET(rc);
6716 } else if (set->type == LYXP_SET_NODE_SET) {
6717 /* 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 +01006718 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006719
6720 /* empty set, nothing to evaluate */
6721 if (!set->used) {
6722 goto only_parse;
6723 }
6724
6725 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006726 orig_pos = 0;
6727 orig_size = set->used;
6728 orig_parent = NULL;
6729 for (i = 0; i < set->used; ) {
6730 set_init(&set2, set);
6731 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6732 /* remember the node context position for position() and context size for last(),
6733 * predicates should always be evaluated with respect to the child axis (since we do
6734 * not support explicit axes) so we assign positions based on their parents */
6735 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6736 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6737 orig_pos = 1;
6738 } else {
6739 ++orig_pos;
6740 }
6741
6742 set2.ctx_pos = orig_pos;
6743 set2.ctx_size = orig_size;
6744 *exp_idx = orig_exp;
6745
6746 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6747 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006748 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006749 return rc;
6750 }
6751
6752 /* number is a position */
6753 if (set2.type == LYXP_SET_NUMBER) {
6754 if ((long long)set2.val.num == orig_pos) {
6755 set2.val.num = 1;
6756 } else {
6757 set2.val.num = 0;
6758 }
6759 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006760 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006761
6762 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006763 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006764 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006765 }
6766 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006767 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006768
6769 } else if (set->type == LYXP_SET_SCNODE_SET) {
6770 for (i = 0; i < set->used; ++i) {
6771 if (set->val.scnodes[i].in_ctx == 1) {
6772 /* there is a currently-valid node */
6773 break;
6774 }
6775 }
6776 /* empty set, nothing to evaluate */
6777 if (i == set->used) {
6778 goto only_parse;
6779 }
6780
6781 orig_exp = *exp_idx;
6782
Michal Vasko03ff5a72019-09-11 13:49:33 +02006783 /* set special in_ctx to all the valid snodes */
6784 pred_in_ctx = set_scnode_new_in_ctx(set);
6785
6786 /* use the valid snodes one-by-one */
6787 for (i = 0; i < set->used; ++i) {
6788 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6789 continue;
6790 }
6791 set->val.scnodes[i].in_ctx = 1;
6792
6793 *exp_idx = orig_exp;
6794
6795 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6796 LY_CHECK_RET(rc);
6797
6798 set->val.scnodes[i].in_ctx = pred_in_ctx;
6799 }
6800
6801 /* restore the state as it was before the predicate */
6802 for (i = 0; i < set->used; ++i) {
6803 if (set->val.scnodes[i].in_ctx == 1) {
6804 set->val.scnodes[i].in_ctx = 0;
6805 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6806 set->val.scnodes[i].in_ctx = 1;
6807 }
6808 }
6809
6810 } else {
6811 set2.type = LYXP_SET_EMPTY;
6812 set_fill_set(&set2, set);
6813
6814 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6815 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006816 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006817 return rc;
6818 }
6819
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006820 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006821 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006822 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006823 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006824 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006825 }
6826
6827 /* ']' */
6828 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6829 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6830 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6831 ++(*exp_idx);
6832
6833 return LY_SUCCESS;
6834}
6835
6836/**
6837 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6838 *
6839 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6840 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6841 *
6842 * @param[in] exp Parsed XPath expression.
6843 * @param[in] exp_idx Position in the expression @p exp.
6844 * @param[in] all_desc Whether to search all the descendants or children only.
6845 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6846 * @param[in] options XPath options.
6847 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6848 */
6849static LY_ERR
6850eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6851{
6852 int attr_axis;
6853 LY_ERR rc;
6854
6855 goto step;
6856 do {
6857 /* evaluate '/' or '//' */
6858 if (exp->tok_len[*exp_idx] == 1) {
6859 all_desc = 0;
6860 } else {
6861 assert(exp->tok_len[*exp_idx] == 2);
6862 all_desc = 1;
6863 }
6864 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6865 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6866 ++(*exp_idx);
6867
6868step:
6869 /* Step */
6870 attr_axis = 0;
6871 switch (exp->tokens[*exp_idx]) {
6872 case LYXP_TOKEN_DOT:
6873 /* evaluate '.' */
6874 if (set && (options & LYXP_SCNODE_ALL)) {
6875 rc = moveto_scnode_self(set, all_desc, options);
6876 } else {
6877 rc = moveto_self(set, all_desc, options);
6878 }
6879 LY_CHECK_RET(rc);
6880 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6881 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6882 ++(*exp_idx);
6883 break;
6884
6885 case LYXP_TOKEN_DDOT:
6886 /* evaluate '..' */
6887 if (set && (options & LYXP_SCNODE_ALL)) {
6888 rc = moveto_scnode_parent(set, all_desc, options);
6889 } else {
6890 rc = moveto_parent(set, all_desc, options);
6891 }
6892 LY_CHECK_RET(rc);
6893 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6894 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6895 ++(*exp_idx);
6896 break;
6897
6898 case LYXP_TOKEN_AT:
6899 /* evaluate '@' */
6900 attr_axis = 1;
6901 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6902 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6903 ++(*exp_idx);
6904
6905 /* fall through */
6906 case LYXP_TOKEN_NAMETEST:
6907 case LYXP_TOKEN_NODETYPE:
6908 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6909 LY_CHECK_RET(rc);
6910
6911 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6912 rc = eval_predicate(exp, exp_idx, set, options, 1);
6913 LY_CHECK_RET(rc);
6914 }
6915 break;
6916
6917 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006918 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006919 }
6920 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6921
6922 return LY_SUCCESS;
6923}
6924
6925/**
6926 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6927 *
6928 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6929 *
6930 * @param[in] exp Parsed XPath expression.
6931 * @param[in] exp_idx Position in the expression @p exp.
6932 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6933 * @param[in] options XPath options.
6934 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6935 */
6936static LY_ERR
6937eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6938{
6939 int all_desc;
6940 LY_ERR rc;
6941
6942 if (set) {
6943 /* no matter what tokens follow, we need to be at the root */
6944 moveto_root(set, options);
6945 }
6946
6947 /* '/' RelativeLocationPath? */
6948 if (exp->tok_len[*exp_idx] == 1) {
6949 /* evaluate '/' - deferred */
6950 all_desc = 0;
6951 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6952 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6953 ++(*exp_idx);
6954
Michal Vasko4b9e1052019-09-13 11:25:37 +02006955 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006956 return LY_SUCCESS;
6957 }
6958 switch (exp->tokens[*exp_idx]) {
6959 case LYXP_TOKEN_DOT:
6960 case LYXP_TOKEN_DDOT:
6961 case LYXP_TOKEN_AT:
6962 case LYXP_TOKEN_NAMETEST:
6963 case LYXP_TOKEN_NODETYPE:
6964 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6965 LY_CHECK_RET(rc);
6966 break;
6967 default:
6968 break;
6969 }
6970
6971 /* '//' RelativeLocationPath */
6972 } else {
6973 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6974 all_desc = 1;
6975 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6976 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6977 ++(*exp_idx);
6978
6979 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6980 LY_CHECK_RET(rc);
6981 }
6982
6983 return LY_SUCCESS;
6984}
6985
6986/**
6987 * @brief Evaluate FunctionCall. Logs directly on error.
6988 *
6989 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6990 *
6991 * @param[in] exp Parsed XPath expression.
6992 * @param[in] exp_idx Position in the expression @p exp.
6993 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6994 * @param[in] options XPath options.
6995 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6996 */
6997static LY_ERR
6998eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6999{
7000 LY_ERR rc;
7001 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007002 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007003 struct lyxp_set **args = NULL, **args_aux;
7004
7005 if (set) {
7006 /* FunctionName */
7007 switch (exp->tok_len[*exp_idx]) {
7008 case 3:
7009 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7010 xpath_func = &xpath_not;
7011 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7012 xpath_func = &xpath_sum;
7013 }
7014 break;
7015 case 4:
7016 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7017 xpath_func = &xpath_lang;
7018 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7019 xpath_func = &xpath_last;
7020 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7021 xpath_func = &xpath_name;
7022 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7023 xpath_func = &xpath_true;
7024 }
7025 break;
7026 case 5:
7027 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7028 xpath_func = &xpath_count;
7029 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7030 xpath_func = &xpath_false;
7031 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7032 xpath_func = &xpath_floor;
7033 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7034 xpath_func = &xpath_round;
7035 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7036 xpath_func = &xpath_deref;
7037 }
7038 break;
7039 case 6:
7040 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7041 xpath_func = &xpath_concat;
7042 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7043 xpath_func = &xpath_number;
7044 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7045 xpath_func = &xpath_string;
7046 }
7047 break;
7048 case 7:
7049 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7050 xpath_func = &xpath_boolean;
7051 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7052 xpath_func = &xpath_ceiling;
7053 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7054 xpath_func = &xpath_current;
7055 }
7056 break;
7057 case 8:
7058 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7059 xpath_func = &xpath_contains;
7060 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7061 xpath_func = &xpath_position;
7062 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7063 xpath_func = &xpath_re_match;
7064 }
7065 break;
7066 case 9:
7067 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7068 xpath_func = &xpath_substring;
7069 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7070 xpath_func = &xpath_translate;
7071 }
7072 break;
7073 case 10:
7074 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7075 xpath_func = &xpath_local_name;
7076 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7077 xpath_func = &xpath_enum_value;
7078 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7079 xpath_func = &xpath_bit_is_set;
7080 }
7081 break;
7082 case 11:
7083 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7084 xpath_func = &xpath_starts_with;
7085 }
7086 break;
7087 case 12:
7088 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7089 xpath_func = &xpath_derived_from;
7090 }
7091 break;
7092 case 13:
7093 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7094 xpath_func = &xpath_namespace_uri;
7095 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7096 xpath_func = &xpath_string_length;
7097 }
7098 break;
7099 case 15:
7100 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7101 xpath_func = &xpath_normalize_space;
7102 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7103 xpath_func = &xpath_substring_after;
7104 }
7105 break;
7106 case 16:
7107 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7108 xpath_func = &xpath_substring_before;
7109 }
7110 break;
7111 case 20:
7112 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7113 xpath_func = &xpath_derived_from_or_self;
7114 }
7115 break;
7116 }
7117
7118 if (!xpath_func) {
7119 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7120 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]]);
7121 return LY_EVALID;
7122 }
7123 }
7124
7125 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7126 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7127 ++(*exp_idx);
7128
7129 /* '(' */
7130 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7131 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7132 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7133 ++(*exp_idx);
7134
7135 /* ( Expr ( ',' Expr )* )? */
7136 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7137 if (set) {
7138 args = malloc(sizeof *args);
7139 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7140 arg_count = 1;
7141 args[0] = set_copy(set);
7142 if (!args[0]) {
7143 rc = LY_EMEM;
7144 goto cleanup;
7145 }
7146
7147 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7148 LY_CHECK_GOTO(rc, cleanup);
7149 } else {
7150 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7151 LY_CHECK_GOTO(rc, cleanup);
7152 }
7153 }
7154 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7155 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7156 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7157 ++(*exp_idx);
7158
7159 if (set) {
7160 ++arg_count;
7161 args_aux = realloc(args, arg_count * sizeof *args);
7162 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7163 args = args_aux;
7164 args[arg_count - 1] = set_copy(set);
7165 if (!args[arg_count - 1]) {
7166 rc = LY_EMEM;
7167 goto cleanup;
7168 }
7169
7170 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7171 LY_CHECK_GOTO(rc, cleanup);
7172 } else {
7173 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7174 LY_CHECK_GOTO(rc, cleanup);
7175 }
7176 }
7177
7178 /* ')' */
7179 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7180 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7181 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7182 ++(*exp_idx);
7183
7184 if (set) {
7185 /* evaluate function */
7186 rc = xpath_func(args, arg_count, set, options);
7187
7188 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007189 /* merge all nodes from arg evaluations */
7190 for (i = 0; i < arg_count; ++i) {
7191 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007192 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007193 }
7194 }
7195 } else {
7196 rc = LY_SUCCESS;
7197 }
7198
7199cleanup:
7200 for (i = 0; i < arg_count; ++i) {
7201 lyxp_set_free(args[i]);
7202 }
7203 free(args);
7204
7205 return rc;
7206}
7207
7208/**
7209 * @brief Evaluate Number. Logs directly on error.
7210 *
7211 * @param[in] ctx Context for errors.
7212 * @param[in] exp Parsed XPath expression.
7213 * @param[in] exp_idx Position in the expression @p exp.
7214 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7215 * @return LY_ERR
7216 */
7217static LY_ERR
7218eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7219{
7220 long double num;
7221 char *endptr;
7222
7223 if (set) {
7224 errno = 0;
7225 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7226 if (errno) {
7227 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7228 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7229 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7230 return LY_EVALID;
7231 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7232 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7233 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7234 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7235 return LY_EVALID;
7236 }
7237
7238 set_fill_number(set, num);
7239 }
7240
7241 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7242 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7243 ++(*exp_idx);
7244 return LY_SUCCESS;
7245}
7246
7247/**
7248 * @brief Evaluate PathExpr. Logs directly on error.
7249 *
7250 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7251 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7252 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7253 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7254 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7255 *
7256 * @param[in] exp Parsed XPath expression.
7257 * @param[in] exp_idx Position in the expression @p exp.
7258 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7259 * @param[in] options XPath options.
7260 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7261 */
7262static LY_ERR
7263eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7264{
7265 int all_desc, parent_pos_pred;
7266 LY_ERR rc;
7267
7268 switch (exp->tokens[*exp_idx]) {
7269 case LYXP_TOKEN_PAR1:
7270 /* '(' Expr ')' */
7271
7272 /* '(' */
7273 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7274 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7275 ++(*exp_idx);
7276
7277 /* Expr */
7278 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7279 LY_CHECK_RET(rc);
7280
7281 /* ')' */
7282 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7283 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7284 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7285 ++(*exp_idx);
7286
7287 parent_pos_pred = 0;
7288 goto predicate;
7289
7290 case LYXP_TOKEN_DOT:
7291 case LYXP_TOKEN_DDOT:
7292 case LYXP_TOKEN_AT:
7293 case LYXP_TOKEN_NAMETEST:
7294 case LYXP_TOKEN_NODETYPE:
7295 /* RelativeLocationPath */
7296 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7297 LY_CHECK_RET(rc);
7298 break;
7299
7300 case LYXP_TOKEN_FUNCNAME:
7301 /* FunctionCall */
7302 if (!set) {
7303 rc = eval_function_call(exp, exp_idx, NULL, options);
7304 } else {
7305 rc = eval_function_call(exp, exp_idx, set, options);
7306 }
7307 LY_CHECK_RET(rc);
7308
7309 parent_pos_pred = 1;
7310 goto predicate;
7311
7312 case LYXP_TOKEN_OPERATOR_PATH:
7313 /* AbsoluteLocationPath */
7314 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7315 LY_CHECK_RET(rc);
7316 break;
7317
7318 case LYXP_TOKEN_LITERAL:
7319 /* Literal */
7320 if (!set || (options & LYXP_SCNODE_ALL)) {
7321 if (set) {
7322 set_scnode_clear_ctx(set);
7323 }
7324 eval_literal(exp, exp_idx, NULL);
7325 } else {
7326 eval_literal(exp, exp_idx, set);
7327 }
7328
7329 parent_pos_pred = 1;
7330 goto predicate;
7331
7332 case LYXP_TOKEN_NUMBER:
7333 /* Number */
7334 if (!set || (options & LYXP_SCNODE_ALL)) {
7335 if (set) {
7336 set_scnode_clear_ctx(set);
7337 }
Michal Vasko02a77382019-09-12 11:47:35 +02007338 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007339 } else {
7340 rc = eval_number(set->ctx, exp, exp_idx, set);
7341 }
7342 LY_CHECK_RET(rc);
7343
7344 parent_pos_pred = 1;
7345 goto predicate;
7346
7347 default:
7348 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7349 &exp->expr[exp->tok_pos[*exp_idx]]);
7350 return LY_EVALID;
7351 }
7352
7353 return LY_SUCCESS;
7354
7355predicate:
7356 /* Predicate* */
7357 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7358 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7359 LY_CHECK_RET(rc);
7360 }
7361
7362 /* ('/' or '//') RelativeLocationPath */
7363 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7364
7365 /* evaluate '/' or '//' */
7366 if (exp->tok_len[*exp_idx] == 1) {
7367 all_desc = 0;
7368 } else {
7369 assert(exp->tok_len[*exp_idx] == 2);
7370 all_desc = 1;
7371 }
7372
7373 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7374 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7375 ++(*exp_idx);
7376
7377 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7378 LY_CHECK_RET(rc);
7379 }
7380
7381 return LY_SUCCESS;
7382}
7383
7384/**
7385 * @brief Evaluate UnionExpr. Logs directly on error.
7386 *
7387 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7388 *
7389 * @param[in] exp Parsed XPath expression.
7390 * @param[in] exp_idx Position in the expression @p exp.
7391 * @param[in] repeat How many times this expression is repeated.
7392 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7393 * @param[in] options XPath options.
7394 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7395 */
7396static LY_ERR
7397eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7398{
7399 LY_ERR rc = LY_SUCCESS;
7400 struct lyxp_set orig_set, set2;
7401 uint16_t i;
7402
7403 assert(repeat);
7404
7405 set_init(&orig_set, set);
7406 set_init(&set2, set);
7407
7408 set_fill_set(&orig_set, set);
7409
7410 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7411 LY_CHECK_GOTO(rc, cleanup);
7412
7413 /* ('|' PathExpr)* */
7414 for (i = 0; i < repeat; ++i) {
7415 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7416 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7417 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7418 ++(*exp_idx);
7419
7420 if (!set) {
7421 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7422 LY_CHECK_GOTO(rc, cleanup);
7423 continue;
7424 }
7425
7426 set_fill_set(&set2, &orig_set);
7427 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7428 LY_CHECK_GOTO(rc, cleanup);
7429
7430 /* eval */
7431 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007432 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007433 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007434 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007435 LY_CHECK_GOTO(rc, cleanup);
7436 }
7437 }
7438
7439cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007440 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7441 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007442 return rc;
7443}
7444
7445/**
7446 * @brief Evaluate UnaryExpr. Logs directly on error.
7447 *
7448 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7449 *
7450 * @param[in] exp Parsed XPath expression.
7451 * @param[in] exp_idx Position in the expression @p exp.
7452 * @param[in] repeat How many times this expression is repeated.
7453 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7454 * @param[in] options XPath options.
7455 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7456 */
7457static LY_ERR
7458eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7459{
7460 LY_ERR rc;
7461 uint16_t this_op, i;
7462
7463 assert(repeat);
7464
7465 /* ('-')+ */
7466 this_op = *exp_idx;
7467 for (i = 0; i < repeat; ++i) {
7468 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7469
7470 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7471 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7472 ++(*exp_idx);
7473 }
7474
7475 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7476 LY_CHECK_RET(rc);
7477
7478 if (set && (repeat % 2)) {
7479 if (options & LYXP_SCNODE_ALL) {
7480 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7481 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007482 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007483 LY_CHECK_RET(rc);
7484 }
7485 }
7486
7487 return LY_SUCCESS;
7488}
7489
7490/**
7491 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7492 *
7493 * [16] MultiplicativeExpr ::= UnaryExpr
7494 * | MultiplicativeExpr '*' UnaryExpr
7495 * | MultiplicativeExpr 'div' UnaryExpr
7496 * | MultiplicativeExpr 'mod' UnaryExpr
7497 *
7498 * @param[in] exp Parsed XPath expression.
7499 * @param[in] exp_idx Position in the expression @p exp.
7500 * @param[in] repeat How many times this expression is repeated.
7501 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7502 * @param[in] options XPath options.
7503 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7504 */
7505static LY_ERR
7506eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7507{
7508 LY_ERR rc;
7509 uint16_t this_op;
7510 struct lyxp_set orig_set, set2;
7511 uint16_t i;
7512
7513 assert(repeat);
7514
7515 set_init(&orig_set, set);
7516 set_init(&set2, set);
7517
7518 set_fill_set(&orig_set, set);
7519
7520 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7521 LY_CHECK_GOTO(rc, cleanup);
7522
7523 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7524 for (i = 0; i < repeat; ++i) {
7525 this_op = *exp_idx;
7526
7527 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7528 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7529 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7530 ++(*exp_idx);
7531
7532 if (!set) {
7533 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7534 LY_CHECK_GOTO(rc, cleanup);
7535 continue;
7536 }
7537
7538 set_fill_set(&set2, &orig_set);
7539 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7540 LY_CHECK_GOTO(rc, cleanup);
7541
7542 /* eval */
7543 if (options & LYXP_SCNODE_ALL) {
7544 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007545 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007546 set_scnode_clear_ctx(set);
7547 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007548 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007549 LY_CHECK_GOTO(rc, cleanup);
7550 }
7551 }
7552
7553cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007554 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7555 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007556 return rc;
7557}
7558
7559/**
7560 * @brief Evaluate AdditiveExpr. Logs directly on error.
7561 *
7562 * [15] AdditiveExpr ::= MultiplicativeExpr
7563 * | AdditiveExpr '+' MultiplicativeExpr
7564 * | AdditiveExpr '-' MultiplicativeExpr
7565 *
7566 * @param[in] exp Parsed XPath expression.
7567 * @param[in] exp_idx Position in the expression @p exp.
7568 * @param[in] repeat How many times this expression is repeated.
7569 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7570 * @param[in] options XPath options.
7571 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7572 */
7573static LY_ERR
7574eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7575{
7576 LY_ERR rc;
7577 uint16_t this_op;
7578 struct lyxp_set orig_set, set2;
7579 uint16_t i;
7580
7581 assert(repeat);
7582
7583 set_init(&orig_set, set);
7584 set_init(&set2, set);
7585
7586 set_fill_set(&orig_set, set);
7587
7588 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7589 LY_CHECK_GOTO(rc, cleanup);
7590
7591 /* ('+' / '-' MultiplicativeExpr)* */
7592 for (i = 0; i < repeat; ++i) {
7593 this_op = *exp_idx;
7594
7595 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7596 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7597 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7598 ++(*exp_idx);
7599
7600 if (!set) {
7601 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7602 LY_CHECK_GOTO(rc, cleanup);
7603 continue;
7604 }
7605
7606 set_fill_set(&set2, &orig_set);
7607 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7608 LY_CHECK_GOTO(rc, cleanup);
7609
7610 /* eval */
7611 if (options & LYXP_SCNODE_ALL) {
7612 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007613 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007614 set_scnode_clear_ctx(set);
7615 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007616 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007617 LY_CHECK_GOTO(rc, cleanup);
7618 }
7619 }
7620
7621cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007622 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7623 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007624 return rc;
7625}
7626
7627/**
7628 * @brief Evaluate RelationalExpr. Logs directly on error.
7629 *
7630 * [14] RelationalExpr ::= AdditiveExpr
7631 * | RelationalExpr '<' AdditiveExpr
7632 * | RelationalExpr '>' AdditiveExpr
7633 * | RelationalExpr '<=' AdditiveExpr
7634 * | RelationalExpr '>=' AdditiveExpr
7635 *
7636 * @param[in] exp Parsed XPath expression.
7637 * @param[in] exp_idx Position in the expression @p exp.
7638 * @param[in] repeat How many times this expression is repeated.
7639 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7640 * @param[in] options XPath options.
7641 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7642 */
7643static LY_ERR
7644eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7645{
7646 LY_ERR rc;
7647 uint16_t this_op;
7648 struct lyxp_set orig_set, set2;
7649 uint16_t i;
7650
7651 assert(repeat);
7652
7653 set_init(&orig_set, set);
7654 set_init(&set2, set);
7655
7656 set_fill_set(&orig_set, set);
7657
7658 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7659 LY_CHECK_GOTO(rc, cleanup);
7660
7661 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7662 for (i = 0; i < repeat; ++i) {
7663 this_op = *exp_idx;
7664
7665 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7666 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7667 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7668 ++(*exp_idx);
7669
7670 if (!set) {
7671 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7672 LY_CHECK_GOTO(rc, cleanup);
7673 continue;
7674 }
7675
7676 set_fill_set(&set2, &orig_set);
7677 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7678 LY_CHECK_GOTO(rc, cleanup);
7679
7680 /* eval */
7681 if (options & LYXP_SCNODE_ALL) {
7682 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007683 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007684 set_scnode_clear_ctx(set);
7685 } else {
7686 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7687 LY_CHECK_GOTO(rc, cleanup);
7688 }
7689 }
7690
7691cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007692 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7693 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007694 return rc;
7695}
7696
7697/**
7698 * @brief Evaluate EqualityExpr. Logs directly on error.
7699 *
7700 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7701 * | EqualityExpr '!=' RelationalExpr
7702 *
7703 * @param[in] exp Parsed XPath expression.
7704 * @param[in] exp_idx Position in the expression @p exp.
7705 * @param[in] repeat How many times this expression is repeated.
7706 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7707 * @param[in] options XPath options.
7708 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7709 */
7710static LY_ERR
7711eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7712{
7713 LY_ERR rc;
7714 uint16_t this_op;
7715 struct lyxp_set orig_set, set2;
7716 uint16_t i;
7717
7718 assert(repeat);
7719
7720 set_init(&orig_set, set);
7721 set_init(&set2, set);
7722
7723 set_fill_set(&orig_set, set);
7724
7725 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7726 LY_CHECK_GOTO(rc, cleanup);
7727
7728 /* ('=' / '!=' RelationalExpr)* */
7729 for (i = 0; i < repeat; ++i) {
7730 this_op = *exp_idx;
7731
7732 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7733 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7734 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7735 ++(*exp_idx);
7736
7737 if (!set) {
7738 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7739 LY_CHECK_GOTO(rc, cleanup);
7740 continue;
7741 }
7742
7743 set_fill_set(&set2, &orig_set);
7744 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7745 LY_CHECK_GOTO(rc, cleanup);
7746
7747 /* eval */
7748 if (options & LYXP_SCNODE_ALL) {
7749 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7750 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7751 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007752 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007753 set_scnode_clear_ctx(set);
7754 } else {
7755 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7756 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7757 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7758 /* left operand is identityref */
7759 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7760 /* missing prefix in the right operand */
7761 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7762 if (!set2.val.str) {
7763 goto cleanup;
7764 }
7765
7766 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7767 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7768 set2.val.str[strlen(set->local_mod->name)] = ':';
7769 }
7770 }
7771
7772 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7773 LY_CHECK_GOTO(rc, cleanup);
7774 }
7775 }
7776
7777cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007778 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7779 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007780 return rc;
7781}
7782
7783/**
7784 * @brief Evaluate AndExpr. Logs directly on error.
7785 *
7786 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7787 *
7788 * @param[in] exp Parsed XPath expression.
7789 * @param[in] exp_idx Position in the expression @p exp.
7790 * @param[in] repeat How many times this expression is repeated.
7791 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7792 * @param[in] options XPath options.
7793 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7794 */
7795static LY_ERR
7796eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7797{
7798 LY_ERR rc;
7799 struct lyxp_set orig_set, set2;
7800 uint16_t i;
7801
7802 assert(repeat);
7803
7804 set_init(&orig_set, set);
7805 set_init(&set2, set);
7806
7807 set_fill_set(&orig_set, set);
7808
7809 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7810 LY_CHECK_GOTO(rc, cleanup);
7811
7812 /* cast to boolean, we know that will be the final result */
7813 if (set && (options & LYXP_SCNODE_ALL)) {
7814 set_scnode_clear_ctx(set);
7815 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007816 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007817 }
7818
7819 /* ('and' EqualityExpr)* */
7820 for (i = 0; i < repeat; ++i) {
7821 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7822 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7823 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7824 ++(*exp_idx);
7825
7826 /* lazy evaluation */
7827 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7828 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7829 LY_CHECK_GOTO(rc, cleanup);
7830 continue;
7831 }
7832
7833 set_fill_set(&set2, &orig_set);
7834 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7835 LY_CHECK_GOTO(rc, cleanup);
7836
7837 /* eval - just get boolean value actually */
7838 if (set->type == LYXP_SET_SCNODE_SET) {
7839 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007840 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007841 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007842 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007843 set_fill_set(set, &set2);
7844 }
7845 }
7846
7847cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007848 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7849 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007850 return rc;
7851}
7852
7853/**
7854 * @brief Evaluate OrExpr. Logs directly on error.
7855 *
7856 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7857 *
7858 * @param[in] exp Parsed XPath expression.
7859 * @param[in] exp_idx Position in the expression @p exp.
7860 * @param[in] repeat How many times this expression is repeated.
7861 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7862 * @param[in] options XPath options.
7863 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7864 */
7865static LY_ERR
7866eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7867{
7868 LY_ERR rc;
7869 struct lyxp_set orig_set, set2;
7870 uint16_t i;
7871
7872 assert(repeat);
7873
7874 set_init(&orig_set, set);
7875 set_init(&set2, set);
7876
7877 set_fill_set(&orig_set, set);
7878
7879 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7880 LY_CHECK_GOTO(rc, cleanup);
7881
7882 /* cast to boolean, we know that will be the final result */
7883 if (set && (options & LYXP_SCNODE_ALL)) {
7884 set_scnode_clear_ctx(set);
7885 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007886 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007887 }
7888
7889 /* ('or' AndExpr)* */
7890 for (i = 0; i < repeat; ++i) {
7891 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7892 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7893 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7894 ++(*exp_idx);
7895
7896 /* lazy evaluation */
7897 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7898 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7899 LY_CHECK_GOTO(rc, cleanup);
7900 continue;
7901 }
7902
7903 set_fill_set(&set2, &orig_set);
7904 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7905 * but it does not matter */
7906 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7907 LY_CHECK_GOTO(rc, cleanup);
7908
7909 /* eval - just get boolean value actually */
7910 if (set->type == LYXP_SET_SCNODE_SET) {
7911 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007912 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007913 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007914 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007915 set_fill_set(set, &set2);
7916 }
7917 }
7918
7919cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007920 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7921 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007922 return rc;
7923}
7924
7925/**
7926 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7927 *
7928 * @param[in] exp Parsed XPath expression.
7929 * @param[in] exp_idx Position in the expression @p exp.
7930 * @param[in] etype Expression type to evaluate.
7931 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7932 * @param[in] options XPath options.
7933 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7934 */
7935static LY_ERR
7936eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7937{
7938 uint16_t i, count;
7939 enum lyxp_expr_type next_etype;
7940 LY_ERR rc;
7941
7942 /* process operator repeats */
7943 if (!exp->repeat[*exp_idx]) {
7944 next_etype = LYXP_EXPR_NONE;
7945 } else {
7946 /* find etype repeat */
7947 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7948
7949 /* select one-priority lower because etype expression called us */
7950 if (i) {
7951 next_etype = exp->repeat[*exp_idx][i - 1];
7952 /* count repeats for that expression */
7953 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7954 } else {
7955 next_etype = LYXP_EXPR_NONE;
7956 }
7957 }
7958
7959 /* decide what expression are we parsing based on the repeat */
7960 switch (next_etype) {
7961 case LYXP_EXPR_OR:
7962 rc = eval_or_expr(exp, exp_idx, count, set, options);
7963 break;
7964 case LYXP_EXPR_AND:
7965 rc = eval_and_expr(exp, exp_idx, count, set, options);
7966 break;
7967 case LYXP_EXPR_EQUALITY:
7968 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7969 break;
7970 case LYXP_EXPR_RELATIONAL:
7971 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7972 break;
7973 case LYXP_EXPR_ADDITIVE:
7974 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7975 break;
7976 case LYXP_EXPR_MULTIPLICATIVE:
7977 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7978 break;
7979 case LYXP_EXPR_UNARY:
7980 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7981 break;
7982 case LYXP_EXPR_UNION:
7983 rc = eval_union_expr(exp, exp_idx, count, set, options);
7984 break;
7985 case LYXP_EXPR_NONE:
7986 rc = eval_path_expr(exp, exp_idx, set, options);
7987 break;
7988 default:
7989 LOGINT_RET(set->ctx);
7990 }
7991
7992 return rc;
7993}
7994
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007995/**
7996 * @brief Get root type.
7997 *
7998 * @param[in] ctx_node Context node.
7999 * @param[in] ctx_scnode Schema context node.
8000 * @param[in] options XPath options.
8001 * @return Root type.
8002 */
8003static enum lyxp_node_type
8004lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8005{
8006 if (options & LYXP_SCNODE_ALL) {
8007 if (options & LYXP_SCNODE) {
8008 /* general root that can access everything */
8009 return LYXP_NODE_ROOT;
8010 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8011 /* root context node can access only config data (because we said so, it is unspecified) */
8012 return LYXP_NODE_ROOT_CONFIG;
8013 } else {
8014 return LYXP_NODE_ROOT;
8015 }
8016 }
8017
8018 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8019 /* root context node can access only config data (because we said so, it is unspecified) */
8020 return LYXP_NODE_ROOT_CONFIG;
8021 }
8022
8023 return LYXP_NODE_ROOT;
8024}
8025
Michal Vasko03ff5a72019-09-11 13:49:33 +02008026LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008027lyxp_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 +02008028 enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
8029{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008030 uint16_t exp_idx = 0;
8031 LY_ERR rc;
8032
Michal Vaskoecd62de2019-11-13 12:35:11 +01008033 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008034
8035 /* prepare set for evaluation */
8036 exp_idx = 0;
8037 memset(set, 0, sizeof *set);
8038 set->type = LYXP_SET_EMPTY;
Michal Vasko9b368d32020-02-14 13:53:31 +01008039 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, 0);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008040 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008041 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008042 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008043 set->local_mod = local_mod;
8044 set->trees = trees;
8045 set->format = format;
8046
8047 /* evaluate */
8048 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8049 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008050 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008051 }
8052
Michal Vasko03ff5a72019-09-11 13:49:33 +02008053 return rc;
8054}
8055
8056#if 0
8057
8058/* full xml printing of set elements, not used currently */
8059
8060void
8061lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8062{
8063 uint32_t i;
8064 char *str_num;
8065 struct lyout out;
8066
8067 memset(&out, 0, sizeof out);
8068
8069 out.type = LYOUT_STREAM;
8070 out.method.f = f;
8071
8072 switch (set->type) {
8073 case LYXP_SET_EMPTY:
8074 ly_print(&out, "Empty XPath set\n\n");
8075 break;
8076 case LYXP_SET_BOOLEAN:
8077 ly_print(&out, "Boolean XPath set:\n");
8078 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8079 break;
8080 case LYXP_SET_STRING:
8081 ly_print(&out, "String XPath set:\n");
8082 ly_print(&out, "\"%s\"\n\n", set->value.str);
8083 break;
8084 case LYXP_SET_NUMBER:
8085 ly_print(&out, "Number XPath set:\n");
8086
8087 if (isnan(set->value.num)) {
8088 str_num = strdup("NaN");
8089 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8090 str_num = strdup("0");
8091 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8092 str_num = strdup("Infinity");
8093 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8094 str_num = strdup("-Infinity");
8095 } else if ((long long)set->value.num == set->value.num) {
8096 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8097 str_num = NULL;
8098 }
8099 } else {
8100 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8101 str_num = NULL;
8102 }
8103 }
8104 if (!str_num) {
8105 LOGMEM;
8106 return;
8107 }
8108 ly_print(&out, "%s\n\n", str_num);
8109 free(str_num);
8110 break;
8111 case LYXP_SET_NODE_SET:
8112 ly_print(&out, "Node XPath set:\n");
8113
8114 for (i = 0; i < set->used; ++i) {
8115 ly_print(&out, "%d. ", i + 1);
8116 switch (set->node_type[i]) {
8117 case LYXP_NODE_ROOT_ALL:
8118 ly_print(&out, "ROOT all\n\n");
8119 break;
8120 case LYXP_NODE_ROOT_CONFIG:
8121 ly_print(&out, "ROOT config\n\n");
8122 break;
8123 case LYXP_NODE_ROOT_STATE:
8124 ly_print(&out, "ROOT state\n\n");
8125 break;
8126 case LYXP_NODE_ROOT_NOTIF:
8127 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8128 break;
8129 case LYXP_NODE_ROOT_RPC:
8130 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8131 break;
8132 case LYXP_NODE_ROOT_OUTPUT:
8133 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8134 break;
8135 case LYXP_NODE_ELEM:
8136 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8137 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8138 ly_print(&out, "\n");
8139 break;
8140 case LYXP_NODE_TEXT:
8141 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8142 break;
8143 case LYXP_NODE_ATTR:
8144 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8145 break;
8146 }
8147 }
8148 break;
8149 }
8150}
8151
8152#endif
8153
8154LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008155lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008156{
8157 long double num;
8158 char *str;
8159 LY_ERR rc;
8160
8161 if (!set || (set->type == target)) {
8162 return LY_SUCCESS;
8163 }
8164
8165 /* it's not possible to convert anything into a node set */
8166 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8167
8168 if (set->type == LYXP_SET_SCNODE_SET) {
8169 set_free_content(set);
8170 return LY_EINVAL;
8171 }
8172
8173 /* to STRING */
8174 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8175 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8176 switch (set->type) {
8177 case LYXP_SET_NUMBER:
8178 if (isnan(set->val.num)) {
8179 set->val.str = strdup("NaN");
8180 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8181 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8182 set->val.str = strdup("0");
8183 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8184 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8185 set->val.str = strdup("Infinity");
8186 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8187 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8188 set->val.str = strdup("-Infinity");
8189 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8190 } else if ((long long)set->val.num == set->val.num) {
8191 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8192 LOGMEM_RET(set->ctx);
8193 }
8194 set->val.str = str;
8195 } else {
8196 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8197 LOGMEM_RET(set->ctx);
8198 }
8199 set->val.str = str;
8200 }
8201 break;
8202 case LYXP_SET_BOOLEAN:
8203 if (set->val.bool) {
8204 set->val.str = strdup("true");
8205 } else {
8206 set->val.str = strdup("false");
8207 }
8208 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8209 break;
8210 case LYXP_SET_NODE_SET:
8211 assert(set->used);
8212
8213 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008214 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008215
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008216 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008217 LY_CHECK_RET(rc);
8218 set_free_content(set);
8219 set->val.str = str;
8220 break;
8221 case LYXP_SET_EMPTY:
8222 set->val.str = strdup("");
8223 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8224 break;
8225 default:
8226 LOGINT_RET(set->ctx);
8227 }
8228 set->type = LYXP_SET_STRING;
8229 }
8230
8231 /* to NUMBER */
8232 if (target == LYXP_SET_NUMBER) {
8233 switch (set->type) {
8234 case LYXP_SET_STRING:
8235 num = cast_string_to_number(set->val.str);
8236 set_free_content(set);
8237 set->val.num = num;
8238 break;
8239 case LYXP_SET_BOOLEAN:
8240 if (set->val.bool) {
8241 set->val.num = 1;
8242 } else {
8243 set->val.num = 0;
8244 }
8245 break;
8246 default:
8247 LOGINT_RET(set->ctx);
8248 }
8249 set->type = LYXP_SET_NUMBER;
8250 }
8251
8252 /* to BOOLEAN */
8253 if (target == LYXP_SET_BOOLEAN) {
8254 switch (set->type) {
8255 case LYXP_SET_NUMBER:
8256 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8257 set->val.bool = 0;
8258 } else {
8259 set->val.bool = 1;
8260 }
8261 break;
8262 case LYXP_SET_STRING:
8263 if (set->val.str[0]) {
8264 set_free_content(set);
8265 set->val.bool = 1;
8266 } else {
8267 set_free_content(set);
8268 set->val.bool = 0;
8269 }
8270 break;
8271 case LYXP_SET_NODE_SET:
8272 set_free_content(set);
8273
8274 assert(set->used);
8275 set->val.bool = 1;
8276 break;
8277 case LYXP_SET_EMPTY:
8278 set->val.bool = 0;
8279 break;
8280 default:
8281 LOGINT_RET(set->ctx);
8282 }
8283 set->type = LYXP_SET_BOOLEAN;
8284 }
8285
8286 /* to EMPTY */
8287 if (target == LYXP_SET_EMPTY) {
8288 set_free_content(set);
8289 set->type = LYXP_SET_EMPTY;
8290 }
8291
8292 return LY_SUCCESS;
8293}
8294
8295LY_ERR
8296lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8297 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8298{
8299 struct ly_ctx *ctx;
8300 uint16_t exp_idx = 0;
8301
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008302 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008303
8304 ctx = local_mod->ctx;
8305
8306 /* prepare set for evaluation */
8307 exp_idx = 0;
8308 memset(set, 0, sizeof *set);
8309 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008310 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008311 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008312 set->ctx = ctx;
8313 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008314 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008315 set->local_mod = local_mod;
8316 set->format = format;
8317
8318 /* evaluate */
8319 return eval_expr_select(exp, &exp_idx, 0, set, options);
8320}