blob: 6f0617f26c713f82e5dae121a45612233e19aa88 [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);
786 if (idx == -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200787 lyxp_set_free(ret);
788 return NULL;
789 }
Michal Vaskoba716542019-12-16 10:01:58 +0100790 ret->val.scnodes[idx].in_ctx = set->val.scnodes[i].in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200791 }
792 }
793 } else if (set->type == LYXP_SET_NODE_SET) {
794 ret->type = set->type;
795 ret->val.nodes = malloc(set->used * sizeof *ret->val.nodes);
796 LY_CHECK_ERR_RET(!ret->val.nodes, LOGMEM(set->ctx); free(ret), NULL);
797 memcpy(ret->val.nodes, set->val.nodes, set->used * sizeof *ret->val.nodes);
798
799 ret->used = ret->size = set->used;
800 ret->ctx_pos = set->ctx_pos;
801 ret->ctx_size = set->ctx_size;
802 ret->ht = lyht_dup(set->ht);
803 } else {
804 memcpy(ret, set, sizeof *ret);
805 if (set->type == LYXP_SET_STRING) {
806 ret->val.str = strdup(set->val.str);
807 LY_CHECK_ERR_RET(!ret->val.str, LOGMEM(set->ctx); free(ret), NULL);
808 }
809 }
810
811 return ret;
812}
813
814/**
815 * @brief Fill XPath set with a string. Any current data are disposed of.
816 *
817 * @param[in] set Set to fill.
818 * @param[in] string String to fill into \p set.
819 * @param[in] str_len Length of \p string. 0 is a valid value!
820 */
821static void
822set_fill_string(struct lyxp_set *set, const char *string, uint16_t str_len)
823{
824 set_free_content(set);
825
826 set->type = LYXP_SET_STRING;
827 if ((str_len == 0) && (string[0] != '\0')) {
828 string = "";
829 }
830 set->val.str = strndup(string, str_len);
831}
832
833/**
834 * @brief Fill XPath set with a number. Any current data are disposed of.
835 *
836 * @param[in] set Set to fill.
837 * @param[in] number Number to fill into \p set.
838 */
839static void
840set_fill_number(struct lyxp_set *set, long double number)
841{
842 set_free_content(set);
843
844 set->type = LYXP_SET_NUMBER;
845 set->val.num = number;
846}
847
848/**
849 * @brief Fill XPath set with a boolean. Any current data are disposed of.
850 *
851 * @param[in] set Set to fill.
852 * @param[in] boolean Boolean to fill into \p set.
853 */
854static void
855set_fill_boolean(struct lyxp_set *set, int boolean)
856{
857 set_free_content(set);
858
859 set->type = LYXP_SET_BOOLEAN;
860 set->val.bool = boolean;
861}
862
863/**
864 * @brief Fill XPath set with the value from another set (deep assign).
865 * Any current data are disposed of.
866 *
867 * @param[in] trg Set to fill.
868 * @param[in] src Source set to copy into \p trg.
869 */
870static void
871set_fill_set(struct lyxp_set *trg, struct lyxp_set *src)
872{
873 if (!trg || !src) {
874 return;
875 }
876
877 if (trg->type == LYXP_SET_NODE_SET) {
878 free(trg->val.nodes);
879 } else if (trg->type == LYXP_SET_STRING) {
880 free(trg->val.str);
881 }
882 set_init(trg, src);
883
884 if (src->type == LYXP_SET_SCNODE_SET) {
885 trg->type = LYXP_SET_SCNODE_SET;
886 trg->used = src->used;
887 trg->size = src->used;
888
889 trg->val.scnodes = ly_realloc(trg->val.scnodes, trg->size * sizeof *trg->val.scnodes);
890 LY_CHECK_ERR_RET(!trg->val.scnodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
891 memcpy(trg->val.scnodes, src->val.scnodes, src->used * sizeof *src->val.scnodes);
892 } else if (src->type == LYXP_SET_BOOLEAN) {
893 set_fill_boolean(trg, src->val.bool);
894 } else if (src->type == LYXP_SET_NUMBER) {
895 set_fill_number(trg, src->val.num);
896 } else if (src->type == LYXP_SET_STRING) {
897 set_fill_string(trg, src->val.str, strlen(src->val.str));
898 } else {
899 if (trg->type == LYXP_SET_NODE_SET) {
900 free(trg->val.nodes);
901 } else if (trg->type == LYXP_SET_STRING) {
902 free(trg->val.str);
903 }
904
905 if (src->type == LYXP_SET_EMPTY) {
906 trg->type = LYXP_SET_EMPTY;
907 } else {
908 assert(src->type == LYXP_SET_NODE_SET);
909
910 trg->type = LYXP_SET_NODE_SET;
911 trg->used = src->used;
912 trg->size = src->used;
913 trg->ctx_pos = src->ctx_pos;
914 trg->ctx_size = src->ctx_size;
915
916 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
917 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
918 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
919 trg->ht = lyht_dup(src->ht);
920 }
921 }
922}
923
924/**
925 * @brief Clear context of all schema nodes.
926 *
927 * @param[in] set Set to clear.
928 */
929static void
930set_scnode_clear_ctx(struct lyxp_set *set)
931{
932 uint32_t i;
933
934 for (i = 0; i < set->used; ++i) {
935 if (set->val.scnodes[i].in_ctx == 1) {
936 set->val.scnodes[i].in_ctx = 0;
Michal Vasko5c4e5892019-11-14 12:31:38 +0100937 } else if (set->val.scnodes[i].in_ctx == -2) {
938 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200939 }
940 }
941}
942
943/**
944 * @brief Remove a node from a set. Removing last node changes
945 * set into LYXP_SET_EMPTY. Context position aware.
946 *
947 * @param[in] set Set to use.
948 * @param[in] idx Index from @p set of the node to be removed.
949 */
950static void
951set_remove_node(struct lyxp_set *set, uint32_t idx)
952{
953 assert(set && (set->type == LYXP_SET_NODE_SET));
954 assert(idx < set->used);
955
956 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
957
958 --set->used;
959 if (set->used) {
960 memmove(&set->val.nodes[idx], &set->val.nodes[idx + 1],
961 (set->used - idx) * sizeof *set->val.nodes);
962 } else {
963 set_free_content(set);
964 set->type = LYXP_SET_EMPTY;
965 }
966}
967
968/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100969 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200970 *
971 * @param[in] set Set to use.
972 * @param[in] idx Index from @p set of the node to be removed.
973 */
974static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100975set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200976{
977 assert(set && (set->type == LYXP_SET_NODE_SET));
978 assert(idx < set->used);
979
Michal Vasko2caefc12019-11-14 16:07:56 +0100980 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
981 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
982 }
983 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200984}
985
986/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100987 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200988 * set into LYXP_SET_EMPTY. Context position aware.
989 *
990 * @param[in] set Set to consolidate.
991 */
992static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100993set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200994{
995 uint16_t i, orig_used, end;
996 int32_t start;
997
Michal Vasko2caefc12019-11-14 16:07:56 +0100998 assert(set && (set->type != LYXP_SET_EMPTY));
Michal Vasko57eab132019-09-24 11:46:26 +0200999
1000 orig_used = set->used;
1001 set->used = 0;
1002 for (i = 0; i < orig_used;) {
1003 start = -1;
1004 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001005 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001006 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001007 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001008 end = i;
1009 ++i;
1010 break;
1011 }
1012
1013 ++i;
1014 if (i == orig_used) {
1015 end = i;
1016 }
1017 } while (i < orig_used);
1018
1019 if (start > -1) {
1020 /* move the whole chunk of valid nodes together */
1021 if (set->used != (unsigned)start) {
1022 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1023 }
1024 set->used += end - start;
1025 }
1026 }
1027
1028 if (!set->used) {
1029 set_free_content(set);
1030 /* this changes it to LYXP_SET_EMPTY */
1031 memset(set, 0, sizeof *set);
1032 }
1033}
1034
1035/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001036 * @brief Check for duplicates in a node set.
1037 *
1038 * @param[in] set Set to check.
1039 * @param[in] node Node to look for in @p set.
1040 * @param[in] node_type Type of @p node.
1041 * @param[in] skip_idx Index from @p set to skip.
1042 * @return LY_ERR
1043 */
1044static LY_ERR
1045set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1046{
1047 uint32_t i;
1048
Michal Vasko2caefc12019-11-14 16:07:56 +01001049 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001050 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1051 }
1052
1053 for (i = 0; i < set->used; ++i) {
1054 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1055 continue;
1056 }
1057
1058 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1059 return LY_EEXIST;
1060 }
1061 }
1062
1063 return LY_SUCCESS;
1064}
1065
Michal Vaskoecd62de2019-11-13 12:35:11 +01001066int
1067lyxp_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 +02001068{
1069 uint32_t i;
1070
1071 for (i = 0; i < set->used; ++i) {
1072 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1073 continue;
1074 }
1075
1076 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1077 return i;
1078 }
1079 }
1080
1081 return -1;
1082}
1083
Michal Vaskoecd62de2019-11-13 12:35:11 +01001084void
1085lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001086{
1087 uint32_t orig_used, i, j;
1088
1089 assert(((set1->type == LYXP_SET_SCNODE_SET) || (set1->type == LYXP_SET_EMPTY))
1090 && ((set2->type == LYXP_SET_SCNODE_SET) || (set2->type == LYXP_SET_EMPTY)));
1091
1092 if (set2->type == LYXP_SET_EMPTY) {
1093 return;
1094 }
1095
1096 if (set1->type == LYXP_SET_EMPTY) {
1097 memcpy(set1, set2, sizeof *set1);
1098 return;
1099 }
1100
1101 if (set1->used + set2->used > set1->size) {
1102 set1->size = set1->used + set2->used;
1103 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1104 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1105 }
1106
1107 orig_used = set1->used;
1108
1109 for (i = 0; i < set2->used; ++i) {
1110 for (j = 0; j < orig_used; ++j) {
1111 /* detect duplicities */
1112 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1113 break;
1114 }
1115 }
1116
1117 if (j == orig_used) {
1118 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1119 ++set1->used;
1120 }
1121 }
1122
1123 set_free_content(set2);
1124 set2->type = LYXP_SET_EMPTY;
1125}
1126
1127/**
1128 * @brief Insert a node into a set. Context position aware.
1129 *
1130 * @param[in] set Set to use.
1131 * @param[in] node Node to insert to @p set.
1132 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1133 * @param[in] node_type Node type of @p node.
1134 * @param[in] idx Index in @p set to insert into.
1135 */
1136static void
1137set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1138{
1139 assert(set && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)));
1140
1141 if (set->type == LYXP_SET_EMPTY) {
1142 /* first item */
1143 if (idx) {
1144 /* no real harm done, but it is a bug */
1145 LOGINT(set->ctx);
1146 idx = 0;
1147 }
1148 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1149 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1150 set->type = LYXP_SET_NODE_SET;
1151 set->used = 0;
1152 set->size = LYXP_SET_SIZE_START;
1153 set->ctx_pos = 1;
1154 set->ctx_size = 1;
1155 set->ht = NULL;
1156 } else {
1157 /* not an empty set */
1158 if (set->used == set->size) {
1159
1160 /* set is full */
1161 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1162 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1163 set->size += LYXP_SET_SIZE_STEP;
1164 }
1165
1166 if (idx > set->used) {
1167 LOGINT(set->ctx);
1168 idx = set->used;
1169 }
1170
1171 /* make space for the new node */
1172 if (idx < set->used) {
1173 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1174 }
1175 }
1176
1177 /* finally assign the value */
1178 set->val.nodes[idx].node = (struct lyd_node *)node;
1179 set->val.nodes[idx].type = node_type;
1180 set->val.nodes[idx].pos = pos;
1181 ++set->used;
1182
Michal Vasko2caefc12019-11-14 16:07:56 +01001183 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1184 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1185 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001186}
1187
Michal Vaskoecd62de2019-11-13 12:35:11 +01001188int
1189lyxp_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 +02001190{
1191 int ret;
1192
1193 assert(set->type == LYXP_SET_SCNODE_SET);
1194
Michal Vaskoecd62de2019-11-13 12:35:11 +01001195 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001196 if (ret > -1) {
1197 set->val.scnodes[ret].in_ctx = 1;
1198 } else {
1199 if (set->used == set->size) {
1200 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1201 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1202 set->size += LYXP_SET_SIZE_STEP;
1203 }
1204
1205 ret = set->used;
1206 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1207 set->val.scnodes[ret].type = node_type;
1208 set->val.scnodes[ret].in_ctx = 1;
1209 ++set->used;
1210 }
1211
1212 return ret;
1213}
1214
1215/**
1216 * @brief Replace a node in a set with another. Context position aware.
1217 *
1218 * @param[in] set Set to use.
1219 * @param[in] node Node to insert to @p set.
1220 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1221 * @param[in] node_type Node type of @p node.
1222 * @param[in] idx Index in @p set of the node to replace.
1223 */
1224static void
1225set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1226{
1227 assert(set && (idx < set->used));
1228
Michal Vasko2caefc12019-11-14 16:07:56 +01001229 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1230 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1231 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001232 set->val.nodes[idx].node = (struct lyd_node *)node;
1233 set->val.nodes[idx].type = node_type;
1234 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001235 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1236 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1237 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001238}
1239
1240/**
1241 * @brief Set all nodes with ctx 1 to a new unique context value.
1242 *
1243 * @param[in] set Set to modify.
1244 * @return New context value.
1245 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001246static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001247set_scnode_new_in_ctx(struct lyxp_set *set)
1248{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001249 uint32_t i;
1250 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001251
1252 assert(set->type == LYXP_SET_SCNODE_SET);
1253
1254 ret_ctx = 3;
1255retry:
1256 for (i = 0; i < set->used; ++i) {
1257 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1258 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1259 goto retry;
1260 }
1261 }
1262 for (i = 0; i < set->used; ++i) {
1263 if (set->val.scnodes[i].in_ctx == 1) {
1264 set->val.scnodes[i].in_ctx = ret_ctx;
1265 }
1266 }
1267
1268 return ret_ctx;
1269}
1270
1271/**
1272 * @brief Get unique @p node position in the data.
1273 *
1274 * @param[in] node Node to find.
1275 * @param[in] node_type Node type of @p node.
1276 * @param[in] root Root node.
1277 * @param[in] root_type Type of the XPath @p root node.
1278 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1279 * be used to increase efficiency and start the DFS from this node.
1280 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1281 * @return Node position.
1282 */
1283static uint32_t
1284get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1285 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1286{
1287 const struct lyd_node *next, *elem, *top_sibling;
1288 uint32_t pos = 1;
1289
1290 assert(prev && prev_pos && !root->prev->next);
1291
1292 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1293 return 0;
1294 }
1295
1296 if (*prev) {
1297 /* start from the previous element instead from the root */
1298 elem = next = *prev;
1299 pos = *prev_pos;
1300 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1301 goto dfs_search;
1302 }
1303
1304 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1305 /* TREE DFS */
1306 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1307dfs_search:
1308 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1309 goto skip_children;
1310 }
1311
1312 if (elem == node) {
1313 break;
1314 }
1315 ++pos;
1316
1317 /* TREE DFS END */
1318 /* select element for the next run - children first,
1319 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1320 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1321 next = NULL;
1322 } else {
1323 next = lyd_node_children(elem);
1324 }
1325 if (!next) {
1326skip_children:
1327 /* no children */
1328 if (elem == top_sibling) {
1329 /* we are done, root has no children */
1330 elem = NULL;
1331 break;
1332 }
1333 /* try siblings */
1334 next = elem->next;
1335 }
1336 while (!next) {
1337 /* no siblings, go back through parents */
1338 if (elem->parent == top_sibling->parent) {
1339 /* we are done, no next element to process */
1340 elem = NULL;
1341 break;
1342 }
1343 /* parent is already processed, go to its sibling */
1344 elem = (struct lyd_node *)elem->parent;
1345 next = elem->next;
1346 }
1347 }
1348
1349 /* node found */
1350 if (elem) {
1351 break;
1352 }
1353 }
1354
1355 if (!elem) {
1356 if (!(*prev)) {
1357 /* we went from root and failed to find it, cannot be */
1358 LOGINT(node->schema->module->ctx);
1359 return 0;
1360 } else {
1361 *prev = NULL;
1362 *prev_pos = 0;
1363
1364 elem = next = top_sibling = root;
1365 pos = 1;
1366 goto dfs_search;
1367 }
1368 }
1369
1370 /* remember the last found node for next time */
1371 *prev = node;
1372 *prev_pos = pos;
1373
1374 return pos;
1375}
1376
1377/**
1378 * @brief Assign (fill) missing node positions.
1379 *
1380 * @param[in] set Set to fill positions in.
1381 * @param[in] root Context root node.
1382 * @param[in] root_type Context root type.
1383 * @return LY_ERR
1384 */
1385static LY_ERR
1386set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1387{
1388 const struct lyd_node *prev = NULL, *tmp_node;
1389 uint32_t i, tmp_pos = 0;
1390
1391 for (i = 0; i < set->used; ++i) {
1392 if (!set->val.nodes[i].pos) {
1393 tmp_node = NULL;
1394 switch (set->val.nodes[i].type) {
1395 case LYXP_NODE_ATTR:
1396 tmp_node = set->val.attrs[i].attr->parent;
1397 if (!tmp_node) {
1398 LOGINT_RET(root->schema->module->ctx);
1399 }
1400 /* fallthrough */
1401 case LYXP_NODE_ELEM:
1402 case LYXP_NODE_TEXT:
1403 if (!tmp_node) {
1404 tmp_node = set->val.nodes[i].node;
1405 }
1406 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1407 break;
1408 default:
1409 /* all roots have position 0 */
1410 break;
1411 }
1412 }
1413 }
1414
1415 return LY_SUCCESS;
1416}
1417
1418/**
1419 * @brief Get unique @p attr position in the parent attributes.
1420 *
1421 * @param[in] attr Attr to use.
1422 * @return Attribute position.
1423 */
1424static uint16_t
1425get_attr_pos(struct lyd_attr *attr)
1426{
1427 uint16_t pos = 0;
1428 struct lyd_attr *attr2;
1429
1430 for (attr2 = attr->parent->attr; attr2 && (attr2 != attr); attr2 = attr2->next) {
1431 ++pos;
1432 }
1433
1434 assert(attr2);
1435 return pos;
1436}
1437
1438/**
1439 * @brief Compare 2 nodes in respect to XPath document order.
1440 *
1441 * @param[in] item1 1st node.
1442 * @param[in] item2 2nd node.
1443 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1444 */
1445static int
1446set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1447{
1448 uint32_t attr_pos1 = 0, attr_pos2 = 0;
1449
1450 if (item1->pos < item2->pos) {
1451 return -1;
1452 }
1453
1454 if (item1->pos > item2->pos) {
1455 return 1;
1456 }
1457
1458 /* node positions are equal, the fun case */
1459
1460 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1461 /* special case since text nodes are actually saved as their parents */
1462 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1463 if (item1->type == LYXP_NODE_ELEM) {
1464 assert(item2->type == LYXP_NODE_TEXT);
1465 return -1;
1466 } else {
1467 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1468 return 1;
1469 }
1470 }
1471
1472 /* we need attr positions now */
1473 if (item1->type == LYXP_NODE_ATTR) {
1474 attr_pos1 = get_attr_pos((struct lyd_attr *)item1->node);
1475 }
1476 if (item2->type == LYXP_NODE_ATTR) {
1477 attr_pos2 = get_attr_pos((struct lyd_attr *)item2->node);
1478 }
1479
1480 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st ATTR - =pos= - 2nd ATTR */
1481 /* check for duplicates */
1482 if (item1->node == item2->node) {
1483 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_ATTR) || (attr_pos1 == attr_pos2)));
1484 return 0;
1485 }
1486
1487 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd ATTR */
1488 /* elem is always first, 2nd node is after it */
1489 if (item1->type == LYXP_NODE_ELEM) {
1490 assert(item2->type != LYXP_NODE_ELEM);
1491 return -1;
1492 }
1493
1494 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd ATTR, 1st ATTR - any pos - 2nd ELEM, 1st ATTR - >pos> - 2nd ATTR */
1495 /* 2nd is before 1st */
1496 if (((item1->type == LYXP_NODE_TEXT)
1497 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_ATTR)))
1498 || ((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ELEM))
1499 || (((item1->type == LYXP_NODE_ATTR) && (item2->type == LYXP_NODE_ATTR))
1500 && (attr_pos1 > attr_pos2))) {
1501 return 1;
1502 }
1503
1504 /* 1st ATTR - any pos - 2nd TEXT, 1st ATTR <pos< - 2nd ATTR */
1505 /* 2nd is after 1st */
1506 return -1;
1507}
1508
1509/**
1510 * @brief Set cast for comparisons.
1511 *
1512 * @param[in] trg Target set to cast source into.
1513 * @param[in] src Source set.
1514 * @param[in] type Target set type.
1515 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001516 * @return LY_ERR
1517 */
1518static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001519set_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 +02001520{
1521 assert(src->type == LYXP_SET_NODE_SET);
1522
1523 set_init(trg, src);
1524
1525 /* insert node into target set */
1526 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1527
1528 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001529 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001530}
1531
1532#ifndef NDEBUG
1533
1534/**
1535 * @brief Bubble sort @p set into XPath document order.
1536 * Context position aware. Unused in the 'Release' build target.
1537 *
1538 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001539 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1540 */
1541static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001542set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001543{
1544 uint32_t i, j;
1545 int ret = 0, cmp, inverted, change;
1546 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001547 struct lyxp_set_node item;
1548 struct lyxp_set_hash_node hnode;
1549 uint64_t hash;
1550
1551 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1552 return 0;
1553 }
1554
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001555 /* find first top-level node to be used as anchor for positions */
1556 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1557 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001558
1559 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001560 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001561 return -1;
1562 }
1563
1564 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1565 print_set_debug(set);
1566
1567 for (i = 0; i < set->used; ++i) {
1568 inverted = 0;
1569 change = 0;
1570
1571 for (j = 1; j < set->used - i; ++j) {
1572 /* compare node positions */
1573 if (inverted) {
1574 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1575 } else {
1576 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1577 }
1578
1579 /* swap if needed */
1580 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1581 change = 1;
1582
1583 item = set->val.nodes[j - 1];
1584 set->val.nodes[j - 1] = set->val.nodes[j];
1585 set->val.nodes[j] = item;
1586 } else {
1587 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1588 inverted = !inverted;
1589 }
1590 }
1591
1592 ++ret;
1593
1594 if (!change) {
1595 break;
1596 }
1597 }
1598
1599 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1600 print_set_debug(set);
1601
1602 /* check node hashes */
1603 if (set->used >= LYD_HT_MIN_ITEMS) {
1604 assert(set->ht);
1605 for (i = 0; i < set->used; ++i) {
1606 hnode.node = set->val.nodes[i].node;
1607 hnode.type = set->val.nodes[i].type;
1608
1609 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1610 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1611 hash = dict_hash_multi(hash, NULL, 0);
1612
1613 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1614 }
1615 }
1616
1617 return ret - 1;
1618}
1619
1620/**
1621 * @brief Remove duplicate entries in a sorted node set.
1622 *
1623 * @param[in] set Sorted set to check.
1624 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1625 */
1626static LY_ERR
1627set_sorted_dup_node_clean(struct lyxp_set *set)
1628{
1629 uint32_t i = 0;
1630 LY_ERR ret = LY_SUCCESS;
1631
1632 if (set->used > 1) {
1633 while (i < set->used - 1) {
1634 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1635 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001636 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001637 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001638 }
Michal Vasko57eab132019-09-24 11:46:26 +02001639 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001640 }
1641 }
1642
Michal Vasko2caefc12019-11-14 16:07:56 +01001643 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001644 return ret;
1645}
1646
1647#endif
1648
1649/**
1650 * @brief Merge 2 sorted sets into one.
1651 *
1652 * @param[in,out] trg Set to merge into. Duplicates are removed.
1653 * @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 +02001654 * @return LY_ERR
1655 */
1656static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001657set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001658{
1659 uint32_t i, j, k, count, dup_count;
1660 int cmp;
1661 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001662
1663 if (((trg->type != LYXP_SET_NODE_SET) && (trg->type != LYXP_SET_EMPTY))
1664 || ((src->type != LYXP_SET_NODE_SET) && (src->type != LYXP_SET_EMPTY))) {
1665 return LY_EINVAL;
1666 }
1667
1668 if (src->type == LYXP_SET_EMPTY) {
1669 return LY_SUCCESS;
1670 } else if (trg->type == LYXP_SET_EMPTY) {
1671 set_fill_set(trg, src);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001672 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001673 return LY_SUCCESS;
1674 }
1675
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001676 /* find first top-level node to be used as anchor for positions */
1677 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1678 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001679
1680 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001681 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001682 return LY_EINT;
1683 }
1684
1685#ifndef NDEBUG
1686 LOGDBG(LY_LDGXPATH, "MERGE target");
1687 print_set_debug(trg);
1688 LOGDBG(LY_LDGXPATH, "MERGE source");
1689 print_set_debug(src);
1690#endif
1691
1692 /* make memory for the merge (duplicates are not detected yet, so space
1693 * will likely be wasted on them, too bad) */
1694 if (trg->size - trg->used < src->used) {
1695 trg->size = trg->used + src->used;
1696
1697 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1698 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1699 }
1700
1701 i = 0;
1702 j = 0;
1703 count = 0;
1704 dup_count = 0;
1705 do {
1706 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1707 if (!cmp) {
1708 if (!count) {
1709 /* duplicate, just skip it */
1710 ++i;
1711 ++j;
1712 } else {
1713 /* we are copying something already, so let's copy the duplicate too,
1714 * we are hoping that afterwards there are some more nodes to
1715 * copy and this way we can copy them all together */
1716 ++count;
1717 ++dup_count;
1718 ++i;
1719 ++j;
1720 }
1721 } else if (cmp < 0) {
1722 /* inserting src node into trg, just remember it for now */
1723 ++count;
1724 ++i;
1725
1726 /* insert the hash now */
1727 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1728 } else if (count) {
1729copy_nodes:
1730 /* time to actually copy the nodes, we have found the largest block of nodes */
1731 memmove(&trg->val.nodes[j + (count - dup_count)],
1732 &trg->val.nodes[j],
1733 (trg->used - j) * sizeof *trg->val.nodes);
1734 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1735
1736 trg->used += count - dup_count;
1737 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1738 j += count - dup_count;
1739
1740 count = 0;
1741 dup_count = 0;
1742 } else {
1743 ++j;
1744 }
1745 } while ((i < src->used) && (j < trg->used));
1746
1747 if ((i < src->used) || count) {
1748 /* insert all the hashes first */
1749 for (k = i; k < src->used; ++k) {
1750 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1751 }
1752
1753 /* loop ended, but we need to copy something at trg end */
1754 count += src->used - i;
1755 i = src->used;
1756 goto copy_nodes;
1757 }
1758
1759 /* we are inserting hashes before the actual node insert, which causes
1760 * situations when there were initially not enough items for a hash table,
1761 * but even after some were inserted, hash table was not created (during
1762 * insertion the number of items is not updated yet) */
1763 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1764 set_insert_node_hash(trg, NULL, 0);
1765 }
1766
1767#ifndef NDEBUG
1768 LOGDBG(LY_LDGXPATH, "MERGE result");
1769 print_set_debug(trg);
1770#endif
1771
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001772 lyxp_set_cast(src, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001773 return LY_SUCCESS;
1774}
1775
1776/*
1777 * (re)parse functions
1778 *
1779 * Parse functions parse the expression into
1780 * tokens (syntactic analysis).
1781 *
1782 * Reparse functions perform semantic analysis
1783 * (do not save the result, just a check) of
1784 * the expression and fill repeat indices.
1785 */
1786
1787/**
1788 * @brief Look at the next token and check its kind.
1789 *
1790 * @param[in] ctx Context for logging.
1791 * @param[in] exp Expression to use.
1792 * @param[in] exp_idx Position in the expression \p exp.
1793 * @param[in] want_tok Expected token.
1794 * @param[in] strict Whether the token is strictly required (print error if
1795 * not the next one) or we simply want to check whether it is the next or not.
1796 * @return LY_ERR
1797 */
1798static LY_ERR
1799exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1800{
1801 if (exp->used == exp_idx) {
1802 if (strict) {
1803 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1804 }
1805 return LY_EINVAL;
1806 }
1807
1808 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1809 if (strict) {
1810 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1811 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1812 }
1813 return LY_EINVAL;
1814 }
1815
1816 return LY_SUCCESS;
1817}
1818
1819/**
1820 * @brief Stack operation push on the repeat array.
1821 *
1822 * @param[in] exp Expression to use.
1823 * @param[in] exp_idx Position in the expresion \p exp.
1824 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1825 */
1826static void
1827exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1828{
1829 uint16_t i;
1830
1831 if (exp->repeat[exp_idx]) {
1832 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1833 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1834 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1835 exp->repeat[exp_idx][i] = repeat_op_idx;
1836 exp->repeat[exp_idx][i + 1] = 0;
1837 } else {
1838 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1839 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1840 exp->repeat[exp_idx][0] = repeat_op_idx;
1841 }
1842}
1843
1844/**
1845 * @brief Reparse Predicate. Logs directly on error.
1846 *
1847 * [7] Predicate ::= '[' Expr ']'
1848 *
1849 * @param[in] ctx Context for logging.
1850 * @param[in] exp Parsed XPath expression.
1851 * @param[in] exp_idx Position in the expression @p exp.
1852 * @return LY_ERR
1853 */
1854static LY_ERR
1855reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1856{
1857 LY_ERR rc;
1858
1859 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1860 LY_CHECK_RET(rc);
1861 ++(*exp_idx);
1862
1863 rc = reparse_or_expr(ctx, exp, exp_idx);
1864 LY_CHECK_RET(rc);
1865
1866 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1867 LY_CHECK_RET(rc);
1868 ++(*exp_idx);
1869
1870 return LY_SUCCESS;
1871}
1872
1873/**
1874 * @brief Reparse RelativeLocationPath. Logs directly on error.
1875 *
1876 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1877 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1878 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1879 *
1880 * @param[in] ctx Context for logging.
1881 * @param[in] exp Parsed XPath expression.
1882 * @param[in] exp_idx Position in the expression \p exp.
1883 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1884 */
1885static LY_ERR
1886reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1887{
1888 LY_ERR rc;
1889
1890 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1891 LY_CHECK_RET(rc);
1892
1893 goto step;
1894 do {
1895 /* '/' or '//' */
1896 ++(*exp_idx);
1897
1898 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1899 LY_CHECK_RET(rc);
1900step:
1901 /* Step */
1902 switch (exp->tokens[*exp_idx]) {
1903 case LYXP_TOKEN_DOT:
1904 ++(*exp_idx);
1905 break;
1906
1907 case LYXP_TOKEN_DDOT:
1908 ++(*exp_idx);
1909 break;
1910
1911 case LYXP_TOKEN_AT:
1912 ++(*exp_idx);
1913
1914 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1915 LY_CHECK_RET(rc);
1916 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1917 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1918 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1919 return LY_EVALID;
1920 }
1921 /* fall through */
1922 case LYXP_TOKEN_NAMETEST:
1923 ++(*exp_idx);
1924 goto reparse_predicate;
1925 break;
1926
1927 case LYXP_TOKEN_NODETYPE:
1928 ++(*exp_idx);
1929
1930 /* '(' */
1931 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1932 LY_CHECK_RET(rc);
1933 ++(*exp_idx);
1934
1935 /* ')' */
1936 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1937 LY_CHECK_RET(rc);
1938 ++(*exp_idx);
1939
1940reparse_predicate:
1941 /* Predicate* */
1942 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1943 rc = reparse_predicate(ctx, exp, exp_idx);
1944 LY_CHECK_RET(rc);
1945 }
1946 break;
1947 default:
1948 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1949 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1950 return LY_EVALID;
1951 }
1952 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1953
1954 return LY_SUCCESS;
1955}
1956
1957/**
1958 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1959 *
1960 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1961 *
1962 * @param[in] ctx Context for logging.
1963 * @param[in] exp Parsed XPath expression.
1964 * @param[in] exp_idx Position in the expression \p exp.
1965 * @return LY_ERR
1966 */
1967static LY_ERR
1968reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1969{
1970 LY_ERR rc;
1971
1972 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1973 LY_CHECK_RET(rc);
1974
1975 /* '/' RelativeLocationPath? */
1976 if (exp->tok_len[*exp_idx] == 1) {
1977 /* '/' */
1978 ++(*exp_idx);
1979
1980 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1981 return LY_SUCCESS;
1982 }
1983 switch (exp->tokens[*exp_idx]) {
1984 case LYXP_TOKEN_DOT:
1985 case LYXP_TOKEN_DDOT:
1986 case LYXP_TOKEN_AT:
1987 case LYXP_TOKEN_NAMETEST:
1988 case LYXP_TOKEN_NODETYPE:
1989 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1990 LY_CHECK_RET(rc);
1991 /* fall through */
1992 default:
1993 break;
1994 }
1995
1996 /* '//' RelativeLocationPath */
1997 } else {
1998 /* '//' */
1999 ++(*exp_idx);
2000
2001 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2002 LY_CHECK_RET(rc);
2003 }
2004
2005 return LY_SUCCESS;
2006}
2007
2008/**
2009 * @brief Reparse FunctionCall. Logs directly on error.
2010 *
2011 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2012 *
2013 * @param[in] ctx Context for logging.
2014 * @param[in] exp Parsed XPath expression.
2015 * @param[in] exp_idx Position in the expression @p exp.
2016 * @return LY_ERR
2017 */
2018static LY_ERR
2019reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2020{
2021 int min_arg_count = -1, max_arg_count, arg_count;
2022 uint16_t func_exp_idx;
2023 LY_ERR rc;
2024
2025 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2026 LY_CHECK_RET(rc);
2027 func_exp_idx = *exp_idx;
2028 switch (exp->tok_len[*exp_idx]) {
2029 case 3:
2030 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2031 min_arg_count = 1;
2032 max_arg_count = 1;
2033 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2034 min_arg_count = 1;
2035 max_arg_count = 1;
2036 }
2037 break;
2038 case 4:
2039 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2040 min_arg_count = 1;
2041 max_arg_count = 1;
2042 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2043 min_arg_count = 0;
2044 max_arg_count = 0;
2045 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2046 min_arg_count = 0;
2047 max_arg_count = 1;
2048 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2049 min_arg_count = 0;
2050 max_arg_count = 0;
2051 }
2052 break;
2053 case 5:
2054 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2055 min_arg_count = 1;
2056 max_arg_count = 1;
2057 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2058 min_arg_count = 0;
2059 max_arg_count = 0;
2060 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2061 min_arg_count = 1;
2062 max_arg_count = 1;
2063 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2064 min_arg_count = 1;
2065 max_arg_count = 1;
2066 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2067 min_arg_count = 1;
2068 max_arg_count = 1;
2069 }
2070 break;
2071 case 6:
2072 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2073 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002074 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002075 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2076 min_arg_count = 0;
2077 max_arg_count = 1;
2078 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2079 min_arg_count = 0;
2080 max_arg_count = 1;
2081 }
2082 break;
2083 case 7:
2084 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2085 min_arg_count = 1;
2086 max_arg_count = 1;
2087 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2088 min_arg_count = 1;
2089 max_arg_count = 1;
2090 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2091 min_arg_count = 0;
2092 max_arg_count = 0;
2093 }
2094 break;
2095 case 8:
2096 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2097 min_arg_count = 2;
2098 max_arg_count = 2;
2099 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2100 min_arg_count = 0;
2101 max_arg_count = 0;
2102 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2103 min_arg_count = 2;
2104 max_arg_count = 2;
2105 }
2106 break;
2107 case 9:
2108 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2109 min_arg_count = 2;
2110 max_arg_count = 3;
2111 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2112 min_arg_count = 3;
2113 max_arg_count = 3;
2114 }
2115 break;
2116 case 10:
2117 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2118 min_arg_count = 0;
2119 max_arg_count = 1;
2120 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2121 min_arg_count = 1;
2122 max_arg_count = 1;
2123 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2124 min_arg_count = 2;
2125 max_arg_count = 2;
2126 }
2127 break;
2128 case 11:
2129 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2130 min_arg_count = 2;
2131 max_arg_count = 2;
2132 }
2133 break;
2134 case 12:
2135 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2136 min_arg_count = 2;
2137 max_arg_count = 2;
2138 }
2139 break;
2140 case 13:
2141 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2142 min_arg_count = 0;
2143 max_arg_count = 1;
2144 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2145 min_arg_count = 0;
2146 max_arg_count = 1;
2147 }
2148 break;
2149 case 15:
2150 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2151 min_arg_count = 0;
2152 max_arg_count = 1;
2153 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2154 min_arg_count = 2;
2155 max_arg_count = 2;
2156 }
2157 break;
2158 case 16:
2159 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2160 min_arg_count = 2;
2161 max_arg_count = 2;
2162 }
2163 break;
2164 case 20:
2165 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2166 min_arg_count = 2;
2167 max_arg_count = 2;
2168 }
2169 break;
2170 }
2171 if (min_arg_count == -1) {
2172 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2173 return LY_EINVAL;
2174 }
2175 ++(*exp_idx);
2176
2177 /* '(' */
2178 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2179 LY_CHECK_RET(rc);
2180 ++(*exp_idx);
2181
2182 /* ( Expr ( ',' Expr )* )? */
2183 arg_count = 0;
2184 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2185 LY_CHECK_RET(rc);
2186 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2187 ++arg_count;
2188 rc = reparse_or_expr(ctx, exp, exp_idx);
2189 LY_CHECK_RET(rc);
2190 }
2191 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2192 ++(*exp_idx);
2193
2194 ++arg_count;
2195 rc = reparse_or_expr(ctx, exp, exp_idx);
2196 LY_CHECK_RET(rc);
2197 }
2198
2199 /* ')' */
2200 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2201 LY_CHECK_RET(rc);
2202 ++(*exp_idx);
2203
2204 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2205 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2206 &exp->expr[exp->tok_pos[func_exp_idx]]);
2207 return LY_EVALID;
2208 }
2209
2210 return LY_SUCCESS;
2211}
2212
2213/**
2214 * @brief Reparse PathExpr. Logs directly on error.
2215 *
2216 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2217 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2218 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2219 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2220 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2221 *
2222 * @param[in] ctx Context for logging.
2223 * @param[in] exp Parsed XPath expression.
2224 * @param[in] exp_idx Position in the expression @p exp.
2225 * @return LY_ERR
2226 */
2227static LY_ERR
2228reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2229{
2230 LY_ERR rc;
2231
2232 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2233 return -1;
2234 }
2235
2236 switch (exp->tokens[*exp_idx]) {
2237 case LYXP_TOKEN_PAR1:
2238 /* '(' Expr ')' Predicate* */
2239 ++(*exp_idx);
2240
2241 rc = reparse_or_expr(ctx, exp, exp_idx);
2242 LY_CHECK_RET(rc);
2243
2244 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2245 LY_CHECK_RET(rc);
2246 ++(*exp_idx);
2247 goto predicate;
2248 break;
2249 case LYXP_TOKEN_DOT:
2250 case LYXP_TOKEN_DDOT:
2251 case LYXP_TOKEN_AT:
2252 case LYXP_TOKEN_NAMETEST:
2253 case LYXP_TOKEN_NODETYPE:
2254 /* RelativeLocationPath */
2255 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2256 LY_CHECK_RET(rc);
2257 break;
2258 case LYXP_TOKEN_FUNCNAME:
2259 /* FunctionCall */
2260 rc = reparse_function_call(ctx, exp, exp_idx);
2261 LY_CHECK_RET(rc);
2262 goto predicate;
2263 break;
2264 case LYXP_TOKEN_OPERATOR_PATH:
2265 /* AbsoluteLocationPath */
2266 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2267 LY_CHECK_RET(rc);
2268 break;
2269 case LYXP_TOKEN_LITERAL:
2270 /* Literal */
2271 ++(*exp_idx);
2272 goto predicate;
2273 break;
2274 case LYXP_TOKEN_NUMBER:
2275 /* Number */
2276 ++(*exp_idx);
2277 goto predicate;
2278 break;
2279 default:
2280 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2281 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2282 return LY_EVALID;
2283 }
2284
2285 return LY_SUCCESS;
2286
2287predicate:
2288 /* Predicate* */
2289 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2290 rc = reparse_predicate(ctx, exp, exp_idx);
2291 LY_CHECK_RET(rc);
2292 }
2293
2294 /* ('/' or '//') RelativeLocationPath */
2295 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2296
2297 /* '/' or '//' */
2298 ++(*exp_idx);
2299
2300 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2301 LY_CHECK_RET(rc);
2302 }
2303
2304 return LY_SUCCESS;
2305}
2306
2307/**
2308 * @brief Reparse UnaryExpr. Logs directly on error.
2309 *
2310 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2311 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2312 *
2313 * @param[in] ctx Context for logging.
2314 * @param[in] exp Parsed XPath expression.
2315 * @param[in] exp_idx Position in the expression @p exp.
2316 * @return LY_ERR
2317 */
2318static LY_ERR
2319reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2320{
2321 uint16_t prev_exp;
2322 LY_ERR rc;
2323
2324 /* ('-')* */
2325 prev_exp = *exp_idx;
2326 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2327 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2328 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2329 ++(*exp_idx);
2330 }
2331
2332 /* PathExpr */
2333 prev_exp = *exp_idx;
2334 rc = reparse_path_expr(ctx, exp, exp_idx);
2335 LY_CHECK_RET(rc);
2336
2337 /* ('|' PathExpr)* */
2338 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2339 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2340 ++(*exp_idx);
2341
2342 rc = reparse_path_expr(ctx, exp, exp_idx);
2343 LY_CHECK_RET(rc);
2344 }
2345
2346 return LY_SUCCESS;
2347}
2348
2349/**
2350 * @brief Reparse AdditiveExpr. Logs directly on error.
2351 *
2352 * [15] AdditiveExpr ::= MultiplicativeExpr
2353 * | AdditiveExpr '+' MultiplicativeExpr
2354 * | AdditiveExpr '-' MultiplicativeExpr
2355 * [16] MultiplicativeExpr ::= UnaryExpr
2356 * | MultiplicativeExpr '*' UnaryExpr
2357 * | MultiplicativeExpr 'div' UnaryExpr
2358 * | MultiplicativeExpr 'mod' UnaryExpr
2359 *
2360 * @param[in] ctx Context for logging.
2361 * @param[in] exp Parsed XPath expression.
2362 * @param[in] exp_idx Position in the expression @p exp.
2363 * @return LY_ERR
2364 */
2365static LY_ERR
2366reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2367{
2368 uint16_t prev_add_exp, prev_mul_exp;
2369 LY_ERR rc;
2370
2371 prev_add_exp = *exp_idx;
2372 goto reparse_multiplicative_expr;
2373
2374 /* ('+' / '-' MultiplicativeExpr)* */
2375 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2376 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2377 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2378 ++(*exp_idx);
2379
2380reparse_multiplicative_expr:
2381 /* UnaryExpr */
2382 prev_mul_exp = *exp_idx;
2383 rc = reparse_unary_expr(ctx, exp, exp_idx);
2384 LY_CHECK_RET(rc);
2385
2386 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2387 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2388 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2389 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2390 ++(*exp_idx);
2391
2392 rc = reparse_unary_expr(ctx, exp, exp_idx);
2393 LY_CHECK_RET(rc);
2394 }
2395 }
2396
2397 return LY_SUCCESS;
2398}
2399
2400/**
2401 * @brief Reparse EqualityExpr. Logs directly on error.
2402 *
2403 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2404 * | EqualityExpr '!=' RelationalExpr
2405 * [14] RelationalExpr ::= AdditiveExpr
2406 * | RelationalExpr '<' AdditiveExpr
2407 * | RelationalExpr '>' AdditiveExpr
2408 * | RelationalExpr '<=' AdditiveExpr
2409 * | RelationalExpr '>=' AdditiveExpr
2410 *
2411 * @param[in] ctx Context for logging.
2412 * @param[in] exp Parsed XPath expression.
2413 * @param[in] exp_idx Position in the expression @p exp.
2414 * @return LY_ERR
2415 */
2416static LY_ERR
2417reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2418{
2419 uint16_t prev_eq_exp, prev_rel_exp;
2420 LY_ERR rc;
2421
2422 prev_eq_exp = *exp_idx;
2423 goto reparse_additive_expr;
2424
2425 /* ('=' / '!=' RelationalExpr)* */
2426 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2427 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2428 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2429 ++(*exp_idx);
2430
2431reparse_additive_expr:
2432 /* AdditiveExpr */
2433 prev_rel_exp = *exp_idx;
2434 rc = reparse_additive_expr(ctx, exp, exp_idx);
2435 LY_CHECK_RET(rc);
2436
2437 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2438 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2439 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2440 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2441 ++(*exp_idx);
2442
2443 rc = reparse_additive_expr(ctx, exp, exp_idx);
2444 LY_CHECK_RET(rc);
2445 }
2446 }
2447
2448 return LY_SUCCESS;
2449}
2450
2451/**
2452 * @brief Reparse OrExpr. Logs directly on error.
2453 *
2454 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2455 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2456 *
2457 * @param[in] ctx Context for logging.
2458 * @param[in] exp Parsed XPath expression.
2459 * @param[in] exp_idx Position in the expression @p exp.
2460 * @return LY_ERR
2461 */
2462static LY_ERR
2463reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2464{
2465 uint16_t prev_or_exp, prev_and_exp;
2466 LY_ERR rc;
2467
2468 prev_or_exp = *exp_idx;
2469 goto reparse_equality_expr;
2470
2471 /* ('or' AndExpr)* */
2472 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2473 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2474 ++(*exp_idx);
2475
2476reparse_equality_expr:
2477 /* EqualityExpr */
2478 prev_and_exp = *exp_idx;
2479 rc = reparse_equality_expr(ctx, exp, exp_idx);
2480 LY_CHECK_RET(rc);
2481
2482 /* ('and' EqualityExpr)* */
2483 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2484 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2485 ++(*exp_idx);
2486
2487 rc = reparse_equality_expr(ctx, exp, exp_idx);
2488 LY_CHECK_RET(rc);
2489 }
2490 }
2491
2492 return LY_SUCCESS;
2493}
Radek Krejcib1646a92018-11-02 16:08:26 +01002494
2495/**
2496 * @brief Parse NCName.
2497 *
2498 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002499 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002500 */
Radek Krejcid4270262019-01-07 15:07:25 +01002501static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002502parse_ncname(const char *ncname)
2503{
2504 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002505 size_t size;
2506 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002507
2508 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2509 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2510 return len;
2511 }
2512
2513 do {
2514 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002515 if (!*ncname) {
2516 break;
2517 }
Radek Krejcid4270262019-01-07 15:07:25 +01002518 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002519 } while (is_xmlqnamechar(uc) && (uc != ':'));
2520
2521 return len;
2522}
2523
2524/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002525 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002526 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002527 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002528 * @param[in] exp Expression to use.
2529 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002530 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002531 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002532 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002533 */
2534static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002535exp_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 +01002536{
2537 uint32_t prev;
2538
2539 if (exp->used == exp->size) {
2540 prev = exp->size;
2541 exp->size += LYXP_EXPR_SIZE_STEP;
2542 if (prev > exp->size) {
2543 LOGINT(ctx);
2544 return LY_EINT;
2545 }
2546
2547 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2548 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2549 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2550 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2551 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2552 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2553 }
2554
2555 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002556 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002557 exp->tok_len[exp->used] = tok_len;
2558 ++exp->used;
2559 return LY_SUCCESS;
2560}
2561
2562void
2563lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2564{
2565 uint16_t i;
2566
2567 if (!expr) {
2568 return;
2569 }
2570
2571 lydict_remove(ctx, expr->expr);
2572 free(expr->tokens);
2573 free(expr->tok_pos);
2574 free(expr->tok_len);
2575 if (expr->repeat) {
2576 for (i = 0; i < expr->used; ++i) {
2577 free(expr->repeat[i]);
2578 }
2579 }
2580 free(expr->repeat);
2581 free(expr);
2582}
2583
2584struct lyxp_expr *
2585lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2586{
2587 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002588 size_t parsed = 0, tok_len;
2589 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002590 enum lyxp_token tok_type;
2591 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002592 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002593
2594 if (strlen(expr) > UINT16_MAX) {
2595 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2596 return NULL;
2597 }
2598
2599 /* init lyxp_expr structure */
2600 ret = calloc(1, sizeof *ret);
2601 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2602 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2603 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2604 ret->used = 0;
2605 ret->size = LYXP_EXPR_SIZE_START;
2606 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2607 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2608
2609 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2610 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2611
2612 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2613 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2614
2615 while (is_xmlws(expr[parsed])) {
2616 ++parsed;
2617 }
2618
2619 do {
2620 if (expr[parsed] == '(') {
2621
2622 /* '(' */
2623 tok_len = 1;
2624 tok_type = LYXP_TOKEN_PAR1;
2625
2626 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2627 /* it is a NodeType/FunctionName after all */
2628 if (((ret->tok_len[ret->used - 1] == 4)
2629 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2630 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2631 ((ret->tok_len[ret->used - 1] == 7)
2632 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2633 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2634 } else {
2635 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2636 }
2637 prev_function_check = 0;
2638 }
2639
2640 } else if (expr[parsed] == ')') {
2641
2642 /* ')' */
2643 tok_len = 1;
2644 tok_type = LYXP_TOKEN_PAR2;
2645
2646 } else if (expr[parsed] == '[') {
2647
2648 /* '[' */
2649 tok_len = 1;
2650 tok_type = LYXP_TOKEN_BRACK1;
2651
2652 } else if (expr[parsed] == ']') {
2653
2654 /* ']' */
2655 tok_len = 1;
2656 tok_type = LYXP_TOKEN_BRACK2;
2657
2658 } else if (!strncmp(&expr[parsed], "..", 2)) {
2659
2660 /* '..' */
2661 tok_len = 2;
2662 tok_type = LYXP_TOKEN_DDOT;
2663
2664 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2665
2666 /* '.' */
2667 tok_len = 1;
2668 tok_type = LYXP_TOKEN_DOT;
2669
2670 } else if (expr[parsed] == '@') {
2671
2672 /* '@' */
2673 tok_len = 1;
2674 tok_type = LYXP_TOKEN_AT;
2675
2676 } else if (expr[parsed] == ',') {
2677
2678 /* ',' */
2679 tok_len = 1;
2680 tok_type = LYXP_TOKEN_COMMA;
2681
2682 } else if (expr[parsed] == '\'') {
2683
2684 /* Literal with ' */
2685 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2686 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2687 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2688 ++tok_len;
2689 tok_type = LYXP_TOKEN_LITERAL;
2690
2691 } else if (expr[parsed] == '\"') {
2692
2693 /* Literal with " */
2694 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\"'); ++tok_len);
2695 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2696 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2697 ++tok_len;
2698 tok_type = LYXP_TOKEN_LITERAL;
2699
2700 } else if ((expr[parsed] == '.') || (isdigit(expr[parsed]))) {
2701
2702 /* Number */
2703 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2704 if (expr[parsed + tok_len] == '.') {
2705 ++tok_len;
2706 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2707 }
2708 tok_type = LYXP_TOKEN_NUMBER;
2709
2710 } else if (expr[parsed] == '/') {
2711
2712 /* Operator '/', '//' */
2713 if (!strncmp(&expr[parsed], "//", 2)) {
2714 tok_len = 2;
2715 } else {
2716 tok_len = 1;
2717 }
2718 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2719
2720 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2721 || !strncmp(&expr[parsed], ">=", 2)) {
2722
2723 /* Operator '!=', '<=', '>=' */
2724 tok_len = 2;
2725 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2726
2727 } else if (expr[parsed] == '|') {
2728
2729 /* Operator '|' */
2730 tok_len = 1;
2731 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2732
2733 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2734
2735 /* Operator '+', '-' */
2736 tok_len = 1;
2737 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2738
2739 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2740
2741 /* Operator '=', '<', '>' */
2742 tok_len = 1;
2743 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2744
2745 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2746 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2747 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2748 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2749 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2750 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2751 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2752 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2753 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2754
2755 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2756 if (expr[parsed] == '*') {
2757 tok_len = 1;
2758 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2759
2760 } else if (!strncmp(&expr[parsed], "or", 2)) {
2761 tok_len = 2;
2762 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2763
2764 } else if (!strncmp(&expr[parsed], "and", 3)) {
2765 tok_len = 3;
2766 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2767
2768 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2769 tok_len = 3;
2770 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2771
2772 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002773 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2774 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 +01002775 goto error;
2776 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002777 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002778 goto error;
2779 }
2780 } else if (expr[parsed] == '*') {
2781
2782 /* NameTest '*' */
2783 tok_len = 1;
2784 tok_type = LYXP_TOKEN_NAMETEST;
2785
2786 } else {
2787
2788 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2789 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002790 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 +01002791 tok_len = ncname_len;
2792
2793 if (expr[parsed + tok_len] == ':') {
2794 ++tok_len;
2795 if (expr[parsed + tok_len] == '*') {
2796 ++tok_len;
2797 } else {
2798 ncname_len = parse_ncname(&expr[parsed + tok_len]);
Radek Krejcid4270262019-01-07 15:07:25 +01002799 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 +01002800 tok_len += ncname_len;
2801 }
2802 /* remove old flag to prevent ambiguities */
2803 prev_function_check = 0;
2804 tok_type = LYXP_TOKEN_NAMETEST;
2805 } else {
2806 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2807 prev_function_check = 1;
2808 tok_type = LYXP_TOKEN_NAMETEST;
2809 }
2810 }
2811
2812 /* store the token, move on to the next one */
2813 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2814 parsed += tok_len;
2815 while (is_xmlws(expr[parsed])) {
2816 ++parsed;
2817 }
2818
2819 } while (expr[parsed]);
2820
2821 /* prealloc repeat */
2822 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2823 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2824
Michal Vasko03ff5a72019-09-11 13:49:33 +02002825 /* fill repeat */
2826 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2827 if (ret->used > exp_idx) {
2828 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2829 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2830 &ret->expr[ret->tok_pos[exp_idx]]);
2831 goto error;
2832 }
2833
2834 print_expr_struct_debug(ret);
2835
Radek Krejcib1646a92018-11-02 16:08:26 +01002836 return ret;
2837
2838error:
2839 lyxp_expr_free(ctx, ret);
2840 return NULL;
2841}
2842
Michal Vasko03ff5a72019-09-11 13:49:33 +02002843/*
2844 * warn functions
2845 *
2846 * Warn functions check specific reasonable conditions for schema XPath
2847 * and print a warning if they are not satisfied.
2848 */
2849
2850/**
2851 * @brief Get the last-added schema node that is currently in the context.
2852 *
2853 * @param[in] set Set to search in.
2854 * @return Last-added schema context node, NULL if no node is in context.
2855 */
2856static struct lysc_node *
2857warn_get_scnode_in_ctx(struct lyxp_set *set)
2858{
2859 uint32_t i;
2860
2861 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2862 return NULL;
2863 }
2864
2865 i = set->used;
2866 do {
2867 --i;
2868 if (set->val.scnodes[i].in_ctx == 1) {
2869 /* if there are more, simply return the first found (last added) */
2870 return set->val.scnodes[i].scnode;
2871 }
2872 } while (i);
2873
2874 return NULL;
2875}
2876
2877/**
2878 * @brief Test whether a type is numeric - integer type or decimal64.
2879 *
2880 * @param[in] type Type to test.
2881 * @return 1 if numeric, 0 otherwise.
2882 */
2883static int
2884warn_is_numeric_type(struct lysc_type *type)
2885{
2886 struct lysc_type_union *uni;
2887 int ret;
2888 uint32_t i;
2889
2890 switch (type->basetype) {
2891 case LY_TYPE_DEC64:
2892 case LY_TYPE_INT8:
2893 case LY_TYPE_UINT8:
2894 case LY_TYPE_INT16:
2895 case LY_TYPE_UINT16:
2896 case LY_TYPE_INT32:
2897 case LY_TYPE_UINT32:
2898 case LY_TYPE_INT64:
2899 case LY_TYPE_UINT64:
2900 return 1;
2901 case LY_TYPE_UNION:
2902 uni = (struct lysc_type_union *)type;
2903 LY_ARRAY_FOR(uni->types, i) {
2904 ret = warn_is_numeric_type(uni->types[i]);
2905 if (ret) {
2906 /* found a suitable type */
2907 return 1;
2908 }
2909 }
2910 /* did not find any suitable type */
2911 return 0;
2912 case LY_TYPE_LEAFREF:
2913 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2914 default:
2915 return 0;
2916 }
2917}
2918
2919/**
2920 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2921 *
2922 * @param[in] type Type to test.
2923 * @return 1 if string, 0 otherwise.
2924 */
2925static int
2926warn_is_string_type(struct lysc_type *type)
2927{
2928 struct lysc_type_union *uni;
2929 int ret;
2930 uint32_t i;
2931
2932 switch (type->basetype) {
2933 case LY_TYPE_BITS:
2934 case LY_TYPE_ENUM:
2935 case LY_TYPE_IDENT:
2936 case LY_TYPE_INST:
2937 case LY_TYPE_STRING:
2938 return 1;
2939 case LY_TYPE_UNION:
2940 uni = (struct lysc_type_union *)type;
2941 LY_ARRAY_FOR(uni->types, i) {
2942 ret = warn_is_string_type(uni->types[i]);
2943 if (ret) {
2944 /* found a suitable type */
2945 return 1;
2946 }
2947 }
2948 /* did not find any suitable type */
2949 return 0;
2950 case LY_TYPE_LEAFREF:
2951 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2952 default:
2953 return 0;
2954 }
2955}
2956
2957/**
2958 * @brief Test whether a type is one specific type.
2959 *
2960 * @param[in] type Type to test.
2961 * @param[in] base Expected type.
2962 * @return 1 if it is, 0 otherwise.
2963 */
2964static int
2965warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2966{
2967 struct lysc_type_union *uni;
2968 int ret;
2969 uint32_t i;
2970
2971 if (type->basetype == base) {
2972 return 1;
2973 } else if (type->basetype == LY_TYPE_UNION) {
2974 uni = (struct lysc_type_union *)type;
2975 LY_ARRAY_FOR(uni->types, i) {
2976 ret = warn_is_specific_type(uni->types[i], base);
2977 if (ret) {
2978 /* found a suitable type */
2979 return 1;
2980 }
2981 }
2982 /* did not find any suitable type */
2983 return 0;
2984 } else if (type->basetype == LY_TYPE_LEAFREF) {
2985 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2986 }
2987
2988 return 0;
2989}
2990
2991/**
2992 * @brief Get next type of a (union) type.
2993 *
2994 * @param[in] type Base type.
2995 * @param[in] prev_type Previously returned type.
2996 * @return Next type or NULL.
2997 */
2998static struct lysc_type *
2999warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
3000{
3001 struct lysc_type_union *uni;
3002 int found = 0;
3003 uint32_t i;
3004
3005 switch (type->basetype) {
3006 case LY_TYPE_UNION:
3007 uni = (struct lysc_type_union *)type;
3008 if (!prev_type) {
3009 return uni->types[0];
3010 }
3011 LY_ARRAY_FOR(uni->types, i) {
3012 if (found) {
3013 return uni->types[i];
3014 }
3015 if (prev_type == uni->types[i]) {
3016 found = 1;
3017 }
3018 }
3019 return NULL;
3020 default:
3021 if (prev_type) {
3022 assert(type == prev_type);
3023 return NULL;
3024 } else {
3025 return type;
3026 }
3027 }
3028}
3029
3030/**
3031 * @brief Test whether 2 types have a common type.
3032 *
3033 * @param[in] type1 First type.
3034 * @param[in] type2 Second type.
3035 * @return 1 if they do, 0 otherwise.
3036 */
3037static int
3038warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3039{
3040 struct lysc_type *t1, *rt1, *t2, *rt2;
3041
3042 t1 = NULL;
3043 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3044 if (t1->basetype == LY_TYPE_LEAFREF) {
3045 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3046 } else {
3047 rt1 = t1;
3048 }
3049
3050 t2 = NULL;
3051 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3052 if (t2->basetype == LY_TYPE_LEAFREF) {
3053 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3054 } else {
3055 rt2 = t2;
3056 }
3057
3058 if (rt2->basetype == rt1->basetype) {
3059 /* match found */
3060 return 1;
3061 }
3062 }
3063 }
3064
3065 return 0;
3066}
3067
3068/**
3069 * @brief Check both operands of comparison operators.
3070 *
3071 * @param[in] ctx Context for errors.
3072 * @param[in] set1 First operand set.
3073 * @param[in] set2 Second operand set.
3074 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3075 * @param[in] expr Start of the expression to print with the warning.
3076 * @param[in] tok_pos Token position.
3077 */
3078static void
3079warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3080{
3081 struct lysc_node_leaf *node1, *node2;
3082 int leaves = 1, warning = 0;
3083
3084 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3085 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3086
3087 if (!node1 && !node2) {
3088 /* no node-sets involved, nothing to do */
3089 return;
3090 }
3091
3092 if (node1) {
3093 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3094 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3095 warning = 1;
3096 leaves = 0;
3097 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3098 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3099 warning = 1;
3100 }
3101 }
3102
3103 if (node2) {
3104 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3105 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3106 warning = 1;
3107 leaves = 0;
3108 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3109 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3110 warning = 1;
3111 }
3112 }
3113
3114 if (node1 && node2 && leaves && !numbers_only) {
3115 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3116 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3117 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3118 && !warn_is_equal_type(node1->type, node2->type))) {
3119 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3120 warning = 1;
3121 }
3122 }
3123
3124 if (warning) {
3125 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3126 }
3127}
3128
3129/**
3130 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3131 *
3132 * @param[in] exp Parsed XPath expression.
3133 * @param[in] set Set with the leaf/leaf-list.
3134 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3135 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3136 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3137 */
3138static void
3139warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3140{
3141 struct lysc_node *scnode;
3142 struct lysc_type *type;
3143 char *value;
3144 LY_ERR rc;
3145 struct ly_err_item *err = NULL;
3146
3147 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3148 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3149 /* check that the node can have the specified value */
3150 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3151 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3152 } else {
3153 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3154 }
3155 if (!value) {
3156 LOGMEM(set->ctx);
3157 return;
3158 }
3159
3160 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3161 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3162 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3163 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3164 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3165 exp->expr + exp->tok_pos[equal_exp]);
3166 }
3167
3168 type = ((struct lysc_node_leaf *)scnode)->type;
3169 if (type->basetype != LY_TYPE_IDENT) {
3170 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3171 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3172
3173 if (err) {
3174 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3175 ly_err_free(err);
3176 } else if (rc != LY_SUCCESS) {
3177 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3178 }
3179 if (rc != LY_SUCCESS) {
3180 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3181 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3182 exp->expr + exp->tok_pos[equal_exp]);
3183 }
3184 }
3185 free(value);
3186 }
3187}
3188
3189/*
3190 * XPath functions
3191 */
3192
3193/**
3194 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3195 * depending on whether the first node bit value from the second argument is set.
3196 *
3197 * @param[in] args Array of arguments.
3198 * @param[in] arg_count Count of elements in @p args.
3199 * @param[in,out] set Context and result set at the same time.
3200 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003201 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003202 */
3203static LY_ERR
3204xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3205{
3206 struct lyd_node_term *leaf;
3207 struct lysc_node_leaf *sleaf;
3208 struct lysc_type_bits *bits;
3209 LY_ERR rc = LY_SUCCESS;
3210 uint32_t i;
3211
3212 if (options & LYXP_SCNODE_ALL) {
3213 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3214 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003215 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3216 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 +02003217 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3218 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003219 }
3220
3221 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3222 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3223 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 +02003224 } else if (!warn_is_string_type(sleaf->type)) {
3225 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003226 }
3227 }
3228 set_scnode_clear_ctx(set);
3229 return rc;
3230 }
3231
3232 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3233 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)");
3234 return LY_EVALID;
3235 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003236 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003237 LY_CHECK_RET(rc);
3238
3239 set_fill_boolean(set, 0);
3240 if (args[0]->type == LYXP_SET_NODE_SET) {
3241 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3242 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3243 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3244 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
3245 LY_ARRAY_FOR(bits->bits, i) {
3246 if (!strcmp(bits->bits[i].name, args[1]->val.str)) {
3247 set_fill_boolean(set, 1);
3248 break;
3249 }
3250 }
3251 }
3252 }
3253
3254 return LY_SUCCESS;
3255}
3256
3257/**
3258 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3259 * with the argument converted to boolean.
3260 *
3261 * @param[in] args Array of arguments.
3262 * @param[in] arg_count Count of elements in @p args.
3263 * @param[in,out] set Context and result set at the same time.
3264 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003265 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003266 */
3267static LY_ERR
3268xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3269{
3270 LY_ERR rc;
3271
3272 if (options & LYXP_SCNODE_ALL) {
3273 set_scnode_clear_ctx(set);
3274 return LY_SUCCESS;
3275 }
3276
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003277 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003278 LY_CHECK_RET(rc);
3279 set_fill_set(set, args[0]);
3280
3281 return LY_SUCCESS;
3282}
3283
3284/**
3285 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3286 * with the first argument rounded up to the nearest integer.
3287 *
3288 * @param[in] args Array of arguments.
3289 * @param[in] arg_count Count of elements in @p args.
3290 * @param[in,out] set Context and result set at the same time.
3291 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003292 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003293 */
3294static LY_ERR
3295xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3296{
3297 struct lysc_node_leaf *sleaf;
3298 LY_ERR rc = LY_SUCCESS;
3299
3300 if (options & LYXP_SCNODE_ALL) {
3301 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3302 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003303 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3304 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 +02003305 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3306 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003307 }
3308 set_scnode_clear_ctx(set);
3309 return rc;
3310 }
3311
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003312 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003313 LY_CHECK_RET(rc);
3314 if ((long long)args[0]->val.num != args[0]->val.num) {
3315 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3316 } else {
3317 set_fill_number(set, args[0]->val.num);
3318 }
3319
3320 return LY_SUCCESS;
3321}
3322
3323/**
3324 * @brief Execute the XPath concat(string, string, string*) function.
3325 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3326 *
3327 * @param[in] args Array of arguments.
3328 * @param[in] arg_count Count of elements in @p args.
3329 * @param[in,out] set Context and result set at the same time.
3330 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003331 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003332 */
3333static LY_ERR
3334xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3335{
3336 uint16_t i;
3337 char *str = NULL;
3338 size_t used = 1;
3339 LY_ERR rc = LY_SUCCESS;
3340 struct lysc_node_leaf *sleaf;
3341
3342 if (options & LYXP_SCNODE_ALL) {
3343 for (i = 0; i < arg_count; ++i) {
3344 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3345 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3346 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3347 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003348 } else if (!warn_is_string_type(sleaf->type)) {
3349 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 +02003350 }
3351 }
3352 }
3353 set_scnode_clear_ctx(set);
3354 return rc;
3355 }
3356
3357 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003358 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003359 if (rc != LY_SUCCESS) {
3360 free(str);
3361 return rc;
3362 }
3363
3364 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3365 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3366 strcpy(str + used - 1, args[i]->val.str);
3367 used += strlen(args[i]->val.str);
3368 }
3369
3370 /* free, kind of */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003371 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003372 set->type = LYXP_SET_STRING;
3373 set->val.str = str;
3374
3375 return LY_SUCCESS;
3376}
3377
3378/**
3379 * @brief Execute the XPath contains(string, string) function.
3380 * Returns LYXP_SET_BOOLEAN whether the second argument can
3381 * be found in the first or not.
3382 *
3383 * @param[in] args Array of arguments.
3384 * @param[in] arg_count Count of elements in @p args.
3385 * @param[in,out] set Context and result set at the same time.
3386 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003387 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003388 */
3389static LY_ERR
3390xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3391{
3392 struct lysc_node_leaf *sleaf;
3393 LY_ERR rc = LY_SUCCESS;
3394
3395 if (options & LYXP_SCNODE_ALL) {
3396 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3397 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3398 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 +02003399 } else if (!warn_is_string_type(sleaf->type)) {
3400 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003401 }
3402 }
3403
3404 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3405 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3406 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 +02003407 } else if (!warn_is_string_type(sleaf->type)) {
3408 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003409 }
3410 }
3411 set_scnode_clear_ctx(set);
3412 return rc;
3413 }
3414
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003415 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003416 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003417 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003418 LY_CHECK_RET(rc);
3419
3420 if (strstr(args[0]->val.str, args[1]->val.str)) {
3421 set_fill_boolean(set, 1);
3422 } else {
3423 set_fill_boolean(set, 0);
3424 }
3425
3426 return LY_SUCCESS;
3427}
3428
3429/**
3430 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3431 * with the size of the node-set from the argument.
3432 *
3433 * @param[in] args Array of arguments.
3434 * @param[in] arg_count Count of elements in @p args.
3435 * @param[in,out] set Context and result set at the same time.
3436 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003437 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003438 */
3439static LY_ERR
3440xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3441{
3442 struct lysc_node *scnode = NULL;
3443 LY_ERR rc = LY_SUCCESS;
3444
3445 if (options & LYXP_SCNODE_ALL) {
3446 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3447 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003448 }
3449 set_scnode_clear_ctx(set);
3450 return rc;
3451 }
3452
3453 if (args[0]->type == LYXP_SET_EMPTY) {
3454 set_fill_number(set, 0);
3455 return LY_SUCCESS;
3456 }
3457
3458 if (args[0]->type != LYXP_SET_NODE_SET) {
3459 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3460 return LY_EVALID;
3461 }
3462
3463 set_fill_number(set, args[0]->used);
3464 return LY_SUCCESS;
3465}
3466
3467/**
3468 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3469 * with the context with the intial node.
3470 *
3471 * @param[in] args Array of arguments.
3472 * @param[in] arg_count Count of elements in @p args.
3473 * @param[in,out] set Context and result set at the same time.
3474 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003475 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003476 */
3477static LY_ERR
3478xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3479{
3480 if (arg_count || args) {
3481 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3482 return LY_EVALID;
3483 }
3484
3485 if (options & LYXP_SCNODE_ALL) {
3486 set_scnode_clear_ctx(set);
3487
Michal Vaskoecd62de2019-11-13 12:35:11 +01003488 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003489 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003490 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003491
3492 /* position is filled later */
3493 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3494 }
3495
3496 return LY_SUCCESS;
3497}
3498
3499/**
3500 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3501 * leafref or instance-identifier target node(s).
3502 *
3503 * @param[in] args Array of arguments.
3504 * @param[in] arg_count Count of elements in @p args.
3505 * @param[in,out] set Context and result set at the same time.
3506 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003507 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003508 */
3509static LY_ERR
3510xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3511{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003512 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003513 struct lyd_node_term *leaf;
3514 struct lysc_node_leaf *sleaf;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003515 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003516 const struct lyd_node *node;
3517 char *errmsg = NULL;
3518 const char *val;
3519 int dynamic;
3520 LY_ERR rc = LY_SUCCESS;
3521
3522 if (options & LYXP_SCNODE_ALL) {
3523 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3524 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003525 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3526 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 +02003527 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3528 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3529 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003530 }
3531 set_scnode_clear_ctx(set);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003532 if ((rc == LY_SUCCESS) && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
3533 cctx.ctx = set->ctx;
3534 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3535 /* it was already validated, it must succeed */
3536 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003537 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003538 }
3539 }
3540
Michal Vasko03ff5a72019-09-11 13:49:33 +02003541 return rc;
3542 }
3543
3544 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3545 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3546 return LY_EVALID;
3547 }
3548
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003549 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003550 if (args[0]->type != LYXP_SET_EMPTY) {
3551 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3552 sleaf = (struct lysc_node_leaf *)leaf->schema;
3553 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3554 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3555 /* find leafref target */
3556 val = lyd_value2str(leaf, &dynamic);
3557 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
3558 set->trees, &leaf->value, &errmsg);
3559 if (dynamic) {
3560 free((char *)val);
3561 }
3562 if (!node) {
3563 LOGERR(set->ctx, LY_EINVAL, errmsg);
3564 free(errmsg);
3565 return LY_EINVAL;
3566 }
3567
3568 /* insert it */
3569 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3570 } else {
3571 assert(sleaf->type->basetype == LY_TYPE_INST);
3572 node = (struct lyd_node *)lyd_target(leaf->value.target, set->trees);
3573 if (!node) {
3574 val = lyd_value2str(leaf, &dynamic);
3575 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3576 if (dynamic) {
3577 free((char *)val);
3578 }
3579 return LY_EVALID;
3580 }
3581 }
3582 }
3583 }
3584
3585 return LY_SUCCESS;
3586}
3587
3588/**
3589 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3590 * on whether the first argument nodes contain a node of an identity derived from the second
3591 * argument identity.
3592 *
3593 * @param[in] args Array of arguments.
3594 * @param[in] arg_count Count of elements in @p args.
3595 * @param[in,out] set Context and result set at the same time.
3596 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003597 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003598 */
3599static LY_ERR
3600xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3601{
3602 uint16_t i;
3603 struct lyd_node_term *leaf;
3604 struct lysc_node_leaf *sleaf;
3605 struct lyd_value data = {0};
3606 struct ly_err_item *err = NULL;
3607 LY_ERR rc = LY_SUCCESS;
3608 int found;
3609
3610 if (options & LYXP_SCNODE_ALL) {
3611 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3612 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003613 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3614 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 +02003615 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3616 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003617 }
3618
3619 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3620 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3621 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 +02003622 } else if (!warn_is_string_type(sleaf->type)) {
3623 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003624 }
3625 }
3626 set_scnode_clear_ctx(set);
3627 return rc;
3628 }
3629
3630 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3631 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "derived-from(node-set, string)");
3632 return LY_EVALID;
3633 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003634 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003635 LY_CHECK_RET(rc);
3636
3637 set_fill_boolean(set, 0);
3638 if (args[0]->type != LYXP_SET_EMPTY) {
3639 found = 0;
3640 for (i = 0; i < args[0]->used; ++i) {
3641 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3642 sleaf = (struct lysc_node_leaf *)leaf->schema;
3643 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3644 /* store args[1] into ident */
3645 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3646 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3647 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3648 if (err) {
3649 ly_err_print(err);
3650 ly_err_free(err);
3651 }
3652 LY_CHECK_RET(rc);
3653
3654 LY_ARRAY_FOR(data.ident->derived, i) {
3655 if (data.ident->derived[i] == leaf->value.ident) {
3656 set_fill_boolean(set, 1);
3657 found = 1;
3658 break;
3659 }
3660 }
3661 if (found) {
3662 break;
3663 }
3664 }
3665 }
3666 }
3667
3668 return LY_SUCCESS;
3669}
3670
3671/**
3672 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3673 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3674 * the second argument identity.
3675 *
3676 * @param[in] args Array of arguments.
3677 * @param[in] arg_count Count of elements in @p args.
3678 * @param[in,out] set Context and result set at the same time.
3679 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003680 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003681 */
3682static LY_ERR
3683xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3684{
3685 uint16_t i;
3686 struct lyd_node_term *leaf;
3687 struct lysc_node_leaf *sleaf;
3688 struct lyd_value data = {0};
3689 struct ly_err_item *err = NULL;
3690 LY_ERR rc = LY_SUCCESS;
3691 int found;
3692
3693 if (options & LYXP_SCNODE_ALL) {
3694 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3695 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003696 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3697 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 +02003698 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3699 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003700 }
3701
3702 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3703 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3704 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 +02003705 } else if (!warn_is_string_type(sleaf->type)) {
3706 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003707 }
3708 }
3709 set_scnode_clear_ctx(set);
3710 return rc;
3711 }
3712
3713 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3714 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)");
3715 return LY_EVALID;
3716 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003717 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003718 LY_CHECK_RET(rc);
3719
3720 set_fill_boolean(set, 0);
3721 if (args[0]->type != LYXP_SET_EMPTY) {
3722 found = 0;
3723 for (i = 0; i < args[0]->used; ++i) {
3724 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3725 sleaf = (struct lysc_node_leaf *)leaf->schema;
3726 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3727 /* store args[1] into ident */
3728 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3729 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3730 (struct lyd_node *)leaf, set->trees, &data, NULL, &err);
3731 if (err) {
3732 ly_err_print(err);
3733 ly_err_free(err);
3734 }
3735 LY_CHECK_RET(rc);
3736
3737 if (data.ident == leaf->value.ident) {
3738 set_fill_boolean(set, 1);
3739 break;
3740 }
3741 LY_ARRAY_FOR(data.ident->derived, i) {
3742 if (data.ident->derived[i] == leaf->value.ident) {
3743 set_fill_boolean(set, 1);
3744 found = 1;
3745 break;
3746 }
3747 }
3748 if (found) {
3749 break;
3750 }
3751 }
3752 }
3753 }
3754
3755 return LY_SUCCESS;
3756}
3757
3758/**
3759 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3760 * with the integer value of the first node's enum value, otherwise NaN.
3761 *
3762 * @param[in] args Array of arguments.
3763 * @param[in] arg_count Count of elements in @p args.
3764 * @param[in,out] set Context and result set at the same time.
3765 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003766 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003767 */
3768static LY_ERR
3769xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3770{
3771 struct lyd_node_term *leaf;
3772 struct lysc_node_leaf *sleaf;
3773 LY_ERR rc = LY_SUCCESS;
3774
3775 if (options & LYXP_SCNODE_ALL) {
3776 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3777 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003778 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3779 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 +02003780 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3781 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003782 }
3783 set_scnode_clear_ctx(set);
3784 return rc;
3785 }
3786
3787 if ((args[0]->type != LYXP_SET_NODE_SET) && (args[0]->type != LYXP_SET_EMPTY)) {
3788 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3789 return LY_EVALID;
3790 }
3791
3792 set_fill_number(set, NAN);
3793 if (args[0]->type == LYXP_SET_NODE_SET) {
3794 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3795 sleaf = (struct lysc_node_leaf *)leaf->schema;
3796 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3797 set_fill_number(set, leaf->value.enum_item->value);
3798 }
3799 }
3800
3801 return LY_SUCCESS;
3802}
3803
3804/**
3805 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3806 * with false value.
3807 *
3808 * @param[in] args Array of arguments.
3809 * @param[in] arg_count Count of elements in @p args.
3810 * @param[in,out] set Context and result set at the same time.
3811 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003812 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003813 */
3814static LY_ERR
3815xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3816{
3817 if (options & LYXP_SCNODE_ALL) {
3818 set_scnode_clear_ctx(set);
3819 return LY_SUCCESS;
3820 }
3821
3822 set_fill_boolean(set, 0);
3823 return LY_SUCCESS;
3824}
3825
3826/**
3827 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3828 * with the first argument floored (truncated).
3829 *
3830 * @param[in] args Array of arguments.
3831 * @param[in] arg_count Count of elements in @p args.
3832 * @param[in,out] set Context and result set at the same time.
3833 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003834 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003835 */
3836static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003837xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003838{
3839 LY_ERR rc;
3840
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003841 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003842 LY_CHECK_RET(rc);
3843 if (isfinite(args[0]->val.num)) {
3844 set_fill_number(set, (long long)args[0]->val.num);
3845 }
3846
3847 return LY_SUCCESS;
3848}
3849
3850/**
3851 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3852 * whether the language of the text matches the one from the argument.
3853 *
3854 * @param[in] args Array of arguments.
3855 * @param[in] arg_count Count of elements in @p args.
3856 * @param[in,out] set Context and result set at the same time.
3857 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003858 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003859 */
3860static LY_ERR
3861xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3862{
3863 const struct lyd_node *node;
3864 struct lysc_node_leaf *sleaf;
3865 struct lyd_attr *attr = NULL;
3866 const char *val;
3867 int i, dynamic;
3868 LY_ERR rc = LY_SUCCESS;
3869
3870 if (options & LYXP_SCNODE_ALL) {
3871 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3872 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3873 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 +02003874 } else if (!warn_is_string_type(sleaf->type)) {
3875 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003876 }
3877 }
3878 set_scnode_clear_ctx(set);
3879 return rc;
3880 }
3881
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003882 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003883 LY_CHECK_RET(rc);
3884
3885 if (set->type == LYXP_SET_EMPTY) {
3886 set_fill_boolean(set, 0);
3887 return LY_SUCCESS;
3888 }
3889 if (set->type != LYXP_SET_NODE_SET) {
3890 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3891 return LY_EVALID;
3892 }
3893
3894 switch (set->val.nodes[0].type) {
3895 case LYXP_NODE_ELEM:
3896 case LYXP_NODE_TEXT:
3897 node = set->val.nodes[0].node;
3898 break;
3899 case LYXP_NODE_ATTR:
3900 node = set->val.attrs[0].attr->parent;
3901 break;
3902 default:
3903 /* nothing to do with roots */
3904 set_fill_boolean(set, 0);
3905 return LY_SUCCESS;
3906 }
3907
3908 /* find lang attribute */
3909 for (; node; node = (struct lyd_node *)node->parent) {
3910 for (attr = node->attr; attr; attr = attr->next) {
3911 /* annotations */
3912 if (attr->name && !strcmp(attr->name, "lang") && !strcmp(attr->annotation->module->name, "xml")) {
3913 break;
3914 }
3915 }
3916
3917 if (attr) {
3918 break;
3919 }
3920 }
3921
3922 /* compare languages */
3923 if (!attr) {
3924 set_fill_boolean(set, 0);
3925 } else {
3926 val = lyd_attr2str(attr, &dynamic);
3927 for (i = 0; args[0]->val.str[i]; ++i) {
3928 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3929 set_fill_boolean(set, 0);
3930 break;
3931 }
3932 }
3933 if (!args[0]->val.str[i]) {
3934 if (!val[i] || (val[i] == '-')) {
3935 set_fill_boolean(set, 1);
3936 } else {
3937 set_fill_boolean(set, 0);
3938 }
3939 }
3940 if (dynamic) {
3941 free((char *)val);
3942 }
3943 }
3944
3945 return LY_SUCCESS;
3946}
3947
3948/**
3949 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3950 * with the context size.
3951 *
3952 * @param[in] args Array of arguments.
3953 * @param[in] arg_count Count of elements in @p args.
3954 * @param[in,out] set Context and result set at the same time.
3955 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003956 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003957 */
3958static LY_ERR
3959xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3960{
3961 if (options & LYXP_SCNODE_ALL) {
3962 set_scnode_clear_ctx(set);
3963 return LY_SUCCESS;
3964 }
3965
3966 if (set->type == LYXP_SET_EMPTY) {
3967 set_fill_number(set, 0);
3968 return LY_SUCCESS;
3969 }
3970 if (set->type != LYXP_SET_NODE_SET) {
3971 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3972 return LY_EVALID;
3973 }
3974
3975 set_fill_number(set, set->ctx_size);
3976 return LY_SUCCESS;
3977}
3978
3979/**
3980 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3981 * with the node name without namespace from the argument or the context.
3982 *
3983 * @param[in] args Array of arguments.
3984 * @param[in] arg_count Count of elements in @p args.
3985 * @param[in,out] set Context and result set at the same time.
3986 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003987 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003988 */
3989static LY_ERR
3990xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3991{
3992 struct lyxp_set_node *item;
3993 /* suppress unused variable warning */
3994 (void)options;
3995
3996 if (options & LYXP_SCNODE_ALL) {
3997 set_scnode_clear_ctx(set);
3998 return LY_SUCCESS;
3999 }
4000
4001 if (arg_count) {
4002 if (args[0]->type == LYXP_SET_EMPTY) {
4003 set_fill_string(set, "", 0);
4004 return LY_SUCCESS;
4005 }
4006 if (args[0]->type != LYXP_SET_NODE_SET) {
4007 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
4008 return LY_EVALID;
4009 }
4010
4011 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004012 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004013
4014 item = &args[0]->val.nodes[0];
4015 } else {
4016 if (set->type == LYXP_SET_EMPTY) {
4017 set_fill_string(set, "", 0);
4018 return LY_SUCCESS;
4019 }
4020 if (set->type != LYXP_SET_NODE_SET) {
4021 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4022 return LY_EVALID;
4023 }
4024
4025 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004026 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004027
4028 item = &set->val.nodes[0];
4029 }
4030
4031 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004032 case LYXP_NODE_NONE:
4033 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004034 case LYXP_NODE_ROOT:
4035 case LYXP_NODE_ROOT_CONFIG:
4036 case LYXP_NODE_TEXT:
4037 set_fill_string(set, "", 0);
4038 break;
4039 case LYXP_NODE_ELEM:
4040 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4041 break;
4042 case LYXP_NODE_ATTR:
4043 set_fill_string(set, ((struct lyd_attr *)item->node)->name, strlen(((struct lyd_attr *)item->node)->name));
4044 break;
4045 }
4046
4047 return LY_SUCCESS;
4048}
4049
4050/**
4051 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4052 * with the node name fully qualified (with namespace) from the argument or the context.
4053 *
4054 * @param[in] args Array of arguments.
4055 * @param[in] arg_count Count of elements in @p args.
4056 * @param[in,out] set Context and result set at the same time.
4057 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004058 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004059 */
4060static LY_ERR
4061xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4062{
4063 struct lyxp_set_node *item;
4064 struct lys_module *mod;
4065 char *str;
4066 const char *name;
4067 int rc;
4068
4069 if (options & LYXP_SCNODE_ALL) {
4070 set_scnode_clear_ctx(set);
4071 return LY_SUCCESS;
4072 }
4073
4074 if (arg_count) {
4075 if (args[0]->type == LYXP_SET_EMPTY) {
4076 set_fill_string(set, "", 0);
4077 return LY_SUCCESS;
4078 }
4079 if (args[0]->type != LYXP_SET_NODE_SET) {
4080 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4081 return LY_EVALID;
4082 }
4083
4084 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004085 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004086
4087 item = &args[0]->val.nodes[0];
4088 } else {
4089 if (set->type == LYXP_SET_EMPTY) {
4090 set_fill_string(set, "", 0);
4091 return LY_SUCCESS;
4092 }
4093 if (set->type != LYXP_SET_NODE_SET) {
4094 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4095 return LY_EVALID;
4096 }
4097
4098 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004099 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004100
4101 item = &set->val.nodes[0];
4102 }
4103
4104 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004105 case LYXP_NODE_NONE:
4106 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004107 case LYXP_NODE_ROOT:
4108 case LYXP_NODE_ROOT_CONFIG:
4109 case LYXP_NODE_TEXT:
4110 mod = NULL;
4111 name = NULL;
4112 break;
4113 case LYXP_NODE_ELEM:
4114 mod = item->node->schema->module;
4115 name = item->node->schema->name;
4116 break;
4117 case LYXP_NODE_ATTR:
4118 mod = ((struct lyd_attr *)item->node)->annotation->module;
4119 name = ((struct lyd_attr *)item->node)->name;
4120 break;
4121 }
4122
4123 if (mod && name) {
4124 switch (set->format) {
4125 case LYD_UNKNOWN:
4126 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4127 break;
4128 case LYD_JSON:
4129 rc = asprintf(&str, "%s:%s", mod->name, name);
4130 break;
Michal Vasko9409ef62019-09-12 11:47:17 +02004131 default:
4132 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004133 }
4134 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4135 set_fill_string(set, str, strlen(str));
4136 free(str);
4137 } else {
4138 set_fill_string(set, "", 0);
4139 }
4140
4141 return LY_SUCCESS;
4142}
4143
4144/**
4145 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4146 * with the namespace of the node from the argument or the context.
4147 *
4148 * @param[in] args Array of arguments.
4149 * @param[in] arg_count Count of elements in @p args.
4150 * @param[in,out] set Context and result set at the same time.
4151 * @param[in] options XPath options.
4152 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4153 */
4154static LY_ERR
4155xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4156{
4157 struct lyxp_set_node *item;
4158 struct lys_module *mod;
4159 /* suppress unused variable warning */
4160 (void)options;
4161
4162 if (options & LYXP_SCNODE_ALL) {
4163 set_scnode_clear_ctx(set);
4164 return LY_SUCCESS;
4165 }
4166
4167 if (arg_count) {
4168 if (args[0]->type == LYXP_SET_EMPTY) {
4169 set_fill_string(set, "", 0);
4170 return LY_SUCCESS;
4171 }
4172 if (args[0]->type != LYXP_SET_NODE_SET) {
4173 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "namespace-uri(node-set?)");
4174 return LY_EVALID;
4175 }
4176
4177 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004178 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004179
4180 item = &args[0]->val.nodes[0];
4181 } else {
4182 if (set->type == LYXP_SET_EMPTY) {
4183 set_fill_string(set, "", 0);
4184 return LY_SUCCESS;
4185 }
4186 if (set->type != LYXP_SET_NODE_SET) {
4187 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4188 return LY_EVALID;
4189 }
4190
4191 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004192 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004193
4194 item = &set->val.nodes[0];
4195 }
4196
4197 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004198 case LYXP_NODE_NONE:
4199 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004200 case LYXP_NODE_ROOT:
4201 case LYXP_NODE_ROOT_CONFIG:
4202 case LYXP_NODE_TEXT:
4203 set_fill_string(set, "", 0);
4204 break;
4205 case LYXP_NODE_ELEM:
4206 case LYXP_NODE_ATTR:
4207 if (item->type == LYXP_NODE_ELEM) {
4208 mod = item->node->schema->module;
4209 } else { /* LYXP_NODE_ATTR */
4210 /* annotations */
4211 mod = ((struct lyd_attr *)item->node)->annotation->module;
4212 }
4213
4214 set_fill_string(set, mod->ns, strlen(mod->ns));
4215 break;
4216 }
4217
4218 return LY_SUCCESS;
4219}
4220
4221/**
4222 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4223 * with only nodes from the context. In practice it either leaves the context
4224 * as it is or returns an empty node set.
4225 *
4226 * @param[in] args Array of arguments.
4227 * @param[in] arg_count Count of elements in @p args.
4228 * @param[in,out] set Context and result set at the same time.
4229 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004230 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004231 */
4232static LY_ERR
4233xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4234{
4235 if (options & LYXP_SCNODE_ALL) {
4236 set_scnode_clear_ctx(set);
4237 return LY_SUCCESS;
4238 }
4239
4240 if (set->type != LYXP_SET_NODE_SET) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004241 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004242 }
4243 return LY_SUCCESS;
4244}
4245
4246/**
4247 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4248 * with normalized value (no leading, trailing, double white spaces) of the node
4249 * from the argument or the context.
4250 *
4251 * @param[in] args Array of arguments.
4252 * @param[in] arg_count Count of elements in @p args.
4253 * @param[in,out] set Context and result set at the same time.
4254 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004255 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004256 */
4257static LY_ERR
4258xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4259{
4260 uint16_t i, new_used;
4261 char *new;
4262 int have_spaces = 0, space_before = 0;
4263 struct lysc_node_leaf *sleaf;
4264 LY_ERR rc = LY_SUCCESS;
4265
4266 if (options & LYXP_SCNODE_ALL) {
4267 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4268 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4269 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 +02004270 } else if (!warn_is_string_type(sleaf->type)) {
4271 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004272 }
4273 }
4274 set_scnode_clear_ctx(set);
4275 return rc;
4276 }
4277
4278 if (arg_count) {
4279 set_fill_set(set, args[0]);
4280 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004281 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004282 LY_CHECK_RET(rc);
4283
4284 /* is there any normalization necessary? */
4285 for (i = 0; set->val.str[i]; ++i) {
4286 if (is_xmlws(set->val.str[i])) {
4287 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4288 have_spaces = 1;
4289 break;
4290 }
4291 space_before = 1;
4292 } else {
4293 space_before = 0;
4294 }
4295 }
4296
4297 /* yep, there is */
4298 if (have_spaces) {
4299 /* it's enough, at least one character will go, makes space for ending '\0' */
4300 new = malloc(strlen(set->val.str) * sizeof(char));
4301 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4302 new_used = 0;
4303
4304 space_before = 0;
4305 for (i = 0; set->val.str[i]; ++i) {
4306 if (is_xmlws(set->val.str[i])) {
4307 if ((i == 0) || space_before) {
4308 space_before = 1;
4309 continue;
4310 } else {
4311 space_before = 1;
4312 }
4313 } else {
4314 space_before = 0;
4315 }
4316
4317 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4318 ++new_used;
4319 }
4320
4321 /* at worst there is one trailing space now */
4322 if (new_used && is_xmlws(new[new_used - 1])) {
4323 --new_used;
4324 }
4325
4326 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4327 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4328 new[new_used] = '\0';
4329
4330 free(set->val.str);
4331 set->val.str = new;
4332 }
4333
4334 return LY_SUCCESS;
4335}
4336
4337/**
4338 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4339 * with the argument converted to boolean and logically inverted.
4340 *
4341 * @param[in] args Array of arguments.
4342 * @param[in] arg_count Count of elements in @p args.
4343 * @param[in,out] set Context and result set at the same time.
4344 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004345 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004346 */
4347static LY_ERR
4348xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4349{
4350 if (options & LYXP_SCNODE_ALL) {
4351 set_scnode_clear_ctx(set);
4352 return LY_SUCCESS;
4353 }
4354
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004355 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004356 if (args[0]->val.bool) {
4357 set_fill_boolean(set, 0);
4358 } else {
4359 set_fill_boolean(set, 1);
4360 }
4361
4362 return LY_SUCCESS;
4363}
4364
4365/**
4366 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4367 * with the number representation of either the argument or the context.
4368 *
4369 * @param[in] args Array of arguments.
4370 * @param[in] arg_count Count of elements in @p args.
4371 * @param[in,out] set Context and result set at the same time.
4372 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004373 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004374 */
4375static LY_ERR
4376xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4377{
4378 LY_ERR rc;
4379
4380 if (options & LYXP_SCNODE_ALL) {
4381 set_scnode_clear_ctx(set);
4382 return LY_SUCCESS;
4383 }
4384
4385 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004386 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004387 LY_CHECK_RET(rc);
4388 set_fill_set(set, args[0]);
4389 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004390 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004391 LY_CHECK_RET(rc);
4392 }
4393
4394 return LY_SUCCESS;
4395}
4396
4397/**
4398 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4399 * with the context position.
4400 *
4401 * @param[in] args Array of arguments.
4402 * @param[in] arg_count Count of elements in @p args.
4403 * @param[in,out] set Context and result set at the same time.
4404 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004405 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004406 */
4407static LY_ERR
4408xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4409{
4410 if (options & LYXP_SCNODE_ALL) {
4411 set_scnode_clear_ctx(set);
4412 return LY_SUCCESS;
4413 }
4414
4415 if (set->type == LYXP_SET_EMPTY) {
4416 set_fill_number(set, 0);
4417 return LY_SUCCESS;
4418 }
4419 if (set->type != LYXP_SET_NODE_SET) {
4420 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4421 return LY_EVALID;
4422 }
4423
4424 set_fill_number(set, set->ctx_pos);
4425
4426 /* UNUSED in 'Release' build type */
4427 (void)options;
4428 return LY_SUCCESS;
4429}
4430
4431/**
4432 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4433 * depending on whether the second argument regex matches the first argument string. For details refer to
4434 * YANG 1.1 RFC section 10.2.1.
4435 *
4436 * @param[in] args Array of arguments.
4437 * @param[in] arg_count Count of elements in @p args.
4438 * @param[in,out] set Context and result set at the same time.
4439 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004440 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004441 */
4442static LY_ERR
4443xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4444{
4445 struct lysc_pattern **patterns = NULL, **pattern;
4446 struct lysc_node_leaf *sleaf;
4447 char *path;
4448 LY_ERR rc = LY_SUCCESS;
4449 struct ly_err_item *err;
4450
4451 if (options & LYXP_SCNODE_ALL) {
4452 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4453 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4454 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 +02004455 } else if (!warn_is_string_type(sleaf->type)) {
4456 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004457 }
4458 }
4459
4460 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4461 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4462 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 +02004463 } else if (!warn_is_string_type(sleaf->type)) {
4464 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004465 }
4466 }
4467 set_scnode_clear_ctx(set);
4468 return rc;
4469 }
4470
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004471 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004472 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004473 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004474 LY_CHECK_RET(rc);
4475
4476 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4477 *pattern = malloc(sizeof **pattern);
4478 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4479 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4480 free(path);
4481 if (rc != LY_SUCCESS) {
4482 LY_ARRAY_FREE(patterns);
4483 return rc;
4484 }
4485
4486 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4487 pcre2_code_free((*pattern)->code);
4488 free(*pattern);
4489 LY_ARRAY_FREE(patterns);
4490 if (rc && (rc != LY_EVALID)) {
4491 ly_err_print(err);
4492 ly_err_free(err);
4493 return rc;
4494 }
4495
4496 if (rc == LY_EVALID) {
4497 ly_err_free(err);
4498 set_fill_boolean(set, 0);
4499 } else {
4500 set_fill_boolean(set, 1);
4501 }
4502
4503 return LY_SUCCESS;
4504}
4505
4506/**
4507 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4508 * with the rounded first argument. For details refer to
4509 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4510 *
4511 * @param[in] args Array of arguments.
4512 * @param[in] arg_count Count of elements in @p args.
4513 * @param[in,out] set Context and result set at the same time.
4514 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004515 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004516 */
4517static LY_ERR
4518xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4519{
4520 struct lysc_node_leaf *sleaf;
4521 LY_ERR rc = LY_SUCCESS;
4522
4523 if (options & LYXP_SCNODE_ALL) {
4524 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4525 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004526 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4527 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 +02004528 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4529 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004530 }
4531 set_scnode_clear_ctx(set);
4532 return rc;
4533 }
4534
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004535 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004536 LY_CHECK_RET(rc);
4537
4538 /* cover only the cases where floor can't be used */
4539 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4540 set_fill_number(set, -0.0f);
4541 } else {
4542 args[0]->val.num += 0.5;
4543 rc = xpath_floor(args, 1, args[0], options);
4544 LY_CHECK_RET(rc);
4545 set_fill_number(set, args[0]->val.num);
4546 }
4547
4548 return LY_SUCCESS;
4549}
4550
4551/**
4552 * @brief Execute the XPath starts-with(string, string) function.
4553 * Returns LYXP_SET_BOOLEAN whether the second argument is
4554 * the prefix of the first or not.
4555 *
4556 * @param[in] args Array of arguments.
4557 * @param[in] arg_count Count of elements in @p args.
4558 * @param[in,out] set Context and result set at the same time.
4559 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004560 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004561 */
4562static LY_ERR
4563xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4564{
4565 struct lysc_node_leaf *sleaf;
4566 LY_ERR rc = LY_SUCCESS;
4567
4568 if (options & LYXP_SCNODE_ALL) {
4569 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4570 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4571 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 +02004572 } else if (!warn_is_string_type(sleaf->type)) {
4573 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004574 }
4575 }
4576
4577 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4578 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4579 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 +02004580 } else if (!warn_is_string_type(sleaf->type)) {
4581 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004582 }
4583 }
4584 set_scnode_clear_ctx(set);
4585 return rc;
4586 }
4587
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004588 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004589 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004590 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004591 LY_CHECK_RET(rc);
4592
4593 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4594 set_fill_boolean(set, 0);
4595 } else {
4596 set_fill_boolean(set, 1);
4597 }
4598
4599 return LY_SUCCESS;
4600}
4601
4602/**
4603 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4604 * with the string representation of either the argument or the context.
4605 *
4606 * @param[in] args Array of arguments.
4607 * @param[in] arg_count Count of elements in @p args.
4608 * @param[in,out] set Context and result set at the same time.
4609 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004610 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004611 */
4612static LY_ERR
4613xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4614{
4615 LY_ERR rc;
4616
4617 if (options & LYXP_SCNODE_ALL) {
4618 set_scnode_clear_ctx(set);
4619 return LY_SUCCESS;
4620 }
4621
4622 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004623 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004624 LY_CHECK_RET(rc);
4625 set_fill_set(set, args[0]);
4626 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004627 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004628 LY_CHECK_RET(rc);
4629 }
4630
4631 return LY_SUCCESS;
4632}
4633
4634/**
4635 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4636 * with the length of the string in either the argument or the context.
4637 *
4638 * @param[in] args Array of arguments.
4639 * @param[in] arg_count Count of elements in @p args.
4640 * @param[in,out] set Context and result set at the same time.
4641 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004642 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004643 */
4644static LY_ERR
4645xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4646{
4647 struct lysc_node_leaf *sleaf;
4648 LY_ERR rc = LY_SUCCESS;
4649
4650 if (options & LYXP_SCNODE_ALL) {
4651 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4652 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4653 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 +02004654 } else if (!warn_is_string_type(sleaf->type)) {
4655 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004656 }
4657 }
4658 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4659 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4660 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 +02004661 } else if (!warn_is_string_type(sleaf->type)) {
4662 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004663 }
4664 }
4665 set_scnode_clear_ctx(set);
4666 return rc;
4667 }
4668
4669 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004670 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004671 LY_CHECK_RET(rc);
4672 set_fill_number(set, strlen(args[0]->val.str));
4673 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004674 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004675 LY_CHECK_RET(rc);
4676 set_fill_number(set, strlen(set->val.str));
4677 }
4678
4679 return LY_SUCCESS;
4680}
4681
4682/**
4683 * @brief Execute the XPath substring(string, number, number?) function.
4684 * Returns LYXP_SET_STRING substring of the first argument starting
4685 * on the second argument index ending on the third argument index,
4686 * indexed from 1. For exact definition refer to
4687 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4688 *
4689 * @param[in] args Array of arguments.
4690 * @param[in] arg_count Count of elements in @p args.
4691 * @param[in,out] set Context and result set at the same time.
4692 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004693 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004694 */
4695static LY_ERR
4696xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4697{
4698 int start, len;
4699 uint16_t str_start, str_len, pos;
4700 struct lysc_node_leaf *sleaf;
4701 LY_ERR rc = LY_SUCCESS;
4702
4703 if (options & LYXP_SCNODE_ALL) {
4704 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4705 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4706 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 +02004707 } else if (!warn_is_string_type(sleaf->type)) {
4708 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004709 }
4710 }
4711
4712 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4713 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4714 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 +02004715 } else if (!warn_is_numeric_type(sleaf->type)) {
4716 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004717 }
4718 }
4719
4720 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4721 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4722 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4723 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 +02004724 } else if (!warn_is_numeric_type(sleaf->type)) {
4725 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004726 }
4727 }
4728 set_scnode_clear_ctx(set);
4729 return rc;
4730 }
4731
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004732 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004733 LY_CHECK_RET(rc);
4734
4735 /* start */
4736 if (xpath_round(&args[1], 1, args[1], options)) {
4737 return -1;
4738 }
4739 if (isfinite(args[1]->val.num)) {
4740 start = args[1]->val.num - 1;
4741 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4742 start = INT_MIN;
4743 } else {
4744 start = INT_MAX;
4745 }
4746
4747 /* len */
4748 if (arg_count == 3) {
4749 rc = xpath_round(&args[2], 1, args[2], options);
4750 LY_CHECK_RET(rc);
4751 if (isfinite(args[2]->val.num)) {
4752 len = args[2]->val.num;
4753 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4754 len = 0;
4755 } else {
4756 len = INT_MAX;
4757 }
4758 } else {
4759 len = INT_MAX;
4760 }
4761
4762 /* find matching character positions */
4763 str_start = 0;
4764 str_len = 0;
4765 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4766 if (pos < start) {
4767 ++str_start;
4768 } else if (pos < start + len) {
4769 ++str_len;
4770 } else {
4771 break;
4772 }
4773 }
4774
4775 set_fill_string(set, args[0]->val.str + str_start, str_len);
4776 return LY_SUCCESS;
4777}
4778
4779/**
4780 * @brief Execute the XPath substring-after(string, string) function.
4781 * Returns LYXP_SET_STRING with the string succeeding the occurance
4782 * of the second argument in the first or an empty string.
4783 *
4784 * @param[in] args Array of arguments.
4785 * @param[in] arg_count Count of elements in @p args.
4786 * @param[in,out] set Context and result set at the same time.
4787 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004788 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004789 */
4790static LY_ERR
4791xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4792{
4793 char *ptr;
4794 struct lysc_node_leaf *sleaf;
4795 LY_ERR rc = LY_SUCCESS;
4796
4797 if (options & LYXP_SCNODE_ALL) {
4798 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4799 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4800 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 +02004801 } else if (!warn_is_string_type(sleaf->type)) {
4802 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004803 }
4804 }
4805
4806 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4807 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4808 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 +02004809 } else if (!warn_is_string_type(sleaf->type)) {
4810 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004811 }
4812 }
4813 set_scnode_clear_ctx(set);
4814 return rc;
4815 }
4816
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004817 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004818 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004819 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004820 LY_CHECK_RET(rc);
4821
4822 ptr = strstr(args[0]->val.str, args[1]->val.str);
4823 if (ptr) {
4824 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4825 } else {
4826 set_fill_string(set, "", 0);
4827 }
4828
4829 return LY_SUCCESS;
4830}
4831
4832/**
4833 * @brief Execute the XPath substring-before(string, string) function.
4834 * Returns LYXP_SET_STRING with the string preceding the occurance
4835 * of the second argument in the first or an empty string.
4836 *
4837 * @param[in] args Array of arguments.
4838 * @param[in] arg_count Count of elements in @p args.
4839 * @param[in,out] set Context and result set at the same time.
4840 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004841 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004842 */
4843static LY_ERR
4844xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4845{
4846 char *ptr;
4847 struct lysc_node_leaf *sleaf;
4848 LY_ERR rc = LY_SUCCESS;
4849
4850 if (options & LYXP_SCNODE_ALL) {
4851 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4852 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4853 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 +02004854 } else if (!warn_is_string_type(sleaf->type)) {
4855 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004856 }
4857 }
4858
4859 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4860 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4861 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 +02004862 } else if (!warn_is_string_type(sleaf->type)) {
4863 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004864 }
4865 }
4866 set_scnode_clear_ctx(set);
4867 return rc;
4868 }
4869
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004870 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004871 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004872 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004873 LY_CHECK_RET(rc);
4874
4875 ptr = strstr(args[0]->val.str, args[1]->val.str);
4876 if (ptr) {
4877 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4878 } else {
4879 set_fill_string(set, "", 0);
4880 }
4881
4882 return LY_SUCCESS;
4883}
4884
4885/**
4886 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4887 * with the sum of all the nodes in the context.
4888 *
4889 * @param[in] args Array of arguments.
4890 * @param[in] arg_count Count of elements in @p args.
4891 * @param[in,out] set Context and result set at the same time.
4892 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004893 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004894 */
4895static LY_ERR
4896xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4897{
4898 long double num;
4899 char *str;
4900 uint16_t i;
4901 struct lyxp_set set_item;
4902 struct lysc_node_leaf *sleaf;
4903 LY_ERR rc = LY_SUCCESS;
4904
4905 if (options & LYXP_SCNODE_ALL) {
4906 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4907 for (i = 0; i < args[0]->used; ++i) {
4908 if (args[0]->val.scnodes[i].in_ctx == 1) {
4909 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4910 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4911 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4912 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004913 } else if (!warn_is_numeric_type(sleaf->type)) {
4914 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004915 }
4916 }
4917 }
4918 }
4919 set_scnode_clear_ctx(set);
4920 return rc;
4921 }
4922
4923 set_fill_number(set, 0);
4924 if (args[0]->type == LYXP_SET_EMPTY) {
4925 return LY_SUCCESS;
4926 }
4927
4928 if (args[0]->type != LYXP_SET_NODE_SET) {
4929 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4930 return LY_EVALID;
4931 }
4932
Michal Vasko5c4e5892019-11-14 12:31:38 +01004933 set_init(&set_item, set);
4934
Michal Vasko03ff5a72019-09-11 13:49:33 +02004935 set_item.type = LYXP_SET_NODE_SET;
4936 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4937 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4938
4939 set_item.used = 1;
4940 set_item.size = 1;
4941
4942 for (i = 0; i < args[0]->used; ++i) {
4943 set_item.val.nodes[0] = args[0]->val.nodes[i];
4944
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004945 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004946 LY_CHECK_RET(rc);
4947 num = cast_string_to_number(str);
4948 free(str);
4949 set->val.num += num;
4950 }
4951
4952 free(set_item.val.nodes);
4953
4954 return LY_SUCCESS;
4955}
4956
4957/**
4958 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4959 * with the text content of the nodes in the context.
4960 *
4961 * @param[in] args Array of arguments.
4962 * @param[in] arg_count Count of elements in @p args.
4963 * @param[in,out] set Context and result set at the same time.
4964 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004965 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004966 */
4967static LY_ERR
4968xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4969{
4970 uint32_t i;
4971
4972 if (options & LYXP_SCNODE_ALL) {
4973 set_scnode_clear_ctx(set);
4974 return LY_SUCCESS;
4975 }
4976
4977 if (set->type == LYXP_SET_EMPTY) {
4978 return LY_SUCCESS;
4979 }
4980 if (set->type != LYXP_SET_NODE_SET) {
4981 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4982 return LY_EVALID;
4983 }
4984
4985 for (i = 0; i < set->used;) {
4986 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004987 case LYXP_NODE_NONE:
4988 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004989 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004990 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4991 set->val.nodes[i].type = LYXP_NODE_TEXT;
4992 ++i;
4993 break;
4994 }
4995 /* fall through */
4996 case LYXP_NODE_ROOT:
4997 case LYXP_NODE_ROOT_CONFIG:
4998 case LYXP_NODE_TEXT:
4999 case LYXP_NODE_ATTR:
5000 set_remove_node(set, i);
5001 break;
5002 }
5003 }
5004
5005 return LY_SUCCESS;
5006}
5007
5008/**
5009 * @brief Execute the XPath translate(string, string, string) function.
5010 * Returns LYXP_SET_STRING with the first argument with the characters
5011 * from the second argument replaced by those on the corresponding
5012 * positions in the third argument.
5013 *
5014 * @param[in] args Array of arguments.
5015 * @param[in] arg_count Count of elements in @p args.
5016 * @param[in,out] set Context and result set at the same time.
5017 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005018 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005019 */
5020static LY_ERR
5021xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5022{
5023 uint16_t i, j, new_used;
5024 char *new;
5025 int found, have_removed;
5026 struct lysc_node_leaf *sleaf;
5027 LY_ERR rc = LY_SUCCESS;
5028
5029 if (options & LYXP_SCNODE_ALL) {
5030 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5031 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5032 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 +02005033 } else if (!warn_is_string_type(sleaf->type)) {
5034 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005035 }
5036 }
5037
5038 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5039 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5040 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 +02005041 } else if (!warn_is_string_type(sleaf->type)) {
5042 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005043 }
5044 }
5045
5046 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5047 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5048 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 +02005049 } else if (!warn_is_string_type(sleaf->type)) {
5050 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005051 }
5052 }
5053 set_scnode_clear_ctx(set);
5054 return rc;
5055 }
5056
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005057 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005058 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005059 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005060 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005061 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005062 LY_CHECK_RET(rc);
5063
5064 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5065 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5066 new_used = 0;
5067
5068 have_removed = 0;
5069 for (i = 0; args[0]->val.str[i]; ++i) {
5070 found = 0;
5071
5072 for (j = 0; args[1]->val.str[j]; ++j) {
5073 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5074 /* removing this char */
5075 if (j >= strlen(args[2]->val.str)) {
5076 have_removed = 1;
5077 found = 1;
5078 break;
5079 }
5080 /* replacing this char */
5081 new[new_used] = args[2]->val.str[j];
5082 ++new_used;
5083 found = 1;
5084 break;
5085 }
5086 }
5087
5088 /* copying this char */
5089 if (!found) {
5090 new[new_used] = args[0]->val.str[i];
5091 ++new_used;
5092 }
5093 }
5094
5095 if (have_removed) {
5096 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5097 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5098 }
5099 new[new_used] = '\0';
5100
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005101 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005102 set->type = LYXP_SET_STRING;
5103 set->val.str = new;
5104
5105 return LY_SUCCESS;
5106}
5107
5108/**
5109 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5110 * with true value.
5111 *
5112 * @param[in] args Array of arguments.
5113 * @param[in] arg_count Count of elements in @p args.
5114 * @param[in,out] set Context and result set at the same time.
5115 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005116 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005117 */
5118static LY_ERR
5119xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5120{
5121 if (options & LYXP_SCNODE_ALL) {
5122 set_scnode_clear_ctx(set);
5123 return LY_SUCCESS;
5124 }
5125
5126 set_fill_boolean(set, 1);
5127 return LY_SUCCESS;
5128}
5129
5130/*
5131 * moveto functions
5132 *
5133 * They and only they actually change the context (set).
5134 */
5135
5136/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005137 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005138 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005139 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5140 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5141 * @param[in] set Set with XPath context.
5142 * @param[out] moveto_mod Expected module of a matching node.
5143 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005144 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005145static LY_ERR
5146moveto_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 +02005147{
Michal Vasko6346ece2019-09-24 13:12:53 +02005148 const struct lys_module *mod;
5149 const char *ptr;
5150 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005151 char *str;
5152
Michal Vasko6346ece2019-09-24 13:12:53 +02005153 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5154 /* specific module */
5155 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005156
Michal Vasko6346ece2019-09-24 13:12:53 +02005157 switch (set->format) {
5158 case LYD_UNKNOWN:
5159 /* schema, search all local module imports */
5160 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5161 break;
5162 case LYD_JSON:
5163 /* JSON data, search in context */
5164 str = strndup(*qname, pref_len);
5165 mod = ly_ctx_get_module(set->ctx, str, NULL);
5166 free(str);
5167 break;
5168 default:
5169 LOGINT_RET(set->ctx);
5170 }
5171
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005172 /* Check for errors and non-implemented modules, as they are not valid */
5173 if (!mod || !mod->implemented) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005174 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5175 return LY_EVALID;
5176 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005177
Michal Vasko6346ece2019-09-24 13:12:53 +02005178 *qname += pref_len + 1;
5179 *qname_len -= pref_len + 1;
5180 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5181 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005182 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005183 } else {
5184 /* local module */
5185 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005186 }
5187
Michal Vasko6346ece2019-09-24 13:12:53 +02005188 *moveto_mod = mod;
5189 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005190}
5191
5192/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005193 * @brief Move context @p set to the root. Handles absolute path.
5194 * Result is LYXP_SET_NODE_SET.
5195 *
5196 * @param[in,out] set Set to use.
5197 * @param[in] options Xpath options.
5198 */
5199static void
5200moveto_root(struct lyxp_set *set, int options)
5201{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005202 if (!set) {
5203 return;
5204 }
5205
5206 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005207 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005208 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005209 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005210 lyxp_set_cast(set, LYXP_SET_EMPTY);
5211 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005212 }
5213}
5214
5215/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005216 * @brief Check whether a node has some unresolved "when".
5217 *
5218 * @param[in] node Node to check.
5219 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5220 */
5221static LY_ERR
5222moveto_when_check(const struct lyd_node *node)
5223{
5224 const struct lysc_node *schema;
5225
5226 if (!node) {
5227 return LY_SUCCESS;
5228 }
5229
5230 schema = node->schema;
5231 do {
5232 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5233 return LY_EINCOMPLETE;
5234 }
5235 schema = schema->parent;
5236 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5237
5238 return LY_SUCCESS;
5239}
5240
5241/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005242 * @brief Check @p node as a part of NameTest processing.
5243 *
5244 * @param[in] node Node to check.
5245 * @param[in] root_type XPath root node type.
5246 * @param[in] node_name Node name to move to. Must be in the dictionary!
5247 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005248 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5249 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005250 */
5251static LY_ERR
5252moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5253 const struct lys_module *moveto_mod)
5254{
5255 /* module check */
5256 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005257 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005258 }
5259
Michal Vasko5c4e5892019-11-14 12:31:38 +01005260 /* context check */
5261 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005262 return LY_EINVAL;
5263 }
5264
5265 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005266 if (strcmp(node_name, "*") && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005267 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005268 }
5269
Michal Vaskoa1424542019-11-14 16:08:52 +01005270 /* when check */
5271 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005272 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005273 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005274
5275 /* match */
5276 return LY_SUCCESS;
5277}
5278
5279/**
5280 * @brief Check @p node as a part of schema NameTest processing.
5281 *
5282 * @param[in] node Schema node to check.
5283 * @param[in] root_type XPath root node type.
5284 * @param[in] node_name Node name to move to. Must be in the dictionary!
5285 * @param[in] moveto_mod Expected module of the node.
Michal Vasko6346ece2019-09-24 13:12:53 +02005286 * @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 +02005287 */
5288static LY_ERR
5289moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005290 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005291{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005292 /* module check */
5293 if (strcmp(node_name, "*") && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005294 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005295 }
5296
5297 /* context check */
5298 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5299 return LY_EINVAL;
5300 }
5301
5302 /* name check */
Michal Vasko465a0e12019-11-07 11:11:58 +01005303 if (strcmp(node_name, "*") && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005304 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005305 }
5306
5307 /* match */
5308 return LY_SUCCESS;
5309}
5310
5311/**
5312 * @brief Move context @p set to a node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5313 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5314 *
5315 * @param[in,out] set Set to use.
5316 * @param[in] qname Qualified node name to move to.
5317 * @param[in] qname_len Length of @p qname.
5318 * @param[in] options XPath options.
5319 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5320 */
5321static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005322moveto_node(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005323{
Michal Vasko79bebfd2019-11-14 16:09:19 +01005324 uint32_t i, j;
Michal Vasko6346ece2019-09-24 13:12:53 +02005325 int replaced;
5326 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005327 const struct lys_module *moveto_mod;
5328 const struct lyd_node *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005329 LY_ERR rc;
5330
5331 if (!set || (set->type == LYXP_SET_EMPTY)) {
5332 return LY_SUCCESS;
5333 }
5334
5335 if (set->type != LYXP_SET_NODE_SET) {
5336 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5337 return LY_EVALID;
5338 }
5339
Michal Vasko6346ece2019-09-24 13:12:53 +02005340 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5341 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005342
5343 /* name */
5344 name_dict = lydict_insert(set->ctx, qname, qname_len);
5345
5346 for (i = 0; i < set->used; ) {
5347 replaced = 0;
5348
5349 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 +01005350 assert(!set->val.nodes[i].node);
5351 /* search in all the trees */
Michal Vasko79bebfd2019-11-14 16:09:19 +01005352 LY_ARRAY_FOR(set->trees, j) {
5353 for (sub = set->trees[j]; sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005354 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005355 if (rc == LY_SUCCESS) {
5356 /* pos filled later */
5357 if (!replaced) {
5358 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5359 replaced = 1;
5360 } else {
5361 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5362 }
5363 ++i;
5364 } else if (rc == LY_EINCOMPLETE) {
5365 lydict_remove(set->ctx, name_dict);
5366 return rc;
5367 }
5368 }
5369 }
5370
Michal Vasko5c4e5892019-11-14 12:31:38 +01005371 /* skip nodes without children - leaves, leaflists, anyxmls (ouput root will eval to true) */
5372 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005373
5374 for (sub = lyd_node_children(set->val.nodes[i].node); sub; sub = sub->next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005375 rc = moveto_node_check(sub, set->root_type, name_dict, moveto_mod);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005376 if (rc == LY_SUCCESS) {
5377 if (!replaced) {
5378 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5379 replaced = 1;
5380 } else {
5381 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5382 }
5383 ++i;
5384 } else if (rc == LY_EINCOMPLETE) {
5385 lydict_remove(set->ctx, name_dict);
5386 return rc;
5387 }
5388 }
5389 }
5390
5391 if (!replaced) {
5392 /* no match */
5393 set_remove_node(set, i);
5394 }
5395 }
5396 lydict_remove(set->ctx, name_dict);
5397
5398 return LY_SUCCESS;
5399}
5400
5401/**
5402 * @brief Move context @p set to a schema node. Handles '/' and '*', 'NAME', 'PREFIX:*', or 'PREFIX:NAME'.
5403 * Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5404 *
5405 * @param[in,out] set Set to use.
5406 * @param[in] qname Qualified node name to move to.
5407 * @param[in] qname_len Length of @p qname.
5408 * @param[in] options XPath options.
5409 * @return LY_ERR
5410 */
5411static LY_ERR
5412moveto_scnode(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5413{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005414 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005415 uint32_t mod_idx;
Michal Vasko6346ece2019-09-24 13:12:53 +02005416 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005417 const struct lys_module *moveto_mod;
5418 const struct lysc_node *sub, *start_parent;
Michal Vasko6346ece2019-09-24 13:12:53 +02005419 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005420
5421 if (!set || (set->type == LYXP_SET_EMPTY)) {
5422 return LY_SUCCESS;
5423 }
5424
5425 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005426 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 +02005427 return LY_EVALID;
5428 }
5429
Michal Vasko6346ece2019-09-24 13:12:53 +02005430 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5431 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005432
5433 /* name */
5434 name_dict = lydict_insert(set->ctx, qname, qname_len);
5435
Michal Vaskocafad9d2019-11-07 15:20:03 +01005436 /* getnext opts */
5437 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5438 if (options & LYXP_SCNODE_OUTPUT) {
5439 getnext_opts |= LYS_GETNEXT_OUTPUT;
5440 }
5441
Michal Vasko03ff5a72019-09-11 13:49:33 +02005442 orig_used = set->used;
5443 for (i = 0; i < orig_used; ++i) {
5444 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005445 if (set->val.scnodes[i].in_ctx != -2) {
5446 continue;
5447 }
5448
5449 /* remember context node */
5450 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005451 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005452
5453 start_parent = set->val.scnodes[i].scnode;
5454
5455 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
5456 /* it can actually be in any module, it's all <running>, but we know it's moveto_mod (if set),
5457 * so use it directly (root node itself is useless in this case) */
5458 mod_idx = 0;
5459 while (moveto_mod || (moveto_mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
5460 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005461 /* module may not be implemented */
5462 while (moveto_mod->implemented && (sub = lys_getnext(sub, NULL, moveto_mod->compiled, getnext_opts))) {
Michal Vaskocafad9d2019-11-07 15:20:03 +01005463 if (!moveto_scnode_check(sub, set->root_type, name_dict, moveto_mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005464 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005465 /* we need to prevent these nodes from being considered in this moveto */
5466 if ((idx < orig_used) && (idx > i)) {
5467 set->val.scnodes[idx].in_ctx = 2;
5468 temp_ctx = 1;
5469 }
5470 }
5471 }
5472
5473 if (!mod_idx) {
5474 /* moveto_mod was specified, we are not going through the whole context */
5475 break;
5476 }
5477 /* next iteration */
5478 moveto_mod = NULL;
5479 }
5480
5481 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5482 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5483 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005484 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
5485 if (!moveto_scnode_check(sub, set->root_type, name_dict, (moveto_mod ? moveto_mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005486 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005487 if ((idx < orig_used) && (idx > i)) {
5488 set->val.scnodes[idx].in_ctx = 2;
5489 temp_ctx = 1;
5490 }
5491 }
5492 }
5493 }
5494 }
5495 lydict_remove(set->ctx, name_dict);
5496
5497 /* correct temporary in_ctx values */
5498 if (temp_ctx) {
5499 for (i = 0; i < orig_used; ++i) {
5500 if (set->val.scnodes[i].in_ctx == 2) {
5501 set->val.scnodes[i].in_ctx = 1;
5502 }
5503 }
5504 }
5505
5506 return LY_SUCCESS;
5507}
5508
5509/**
5510 * @brief Move context @p set to a node and all its descendants. Handles '//' and '*', 'NAME',
5511 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5512 * Context position aware.
5513 *
5514 * @param[in] set Set to use.
5515 * @param[in] qname Qualified node name to move to.
5516 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005517 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5518 */
5519static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005520moveto_node_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005521{
5522 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005523 const char *name_dict = NULL; /* optimization - so we can do (==) instead (!strncmp(...)) in moveto_node_check() */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005524 const struct lyd_node *next, *elem, *start;
5525 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005526 struct lyxp_set ret_set;
5527 LY_ERR rc;
5528
5529 if (!set || (set->type == LYXP_SET_EMPTY)) {
5530 return LY_SUCCESS;
5531 }
5532
5533 if (set->type != LYXP_SET_NODE_SET) {
5534 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5535 return LY_EVALID;
5536 }
5537
Michal Vasko6346ece2019-09-24 13:12:53 +02005538 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5539 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005540
5541 /* 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 +01005542 rc = moveto_node(set, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005543 LY_CHECK_RET(rc);
5544
Michal Vasko6346ece2019-09-24 13:12:53 +02005545 /* name */
5546 name_dict = lydict_insert(set->ctx, qname, qname_len);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005547
Michal Vasko6346ece2019-09-24 13:12:53 +02005548 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005549 set_init(&ret_set, set);
5550 for (i = 0; i < set->used; ++i) {
5551
5552 /* TREE DFS */
5553 start = set->val.nodes[i].node;
5554 for (elem = next = start; elem; elem = next) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005555 rc = moveto_node_check(elem, set->root_type, name_dict, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005556 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005557 /* add matching node into result set */
5558 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5559 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5560 /* the node is a duplicate, we'll process it later in the set */
5561 goto skip_children;
5562 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005563 } else if (rc == LY_EINCOMPLETE) {
5564 lydict_remove(set->ctx, name_dict);
5565 return rc;
5566 } else if (rc == LY_EINVAL) {
5567 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005568 }
5569
5570 /* TREE DFS NEXT ELEM */
5571 /* select element for the next run - children first */
5572 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5573 next = NULL;
5574 } else {
5575 next = lyd_node_children(elem);
5576 }
5577 if (!next) {
5578skip_children:
5579 /* no children, so try siblings, but only if it's not the start,
5580 * that is considered to be the root and it's siblings are not traversed */
5581 if (elem != start) {
5582 next = elem->next;
5583 } else {
5584 break;
5585 }
5586 }
5587 while (!next) {
5588 /* no siblings, go back through the parents */
5589 if ((struct lyd_node *)elem->parent == start) {
5590 /* we are done, no next element to process */
5591 break;
5592 }
5593 /* parent is already processed, go to its sibling */
5594 elem = (struct lyd_node *)elem->parent;
5595 next = elem->next;
5596 }
5597 }
5598 }
5599
5600 /* make the temporary set the current one */
5601 ret_set.ctx_pos = set->ctx_pos;
5602 ret_set.ctx_size = set->ctx_size;
5603 set_free_content(set);
5604 memcpy(set, &ret_set, sizeof *set);
5605
Michal Vasko6346ece2019-09-24 13:12:53 +02005606 lydict_remove(set->ctx, name_dict);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005607 return LY_SUCCESS;
5608}
5609
5610/**
5611 * @brief Move context @p set to a schema node and all its descendants. Handles '//' and '*', 'NAME',
5612 * 'PREFIX:*', or 'PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5613 *
5614 * @param[in] set Set to use.
5615 * @param[in] qname Qualified node name to move to.
5616 * @param[in] qname_len Length of @p qname.
5617 * @param[in] options XPath options.
5618 * @return LY_ERR
5619 */
5620static LY_ERR
5621moveto_scnode_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len, int options)
5622{
Michal Vasko6346ece2019-09-24 13:12:53 +02005623 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005624 const struct lysc_node *next, *elem, *start;
5625 const struct lys_module *moveto_mod;
Michal Vasko6346ece2019-09-24 13:12:53 +02005626 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005627
5628 if (!set || (set->type == LYXP_SET_EMPTY)) {
5629 return LY_SUCCESS;
5630 }
5631
5632 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005633 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 +02005634 return LY_EVALID;
5635 }
5636
Michal Vasko6346ece2019-09-24 13:12:53 +02005637 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5638 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005639
5640 orig_used = set->used;
5641 for (i = 0; i < orig_used; ++i) {
5642 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005643 if (set->val.scnodes[i].in_ctx != -2) {
5644 continue;
5645 }
5646
5647 /* remember context node */
5648 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005649 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005650
5651 /* TREE DFS */
5652 start = set->val.scnodes[i].scnode;
5653 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005654 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5655 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005656 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005657 }
5658
Michal Vaskocafad9d2019-11-07 15:20:03 +01005659 rc = moveto_scnode_check(elem, set->root_type, qname, moveto_mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005660 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005661 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005662 set->val.scnodes[idx].in_ctx = 1;
5663 if (idx > i) {
5664 /* we will process it later in the set */
5665 goto skip_children;
5666 }
5667 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005668 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005669 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005670 } else if (rc == LY_EINVAL) {
5671 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005672 }
5673
5674next_iter:
5675 /* TREE DFS NEXT ELEM */
5676 /* select element for the next run - children first */
5677 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
5678 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5679 next = NULL;
5680 }
5681 if (!next) {
5682skip_children:
5683 /* no children, so try siblings, but only if it's not the start,
5684 * that is considered to be the root and it's siblings are not traversed */
5685 if (elem != start) {
5686 next = elem->next;
5687 } else {
5688 break;
5689 }
5690 }
5691 while (!next) {
5692 /* no siblings, go back through the parents */
5693 if (elem->parent == start) {
5694 /* we are done, no next element to process */
5695 break;
5696 }
5697 /* parent is already processed, go to its sibling */
5698 elem = elem->parent;
5699 next = elem->next;
5700 }
5701 }
5702 }
5703
5704 return LY_SUCCESS;
5705}
5706
5707/**
5708 * @brief Move context @p set to an attribute. Handles '/' and '@*', '@NAME', '@PREFIX:*',
5709 * or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5710 * Indirectly context position aware.
5711 *
5712 * @param[in,out] set Set to use.
5713 * @param[in] qname Qualified node name to move to.
5714 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005715 * @return LY_ERR
5716 */
5717static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005718moveto_attr(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005719{
5720 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005721 int replaced, all = 0;
5722 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005723 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005724 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005725
5726 if (!set || (set->type == LYXP_SET_EMPTY)) {
5727 return LY_SUCCESS;
5728 }
5729
5730 if (set->type != LYXP_SET_NODE_SET) {
5731 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5732 return LY_EVALID;
5733 }
5734
Michal Vasko6346ece2019-09-24 13:12:53 +02005735 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5736 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005737
5738 if ((qname_len == 1) && (qname[0] == '*')) {
5739 all = 1;
5740 }
5741
5742 for (i = 0; i < set->used; ) {
5743 replaced = 0;
5744
5745 /* only attributes of an elem (not dummy) can be in the result, skip all the rest;
5746 * our attributes are always qualified */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005747 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005748 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5749
5750 /* check "namespace" */
5751 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5752 continue;
5753 }
5754
5755 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5756 /* match */
5757 if (!replaced) {
5758 set->val.attrs[i].attr = sub;
5759 set->val.attrs[i].type = LYXP_NODE_ATTR;
5760 /* pos does not change */
5761 replaced = 1;
5762 } else {
5763 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_ATTR, i + 1);
5764 }
5765 ++i;
5766 }
5767 }
5768 }
5769
5770 if (!replaced) {
5771 /* no match */
5772 set_remove_node(set, i);
5773 }
5774 }
5775
5776 return LY_SUCCESS;
5777}
5778
5779/**
5780 * @brief Move context @p set1 to union with @p set2. @p set2 is emptied afterwards.
5781 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
5782 *
5783 * @param[in,out] set1 Set to use for the result.
5784 * @param[in] set2 Set that is copied to @p set1.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005785 * @return LY_ERR
5786 */
5787static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005788moveto_union(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005789{
5790 LY_ERR rc;
5791
5792 if (((set1->type != LYXP_SET_NODE_SET) && (set1->type != LYXP_SET_EMPTY))
5793 || ((set2->type != LYXP_SET_NODE_SET) && (set2->type != LYXP_SET_EMPTY))) {
5794 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5795 return LY_EVALID;
5796 }
5797
5798 /* set2 is empty or both set1 and set2 */
5799 if (set2->type == LYXP_SET_EMPTY) {
5800 return LY_SUCCESS;
5801 }
5802
5803 if (set1->type == LYXP_SET_EMPTY) {
5804 memcpy(set1, set2, sizeof *set1);
5805 /* dynamic memory belongs to set1 now, do not free */
5806 set2->type = LYXP_SET_EMPTY;
5807 return LY_SUCCESS;
5808 }
5809
5810 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005811 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005812
5813 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005814 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005815 LY_CHECK_RET(rc);
5816
5817 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005818 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005819
5820 return LY_SUCCESS;
5821}
5822
5823/**
5824 * @brief Move context @p set to an attribute in any of the descendants. Handles '//' and '@*',
5825 * '@NAME', '@PREFIX:*', or '@PREFIX:NAME'. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5826 * Context position aware.
5827 *
5828 * @param[in,out] set Set to use.
5829 * @param[in] qname Qualified node name to move to.
5830 * @param[in] qname_len Length of @p qname.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005831 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5832 */
5833static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005834moveto_attr_alldesc(struct lyxp_set *set, const char *qname, uint16_t qname_len)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005835{
5836 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005837 int replaced, all = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005838 struct lyd_attr *sub;
Michal Vasko6346ece2019-09-24 13:12:53 +02005839 const struct lys_module *moveto_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005840 struct lyxp_set *set_all_desc = NULL;
5841 LY_ERR rc;
5842
5843 if (!set || (set->type == LYXP_SET_EMPTY)) {
5844 return LY_SUCCESS;
5845 }
5846
5847 if (set->type != LYXP_SET_NODE_SET) {
5848 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5849 return LY_EVALID;
5850 }
5851
Michal Vasko6346ece2019-09-24 13:12:53 +02005852 rc = moveto_resolve_model(&qname, &qname_len, set, &moveto_mod);
5853 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005854
5855 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5856 * but it likely won't be used much, so it's a waste of time */
5857 /* copy the context */
5858 set_all_desc = set_copy(set);
5859 /* get all descendant nodes (the original context nodes are removed) */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005860 rc = moveto_node_alldesc(set_all_desc, "*", 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005861 if (rc != LY_SUCCESS) {
5862 lyxp_set_free(set_all_desc);
5863 return rc;
5864 }
5865 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005866 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005867 if (rc != LY_SUCCESS) {
5868 lyxp_set_free(set_all_desc);
5869 return rc;
5870 }
5871 lyxp_set_free(set_all_desc);
5872
5873 if ((qname_len == 1) && (qname[0] == '*')) {
5874 all = 1;
5875 }
5876
5877 for (i = 0; i < set->used; ) {
5878 replaced = 0;
5879
5880 /* only attributes of an elem can be in the result, skip all the rest,
5881 * we have all attributes qualified in lyd tree */
5882 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5883 for (sub = set->val.nodes[i].node->attr; sub; sub = sub->next) {
5884 /* check "namespace" */
5885 if (moveto_mod && (sub->annotation->module != moveto_mod)) {
5886 continue;
5887 }
5888
5889 if (all || (!strncmp(sub->name, qname, qname_len) && !sub->name[qname_len])) {
5890 /* match */
5891 if (!replaced) {
5892 set->val.attrs[i].attr = sub;
5893 set->val.attrs[i].type = LYXP_NODE_ATTR;
5894 /* pos does not change */
5895 replaced = 1;
5896 } else {
5897 set_insert_node(set, (struct lyd_node *)sub, set->val.attrs[i].pos, LYXP_NODE_ATTR, i + 1);
5898 }
5899 ++i;
5900 }
5901 }
5902 }
5903
5904 if (!replaced) {
5905 /* no match */
5906 set_remove_node(set, i);
5907 }
5908 }
5909
5910 return LY_SUCCESS;
5911}
5912
5913/**
5914 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5915 * (or LYXP_SET_EMPTY). Context position aware.
5916 *
5917 * @param[in] parent Current parent.
5918 * @param[in] parent_pos Position of @p parent.
5919 * @param[in] parent_type Node type of @p parent.
5920 * @param[in,out] to_set Set to use.
5921 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005922 * @param[in] options XPath options.
5923 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5924 */
5925static LY_ERR
5926moveto_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 +01005927 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005928{
5929 const struct lyd_node *sub;
5930 LY_ERR rc;
5931
5932 switch (parent_type) {
5933 case LYXP_NODE_ROOT:
5934 case LYXP_NODE_ROOT_CONFIG:
5935 /* add the same node but as an element */
5936 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5937 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5938
5939 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005940 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005941 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005942 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005943 LY_CHECK_RET(rc);
5944 }
5945 }
5946 break;
5947 case LYXP_NODE_ELEM:
5948 /* add all the children ... */
5949 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5950 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5951 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005952 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005953 continue;
5954 }
5955
Michal Vaskoa1424542019-11-14 16:08:52 +01005956 /* when check */
5957 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005958 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005959 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005960
5961 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5962 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5963
Michal Vasko5c4e5892019-11-14 12:31:38 +01005964 /* skip anydata/anyxml nodes */
5965 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005966 continue;
5967 }
5968
5969 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005970 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005971 LY_CHECK_RET(rc);
5972 }
5973 }
5974
5975 /* ... or add their text node, ... */
5976 } else {
5977 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5978 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5979 }
5980 }
5981 break;
5982 default:
5983 LOGINT_RET(parent->schema->module->ctx);
5984 }
5985
5986 return LY_SUCCESS;
5987}
5988
5989/**
5990 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5991 * (or LYXP_SET_EMPTY). Context position aware.
5992 *
5993 * @param[in,out] set Set to use.
5994 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
5995 * @param[in] options XPath options.
5996 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5997 */
5998static LY_ERR
5999moveto_self(struct lyxp_set *set, int all_desc, int options)
6000{
6001 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006002 struct lyxp_set ret_set;
6003 LY_ERR rc;
6004
6005 if (!set || (set->type == LYXP_SET_EMPTY)) {
6006 return LY_SUCCESS;
6007 }
6008
6009 if (set->type != LYXP_SET_NODE_SET) {
6010 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6011 return LY_EVALID;
6012 }
6013
6014 /* nothing to do */
6015 if (!all_desc) {
6016 return LY_SUCCESS;
6017 }
6018
Michal Vasko03ff5a72019-09-11 13:49:33 +02006019 /* add all the children, they get added recursively */
6020 set_init(&ret_set, set);
6021 for (i = 0; i < set->used; ++i) {
6022 /* copy the current node to tmp */
6023 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6024
6025 /* do not touch attributes and text nodes */
6026 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_ATTR)) {
6027 continue;
6028 }
6029
Michal Vasko5c4e5892019-11-14 12:31:38 +01006030 /* skip anydata/anyxml nodes */
6031 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006032 continue;
6033 }
6034
6035 /* add all the children */
6036 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 +01006037 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006038 if (rc != LY_SUCCESS) {
6039 set_free_content(&ret_set);
6040 return rc;
6041 }
6042 }
6043
6044 /* use the temporary set as the current one */
6045 ret_set.ctx_pos = set->ctx_pos;
6046 ret_set.ctx_size = set->ctx_size;
6047 set_free_content(set);
6048 memcpy(set, &ret_set, sizeof *set);
6049
6050 return LY_SUCCESS;
6051}
6052
6053/**
6054 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6055 * (or LYXP_SET_EMPTY).
6056 *
6057 * @param[in,out] set Set to use.
6058 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6059 * @param[in] options XPath options.
6060 * @return LY_ERR
6061 */
6062static LY_ERR
6063moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6064{
6065 const struct lysc_node *sub;
6066 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006067
6068 if (!set || (set->type == LYXP_SET_EMPTY)) {
6069 return LY_SUCCESS;
6070 }
6071
6072 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006073 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 +02006074 return LY_EVALID;
6075 }
6076
6077 /* nothing to do */
6078 if (!all_desc) {
6079 return LY_SUCCESS;
6080 }
6081
Michal Vasko03ff5a72019-09-11 13:49:33 +02006082 /* add all the children, they get added recursively */
6083 for (i = 0; i < set->used; ++i) {
6084 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006085 if (set->val.scnodes[i].in_ctx != -2) {
6086 continue;
6087 }
6088
6089 /* remember context node (it was traversed again so it changes to a normal node) */
6090 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006091 }
6092
6093 /* add all the children */
6094 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6095 sub = NULL;
6096 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6097 /* RPC input/output check */
6098 if (options & LYXP_SCNODE_OUTPUT) {
6099 if (sub->parent->nodetype == LYS_INPUT) {
6100 continue;
6101 }
6102 } else {
6103 if (sub->parent->nodetype == LYS_OUTPUT) {
6104 continue;
6105 }
6106 }
6107
6108 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006109 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006110 continue;
6111 }
6112
Michal Vaskoecd62de2019-11-13 12:35:11 +01006113 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006114 /* throw away the insert index, we want to consider that node again, recursively */
6115 }
6116 }
6117 }
6118
6119 return LY_SUCCESS;
6120}
6121
6122/**
6123 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6124 * (or LYXP_SET_EMPTY). Context position aware.
6125 *
6126 * @param[in] set Set to use.
6127 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6128 * @param[in] options XPath options.
6129 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6130 */
6131static LY_ERR
6132moveto_parent(struct lyxp_set *set, int all_desc, int options)
6133{
6134 LY_ERR rc;
6135 uint32_t i;
6136 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006137 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006138
6139 if (!set || (set->type == LYXP_SET_EMPTY)) {
6140 return LY_SUCCESS;
6141 }
6142
6143 if (set->type != LYXP_SET_NODE_SET) {
6144 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6145 return LY_EVALID;
6146 }
6147
6148 if (all_desc) {
6149 /* <path>//.. == <path>//./.. */
6150 rc = moveto_self(set, 1, options);
6151 LY_CHECK_RET(rc);
6152 }
6153
Michal Vasko57eab132019-09-24 11:46:26 +02006154 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006155 node = set->val.nodes[i].node;
6156
6157 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6158 new_node = (struct lyd_node *)node->parent;
6159 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6160 new_node = node;
6161 } else if (set->val.nodes[i].type == LYXP_NODE_ATTR) {
6162 new_node = set->val.attrs[i].attr->parent;
6163 if (!new_node) {
6164 LOGINT_RET(set->ctx);
6165 }
6166 } else {
6167 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006168 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006169 continue;
6170 }
6171
Michal Vaskoa1424542019-11-14 16:08:52 +01006172 /* when check */
6173 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006174 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006175 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006176
6177 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006178 if (!new_node) {
6179 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006180
6181 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6182 } else {
6183 new_type = LYXP_NODE_ELEM;
6184 }
6185
Michal Vasko03ff5a72019-09-11 13:49:33 +02006186 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006187 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006188 } else {
6189 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006190 }
6191 }
6192
Michal Vasko2caefc12019-11-14 16:07:56 +01006193 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006194 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006195
6196 return LY_SUCCESS;
6197}
6198
6199/**
6200 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6201 * (or LYXP_SET_EMPTY).
6202 *
6203 * @param[in] set Set to use.
6204 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6205 * @param[in] options XPath options.
6206 * @return LY_ERR
6207 */
6208static LY_ERR
6209moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6210{
6211 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006212 const struct lysc_node *node, *new_node;
6213 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006214 LY_ERR rc;
6215
6216 if (!set || (set->type == LYXP_SET_EMPTY)) {
6217 return LY_SUCCESS;
6218 }
6219
6220 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006221 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 +02006222 return LY_EVALID;
6223 }
6224
6225 if (all_desc) {
6226 /* <path>//.. == <path>//./.. */
6227 rc = moveto_scnode_self(set, 1, options);
6228 LY_CHECK_RET(rc);
6229 }
6230
Michal Vasko03ff5a72019-09-11 13:49:33 +02006231 orig_used = set->used;
6232 for (i = 0; i < orig_used; ++i) {
6233 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006234 if (set->val.scnodes[i].in_ctx != -2) {
6235 continue;
6236 }
6237
6238 /* remember context node */
6239 set->val.scnodes[i].in_ctx = -1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006240 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006241
6242 node = set->val.scnodes[i].scnode;
6243
6244 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
6245 for (new_node = node->parent;
6246 new_node && (new_node->nodetype & (LYS_CHOICE | LYS_CASE));
6247 new_node = new_node->parent);
6248 } else {
6249 /* root does not have a parent */
6250 continue;
6251 }
6252
Michal Vasko03ff5a72019-09-11 13:49:33 +02006253 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006254 if (!new_node) {
6255 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006256
6257 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6258 } else {
6259 new_type = LYXP_NODE_ELEM;
6260 }
6261
Michal Vaskoecd62de2019-11-13 12:35:11 +01006262 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006263 if ((idx < orig_used) && (idx > i)) {
6264 set->val.scnodes[idx].in_ctx = 2;
6265 temp_ctx = 1;
6266 }
6267 }
6268
6269 if (temp_ctx) {
6270 for (i = 0; i < orig_used; ++i) {
6271 if (set->val.scnodes[i].in_ctx == 2) {
6272 set->val.scnodes[i].in_ctx = 1;
6273 }
6274 }
6275 }
6276
6277 return LY_SUCCESS;
6278}
6279
6280/**
6281 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6282 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6283 *
6284 * @param[in,out] set1 Set to use for the result.
6285 * @param[in] set2 Set acting as the second operand for @p op.
6286 * @param[in] op Comparison operator to process.
6287 * @param[in] options XPath options.
6288 * @return LY_ERR
6289 */
6290static LY_ERR
6291moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6292{
6293 /*
6294 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6295 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6296 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6297 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6298 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6299 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6300 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6301 *
6302 * '=' or '!='
6303 * BOOLEAN + BOOLEAN
6304 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6305 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6306 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6307 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6308 * NUMBER + NUMBER
6309 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6310 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6311 * STRING + STRING
6312 *
6313 * '<=', '<', '>=', '>'
6314 * NUMBER + NUMBER
6315 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6316 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6317 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6318 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6319 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6320 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6321 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6322 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6323 */
6324 struct lyxp_set iter1, iter2;
6325 int result;
6326 int64_t i;
6327 LY_ERR rc;
6328
6329 iter1.type = LYXP_SET_EMPTY;
6330
6331 /* empty node-sets are always false */
6332 if ((set1->type == LYXP_SET_EMPTY) || (set2->type == LYXP_SET_EMPTY)) {
6333 set_fill_boolean(set1, 0);
6334 return LY_SUCCESS;
6335 }
6336
6337 /* iterative evaluation with node-sets */
6338 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6339 if (set1->type == LYXP_SET_NODE_SET) {
6340 for (i = 0; i < set1->used; ++i) {
6341 switch (set2->type) {
6342 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006343 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006344 break;
6345 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006346 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006347 break;
6348 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006349 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006350 break;
6351 }
6352 LY_CHECK_RET(rc);
6353
6354 rc = moveto_op_comp(&iter1, set2, op, options);
6355 if (rc != LY_SUCCESS) {
6356 set_free_content(&iter1);
6357 return rc;
6358 }
6359
6360 /* lazy evaluation until true */
6361 if (iter1.val.bool) {
6362 set_fill_boolean(set1, 1);
6363 return LY_SUCCESS;
6364 }
6365 }
6366 } else {
6367 for (i = 0; i < set2->used; ++i) {
6368 switch (set1->type) {
6369 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006370 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006371 break;
6372 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006373 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006374 break;
6375 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006376 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006377 break;
6378 }
6379 LY_CHECK_RET(rc);
6380
6381 set_fill_set(&iter1, set1);
6382
6383 rc = moveto_op_comp(&iter1, &iter2, op, options);
6384 if (rc != LY_SUCCESS) {
6385 set_free_content(&iter1);
6386 set_free_content(&iter2);
6387 return rc;
6388 }
6389 set_free_content(&iter2);
6390
6391 /* lazy evaluation until true */
6392 if (iter1.val.bool) {
6393 set_fill_boolean(set1, 1);
6394 return LY_SUCCESS;
6395 }
6396 }
6397 }
6398
6399 /* false for all nodes */
6400 set_fill_boolean(set1, 0);
6401 return LY_SUCCESS;
6402 }
6403
6404 /* first convert properly */
6405 if ((op[0] == '=') || (op[0] == '!')) {
6406 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006407 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6408 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006409 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006410 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006411 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006412 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006413 LY_CHECK_RET(rc);
6414 } /* else we have 2 strings */
6415 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006416 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006417 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006418 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006419 LY_CHECK_RET(rc);
6420 }
6421
6422 assert(set1->type == set2->type);
6423
6424 /* compute result */
6425 if (op[0] == '=') {
6426 if (set1->type == LYXP_SET_BOOLEAN) {
6427 result = (set1->val.bool == set2->val.bool);
6428 } else if (set1->type == LYXP_SET_NUMBER) {
6429 result = (set1->val.num == set2->val.num);
6430 } else {
6431 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006432 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006433 }
6434 } else if (op[0] == '!') {
6435 if (set1->type == LYXP_SET_BOOLEAN) {
6436 result = (set1->val.bool != set2->val.bool);
6437 } else if (set1->type == LYXP_SET_NUMBER) {
6438 result = (set1->val.num != set2->val.num);
6439 } else {
6440 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006441 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006442 }
6443 } else {
6444 assert(set1->type == LYXP_SET_NUMBER);
6445 if (op[0] == '<') {
6446 if (op[1] == '=') {
6447 result = (set1->val.num <= set2->val.num);
6448 } else {
6449 result = (set1->val.num < set2->val.num);
6450 }
6451 } else {
6452 if (op[1] == '=') {
6453 result = (set1->val.num >= set2->val.num);
6454 } else {
6455 result = (set1->val.num > set2->val.num);
6456 }
6457 }
6458 }
6459
6460 /* assign result */
6461 if (result) {
6462 set_fill_boolean(set1, 1);
6463 } else {
6464 set_fill_boolean(set1, 0);
6465 }
6466
6467 return LY_SUCCESS;
6468}
6469
6470/**
6471 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6472 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6473 *
6474 * @param[in,out] set1 Set to use for the result.
6475 * @param[in] set2 Set acting as the second operand for @p op.
6476 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006477 * @return LY_ERR
6478 */
6479static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006480moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006481{
6482 LY_ERR rc;
6483
6484 /* unary '-' */
6485 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006486 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006487 LY_CHECK_RET(rc);
6488 set1->val.num *= -1;
6489 lyxp_set_free(set2);
6490 return LY_SUCCESS;
6491 }
6492
6493 assert(set1 && set2);
6494
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006495 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006496 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006497 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006498 LY_CHECK_RET(rc);
6499
6500 switch (op[0]) {
6501 /* '+' */
6502 case '+':
6503 set1->val.num += set2->val.num;
6504 break;
6505
6506 /* '-' */
6507 case '-':
6508 set1->val.num -= set2->val.num;
6509 break;
6510
6511 /* '*' */
6512 case '*':
6513 set1->val.num *= set2->val.num;
6514 break;
6515
6516 /* 'div' */
6517 case 'd':
6518 set1->val.num /= set2->val.num;
6519 break;
6520
6521 /* 'mod' */
6522 case 'm':
6523 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6524 break;
6525
6526 default:
6527 LOGINT_RET(set1->ctx);
6528 }
6529
6530 return LY_SUCCESS;
6531}
6532
6533/*
6534 * eval functions
6535 *
6536 * They execute a parsed XPath expression on some data subtree.
6537 */
6538
6539/**
6540 * @brief Evaluate Literal. Logs directly on error.
6541 *
6542 * @param[in] exp Parsed XPath expression.
6543 * @param[in] exp_idx Position in the expression @p exp.
6544 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6545 */
6546static void
6547eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6548{
6549 if (set) {
6550 if (exp->tok_len[*exp_idx] == 2) {
6551 set_fill_string(set, "", 0);
6552 } else {
6553 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6554 }
6555 }
6556 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6557 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6558 ++(*exp_idx);
6559}
6560
6561/**
6562 * @brief Evaluate NodeTest. Logs directly on error.
6563 *
6564 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6565 *
6566 * @param[in] exp Parsed XPath expression.
6567 * @param[in] exp_idx Position in the expression @p exp.
6568 * @param[in] attr_axis Whether to search attributes or standard nodes.
6569 * @param[in] all_desc Whether to search all the descendants or children only.
6570 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6571 * @param[in] options XPath options.
6572 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6573 */
6574static int
6575eval_node_test(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
6576 struct lyxp_set *set, int options)
6577{
6578 int i;
6579 char *path;
6580 LY_ERR rc;
6581
6582 switch (exp->tokens[*exp_idx]) {
6583 case LYXP_TOKEN_NAMETEST:
6584 if (attr_axis) {
6585 if (set && (options & LYXP_SCNODE_ALL)) {
6586 set_scnode_clear_ctx(set);
6587 rc = LY_SUCCESS;
6588 } else {
6589 if (all_desc) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006590 rc = moveto_attr_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006591 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006592 rc = moveto_attr(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006593 }
6594 }
6595 } else {
6596 if (all_desc) {
6597 if (set && (options & LYXP_SCNODE_ALL)) {
6598 rc = moveto_scnode_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6599 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006600 rc = moveto_node_alldesc(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006601 }
6602 } else {
6603 if (set && (options & LYXP_SCNODE_ALL)) {
6604 rc = moveto_scnode(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx], options);
6605 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006606 rc = moveto_node(set, &exp->expr[exp->tok_pos[*exp_idx]], exp->tok_len[*exp_idx]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006607 }
6608 }
6609
6610 if ((rc == LY_SUCCESS) && set && (options & LYXP_SCNODE_ALL)) {
6611 for (i = set->used - 1; i > -1; --i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006612 if (set->val.scnodes[i].in_ctx > 0) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006613 break;
6614 }
6615 }
6616 if (i == -1) {
6617 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6618 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6619 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6620 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6621 free(path);
6622 }
6623 }
6624 }
6625 LY_CHECK_RET(rc);
6626
6627 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6628 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6629 ++(*exp_idx);
6630 break;
6631
6632 case LYXP_TOKEN_NODETYPE:
6633 if (set) {
6634 assert(exp->tok_len[*exp_idx] == 4);
6635 if (set->type == LYXP_SET_SCNODE_SET) {
6636 set_scnode_clear_ctx(set);
6637 /* just for the debug message underneath */
6638 set = NULL;
6639 } else {
6640 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
6641 rc = xpath_node(NULL, 0, set, options);
6642 LY_CHECK_RET(rc);
6643 } else {
6644 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
6645 rc = xpath_text(NULL, 0, set, options);
6646 LY_CHECK_RET(rc);
6647 }
6648 }
6649 }
6650 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6651 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6652 ++(*exp_idx);
6653
6654 /* '(' */
6655 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
6656 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6657 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6658 ++(*exp_idx);
6659
6660 /* ')' */
6661 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
6662 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6663 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6664 ++(*exp_idx);
6665 break;
6666
6667 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006668 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006669 }
6670
6671 return LY_SUCCESS;
6672}
6673
6674/**
6675 * @brief Evaluate Predicate. Logs directly on error.
6676 *
6677 * [7] Predicate ::= '[' Expr ']'
6678 *
6679 * @param[in] exp Parsed XPath expression.
6680 * @param[in] exp_idx Position in the expression @p exp.
6681 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6682 * @param[in] options XPath options.
6683 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6684 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6685 */
6686static LY_ERR
6687eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6688{
6689 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006690 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006691 uint32_t orig_pos, orig_size;
6692 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006693 struct lyxp_set set2;
6694 struct lyd_node *orig_parent;
6695
6696 /* '[' */
6697 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6698 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6699 ++(*exp_idx);
6700
6701 if (!set) {
6702only_parse:
6703 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6704 LY_CHECK_RET(rc);
6705 } else if (set->type == LYXP_SET_NODE_SET) {
6706 /* 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 +01006707 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006708
6709 /* empty set, nothing to evaluate */
6710 if (!set->used) {
6711 goto only_parse;
6712 }
6713
6714 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006715 orig_pos = 0;
6716 orig_size = set->used;
6717 orig_parent = NULL;
6718 for (i = 0; i < set->used; ) {
6719 set_init(&set2, set);
6720 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6721 /* remember the node context position for position() and context size for last(),
6722 * predicates should always be evaluated with respect to the child axis (since we do
6723 * not support explicit axes) so we assign positions based on their parents */
6724 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6725 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6726 orig_pos = 1;
6727 } else {
6728 ++orig_pos;
6729 }
6730
6731 set2.ctx_pos = orig_pos;
6732 set2.ctx_size = orig_size;
6733 *exp_idx = orig_exp;
6734
6735 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6736 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006737 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006738 return rc;
6739 }
6740
6741 /* number is a position */
6742 if (set2.type == LYXP_SET_NUMBER) {
6743 if ((long long)set2.val.num == orig_pos) {
6744 set2.val.num = 1;
6745 } else {
6746 set2.val.num = 0;
6747 }
6748 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006749 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006750
6751 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006752 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006753 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006754 }
6755 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006756 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006757
6758 } else if (set->type == LYXP_SET_SCNODE_SET) {
6759 for (i = 0; i < set->used; ++i) {
6760 if (set->val.scnodes[i].in_ctx == 1) {
6761 /* there is a currently-valid node */
6762 break;
6763 }
6764 }
6765 /* empty set, nothing to evaluate */
6766 if (i == set->used) {
6767 goto only_parse;
6768 }
6769
6770 orig_exp = *exp_idx;
6771
Michal Vasko03ff5a72019-09-11 13:49:33 +02006772 /* set special in_ctx to all the valid snodes */
6773 pred_in_ctx = set_scnode_new_in_ctx(set);
6774
6775 /* use the valid snodes one-by-one */
6776 for (i = 0; i < set->used; ++i) {
6777 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6778 continue;
6779 }
6780 set->val.scnodes[i].in_ctx = 1;
6781
6782 *exp_idx = orig_exp;
6783
6784 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6785 LY_CHECK_RET(rc);
6786
6787 set->val.scnodes[i].in_ctx = pred_in_ctx;
6788 }
6789
6790 /* restore the state as it was before the predicate */
6791 for (i = 0; i < set->used; ++i) {
6792 if (set->val.scnodes[i].in_ctx == 1) {
6793 set->val.scnodes[i].in_ctx = 0;
6794 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6795 set->val.scnodes[i].in_ctx = 1;
6796 }
6797 }
6798
6799 } else {
6800 set2.type = LYXP_SET_EMPTY;
6801 set_fill_set(&set2, set);
6802
6803 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6804 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006805 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006806 return rc;
6807 }
6808
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006809 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006810 if (!set2.val.bool) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006811 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006812 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006813 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006814 }
6815
6816 /* ']' */
6817 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6818 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6819 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6820 ++(*exp_idx);
6821
6822 return LY_SUCCESS;
6823}
6824
6825/**
6826 * @brief Evaluate RelativeLocationPath. Logs directly on error.
6827 *
6828 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
6829 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6830 *
6831 * @param[in] exp Parsed XPath expression.
6832 * @param[in] exp_idx Position in the expression @p exp.
6833 * @param[in] all_desc Whether to search all the descendants or children only.
6834 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6835 * @param[in] options XPath options.
6836 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
6837 */
6838static LY_ERR
6839eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
6840{
6841 int attr_axis;
6842 LY_ERR rc;
6843
6844 goto step;
6845 do {
6846 /* evaluate '/' or '//' */
6847 if (exp->tok_len[*exp_idx] == 1) {
6848 all_desc = 0;
6849 } else {
6850 assert(exp->tok_len[*exp_idx] == 2);
6851 all_desc = 1;
6852 }
6853 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6854 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6855 ++(*exp_idx);
6856
6857step:
6858 /* Step */
6859 attr_axis = 0;
6860 switch (exp->tokens[*exp_idx]) {
6861 case LYXP_TOKEN_DOT:
6862 /* evaluate '.' */
6863 if (set && (options & LYXP_SCNODE_ALL)) {
6864 rc = moveto_scnode_self(set, all_desc, options);
6865 } else {
6866 rc = moveto_self(set, all_desc, options);
6867 }
6868 LY_CHECK_RET(rc);
6869 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6870 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6871 ++(*exp_idx);
6872 break;
6873
6874 case LYXP_TOKEN_DDOT:
6875 /* evaluate '..' */
6876 if (set && (options & LYXP_SCNODE_ALL)) {
6877 rc = moveto_scnode_parent(set, all_desc, options);
6878 } else {
6879 rc = moveto_parent(set, all_desc, options);
6880 }
6881 LY_CHECK_RET(rc);
6882 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6883 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6884 ++(*exp_idx);
6885 break;
6886
6887 case LYXP_TOKEN_AT:
6888 /* evaluate '@' */
6889 attr_axis = 1;
6890 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6891 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6892 ++(*exp_idx);
6893
6894 /* fall through */
6895 case LYXP_TOKEN_NAMETEST:
6896 case LYXP_TOKEN_NODETYPE:
6897 rc = eval_node_test(exp, exp_idx, attr_axis, all_desc, set, options);
6898 LY_CHECK_RET(rc);
6899
6900 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6901 rc = eval_predicate(exp, exp_idx, set, options, 1);
6902 LY_CHECK_RET(rc);
6903 }
6904 break;
6905
6906 default:
Michal Vasko02a77382019-09-12 11:47:35 +02006907 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006908 }
6909 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
6910
6911 return LY_SUCCESS;
6912}
6913
6914/**
6915 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
6916 *
6917 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
6918 *
6919 * @param[in] exp Parsed XPath expression.
6920 * @param[in] exp_idx Position in the expression @p exp.
6921 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6922 * @param[in] options XPath options.
6923 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6924 */
6925static LY_ERR
6926eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6927{
6928 int all_desc;
6929 LY_ERR rc;
6930
6931 if (set) {
6932 /* no matter what tokens follow, we need to be at the root */
6933 moveto_root(set, options);
6934 }
6935
6936 /* '/' RelativeLocationPath? */
6937 if (exp->tok_len[*exp_idx] == 1) {
6938 /* evaluate '/' - deferred */
6939 all_desc = 0;
6940 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6941 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6942 ++(*exp_idx);
6943
Michal Vasko4b9e1052019-09-13 11:25:37 +02006944 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006945 return LY_SUCCESS;
6946 }
6947 switch (exp->tokens[*exp_idx]) {
6948 case LYXP_TOKEN_DOT:
6949 case LYXP_TOKEN_DDOT:
6950 case LYXP_TOKEN_AT:
6951 case LYXP_TOKEN_NAMETEST:
6952 case LYXP_TOKEN_NODETYPE:
6953 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6954 LY_CHECK_RET(rc);
6955 break;
6956 default:
6957 break;
6958 }
6959
6960 /* '//' RelativeLocationPath */
6961 } else {
6962 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
6963 all_desc = 1;
6964 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6965 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6966 ++(*exp_idx);
6967
6968 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
6969 LY_CHECK_RET(rc);
6970 }
6971
6972 return LY_SUCCESS;
6973}
6974
6975/**
6976 * @brief Evaluate FunctionCall. Logs directly on error.
6977 *
6978 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
6979 *
6980 * @param[in] exp Parsed XPath expression.
6981 * @param[in] exp_idx Position in the expression @p exp.
6982 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6983 * @param[in] options XPath options.
6984 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6985 */
6986static LY_ERR
6987eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
6988{
6989 LY_ERR rc;
6990 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01006991 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006992 struct lyxp_set **args = NULL, **args_aux;
6993
6994 if (set) {
6995 /* FunctionName */
6996 switch (exp->tok_len[*exp_idx]) {
6997 case 3:
6998 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
6999 xpath_func = &xpath_not;
7000 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7001 xpath_func = &xpath_sum;
7002 }
7003 break;
7004 case 4:
7005 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7006 xpath_func = &xpath_lang;
7007 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7008 xpath_func = &xpath_last;
7009 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7010 xpath_func = &xpath_name;
7011 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7012 xpath_func = &xpath_true;
7013 }
7014 break;
7015 case 5:
7016 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7017 xpath_func = &xpath_count;
7018 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7019 xpath_func = &xpath_false;
7020 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7021 xpath_func = &xpath_floor;
7022 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7023 xpath_func = &xpath_round;
7024 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7025 xpath_func = &xpath_deref;
7026 }
7027 break;
7028 case 6:
7029 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7030 xpath_func = &xpath_concat;
7031 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7032 xpath_func = &xpath_number;
7033 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7034 xpath_func = &xpath_string;
7035 }
7036 break;
7037 case 7:
7038 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7039 xpath_func = &xpath_boolean;
7040 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7041 xpath_func = &xpath_ceiling;
7042 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7043 xpath_func = &xpath_current;
7044 }
7045 break;
7046 case 8:
7047 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7048 xpath_func = &xpath_contains;
7049 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7050 xpath_func = &xpath_position;
7051 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7052 xpath_func = &xpath_re_match;
7053 }
7054 break;
7055 case 9:
7056 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7057 xpath_func = &xpath_substring;
7058 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7059 xpath_func = &xpath_translate;
7060 }
7061 break;
7062 case 10:
7063 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7064 xpath_func = &xpath_local_name;
7065 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7066 xpath_func = &xpath_enum_value;
7067 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7068 xpath_func = &xpath_bit_is_set;
7069 }
7070 break;
7071 case 11:
7072 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7073 xpath_func = &xpath_starts_with;
7074 }
7075 break;
7076 case 12:
7077 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7078 xpath_func = &xpath_derived_from;
7079 }
7080 break;
7081 case 13:
7082 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7083 xpath_func = &xpath_namespace_uri;
7084 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7085 xpath_func = &xpath_string_length;
7086 }
7087 break;
7088 case 15:
7089 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7090 xpath_func = &xpath_normalize_space;
7091 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7092 xpath_func = &xpath_substring_after;
7093 }
7094 break;
7095 case 16:
7096 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7097 xpath_func = &xpath_substring_before;
7098 }
7099 break;
7100 case 20:
7101 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7102 xpath_func = &xpath_derived_from_or_self;
7103 }
7104 break;
7105 }
7106
7107 if (!xpath_func) {
7108 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7109 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]]);
7110 return LY_EVALID;
7111 }
7112 }
7113
7114 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7115 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7116 ++(*exp_idx);
7117
7118 /* '(' */
7119 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7120 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7121 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7122 ++(*exp_idx);
7123
7124 /* ( Expr ( ',' Expr )* )? */
7125 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7126 if (set) {
7127 args = malloc(sizeof *args);
7128 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7129 arg_count = 1;
7130 args[0] = set_copy(set);
7131 if (!args[0]) {
7132 rc = LY_EMEM;
7133 goto cleanup;
7134 }
7135
7136 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7137 LY_CHECK_GOTO(rc, cleanup);
7138 } else {
7139 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7140 LY_CHECK_GOTO(rc, cleanup);
7141 }
7142 }
7143 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7144 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7145 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7146 ++(*exp_idx);
7147
7148 if (set) {
7149 ++arg_count;
7150 args_aux = realloc(args, arg_count * sizeof *args);
7151 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7152 args = args_aux;
7153 args[arg_count - 1] = set_copy(set);
7154 if (!args[arg_count - 1]) {
7155 rc = LY_EMEM;
7156 goto cleanup;
7157 }
7158
7159 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7160 LY_CHECK_GOTO(rc, cleanup);
7161 } else {
7162 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7163 LY_CHECK_GOTO(rc, cleanup);
7164 }
7165 }
7166
7167 /* ')' */
7168 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7169 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7170 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7171 ++(*exp_idx);
7172
7173 if (set) {
7174 /* evaluate function */
7175 rc = xpath_func(args, arg_count, set, options);
7176
7177 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007178 /* merge all nodes from arg evaluations */
7179 for (i = 0; i < arg_count; ++i) {
7180 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007181 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007182 }
7183 }
7184 } else {
7185 rc = LY_SUCCESS;
7186 }
7187
7188cleanup:
7189 for (i = 0; i < arg_count; ++i) {
7190 lyxp_set_free(args[i]);
7191 }
7192 free(args);
7193
7194 return rc;
7195}
7196
7197/**
7198 * @brief Evaluate Number. Logs directly on error.
7199 *
7200 * @param[in] ctx Context for errors.
7201 * @param[in] exp Parsed XPath expression.
7202 * @param[in] exp_idx Position in the expression @p exp.
7203 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7204 * @return LY_ERR
7205 */
7206static LY_ERR
7207eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7208{
7209 long double num;
7210 char *endptr;
7211
7212 if (set) {
7213 errno = 0;
7214 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7215 if (errno) {
7216 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7217 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7218 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7219 return LY_EVALID;
7220 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7221 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7222 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7223 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7224 return LY_EVALID;
7225 }
7226
7227 set_fill_number(set, num);
7228 }
7229
7230 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7231 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7232 ++(*exp_idx);
7233 return LY_SUCCESS;
7234}
7235
7236/**
7237 * @brief Evaluate PathExpr. Logs directly on error.
7238 *
7239 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
7240 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7241 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7242 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
7243 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
7244 *
7245 * @param[in] exp Parsed XPath expression.
7246 * @param[in] exp_idx Position in the expression @p exp.
7247 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7248 * @param[in] options XPath options.
7249 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7250 */
7251static LY_ERR
7252eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7253{
7254 int all_desc, parent_pos_pred;
7255 LY_ERR rc;
7256
7257 switch (exp->tokens[*exp_idx]) {
7258 case LYXP_TOKEN_PAR1:
7259 /* '(' Expr ')' */
7260
7261 /* '(' */
7262 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7263 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7264 ++(*exp_idx);
7265
7266 /* Expr */
7267 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7268 LY_CHECK_RET(rc);
7269
7270 /* ')' */
7271 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7272 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7273 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7274 ++(*exp_idx);
7275
7276 parent_pos_pred = 0;
7277 goto predicate;
7278
7279 case LYXP_TOKEN_DOT:
7280 case LYXP_TOKEN_DDOT:
7281 case LYXP_TOKEN_AT:
7282 case LYXP_TOKEN_NAMETEST:
7283 case LYXP_TOKEN_NODETYPE:
7284 /* RelativeLocationPath */
7285 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7286 LY_CHECK_RET(rc);
7287 break;
7288
7289 case LYXP_TOKEN_FUNCNAME:
7290 /* FunctionCall */
7291 if (!set) {
7292 rc = eval_function_call(exp, exp_idx, NULL, options);
7293 } else {
7294 rc = eval_function_call(exp, exp_idx, set, options);
7295 }
7296 LY_CHECK_RET(rc);
7297
7298 parent_pos_pred = 1;
7299 goto predicate;
7300
7301 case LYXP_TOKEN_OPERATOR_PATH:
7302 /* AbsoluteLocationPath */
7303 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7304 LY_CHECK_RET(rc);
7305 break;
7306
7307 case LYXP_TOKEN_LITERAL:
7308 /* Literal */
7309 if (!set || (options & LYXP_SCNODE_ALL)) {
7310 if (set) {
7311 set_scnode_clear_ctx(set);
7312 }
7313 eval_literal(exp, exp_idx, NULL);
7314 } else {
7315 eval_literal(exp, exp_idx, set);
7316 }
7317
7318 parent_pos_pred = 1;
7319 goto predicate;
7320
7321 case LYXP_TOKEN_NUMBER:
7322 /* Number */
7323 if (!set || (options & LYXP_SCNODE_ALL)) {
7324 if (set) {
7325 set_scnode_clear_ctx(set);
7326 }
Michal Vasko02a77382019-09-12 11:47:35 +02007327 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007328 } else {
7329 rc = eval_number(set->ctx, exp, exp_idx, set);
7330 }
7331 LY_CHECK_RET(rc);
7332
7333 parent_pos_pred = 1;
7334 goto predicate;
7335
7336 default:
7337 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7338 &exp->expr[exp->tok_pos[*exp_idx]]);
7339 return LY_EVALID;
7340 }
7341
7342 return LY_SUCCESS;
7343
7344predicate:
7345 /* Predicate* */
7346 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7347 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7348 LY_CHECK_RET(rc);
7349 }
7350
7351 /* ('/' or '//') RelativeLocationPath */
7352 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7353
7354 /* evaluate '/' or '//' */
7355 if (exp->tok_len[*exp_idx] == 1) {
7356 all_desc = 0;
7357 } else {
7358 assert(exp->tok_len[*exp_idx] == 2);
7359 all_desc = 1;
7360 }
7361
7362 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7363 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7364 ++(*exp_idx);
7365
7366 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7367 LY_CHECK_RET(rc);
7368 }
7369
7370 return LY_SUCCESS;
7371}
7372
7373/**
7374 * @brief Evaluate UnionExpr. Logs directly on error.
7375 *
7376 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
7377 *
7378 * @param[in] exp Parsed XPath expression.
7379 * @param[in] exp_idx Position in the expression @p exp.
7380 * @param[in] repeat How many times this expression is repeated.
7381 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7382 * @param[in] options XPath options.
7383 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7384 */
7385static LY_ERR
7386eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7387{
7388 LY_ERR rc = LY_SUCCESS;
7389 struct lyxp_set orig_set, set2;
7390 uint16_t i;
7391
7392 assert(repeat);
7393
7394 set_init(&orig_set, set);
7395 set_init(&set2, set);
7396
7397 set_fill_set(&orig_set, set);
7398
7399 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7400 LY_CHECK_GOTO(rc, cleanup);
7401
7402 /* ('|' PathExpr)* */
7403 for (i = 0; i < repeat; ++i) {
7404 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7405 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7406 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7407 ++(*exp_idx);
7408
7409 if (!set) {
7410 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7411 LY_CHECK_GOTO(rc, cleanup);
7412 continue;
7413 }
7414
7415 set_fill_set(&set2, &orig_set);
7416 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7417 LY_CHECK_GOTO(rc, cleanup);
7418
7419 /* eval */
7420 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007421 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007422 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007423 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007424 LY_CHECK_GOTO(rc, cleanup);
7425 }
7426 }
7427
7428cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007429 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7430 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007431 return rc;
7432}
7433
7434/**
7435 * @brief Evaluate UnaryExpr. Logs directly on error.
7436 *
7437 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
7438 *
7439 * @param[in] exp Parsed XPath expression.
7440 * @param[in] exp_idx Position in the expression @p exp.
7441 * @param[in] repeat How many times this expression is repeated.
7442 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7443 * @param[in] options XPath options.
7444 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7445 */
7446static LY_ERR
7447eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7448{
7449 LY_ERR rc;
7450 uint16_t this_op, i;
7451
7452 assert(repeat);
7453
7454 /* ('-')+ */
7455 this_op = *exp_idx;
7456 for (i = 0; i < repeat; ++i) {
7457 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7458
7459 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7460 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7461 ++(*exp_idx);
7462 }
7463
7464 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7465 LY_CHECK_RET(rc);
7466
7467 if (set && (repeat % 2)) {
7468 if (options & LYXP_SCNODE_ALL) {
7469 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7470 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007471 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007472 LY_CHECK_RET(rc);
7473 }
7474 }
7475
7476 return LY_SUCCESS;
7477}
7478
7479/**
7480 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7481 *
7482 * [16] MultiplicativeExpr ::= UnaryExpr
7483 * | MultiplicativeExpr '*' UnaryExpr
7484 * | MultiplicativeExpr 'div' UnaryExpr
7485 * | MultiplicativeExpr 'mod' UnaryExpr
7486 *
7487 * @param[in] exp Parsed XPath expression.
7488 * @param[in] exp_idx Position in the expression @p exp.
7489 * @param[in] repeat How many times this expression is repeated.
7490 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7491 * @param[in] options XPath options.
7492 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7493 */
7494static LY_ERR
7495eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7496{
7497 LY_ERR rc;
7498 uint16_t this_op;
7499 struct lyxp_set orig_set, set2;
7500 uint16_t i;
7501
7502 assert(repeat);
7503
7504 set_init(&orig_set, set);
7505 set_init(&set2, set);
7506
7507 set_fill_set(&orig_set, set);
7508
7509 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7510 LY_CHECK_GOTO(rc, cleanup);
7511
7512 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7513 for (i = 0; i < repeat; ++i) {
7514 this_op = *exp_idx;
7515
7516 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7517 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7518 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7519 ++(*exp_idx);
7520
7521 if (!set) {
7522 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7523 LY_CHECK_GOTO(rc, cleanup);
7524 continue;
7525 }
7526
7527 set_fill_set(&set2, &orig_set);
7528 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7529 LY_CHECK_GOTO(rc, cleanup);
7530
7531 /* eval */
7532 if (options & LYXP_SCNODE_ALL) {
7533 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007534 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007535 set_scnode_clear_ctx(set);
7536 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007537 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007538 LY_CHECK_GOTO(rc, cleanup);
7539 }
7540 }
7541
7542cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007543 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7544 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007545 return rc;
7546}
7547
7548/**
7549 * @brief Evaluate AdditiveExpr. Logs directly on error.
7550 *
7551 * [15] AdditiveExpr ::= MultiplicativeExpr
7552 * | AdditiveExpr '+' MultiplicativeExpr
7553 * | AdditiveExpr '-' MultiplicativeExpr
7554 *
7555 * @param[in] exp Parsed XPath expression.
7556 * @param[in] exp_idx Position in the expression @p exp.
7557 * @param[in] repeat How many times this expression is repeated.
7558 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7559 * @param[in] options XPath options.
7560 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7561 */
7562static LY_ERR
7563eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7564{
7565 LY_ERR rc;
7566 uint16_t this_op;
7567 struct lyxp_set orig_set, set2;
7568 uint16_t i;
7569
7570 assert(repeat);
7571
7572 set_init(&orig_set, set);
7573 set_init(&set2, set);
7574
7575 set_fill_set(&orig_set, set);
7576
7577 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7578 LY_CHECK_GOTO(rc, cleanup);
7579
7580 /* ('+' / '-' MultiplicativeExpr)* */
7581 for (i = 0; i < repeat; ++i) {
7582 this_op = *exp_idx;
7583
7584 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7585 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7586 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7587 ++(*exp_idx);
7588
7589 if (!set) {
7590 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7591 LY_CHECK_GOTO(rc, cleanup);
7592 continue;
7593 }
7594
7595 set_fill_set(&set2, &orig_set);
7596 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7597 LY_CHECK_GOTO(rc, cleanup);
7598
7599 /* eval */
7600 if (options & LYXP_SCNODE_ALL) {
7601 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007602 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007603 set_scnode_clear_ctx(set);
7604 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007605 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007606 LY_CHECK_GOTO(rc, cleanup);
7607 }
7608 }
7609
7610cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007611 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7612 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007613 return rc;
7614}
7615
7616/**
7617 * @brief Evaluate RelationalExpr. Logs directly on error.
7618 *
7619 * [14] RelationalExpr ::= AdditiveExpr
7620 * | RelationalExpr '<' AdditiveExpr
7621 * | RelationalExpr '>' AdditiveExpr
7622 * | RelationalExpr '<=' AdditiveExpr
7623 * | RelationalExpr '>=' AdditiveExpr
7624 *
7625 * @param[in] exp Parsed XPath expression.
7626 * @param[in] exp_idx Position in the expression @p exp.
7627 * @param[in] repeat How many times this expression is repeated.
7628 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7629 * @param[in] options XPath options.
7630 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7631 */
7632static LY_ERR
7633eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7634{
7635 LY_ERR rc;
7636 uint16_t this_op;
7637 struct lyxp_set orig_set, set2;
7638 uint16_t i;
7639
7640 assert(repeat);
7641
7642 set_init(&orig_set, set);
7643 set_init(&set2, set);
7644
7645 set_fill_set(&orig_set, set);
7646
7647 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7648 LY_CHECK_GOTO(rc, cleanup);
7649
7650 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7651 for (i = 0; i < repeat; ++i) {
7652 this_op = *exp_idx;
7653
7654 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7655 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7656 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7657 ++(*exp_idx);
7658
7659 if (!set) {
7660 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7661 LY_CHECK_GOTO(rc, cleanup);
7662 continue;
7663 }
7664
7665 set_fill_set(&set2, &orig_set);
7666 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7667 LY_CHECK_GOTO(rc, cleanup);
7668
7669 /* eval */
7670 if (options & LYXP_SCNODE_ALL) {
7671 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007672 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007673 set_scnode_clear_ctx(set);
7674 } else {
7675 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7676 LY_CHECK_GOTO(rc, cleanup);
7677 }
7678 }
7679
7680cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007681 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7682 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007683 return rc;
7684}
7685
7686/**
7687 * @brief Evaluate EqualityExpr. Logs directly on error.
7688 *
7689 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
7690 * | EqualityExpr '!=' RelationalExpr
7691 *
7692 * @param[in] exp Parsed XPath expression.
7693 * @param[in] exp_idx Position in the expression @p exp.
7694 * @param[in] repeat How many times this expression is repeated.
7695 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7696 * @param[in] options XPath options.
7697 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7698 */
7699static LY_ERR
7700eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7701{
7702 LY_ERR rc;
7703 uint16_t this_op;
7704 struct lyxp_set orig_set, set2;
7705 uint16_t i;
7706
7707 assert(repeat);
7708
7709 set_init(&orig_set, set);
7710 set_init(&set2, set);
7711
7712 set_fill_set(&orig_set, set);
7713
7714 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7715 LY_CHECK_GOTO(rc, cleanup);
7716
7717 /* ('=' / '!=' RelationalExpr)* */
7718 for (i = 0; i < repeat; ++i) {
7719 this_op = *exp_idx;
7720
7721 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7722 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7723 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7724 ++(*exp_idx);
7725
7726 if (!set) {
7727 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7728 LY_CHECK_GOTO(rc, cleanup);
7729 continue;
7730 }
7731
7732 set_fill_set(&set2, &orig_set);
7733 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7734 LY_CHECK_GOTO(rc, cleanup);
7735
7736 /* eval */
7737 if (options & LYXP_SCNODE_ALL) {
7738 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7739 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7740 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007741 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007742 set_scnode_clear_ctx(set);
7743 } else {
7744 /* special handling of evaluations of identityref comparisons, always compare prefixed identites */
7745 if ((set->type == LYXP_SET_NODE_SET) && (set->val.nodes[0].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
7746 && (((struct lysc_node_leaf *)set->val.nodes[0].node->schema)->type->basetype == LY_TYPE_IDENT)) {
7747 /* left operand is identityref */
7748 if ((set2.type == LYXP_SET_STRING) && !strchr(set2.val.str, ':')) {
7749 /* missing prefix in the right operand */
7750 set2.val.str = ly_realloc(set2.val.str, strlen(set->local_mod->name) + 1 + strlen(set2.val.str) + 1);
7751 if (!set2.val.str) {
7752 goto cleanup;
7753 }
7754
7755 memmove(set2.val.str + strlen(set->local_mod->name) + 1, set2.val.str, strlen(set2.val.str) + 1);
7756 memcpy(set2.val.str, set->local_mod->name, strlen(set->local_mod->name));
7757 set2.val.str[strlen(set->local_mod->name)] = ':';
7758 }
7759 }
7760
7761 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7762 LY_CHECK_GOTO(rc, cleanup);
7763 }
7764 }
7765
7766cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007767 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7768 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007769 return rc;
7770}
7771
7772/**
7773 * @brief Evaluate AndExpr. Logs directly on error.
7774 *
7775 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
7776 *
7777 * @param[in] exp Parsed XPath expression.
7778 * @param[in] exp_idx Position in the expression @p exp.
7779 * @param[in] repeat How many times this expression is repeated.
7780 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7781 * @param[in] options XPath options.
7782 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7783 */
7784static LY_ERR
7785eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7786{
7787 LY_ERR rc;
7788 struct lyxp_set orig_set, set2;
7789 uint16_t i;
7790
7791 assert(repeat);
7792
7793 set_init(&orig_set, set);
7794 set_init(&set2, set);
7795
7796 set_fill_set(&orig_set, set);
7797
7798 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
7799 LY_CHECK_GOTO(rc, cleanup);
7800
7801 /* cast to boolean, we know that will be the final result */
7802 if (set && (options & LYXP_SCNODE_ALL)) {
7803 set_scnode_clear_ctx(set);
7804 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007805 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007806 }
7807
7808 /* ('and' EqualityExpr)* */
7809 for (i = 0; i < repeat; ++i) {
7810 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7811 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
7812 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7813 ++(*exp_idx);
7814
7815 /* lazy evaluation */
7816 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
7817 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
7818 LY_CHECK_GOTO(rc, cleanup);
7819 continue;
7820 }
7821
7822 set_fill_set(&set2, &orig_set);
7823 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
7824 LY_CHECK_GOTO(rc, cleanup);
7825
7826 /* eval - just get boolean value actually */
7827 if (set->type == LYXP_SET_SCNODE_SET) {
7828 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007829 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007830 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007831 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007832 set_fill_set(set, &set2);
7833 }
7834 }
7835
7836cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007837 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7838 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007839 return rc;
7840}
7841
7842/**
7843 * @brief Evaluate OrExpr. Logs directly on error.
7844 *
7845 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
7846 *
7847 * @param[in] exp Parsed XPath expression.
7848 * @param[in] exp_idx Position in the expression @p exp.
7849 * @param[in] repeat How many times this expression is repeated.
7850 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7851 * @param[in] options XPath options.
7852 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7853 */
7854static LY_ERR
7855eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7856{
7857 LY_ERR rc;
7858 struct lyxp_set orig_set, set2;
7859 uint16_t i;
7860
7861 assert(repeat);
7862
7863 set_init(&orig_set, set);
7864 set_init(&set2, set);
7865
7866 set_fill_set(&orig_set, set);
7867
7868 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
7869 LY_CHECK_GOTO(rc, cleanup);
7870
7871 /* cast to boolean, we know that will be the final result */
7872 if (set && (options & LYXP_SCNODE_ALL)) {
7873 set_scnode_clear_ctx(set);
7874 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007875 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007876 }
7877
7878 /* ('or' AndExpr)* */
7879 for (i = 0; i < repeat; ++i) {
7880 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
7881 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
7882 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7883 ++(*exp_idx);
7884
7885 /* lazy evaluation */
7886 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
7887 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
7888 LY_CHECK_GOTO(rc, cleanup);
7889 continue;
7890 }
7891
7892 set_fill_set(&set2, &orig_set);
7893 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
7894 * but it does not matter */
7895 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
7896 LY_CHECK_GOTO(rc, cleanup);
7897
7898 /* eval - just get boolean value actually */
7899 if (set->type == LYXP_SET_SCNODE_SET) {
7900 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007901 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007902 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007903 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007904 set_fill_set(set, &set2);
7905 }
7906 }
7907
7908cleanup:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007909 lyxp_set_cast(&orig_set, LYXP_SET_EMPTY);
7910 lyxp_set_cast(&set2, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007911 return rc;
7912}
7913
7914/**
7915 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
7916 *
7917 * @param[in] exp Parsed XPath expression.
7918 * @param[in] exp_idx Position in the expression @p exp.
7919 * @param[in] etype Expression type to evaluate.
7920 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7921 * @param[in] options XPath options.
7922 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7923 */
7924static LY_ERR
7925eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
7926{
7927 uint16_t i, count;
7928 enum lyxp_expr_type next_etype;
7929 LY_ERR rc;
7930
7931 /* process operator repeats */
7932 if (!exp->repeat[*exp_idx]) {
7933 next_etype = LYXP_EXPR_NONE;
7934 } else {
7935 /* find etype repeat */
7936 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
7937
7938 /* select one-priority lower because etype expression called us */
7939 if (i) {
7940 next_etype = exp->repeat[*exp_idx][i - 1];
7941 /* count repeats for that expression */
7942 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
7943 } else {
7944 next_etype = LYXP_EXPR_NONE;
7945 }
7946 }
7947
7948 /* decide what expression are we parsing based on the repeat */
7949 switch (next_etype) {
7950 case LYXP_EXPR_OR:
7951 rc = eval_or_expr(exp, exp_idx, count, set, options);
7952 break;
7953 case LYXP_EXPR_AND:
7954 rc = eval_and_expr(exp, exp_idx, count, set, options);
7955 break;
7956 case LYXP_EXPR_EQUALITY:
7957 rc = eval_equality_expr(exp, exp_idx, count, set, options);
7958 break;
7959 case LYXP_EXPR_RELATIONAL:
7960 rc = eval_relational_expr(exp, exp_idx, count, set, options);
7961 break;
7962 case LYXP_EXPR_ADDITIVE:
7963 rc = eval_additive_expr(exp, exp_idx, count, set, options);
7964 break;
7965 case LYXP_EXPR_MULTIPLICATIVE:
7966 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
7967 break;
7968 case LYXP_EXPR_UNARY:
7969 rc = eval_unary_expr(exp, exp_idx, count, set, options);
7970 break;
7971 case LYXP_EXPR_UNION:
7972 rc = eval_union_expr(exp, exp_idx, count, set, options);
7973 break;
7974 case LYXP_EXPR_NONE:
7975 rc = eval_path_expr(exp, exp_idx, set, options);
7976 break;
7977 default:
7978 LOGINT_RET(set->ctx);
7979 }
7980
7981 return rc;
7982}
7983
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007984/**
7985 * @brief Get root type.
7986 *
7987 * @param[in] ctx_node Context node.
7988 * @param[in] ctx_scnode Schema context node.
7989 * @param[in] options XPath options.
7990 * @return Root type.
7991 */
7992static enum lyxp_node_type
7993lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
7994{
7995 if (options & LYXP_SCNODE_ALL) {
7996 if (options & LYXP_SCNODE) {
7997 /* general root that can access everything */
7998 return LYXP_NODE_ROOT;
7999 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8000 /* root context node can access only config data (because we said so, it is unspecified) */
8001 return LYXP_NODE_ROOT_CONFIG;
8002 } else {
8003 return LYXP_NODE_ROOT;
8004 }
8005 }
8006
8007 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8008 /* root context node can access only config data (because we said so, it is unspecified) */
8009 return LYXP_NODE_ROOT_CONFIG;
8010 }
8011
8012 return LYXP_NODE_ROOT;
8013}
8014
Michal Vasko03ff5a72019-09-11 13:49:33 +02008015LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008016lyxp_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 +02008017 enum lyxp_node_type ctx_node_type, const struct lyd_node **trees, struct lyxp_set *set, int options)
8018{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008019 uint16_t exp_idx = 0;
8020 LY_ERR rc;
8021
Michal Vaskoecd62de2019-11-13 12:35:11 +01008022 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008023
8024 /* prepare set for evaluation */
8025 exp_idx = 0;
8026 memset(set, 0, sizeof *set);
8027 set->type = LYXP_SET_EMPTY;
8028 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, options);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008029 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008030 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008031 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008032 set->local_mod = local_mod;
8033 set->trees = trees;
8034 set->format = format;
8035
8036 /* evaluate */
8037 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8038 if (rc != LY_SUCCESS) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008039 lyxp_set_cast(set, LYXP_SET_EMPTY);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008040 }
8041
Michal Vasko03ff5a72019-09-11 13:49:33 +02008042 return rc;
8043}
8044
8045#if 0
8046
8047/* full xml printing of set elements, not used currently */
8048
8049void
8050lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8051{
8052 uint32_t i;
8053 char *str_num;
8054 struct lyout out;
8055
8056 memset(&out, 0, sizeof out);
8057
8058 out.type = LYOUT_STREAM;
8059 out.method.f = f;
8060
8061 switch (set->type) {
8062 case LYXP_SET_EMPTY:
8063 ly_print(&out, "Empty XPath set\n\n");
8064 break;
8065 case LYXP_SET_BOOLEAN:
8066 ly_print(&out, "Boolean XPath set:\n");
8067 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8068 break;
8069 case LYXP_SET_STRING:
8070 ly_print(&out, "String XPath set:\n");
8071 ly_print(&out, "\"%s\"\n\n", set->value.str);
8072 break;
8073 case LYXP_SET_NUMBER:
8074 ly_print(&out, "Number XPath set:\n");
8075
8076 if (isnan(set->value.num)) {
8077 str_num = strdup("NaN");
8078 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8079 str_num = strdup("0");
8080 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8081 str_num = strdup("Infinity");
8082 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8083 str_num = strdup("-Infinity");
8084 } else if ((long long)set->value.num == set->value.num) {
8085 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8086 str_num = NULL;
8087 }
8088 } else {
8089 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8090 str_num = NULL;
8091 }
8092 }
8093 if (!str_num) {
8094 LOGMEM;
8095 return;
8096 }
8097 ly_print(&out, "%s\n\n", str_num);
8098 free(str_num);
8099 break;
8100 case LYXP_SET_NODE_SET:
8101 ly_print(&out, "Node XPath set:\n");
8102
8103 for (i = 0; i < set->used; ++i) {
8104 ly_print(&out, "%d. ", i + 1);
8105 switch (set->node_type[i]) {
8106 case LYXP_NODE_ROOT_ALL:
8107 ly_print(&out, "ROOT all\n\n");
8108 break;
8109 case LYXP_NODE_ROOT_CONFIG:
8110 ly_print(&out, "ROOT config\n\n");
8111 break;
8112 case LYXP_NODE_ROOT_STATE:
8113 ly_print(&out, "ROOT state\n\n");
8114 break;
8115 case LYXP_NODE_ROOT_NOTIF:
8116 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8117 break;
8118 case LYXP_NODE_ROOT_RPC:
8119 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8120 break;
8121 case LYXP_NODE_ROOT_OUTPUT:
8122 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8123 break;
8124 case LYXP_NODE_ELEM:
8125 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8126 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8127 ly_print(&out, "\n");
8128 break;
8129 case LYXP_NODE_TEXT:
8130 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8131 break;
8132 case LYXP_NODE_ATTR:
8133 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8134 break;
8135 }
8136 }
8137 break;
8138 }
8139}
8140
8141#endif
8142
8143LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008144lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008145{
8146 long double num;
8147 char *str;
8148 LY_ERR rc;
8149
8150 if (!set || (set->type == target)) {
8151 return LY_SUCCESS;
8152 }
8153
8154 /* it's not possible to convert anything into a node set */
8155 assert((target != LYXP_SET_NODE_SET) && ((set->type != LYXP_SET_SCNODE_SET) || (target == LYXP_SET_EMPTY)));
8156
8157 if (set->type == LYXP_SET_SCNODE_SET) {
8158 set_free_content(set);
8159 return LY_EINVAL;
8160 }
8161
8162 /* to STRING */
8163 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER)
8164 && ((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_EMPTY)))) {
8165 switch (set->type) {
8166 case LYXP_SET_NUMBER:
8167 if (isnan(set->val.num)) {
8168 set->val.str = strdup("NaN");
8169 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8170 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8171 set->val.str = strdup("0");
8172 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8173 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8174 set->val.str = strdup("Infinity");
8175 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8176 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8177 set->val.str = strdup("-Infinity");
8178 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8179 } else if ((long long)set->val.num == set->val.num) {
8180 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8181 LOGMEM_RET(set->ctx);
8182 }
8183 set->val.str = str;
8184 } else {
8185 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8186 LOGMEM_RET(set->ctx);
8187 }
8188 set->val.str = str;
8189 }
8190 break;
8191 case LYXP_SET_BOOLEAN:
8192 if (set->val.bool) {
8193 set->val.str = strdup("true");
8194 } else {
8195 set->val.str = strdup("false");
8196 }
8197 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8198 break;
8199 case LYXP_SET_NODE_SET:
8200 assert(set->used);
8201
8202 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008203 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008204
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008205 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008206 LY_CHECK_RET(rc);
8207 set_free_content(set);
8208 set->val.str = str;
8209 break;
8210 case LYXP_SET_EMPTY:
8211 set->val.str = strdup("");
8212 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8213 break;
8214 default:
8215 LOGINT_RET(set->ctx);
8216 }
8217 set->type = LYXP_SET_STRING;
8218 }
8219
8220 /* to NUMBER */
8221 if (target == LYXP_SET_NUMBER) {
8222 switch (set->type) {
8223 case LYXP_SET_STRING:
8224 num = cast_string_to_number(set->val.str);
8225 set_free_content(set);
8226 set->val.num = num;
8227 break;
8228 case LYXP_SET_BOOLEAN:
8229 if (set->val.bool) {
8230 set->val.num = 1;
8231 } else {
8232 set->val.num = 0;
8233 }
8234 break;
8235 default:
8236 LOGINT_RET(set->ctx);
8237 }
8238 set->type = LYXP_SET_NUMBER;
8239 }
8240
8241 /* to BOOLEAN */
8242 if (target == LYXP_SET_BOOLEAN) {
8243 switch (set->type) {
8244 case LYXP_SET_NUMBER:
8245 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8246 set->val.bool = 0;
8247 } else {
8248 set->val.bool = 1;
8249 }
8250 break;
8251 case LYXP_SET_STRING:
8252 if (set->val.str[0]) {
8253 set_free_content(set);
8254 set->val.bool = 1;
8255 } else {
8256 set_free_content(set);
8257 set->val.bool = 0;
8258 }
8259 break;
8260 case LYXP_SET_NODE_SET:
8261 set_free_content(set);
8262
8263 assert(set->used);
8264 set->val.bool = 1;
8265 break;
8266 case LYXP_SET_EMPTY:
8267 set->val.bool = 0;
8268 break;
8269 default:
8270 LOGINT_RET(set->ctx);
8271 }
8272 set->type = LYXP_SET_BOOLEAN;
8273 }
8274
8275 /* to EMPTY */
8276 if (target == LYXP_SET_EMPTY) {
8277 set_free_content(set);
8278 set->type = LYXP_SET_EMPTY;
8279 }
8280
8281 return LY_SUCCESS;
8282}
8283
8284LY_ERR
8285lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8286 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8287{
8288 struct ly_ctx *ctx;
8289 uint16_t exp_idx = 0;
8290
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008291 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008292
8293 ctx = local_mod->ctx;
8294
8295 /* prepare set for evaluation */
8296 exp_idx = 0;
8297 memset(set, 0, sizeof *set);
8298 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008299 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008300 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008301 set->ctx = ctx;
8302 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008303 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008304 set->local_mod = local_mod;
8305 set->format = format;
8306
8307 /* evaluate */
8308 return eval_expr_select(exp, &exp_idx, 0, set, options);
8309}