blob: 6f7937f98bbc36ce5b2e28426fe6eb1398713a9f [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"
Michal Vaskod3678892020-05-21 10:06:58 +020035#include "tree_data_internal.h"
Michal Vasko03ff5a72019-09-11 13:49:33 +020036#include "plugins_types.h"
37
Michal Vasko03ff5a72019-09-11 13:49:33 +020038static LY_ERR reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx);
Michal Vasko03ff5a72019-09-11 13:49:33 +020039static LY_ERR eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options);
40
41/**
42 * @brief Print the type of an XPath \p set.
43 *
44 * @param[in] set Set to use.
45 * @return Set type string.
46 */
47static const char *
48print_set_type(struct lyxp_set *set)
49{
50 switch (set->type) {
Michal Vasko03ff5a72019-09-11 13:49:33 +020051 case LYXP_SET_NODE_SET:
52 return "node set";
53 case LYXP_SET_SCNODE_SET:
54 return "schema node set";
55 case LYXP_SET_BOOLEAN:
56 return "boolean";
57 case LYXP_SET_NUMBER:
58 return "number";
59 case LYXP_SET_STRING:
60 return "string";
61 }
62
63 return NULL;
64}
65
66/**
67 * @brief Print an XPath token \p tok type.
68 *
69 * @param[in] tok Token to use.
70 * @return Token type string.
71 */
72static const char *
73print_token(enum lyxp_token tok)
74{
75 switch (tok) {
76 case LYXP_TOKEN_PAR1:
77 return "(";
78 case LYXP_TOKEN_PAR2:
79 return ")";
80 case LYXP_TOKEN_BRACK1:
81 return "[";
82 case LYXP_TOKEN_BRACK2:
83 return "]";
84 case LYXP_TOKEN_DOT:
85 return ".";
86 case LYXP_TOKEN_DDOT:
87 return "..";
88 case LYXP_TOKEN_AT:
89 return "@";
90 case LYXP_TOKEN_COMMA:
91 return ",";
92 case LYXP_TOKEN_NAMETEST:
93 return "NameTest";
94 case LYXP_TOKEN_NODETYPE:
95 return "NodeType";
96 case LYXP_TOKEN_FUNCNAME:
97 return "FunctionName";
98 case LYXP_TOKEN_OPERATOR_LOG:
99 return "Operator(Logic)";
100 case LYXP_TOKEN_OPERATOR_COMP:
101 return "Operator(Comparison)";
102 case LYXP_TOKEN_OPERATOR_MATH:
103 return "Operator(Math)";
104 case LYXP_TOKEN_OPERATOR_UNI:
105 return "Operator(Union)";
106 case LYXP_TOKEN_OPERATOR_PATH:
107 return "Operator(Path)";
108 case LYXP_TOKEN_LITERAL:
109 return "Literal";
110 case LYXP_TOKEN_NUMBER:
111 return "Number";
112 default:
113 LOGINT(NULL);
114 return "";
115 }
116}
117
118/**
119 * @brief Print the whole expression \p exp to debug output.
120 *
121 * @param[in] exp Expression to use.
122 */
123static void
124print_expr_struct_debug(struct lyxp_expr *exp)
125{
126 uint16_t i, j;
127 char tmp[128];
128
129 if (!exp || (ly_log_level < LY_LLDBG)) {
130 return;
131 }
132
133 LOGDBG(LY_LDGXPATH, "expression \"%s\":", exp->expr);
134 for (i = 0; i < exp->used; ++i) {
135 sprintf(tmp, "\ttoken %s, in expression \"%.*s\"", print_token(exp->tokens[i]), exp->tok_len[i],
136 &exp->expr[exp->tok_pos[i]]);
137 if (exp->repeat[i]) {
138 sprintf(tmp + strlen(tmp), " (repeat %d", exp->repeat[i][0]);
139 for (j = 1; exp->repeat[i][j]; ++j) {
140 sprintf(tmp + strlen(tmp), ", %d", exp->repeat[i][j]);
141 }
142 strcat(tmp, ")");
143 }
144 LOGDBG(LY_LDGXPATH, tmp);
145 }
146}
147
148#ifndef NDEBUG
149
150/**
151 * @brief Print XPath set content to debug output.
152 *
153 * @param[in] set Set to print.
154 */
155static void
156print_set_debug(struct lyxp_set *set)
157{
158 uint32_t i;
159 char *str;
160 int dynamic;
161 struct lyxp_set_node *item;
162 struct lyxp_set_scnode *sitem;
163
164 if (ly_log_level < LY_LLDBG) {
165 return;
166 }
167
168 switch (set->type) {
169 case LYXP_SET_NODE_SET:
170 LOGDBG(LY_LDGXPATH, "set NODE SET:");
171 for (i = 0; i < set->used; ++i) {
172 item = &set->val.nodes[i];
173
174 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100175 case LYXP_NODE_NONE:
176 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): NONE", i + 1, item->pos);
177 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200178 case LYXP_NODE_ROOT:
179 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT", i + 1, item->pos);
180 break;
181 case LYXP_NODE_ROOT_CONFIG:
182 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ROOT CONFIG", i + 1, item->pos);
183 break;
184 case LYXP_NODE_ELEM:
185 if ((item->node->schema->nodetype == LYS_LIST)
186 && (((struct lyd_node_inner *)item->node)->child->schema->nodetype == LYS_LEAF)) {
187 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (1st child val: %s)", i + 1, item->pos,
188 item->node->schema->name,
189 (str = (char *)lyd_value2str((struct lyd_node_term *)lyd_node_children(item->node), &dynamic)));
190 if (dynamic) {
191 free(str);
192 }
193 } else if (((struct lyd_node_inner *)item->node)->schema->nodetype == LYS_LEAFLIST) {
194 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s (val: %s)", i + 1, item->pos,
195 item->node->schema->name,
196 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
197 if (dynamic) {
198 free(str);
199 }
200 } else {
201 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): ELEM %s", i + 1, item->pos, item->node->schema->name);
202 }
203 break;
204 case LYXP_NODE_TEXT:
205 if (item->node->schema->nodetype & LYS_ANYDATA) {
206 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT <%s>", i + 1, item->pos,
207 item->node->schema->nodetype == LYS_ANYXML ? "anyxml" : "anydata");
208 } else {
209 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): TEXT %s", i + 1, item->pos,
210 (str = (char *)lyd_value2str((struct lyd_node_term *)item->node, &dynamic)));
211 if (dynamic) {
212 free(str);
213 }
214 }
215 break;
Michal Vasko9f96a052020-03-10 09:41:45 +0100216 case LYXP_NODE_META:
217 LOGDBG(LY_LDGXPATH, "\t%d (pos %u): META %s = %s", i + 1, item->pos, set->val.meta[i].meta->name,
218 set->val.meta[i].meta->value);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200219 break;
220 }
221 }
222 break;
223
224 case LYXP_SET_SCNODE_SET:
225 LOGDBG(LY_LDGXPATH, "set SCNODE SET:");
226 for (i = 0; i < set->used; ++i) {
227 sitem = &set->val.scnodes[i];
228
229 switch (sitem->type) {
230 case LYXP_NODE_ROOT:
231 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT", i + 1, sitem->in_ctx);
232 break;
233 case LYXP_NODE_ROOT_CONFIG:
234 LOGDBG(LY_LDGXPATH, "\t%d (%u): ROOT CONFIG", i + 1, sitem->in_ctx);
235 break;
236 case LYXP_NODE_ELEM:
237 LOGDBG(LY_LDGXPATH, "\t%d (%u): ELEM %s", i + 1, sitem->in_ctx, sitem->scnode->name);
238 break;
239 default:
240 LOGINT(NULL);
241 break;
242 }
243 }
244 break;
245
Michal Vasko03ff5a72019-09-11 13:49:33 +0200246 case LYXP_SET_BOOLEAN:
247 LOGDBG(LY_LDGXPATH, "set BOOLEAN");
248 LOGDBG(LY_LDGXPATH, "\t%s", (set->val.bool ? "true" : "false"));
249 break;
250
251 case LYXP_SET_STRING:
252 LOGDBG(LY_LDGXPATH, "set STRING");
253 LOGDBG(LY_LDGXPATH, "\t%s", set->val.str);
254 break;
255
256 case LYXP_SET_NUMBER:
257 LOGDBG(LY_LDGXPATH, "set NUMBER");
258
259 if (isnan(set->val.num)) {
260 str = strdup("NaN");
261 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
262 str = strdup("0");
263 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
264 str = strdup("Infinity");
265 } else if (isinf(set->val.num) && signbit(set->val.num)) {
266 str = strdup("-Infinity");
267 } else if ((long long)set->val.num == set->val.num) {
268 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
269 str = NULL;
270 }
271 } else {
272 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
273 str = NULL;
274 }
275 }
276 LY_CHECK_ERR_RET(!str, LOGMEM(NULL), );
277
278 LOGDBG(LY_LDGXPATH, "\t%s", str);
279 free(str);
280 }
281}
282
283#endif
284
285/**
286 * @brief Realloc the string \p str.
287 *
288 * @param[in] ctx libyang context for logging.
289 * @param[in] needed How much free space is required.
290 * @param[in,out] str Pointer to the string to use.
291 * @param[in,out] used Used bytes in \p str.
292 * @param[in,out] size Allocated bytes in \p str.
293 * @return LY_ERR
294 */
295static LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100296cast_string_realloc(const struct ly_ctx *ctx, uint16_t needed, char **str, uint16_t *used, uint16_t *size)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200297{
298 if (*size - *used < needed) {
299 do {
300 if ((UINT16_MAX - *size) < LYXP_STRING_CAST_SIZE_STEP) {
301 LOGERR(ctx, LY_EINVAL, "XPath string length limit (%u) reached.", UINT16_MAX);
302 return LY_EINVAL;
303 }
304 *size += LYXP_STRING_CAST_SIZE_STEP;
305 } while (*size - *used < needed);
306 *str = ly_realloc(*str, *size * sizeof(char));
307 LY_CHECK_ERR_RET(!(*str), LOGMEM(ctx), LY_EMEM);
308 }
309
310 return LY_SUCCESS;
311}
312
313/**
314 * @brief Cast nodes recursively to one string @p str.
315 *
316 * @param[in] node Node to cast.
317 * @param[in] fake_cont Whether to put the data into a "fake" container.
318 * @param[in] root_type Type of the XPath root.
319 * @param[in] indent Current indent.
320 * @param[in,out] str Resulting string.
321 * @param[in,out] used Used bytes in @p str.
322 * @param[in,out] size Allocated bytes in @p str.
323 * @return LY_ERR
324 */
325static LY_ERR
326cast_string_recursive(const struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, uint16_t indent, char **str,
327 uint16_t *used, uint16_t *size)
328{
329 char *buf, *line, *ptr;
330 const char *value_str;
331 int dynamic;
332 const struct lyd_node *child;
333 struct lyd_node_any *any;
334 LY_ERR rc;
335
336 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
337 return LY_SUCCESS;
338 }
339
340 if (fake_cont) {
341 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
342 LY_CHECK_RET(rc);
343 strcpy(*str + (*used - 1), "\n");
344 ++(*used);
345
346 ++indent;
347 }
348
349 switch (node->schema->nodetype) {
350 case LYS_CONTAINER:
351 case LYS_LIST:
352 case LYS_RPC:
353 case LYS_NOTIF:
354 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
355 LY_CHECK_RET(rc);
356 strcpy(*str + (*used - 1), "\n");
357 ++(*used);
358
359 for (child = lyd_node_children(node); child; child = child->next) {
360 rc = cast_string_recursive(child, 0, root_type, indent + 1, str, used, size);
361 LY_CHECK_RET(rc);
362 }
363
364 break;
365
366 case LYS_LEAF:
367 case LYS_LEAFLIST:
368 value_str = lyd_value2str(((struct lyd_node_term *)node), &dynamic);
369
370 /* print indent */
371 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(value_str) + 1, str, used, size);
372 if (rc != LY_SUCCESS) {
373 if (dynamic) {
374 free((char *)value_str);
375 }
376 return rc;
377 }
378 memset(*str + (*used - 1), ' ', indent * 2);
379 *used += indent * 2;
380
381 /* print value */
382 if (*used == 1) {
383 sprintf(*str + (*used - 1), "%s", value_str);
384 *used += strlen(value_str);
385 } else {
386 sprintf(*str + (*used - 1), "%s\n", value_str);
387 *used += strlen(value_str) + 1;
388 }
389 if (dynamic) {
390 free((char *)value_str);
391 }
392
393 break;
394
395 case LYS_ANYXML:
396 case LYS_ANYDATA:
397 any = (struct lyd_node_any *)node;
398 if (!(void *)any->value.tree) {
399 /* no content */
400 buf = strdup("");
401 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
402 } else {
403 switch (any->value_type) {
404 case LYD_ANYDATA_STRING:
405 case LYD_ANYDATA_XML:
406 case LYD_ANYDATA_JSON:
407 buf = strdup(any->value.json);
408 LY_CHECK_ERR_RET(!buf, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
409 break;
410 case LYD_ANYDATA_DATATREE:
411 rc = lyd_print_mem(&buf, any->value.tree, LYD_XML, LYDP_WITHSIBLINGS);
412 LY_CHECK_RET(rc);
413 break;
414 /* TODO case LYD_ANYDATA_LYB:
415 LOGERR(LYD_NODE_CTX(node), LY_EINVAL, "Cannot convert LYB anydata into string.");
416 return -1;*/
417 }
418 }
419
420 line = strtok_r(buf, "\n", &ptr);
421 do {
422 rc = cast_string_realloc(LYD_NODE_CTX(node), indent * 2 + strlen(line) + 1, str, used, size);
423 if (rc != LY_SUCCESS) {
424 free(buf);
425 return rc;
426 }
427 memset(*str + (*used - 1), ' ', indent * 2);
428 *used += indent * 2;
429
430 strcpy(*str + (*used - 1), line);
431 *used += strlen(line);
432
433 strcpy(*str + (*used - 1), "\n");
434 *used += 1;
435 } while ((line = strtok_r(NULL, "\n", &ptr)));
436
437 free(buf);
438 break;
439
440 default:
441 LOGINT_RET(LYD_NODE_CTX(node));
442 }
443
444 if (fake_cont) {
445 rc = cast_string_realloc(LYD_NODE_CTX(node), 1, str, used, size);
446 LY_CHECK_RET(rc);
447 strcpy(*str + (*used - 1), "\n");
448 ++(*used);
449
450 --indent;
451 }
452
453 return LY_SUCCESS;
454}
455
456/**
457 * @brief Cast an element into a string.
458 *
459 * @param[in] node Node to cast.
460 * @param[in] fake_cont Whether to put the data into a "fake" container.
461 * @param[in] root_type Type of the XPath root.
462 * @param[out] str Element cast to dynamically-allocated string.
463 * @return LY_ERR
464 */
465static LY_ERR
466cast_string_elem(struct lyd_node *node, int fake_cont, enum lyxp_node_type root_type, char **str)
467{
468 uint16_t used, size;
469 LY_ERR rc;
470
471 *str = malloc(LYXP_STRING_CAST_SIZE_START * sizeof(char));
472 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
473 (*str)[0] = '\0';
474 used = 1;
475 size = LYXP_STRING_CAST_SIZE_START;
476
477 rc = cast_string_recursive(node, fake_cont, root_type, 0, str, &used, &size);
478 if (rc != LY_SUCCESS) {
479 free(*str);
480 return rc;
481 }
482
483 if (size > used) {
484 *str = ly_realloc(*str, used * sizeof(char));
485 LY_CHECK_ERR_RET(!*str, LOGMEM(LYD_NODE_CTX(node)), LY_EMEM);
486 }
487 return LY_SUCCESS;
488}
489
490/**
491 * @brief Cast a LYXP_SET_NODE_SET set into a string.
492 * Context position aware.
493 *
494 * @param[in] set Set to cast.
Michal Vasko03ff5a72019-09-11 13:49:33 +0200495 * @param[out] str Cast dynamically-allocated string.
496 * @return LY_ERR
497 */
498static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100499cast_node_set_to_string(struct lyxp_set *set, char **str)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200500{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200501 int dynamic;
502
Michal Vasko03ff5a72019-09-11 13:49:33 +0200503 switch (set->val.nodes[0].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +0100504 case LYXP_NODE_NONE:
505 /* invalid */
506 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200507 case LYXP_NODE_ROOT:
508 case LYXP_NODE_ROOT_CONFIG:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100509 return cast_string_elem(set->val.nodes[0].node, 1, set->root_type, str);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200510 case LYXP_NODE_ELEM:
511 case LYXP_NODE_TEXT:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100512 return cast_string_elem(set->val.nodes[0].node, 0, set->root_type, str);
Michal Vasko9f96a052020-03-10 09:41:45 +0100513 case LYXP_NODE_META:
514 *str = (char *)lyd_meta2str(set->val.meta[0].meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200515 if (!dynamic) {
516 *str = strdup(*str);
517 if (!*str) {
518 LOGMEM_RET(set->ctx);
519 }
520 }
521 return LY_SUCCESS;
522 }
523
524 LOGINT_RET(set->ctx);
525}
526
527/**
528 * @brief Cast a string into an XPath number.
529 *
530 * @param[in] str String to use.
531 * @return Cast number.
532 */
533static long double
534cast_string_to_number(const char *str)
535{
536 long double num;
537 char *ptr;
538
539 errno = 0;
540 num = strtold(str, &ptr);
541 if (errno || *ptr) {
542 num = NAN;
543 }
544 return num;
545}
546
547/**
548 * @brief Callback for checking value equality.
549 *
550 * @param[in] val1_p First value.
551 * @param[in] val2_p Second value.
552 * @param[in] mod Whether hash table is being modified.
553 * @param[in] cb_data Callback data.
554 * @return 0 if not equal, non-zero if equal.
555 */
556static int
557set_values_equal_cb(void *val1_p, void *val2_p, int UNUSED(mod), void *UNUSED(cb_data))
558{
559 struct lyxp_set_hash_node *val1, *val2;
560
561 val1 = (struct lyxp_set_hash_node *)val1_p;
562 val2 = (struct lyxp_set_hash_node *)val2_p;
563
564 if ((val1->node == val2->node) && (val1->type == val2->type)) {
565 return 1;
566 }
567
568 return 0;
569}
570
571/**
572 * @brief Insert node and its hash into set.
573 *
574 * @param[in] set et to insert to.
575 * @param[in] node Node with hash.
576 * @param[in] type Node type.
577 */
578static void
579set_insert_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
580{
581 int r;
582 uint32_t i, hash;
583 struct lyxp_set_hash_node hnode;
584
585 if (!set->ht && (set->used >= LYD_HT_MIN_ITEMS)) {
586 /* create hash table and add all the nodes */
587 set->ht = lyht_new(1, sizeof(struct lyxp_set_hash_node), set_values_equal_cb, NULL, 1);
588 for (i = 0; i < set->used; ++i) {
589 hnode.node = set->val.nodes[i].node;
590 hnode.type = set->val.nodes[i].type;
591
592 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
593 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
594 hash = dict_hash_multi(hash, NULL, 0);
595
596 r = lyht_insert(set->ht, &hnode, hash, NULL);
597 assert(!r);
598 (void)r;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200599
Michal Vasko9d6befd2019-12-11 14:56:56 +0100600 if (hnode.node == node) {
601 /* it was just added, do not add it twice */
602 node = NULL;
603 }
604 }
605 }
606
607 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200608 /* add the new node into hash table */
609 hnode.node = node;
610 hnode.type = type;
611
612 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
613 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
614 hash = dict_hash_multi(hash, NULL, 0);
615
616 r = lyht_insert(set->ht, &hnode, hash, NULL);
617 assert(!r);
618 (void)r;
619 }
620}
621
622/**
623 * @brief Remove node and its hash from set.
624 *
625 * @param[in] set Set to remove from.
626 * @param[in] node Node to remove.
627 * @param[in] type Node type.
628 */
629static void
630set_remove_node_hash(struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type)
631{
632 int r;
633 struct lyxp_set_hash_node hnode;
634 uint32_t hash;
635
636 if (set->ht) {
637 hnode.node = node;
638 hnode.type = type;
639
640 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
641 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
642 hash = dict_hash_multi(hash, NULL, 0);
643
644 r = lyht_remove(set->ht, &hnode, hash);
645 assert(!r);
646 (void)r;
647
648 if (!set->ht->used) {
649 lyht_free(set->ht);
650 set->ht = NULL;
651 }
652 }
653}
654
655/**
656 * @brief Check whether node is in set based on its hash.
657 *
658 * @param[in] set Set to search in.
659 * @param[in] node Node to search for.
660 * @param[in] type Node type.
661 * @param[in] skip_idx Index in @p set to skip.
662 * @return LY_ERR
663 */
664static LY_ERR
665set_dup_node_hash_check(const struct lyxp_set *set, struct lyd_node *node, enum lyxp_node_type type, int skip_idx)
666{
667 struct lyxp_set_hash_node hnode, *match_p;
668 uint32_t hash;
669
670 hnode.node = node;
671 hnode.type = type;
672
673 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
674 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
675 hash = dict_hash_multi(hash, NULL, 0);
676
677 if (!lyht_find(set->ht, &hnode, hash, (void **)&match_p)) {
678 if ((skip_idx > -1) && (set->val.nodes[skip_idx].node == match_p->node) && (set->val.nodes[skip_idx].type == match_p->type)) {
679 /* we found it on the index that should be skipped, find another */
680 hnode = *match_p;
681 if (lyht_find_next(set->ht, &hnode, hash, (void **)&match_p)) {
682 /* none other found */
683 return LY_SUCCESS;
684 }
685 }
686
687 return LY_EEXIST;
688 }
689
690 /* not found */
691 return LY_SUCCESS;
692}
693
Michal Vaskod3678892020-05-21 10:06:58 +0200694void
695lyxp_set_free_content(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +0200696{
697 if (!set) {
698 return;
699 }
700
701 if (set->type == LYXP_SET_NODE_SET) {
702 free(set->val.nodes);
703 lyht_free(set->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200704 } else if (set->type == LYXP_SET_SCNODE_SET) {
705 free(set->val.scnodes);
Michal Vaskod3678892020-05-21 10:06:58 +0200706 lyht_free(set->ht);
707 } else {
708 if (set->type == LYXP_SET_STRING) {
709 free(set->val.str);
710 }
711 set->type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200712 }
Michal Vaskod3678892020-05-21 10:06:58 +0200713
714 set->val.nodes = NULL;
715 set->used = 0;
716 set->size = 0;
717 set->ht = NULL;
718 set->ctx_pos = 0;
719 set->ctx_pos = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200720}
721
Michal Vasko5e0e6eb2019-11-06 15:47:50 +0100722/**
723 * @brief Free dynamically-allocated set.
724 *
725 * @param[in] set Set to free.
726 */
727static void
Michal Vasko03ff5a72019-09-11 13:49:33 +0200728lyxp_set_free(struct lyxp_set *set)
729{
730 if (!set) {
731 return;
732 }
733
Michal Vaskod3678892020-05-21 10:06:58 +0200734 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200735 free(set);
736}
737
738/**
739 * @brief Initialize set context.
740 *
741 * @param[in] new Set to initialize.
742 * @param[in] set Arbitrary initialized set.
743 */
744static void
745set_init(struct lyxp_set *new, struct lyxp_set *set)
746{
747 memset(new, 0, sizeof *new);
Michal Vasko02a77382019-09-12 11:47:35 +0200748 if (set) {
749 new->ctx = set->ctx;
750 new->ctx_node = set->ctx_node;
Michal Vasko588112f2019-12-10 14:51:53 +0100751 new->root_type = set->root_type;
Michal Vasko02a77382019-09-12 11:47:35 +0200752 new->local_mod = set->local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +0100753 new->tree = set->tree;
Michal Vasko02a77382019-09-12 11:47:35 +0200754 new->format = set->format;
755 }
Michal Vasko03ff5a72019-09-11 13:49:33 +0200756}
757
758/**
759 * @brief Create a deep copy of a set.
760 *
761 * @param[in] set Set to copy.
762 * @return Copy of @p set.
763 */
764static struct lyxp_set *
765set_copy(struct lyxp_set *set)
766{
767 struct lyxp_set *ret;
768 uint16_t i;
Michal Vaskoba716542019-12-16 10:01:58 +0100769 int idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200770
771 if (!set) {
772 return NULL;
773 }
774
775 ret = malloc(sizeof *ret);
776 LY_CHECK_ERR_RET(!ret, LOGMEM(set->ctx), NULL);
777 set_init(ret, set);
778
779 if (set->type == LYXP_SET_SCNODE_SET) {
780 ret->type = set->type;
781
782 for (i = 0; i < set->used; ++i) {
Michal Vaskoba716542019-12-16 10:01:58 +0100783 if ((set->val.scnodes[i].in_ctx == 1) || (set->val.scnodes[i].in_ctx == -2)) {
784 idx = lyxp_set_scnode_insert_node(ret, set->val.scnodes[i].scnode, set->val.scnodes[i].type);
Michal Vasko3f27c522020-01-06 08:37:49 +0100785 /* coverity seems to think scnodes can be NULL */
786 if ((idx == -1) || !ret->val.scnodes) {
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{
Michal Vaskod3678892020-05-21 10:06:58 +0200824 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200825
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{
Michal Vaskod3678892020-05-21 10:06:58 +0200842 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200843
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{
Michal Vaskod3678892020-05-21 10:06:58 +0200857 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200858
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
Michal Vaskod3678892020-05-21 10:06:58 +0200905 assert(src->type == LYXP_SET_NODE_SET);
906
907 trg->type = LYXP_SET_NODE_SET;
908 trg->used = src->used;
909 trg->size = src->used;
910 trg->ctx_pos = src->ctx_pos;
911 trg->ctx_size = src->ctx_size;
912
913 trg->val.nodes = malloc(trg->used * sizeof *trg->val.nodes);
914 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx); memset(trg, 0, sizeof *trg), );
915 memcpy(trg->val.nodes, src->val.nodes, src->used * sizeof *src->val.nodes);
916 if (src->ht) {
917 trg->ht = lyht_dup(src->ht);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200918 } else {
Michal Vaskod3678892020-05-21 10:06:58 +0200919 trg->ht = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200920 }
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 {
Michal Vaskod3678892020-05-21 10:06:58 +0200963 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +0200964 }
965}
966
967/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100968 * @brief Remove a node from a set by setting its type to LYXP_NODE_NONE.
Michal Vasko57eab132019-09-24 11:46:26 +0200969 *
970 * @param[in] set Set to use.
971 * @param[in] idx Index from @p set of the node to be removed.
972 */
973static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100974set_remove_node_none(struct lyxp_set *set, uint32_t idx)
Michal Vasko57eab132019-09-24 11:46:26 +0200975{
976 assert(set && (set->type == LYXP_SET_NODE_SET));
977 assert(idx < set->used);
978
Michal Vasko2caefc12019-11-14 16:07:56 +0100979 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
980 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
981 }
982 set->val.nodes[idx].type = LYXP_NODE_NONE;
Michal Vasko57eab132019-09-24 11:46:26 +0200983}
984
985/**
Michal Vasko2caefc12019-11-14 16:07:56 +0100986 * @brief Remove all LYXP_NODE_NONE nodes from a set. Removing last node changes
Michal Vasko57eab132019-09-24 11:46:26 +0200987 * set into LYXP_SET_EMPTY. Context position aware.
988 *
989 * @param[in] set Set to consolidate.
990 */
991static void
Michal Vasko2caefc12019-11-14 16:07:56 +0100992set_remove_nodes_none(struct lyxp_set *set)
Michal Vasko57eab132019-09-24 11:46:26 +0200993{
994 uint16_t i, orig_used, end;
995 int32_t start;
996
Michal Vaskod3678892020-05-21 10:06:58 +0200997 assert(set);
Michal Vasko57eab132019-09-24 11:46:26 +0200998
999 orig_used = set->used;
1000 set->used = 0;
1001 for (i = 0; i < orig_used;) {
1002 start = -1;
1003 do {
Michal Vasko2caefc12019-11-14 16:07:56 +01001004 if ((set->val.nodes[i].type != LYXP_NODE_NONE) && (start == -1)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001005 start = i;
Michal Vasko2caefc12019-11-14 16:07:56 +01001006 } else if ((start > -1) && (set->val.nodes[i].type == LYXP_NODE_NONE)) {
Michal Vasko57eab132019-09-24 11:46:26 +02001007 end = i;
1008 ++i;
1009 break;
1010 }
1011
1012 ++i;
1013 if (i == orig_used) {
1014 end = i;
1015 }
1016 } while (i < orig_used);
1017
1018 if (start > -1) {
1019 /* move the whole chunk of valid nodes together */
1020 if (set->used != (unsigned)start) {
1021 memmove(&set->val.nodes[set->used], &set->val.nodes[start], (end - start) * sizeof *set->val.nodes);
1022 }
1023 set->used += end - start;
1024 }
1025 }
Michal Vasko57eab132019-09-24 11:46:26 +02001026}
1027
1028/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02001029 * @brief Check for duplicates in a node set.
1030 *
1031 * @param[in] set Set to check.
1032 * @param[in] node Node to look for in @p set.
1033 * @param[in] node_type Type of @p node.
1034 * @param[in] skip_idx Index from @p set to skip.
1035 * @return LY_ERR
1036 */
1037static LY_ERR
1038set_dup_node_check(const struct lyxp_set *set, const struct lyd_node *node, enum lyxp_node_type node_type, int skip_idx)
1039{
1040 uint32_t i;
1041
Michal Vasko2caefc12019-11-14 16:07:56 +01001042 if (set->ht && node) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001043 return set_dup_node_hash_check(set, (struct lyd_node *)node, node_type, skip_idx);
1044 }
1045
1046 for (i = 0; i < set->used; ++i) {
1047 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1048 continue;
1049 }
1050
1051 if ((set->val.nodes[i].node == node) && (set->val.nodes[i].type == node_type)) {
1052 return LY_EEXIST;
1053 }
1054 }
1055
1056 return LY_SUCCESS;
1057}
1058
Michal Vaskoecd62de2019-11-13 12:35:11 +01001059int
1060lyxp_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 +02001061{
1062 uint32_t i;
1063
1064 for (i = 0; i < set->used; ++i) {
1065 if ((skip_idx > -1) && (i == (unsigned)skip_idx)) {
1066 continue;
1067 }
1068
1069 if ((set->val.scnodes[i].scnode == node) && (set->val.scnodes[i].type == node_type)) {
1070 return i;
1071 }
1072 }
1073
1074 return -1;
1075}
1076
Michal Vaskoecd62de2019-11-13 12:35:11 +01001077void
1078lyxp_set_scnode_merge(struct lyxp_set *set1, struct lyxp_set *set2)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001079{
1080 uint32_t orig_used, i, j;
1081
Michal Vaskod3678892020-05-21 10:06:58 +02001082 assert((set1->type == LYXP_SET_SCNODE_SET) && (set2->type == LYXP_SET_SCNODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001083
Michal Vaskod3678892020-05-21 10:06:58 +02001084 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001085 return;
1086 }
1087
Michal Vaskod3678892020-05-21 10:06:58 +02001088 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001089 memcpy(set1, set2, sizeof *set1);
1090 return;
1091 }
1092
1093 if (set1->used + set2->used > set1->size) {
1094 set1->size = set1->used + set2->used;
1095 set1->val.scnodes = ly_realloc(set1->val.scnodes, set1->size * sizeof *set1->val.scnodes);
1096 LY_CHECK_ERR_RET(!set1->val.scnodes, LOGMEM(set1->ctx), );
1097 }
1098
1099 orig_used = set1->used;
1100
1101 for (i = 0; i < set2->used; ++i) {
1102 for (j = 0; j < orig_used; ++j) {
1103 /* detect duplicities */
1104 if (set1->val.scnodes[j].scnode == set2->val.scnodes[i].scnode) {
1105 break;
1106 }
1107 }
1108
1109 if (j == orig_used) {
1110 memcpy(&set1->val.scnodes[set1->used], &set2->val.scnodes[i], sizeof *set2->val.scnodes);
1111 ++set1->used;
1112 }
1113 }
1114
Michal Vaskod3678892020-05-21 10:06:58 +02001115 lyxp_set_free_content(set2);
1116 set2->type = LYXP_SET_SCNODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001117}
1118
1119/**
1120 * @brief Insert a node into a set. Context position aware.
1121 *
1122 * @param[in] set Set to use.
1123 * @param[in] node Node to insert to @p set.
1124 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1125 * @param[in] node_type Node type of @p node.
1126 * @param[in] idx Index in @p set to insert into.
1127 */
1128static void
1129set_insert_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1130{
Michal Vaskod3678892020-05-21 10:06:58 +02001131 assert(set && (set->type == LYXP_SET_NODE_SET));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001132
Michal Vaskod3678892020-05-21 10:06:58 +02001133 if (!set->size) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001134 /* first item */
1135 if (idx) {
1136 /* no real harm done, but it is a bug */
1137 LOGINT(set->ctx);
1138 idx = 0;
1139 }
1140 set->val.nodes = malloc(LYXP_SET_SIZE_START * sizeof *set->val.nodes);
1141 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1142 set->type = LYXP_SET_NODE_SET;
1143 set->used = 0;
1144 set->size = LYXP_SET_SIZE_START;
1145 set->ctx_pos = 1;
1146 set->ctx_size = 1;
1147 set->ht = NULL;
1148 } else {
1149 /* not an empty set */
1150 if (set->used == set->size) {
1151
1152 /* set is full */
1153 set->val.nodes = ly_realloc(set->val.nodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.nodes);
1154 LY_CHECK_ERR_RET(!set->val.nodes, LOGMEM(set->ctx), );
1155 set->size += LYXP_SET_SIZE_STEP;
1156 }
1157
1158 if (idx > set->used) {
1159 LOGINT(set->ctx);
1160 idx = set->used;
1161 }
1162
1163 /* make space for the new node */
1164 if (idx < set->used) {
1165 memmove(&set->val.nodes[idx + 1], &set->val.nodes[idx], (set->used - idx) * sizeof *set->val.nodes);
1166 }
1167 }
1168
1169 /* finally assign the value */
1170 set->val.nodes[idx].node = (struct lyd_node *)node;
1171 set->val.nodes[idx].type = node_type;
1172 set->val.nodes[idx].pos = pos;
1173 ++set->used;
1174
Michal Vasko2caefc12019-11-14 16:07:56 +01001175 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1176 set_insert_node_hash(set, (struct lyd_node *)node, node_type);
1177 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001178}
1179
Michal Vaskoecd62de2019-11-13 12:35:11 +01001180int
1181lyxp_set_scnode_insert_node(struct lyxp_set *set, const struct lysc_node *node, enum lyxp_node_type node_type)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001182{
1183 int ret;
1184
1185 assert(set->type == LYXP_SET_SCNODE_SET);
1186
Michal Vaskoecd62de2019-11-13 12:35:11 +01001187 ret = lyxp_set_scnode_dup_node_check(set, node, node_type, -1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001188 if (ret > -1) {
1189 set->val.scnodes[ret].in_ctx = 1;
1190 } else {
1191 if (set->used == set->size) {
1192 set->val.scnodes = ly_realloc(set->val.scnodes, (set->size + LYXP_SET_SIZE_STEP) * sizeof *set->val.scnodes);
1193 LY_CHECK_ERR_RET(!set->val.scnodes, LOGMEM(set->ctx), -1);
1194 set->size += LYXP_SET_SIZE_STEP;
1195 }
1196
1197 ret = set->used;
1198 set->val.scnodes[ret].scnode = (struct lysc_node *)node;
1199 set->val.scnodes[ret].type = node_type;
1200 set->val.scnodes[ret].in_ctx = 1;
1201 ++set->used;
1202 }
1203
1204 return ret;
1205}
1206
1207/**
1208 * @brief Replace a node in a set with another. Context position aware.
1209 *
1210 * @param[in] set Set to use.
1211 * @param[in] node Node to insert to @p set.
1212 * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
1213 * @param[in] node_type Node type of @p node.
1214 * @param[in] idx Index in @p set of the node to replace.
1215 */
1216static void
1217set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
1218{
1219 assert(set && (idx < set->used));
1220
Michal Vasko2caefc12019-11-14 16:07:56 +01001221 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1222 set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1223 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001224 set->val.nodes[idx].node = (struct lyd_node *)node;
1225 set->val.nodes[idx].type = node_type;
1226 set->val.nodes[idx].pos = pos;
Michal Vasko2caefc12019-11-14 16:07:56 +01001227 if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
1228 set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
1229 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02001230}
1231
1232/**
1233 * @brief Set all nodes with ctx 1 to a new unique context value.
1234 *
1235 * @param[in] set Set to modify.
1236 * @return New context value.
1237 */
Michal Vasko5c4e5892019-11-14 12:31:38 +01001238static int32_t
Michal Vasko03ff5a72019-09-11 13:49:33 +02001239set_scnode_new_in_ctx(struct lyxp_set *set)
1240{
Michal Vasko5c4e5892019-11-14 12:31:38 +01001241 uint32_t i;
1242 int32_t ret_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001243
1244 assert(set->type == LYXP_SET_SCNODE_SET);
1245
1246 ret_ctx = 3;
1247retry:
1248 for (i = 0; i < set->used; ++i) {
1249 if (set->val.scnodes[i].in_ctx >= ret_ctx) {
1250 ret_ctx = set->val.scnodes[i].in_ctx + 1;
1251 goto retry;
1252 }
1253 }
1254 for (i = 0; i < set->used; ++i) {
1255 if (set->val.scnodes[i].in_ctx == 1) {
1256 set->val.scnodes[i].in_ctx = ret_ctx;
1257 }
1258 }
1259
1260 return ret_ctx;
1261}
1262
1263/**
1264 * @brief Get unique @p node position in the data.
1265 *
1266 * @param[in] node Node to find.
1267 * @param[in] node_type Node type of @p node.
1268 * @param[in] root Root node.
1269 * @param[in] root_type Type of the XPath @p root node.
1270 * @param[in] prev Node that we think is before @p node in DFS from @p root. Can optionally
1271 * be used to increase efficiency and start the DFS from this node.
1272 * @param[in] prev_pos Node @p prev position. Optional, but must be set if @p prev is set.
1273 * @return Node position.
1274 */
1275static uint32_t
1276get_node_pos(const struct lyd_node *node, enum lyxp_node_type node_type, const struct lyd_node *root,
1277 enum lyxp_node_type root_type, const struct lyd_node **prev, uint32_t *prev_pos)
1278{
1279 const struct lyd_node *next, *elem, *top_sibling;
1280 uint32_t pos = 1;
1281
1282 assert(prev && prev_pos && !root->prev->next);
1283
1284 if ((node_type == LYXP_NODE_ROOT) || (node_type == LYXP_NODE_ROOT_CONFIG)) {
1285 return 0;
1286 }
1287
1288 if (*prev) {
1289 /* start from the previous element instead from the root */
1290 elem = next = *prev;
1291 pos = *prev_pos;
1292 for (top_sibling = elem; top_sibling->parent; top_sibling = (struct lyd_node *)top_sibling->parent);
1293 goto dfs_search;
1294 }
1295
1296 for (top_sibling = root; top_sibling; top_sibling = top_sibling->next) {
1297 /* TREE DFS */
1298 LYD_TREE_DFS_BEGIN(top_sibling, next, elem) {
1299dfs_search:
1300 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (elem->schema->flags & LYS_CONFIG_R)) {
1301 goto skip_children;
1302 }
1303
1304 if (elem == node) {
1305 break;
1306 }
1307 ++pos;
1308
1309 /* TREE DFS END */
1310 /* select element for the next run - children first,
1311 * child exception for lyd_node_leaf and lyd_node_leaflist, but not the root */
1312 if (elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1313 next = NULL;
1314 } else {
1315 next = lyd_node_children(elem);
1316 }
1317 if (!next) {
1318skip_children:
1319 /* no children */
1320 if (elem == top_sibling) {
1321 /* we are done, root has no children */
1322 elem = NULL;
1323 break;
1324 }
1325 /* try siblings */
1326 next = elem->next;
1327 }
1328 while (!next) {
1329 /* no siblings, go back through parents */
1330 if (elem->parent == top_sibling->parent) {
1331 /* we are done, no next element to process */
1332 elem = NULL;
1333 break;
1334 }
1335 /* parent is already processed, go to its sibling */
1336 elem = (struct lyd_node *)elem->parent;
1337 next = elem->next;
1338 }
1339 }
1340
1341 /* node found */
1342 if (elem) {
1343 break;
1344 }
1345 }
1346
1347 if (!elem) {
1348 if (!(*prev)) {
1349 /* we went from root and failed to find it, cannot be */
1350 LOGINT(node->schema->module->ctx);
1351 return 0;
1352 } else {
1353 *prev = NULL;
1354 *prev_pos = 0;
1355
1356 elem = next = top_sibling = root;
1357 pos = 1;
1358 goto dfs_search;
1359 }
1360 }
1361
1362 /* remember the last found node for next time */
1363 *prev = node;
1364 *prev_pos = pos;
1365
1366 return pos;
1367}
1368
1369/**
1370 * @brief Assign (fill) missing node positions.
1371 *
1372 * @param[in] set Set to fill positions in.
1373 * @param[in] root Context root node.
1374 * @param[in] root_type Context root type.
1375 * @return LY_ERR
1376 */
1377static LY_ERR
1378set_assign_pos(struct lyxp_set *set, const struct lyd_node *root, enum lyxp_node_type root_type)
1379{
1380 const struct lyd_node *prev = NULL, *tmp_node;
1381 uint32_t i, tmp_pos = 0;
1382
1383 for (i = 0; i < set->used; ++i) {
1384 if (!set->val.nodes[i].pos) {
1385 tmp_node = NULL;
1386 switch (set->val.nodes[i].type) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001387 case LYXP_NODE_META:
1388 tmp_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001389 if (!tmp_node) {
1390 LOGINT_RET(root->schema->module->ctx);
1391 }
1392 /* fallthrough */
1393 case LYXP_NODE_ELEM:
1394 case LYXP_NODE_TEXT:
1395 if (!tmp_node) {
1396 tmp_node = set->val.nodes[i].node;
1397 }
1398 set->val.nodes[i].pos = get_node_pos(tmp_node, set->val.nodes[i].type, root, root_type, &prev, &tmp_pos);
1399 break;
1400 default:
1401 /* all roots have position 0 */
1402 break;
1403 }
1404 }
1405 }
1406
1407 return LY_SUCCESS;
1408}
1409
1410/**
Michal Vasko9f96a052020-03-10 09:41:45 +01001411 * @brief Get unique @p meta position in the parent metadata.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001412 *
Michal Vasko9f96a052020-03-10 09:41:45 +01001413 * @param[in] meta Metadata to use.
1414 * @return Metadata position.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001415 */
1416static uint16_t
Michal Vasko9f96a052020-03-10 09:41:45 +01001417get_meta_pos(struct lyd_meta *meta)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001418{
1419 uint16_t pos = 0;
Michal Vasko9f96a052020-03-10 09:41:45 +01001420 struct lyd_meta *meta2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001421
Michal Vasko9f96a052020-03-10 09:41:45 +01001422 for (meta2 = meta->parent->meta; meta2 && (meta2 != meta); meta2 = meta2->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001423 ++pos;
1424 }
1425
Michal Vasko9f96a052020-03-10 09:41:45 +01001426 assert(meta2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001427 return pos;
1428}
1429
1430/**
1431 * @brief Compare 2 nodes in respect to XPath document order.
1432 *
1433 * @param[in] item1 1st node.
1434 * @param[in] item2 2nd node.
1435 * @return If 1st > 2nd returns 1, 1st == 2nd returns 0, and 1st < 2nd returns -1.
1436 */
1437static int
1438set_sort_compare(struct lyxp_set_node *item1, struct lyxp_set_node *item2)
1439{
Michal Vasko9f96a052020-03-10 09:41:45 +01001440 uint32_t meta_pos1 = 0, meta_pos2 = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001441
1442 if (item1->pos < item2->pos) {
1443 return -1;
1444 }
1445
1446 if (item1->pos > item2->pos) {
1447 return 1;
1448 }
1449
1450 /* node positions are equal, the fun case */
1451
1452 /* 1st ELEM - == - 2nd TEXT, 1st TEXT - == - 2nd ELEM */
1453 /* special case since text nodes are actually saved as their parents */
1454 if ((item1->node == item2->node) && (item1->type != item2->type)) {
1455 if (item1->type == LYXP_NODE_ELEM) {
1456 assert(item2->type == LYXP_NODE_TEXT);
1457 return -1;
1458 } else {
1459 assert((item1->type == LYXP_NODE_TEXT) && (item2->type == LYXP_NODE_ELEM));
1460 return 1;
1461 }
1462 }
1463
Michal Vasko9f96a052020-03-10 09:41:45 +01001464 /* we need meta positions now */
1465 if (item1->type == LYXP_NODE_META) {
1466 meta_pos1 = get_meta_pos((struct lyd_meta *)item1->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001467 }
Michal Vasko9f96a052020-03-10 09:41:45 +01001468 if (item2->type == LYXP_NODE_META) {
1469 meta_pos2 = get_meta_pos((struct lyd_meta *)item2->node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001470 }
1471
Michal Vasko9f96a052020-03-10 09:41:45 +01001472 /* 1st ROOT - 2nd ROOT, 1st ELEM - 2nd ELEM, 1st TEXT - 2nd TEXT, 1st META - =pos= - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001473 /* check for duplicates */
1474 if (item1->node == item2->node) {
Michal Vasko9f96a052020-03-10 09:41:45 +01001475 assert((item1->type == item2->type) && ((item1->type != LYXP_NODE_META) || (meta_pos1 == meta_pos2)));
Michal Vasko03ff5a72019-09-11 13:49:33 +02001476 return 0;
1477 }
1478
Michal Vasko9f96a052020-03-10 09:41:45 +01001479 /* 1st ELEM - 2nd TEXT, 1st ELEM - any pos - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001480 /* elem is always first, 2nd node is after it */
1481 if (item1->type == LYXP_NODE_ELEM) {
1482 assert(item2->type != LYXP_NODE_ELEM);
1483 return -1;
1484 }
1485
Michal Vasko9f96a052020-03-10 09:41:45 +01001486 /* 1st TEXT - 2nd ELEM, 1st TEXT - any pos - 2nd META, 1st META - any pos - 2nd ELEM, 1st META - >pos> - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001487 /* 2nd is before 1st */
1488 if (((item1->type == LYXP_NODE_TEXT)
Michal Vasko9f96a052020-03-10 09:41:45 +01001489 && ((item2->type == LYXP_NODE_ELEM) || (item2->type == LYXP_NODE_META)))
1490 || ((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_ELEM))
1491 || (((item1->type == LYXP_NODE_META) && (item2->type == LYXP_NODE_META))
1492 && (meta_pos1 > meta_pos2))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001493 return 1;
1494 }
1495
Michal Vasko9f96a052020-03-10 09:41:45 +01001496 /* 1st META - any pos - 2nd TEXT, 1st META <pos< - 2nd META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02001497 /* 2nd is after 1st */
1498 return -1;
1499}
1500
1501/**
1502 * @brief Set cast for comparisons.
1503 *
1504 * @param[in] trg Target set to cast source into.
1505 * @param[in] src Source set.
1506 * @param[in] type Target set type.
1507 * @param[in] src_idx Source set node index.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001508 * @return LY_ERR
1509 */
1510static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001511set_comp_cast(struct lyxp_set *trg, struct lyxp_set *src, enum lyxp_set_type type, uint32_t src_idx)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001512{
1513 assert(src->type == LYXP_SET_NODE_SET);
1514
1515 set_init(trg, src);
1516
1517 /* insert node into target set */
1518 set_insert_node(trg, src->val.nodes[src_idx].node, src->val.nodes[src_idx].pos, src->val.nodes[src_idx].type, 0);
1519
1520 /* cast target set appropriately */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001521 return lyxp_set_cast(trg, type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001522}
1523
1524#ifndef NDEBUG
1525
1526/**
1527 * @brief Bubble sort @p set into XPath document order.
1528 * Context position aware. Unused in the 'Release' build target.
1529 *
1530 * @param[in] set Set to sort.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001531 * @return How many times the whole set was traversed - 1 (if set was sorted, returns 0).
1532 */
1533static int
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001534set_sort(struct lyxp_set *set)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001535{
1536 uint32_t i, j;
1537 int ret = 0, cmp, inverted, change;
1538 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001539 struct lyxp_set_node item;
1540 struct lyxp_set_hash_node hnode;
1541 uint64_t hash;
1542
1543 if ((set->type != LYXP_SET_NODE_SET) || (set->used == 1)) {
1544 return 0;
1545 }
1546
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001547 /* find first top-level node to be used as anchor for positions */
1548 for (root = set->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1549 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001550
1551 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001552 if (set_assign_pos(set, root, set->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001553 return -1;
1554 }
1555
1556 LOGDBG(LY_LDGXPATH, "SORT BEGIN");
1557 print_set_debug(set);
1558
1559 for (i = 0; i < set->used; ++i) {
1560 inverted = 0;
1561 change = 0;
1562
1563 for (j = 1; j < set->used - i; ++j) {
1564 /* compare node positions */
1565 if (inverted) {
1566 cmp = set_sort_compare(&set->val.nodes[j], &set->val.nodes[j - 1]);
1567 } else {
1568 cmp = set_sort_compare(&set->val.nodes[j - 1], &set->val.nodes[j]);
1569 }
1570
1571 /* swap if needed */
1572 if ((inverted && (cmp < 0)) || (!inverted && (cmp > 0))) {
1573 change = 1;
1574
1575 item = set->val.nodes[j - 1];
1576 set->val.nodes[j - 1] = set->val.nodes[j];
1577 set->val.nodes[j] = item;
1578 } else {
1579 /* whether node_pos1 should be smaller than node_pos2 or the other way around */
1580 inverted = !inverted;
1581 }
1582 }
1583
1584 ++ret;
1585
1586 if (!change) {
1587 break;
1588 }
1589 }
1590
1591 LOGDBG(LY_LDGXPATH, "SORT END %d", ret);
1592 print_set_debug(set);
1593
1594 /* check node hashes */
1595 if (set->used >= LYD_HT_MIN_ITEMS) {
1596 assert(set->ht);
1597 for (i = 0; i < set->used; ++i) {
1598 hnode.node = set->val.nodes[i].node;
1599 hnode.type = set->val.nodes[i].type;
1600
1601 hash = dict_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
1602 hash = dict_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
1603 hash = dict_hash_multi(hash, NULL, 0);
1604
1605 assert(!lyht_find(set->ht, &hnode, hash, NULL));
1606 }
1607 }
1608
1609 return ret - 1;
1610}
1611
1612/**
1613 * @brief Remove duplicate entries in a sorted node set.
1614 *
1615 * @param[in] set Sorted set to check.
1616 * @return LY_ERR (LY_EEXIST if some duplicates are found)
1617 */
1618static LY_ERR
1619set_sorted_dup_node_clean(struct lyxp_set *set)
1620{
1621 uint32_t i = 0;
1622 LY_ERR ret = LY_SUCCESS;
1623
1624 if (set->used > 1) {
1625 while (i < set->used - 1) {
1626 if ((set->val.nodes[i].node == set->val.nodes[i + 1].node)
1627 && (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01001628 set_remove_node_none(set, i + 1);
Michal Vasko57eab132019-09-24 11:46:26 +02001629 ret = LY_EEXIST;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001630 }
Michal Vasko57eab132019-09-24 11:46:26 +02001631 ++i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001632 }
1633 }
1634
Michal Vasko2caefc12019-11-14 16:07:56 +01001635 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001636 return ret;
1637}
1638
1639#endif
1640
1641/**
1642 * @brief Merge 2 sorted sets into one.
1643 *
1644 * @param[in,out] trg Set to merge into. Duplicates are removed.
1645 * @param[in] src Set to be merged into @p trg. It is cast to #LYXP_SET_EMPTY on success.
Michal Vasko03ff5a72019-09-11 13:49:33 +02001646 * @return LY_ERR
1647 */
1648static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001649set_sorted_merge(struct lyxp_set *trg, struct lyxp_set *src)
Michal Vasko03ff5a72019-09-11 13:49:33 +02001650{
1651 uint32_t i, j, k, count, dup_count;
1652 int cmp;
1653 const struct lyd_node *root;
Michal Vasko03ff5a72019-09-11 13:49:33 +02001654
Michal Vaskod3678892020-05-21 10:06:58 +02001655 if ((trg->type != LYXP_SET_NODE_SET) || (src->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001656 return LY_EINVAL;
1657 }
1658
Michal Vaskod3678892020-05-21 10:06:58 +02001659 if (!src->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001660 return LY_SUCCESS;
Michal Vaskod3678892020-05-21 10:06:58 +02001661 } else if (!trg->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001662 set_fill_set(trg, src);
Michal Vaskod3678892020-05-21 10:06:58 +02001663 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001664 return LY_SUCCESS;
1665 }
1666
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001667 /* find first top-level node to be used as anchor for positions */
1668 for (root = trg->ctx_node; root->parent; root = (const struct lyd_node *)root->parent);
1669 for (; root->prev->next; root = root->prev);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001670
1671 /* fill positions */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01001672 if (set_assign_pos(trg, root, trg->root_type) || set_assign_pos(src, root, src->root_type)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02001673 return LY_EINT;
1674 }
1675
1676#ifndef NDEBUG
1677 LOGDBG(LY_LDGXPATH, "MERGE target");
1678 print_set_debug(trg);
1679 LOGDBG(LY_LDGXPATH, "MERGE source");
1680 print_set_debug(src);
1681#endif
1682
1683 /* make memory for the merge (duplicates are not detected yet, so space
1684 * will likely be wasted on them, too bad) */
1685 if (trg->size - trg->used < src->used) {
1686 trg->size = trg->used + src->used;
1687
1688 trg->val.nodes = ly_realloc(trg->val.nodes, trg->size * sizeof *trg->val.nodes);
1689 LY_CHECK_ERR_RET(!trg->val.nodes, LOGMEM(src->ctx), LY_EMEM);
1690 }
1691
1692 i = 0;
1693 j = 0;
1694 count = 0;
1695 dup_count = 0;
1696 do {
1697 cmp = set_sort_compare(&src->val.nodes[i], &trg->val.nodes[j]);
1698 if (!cmp) {
1699 if (!count) {
1700 /* duplicate, just skip it */
1701 ++i;
1702 ++j;
1703 } else {
1704 /* we are copying something already, so let's copy the duplicate too,
1705 * we are hoping that afterwards there are some more nodes to
1706 * copy and this way we can copy them all together */
1707 ++count;
1708 ++dup_count;
1709 ++i;
1710 ++j;
1711 }
1712 } else if (cmp < 0) {
1713 /* inserting src node into trg, just remember it for now */
1714 ++count;
1715 ++i;
1716
1717 /* insert the hash now */
1718 set_insert_node_hash(trg, src->val.nodes[i - 1].node, src->val.nodes[i - 1].type);
1719 } else if (count) {
1720copy_nodes:
1721 /* time to actually copy the nodes, we have found the largest block of nodes */
1722 memmove(&trg->val.nodes[j + (count - dup_count)],
1723 &trg->val.nodes[j],
1724 (trg->used - j) * sizeof *trg->val.nodes);
1725 memcpy(&trg->val.nodes[j - dup_count], &src->val.nodes[i - count], count * sizeof *src->val.nodes);
1726
1727 trg->used += count - dup_count;
1728 /* do not change i, except the copying above, we are basically doing exactly what is in the else branch below */
1729 j += count - dup_count;
1730
1731 count = 0;
1732 dup_count = 0;
1733 } else {
1734 ++j;
1735 }
1736 } while ((i < src->used) && (j < trg->used));
1737
1738 if ((i < src->used) || count) {
1739 /* insert all the hashes first */
1740 for (k = i; k < src->used; ++k) {
1741 set_insert_node_hash(trg, src->val.nodes[k].node, src->val.nodes[k].type);
1742 }
1743
1744 /* loop ended, but we need to copy something at trg end */
1745 count += src->used - i;
1746 i = src->used;
1747 goto copy_nodes;
1748 }
1749
1750 /* we are inserting hashes before the actual node insert, which causes
1751 * situations when there were initially not enough items for a hash table,
1752 * but even after some were inserted, hash table was not created (during
1753 * insertion the number of items is not updated yet) */
1754 if (!trg->ht && (trg->used >= LYD_HT_MIN_ITEMS)) {
1755 set_insert_node_hash(trg, NULL, 0);
1756 }
1757
1758#ifndef NDEBUG
1759 LOGDBG(LY_LDGXPATH, "MERGE result");
1760 print_set_debug(trg);
1761#endif
1762
Michal Vaskod3678892020-05-21 10:06:58 +02001763 lyxp_set_free_content(src);
Michal Vasko03ff5a72019-09-11 13:49:33 +02001764 return LY_SUCCESS;
1765}
1766
1767/*
1768 * (re)parse functions
1769 *
1770 * Parse functions parse the expression into
1771 * tokens (syntactic analysis).
1772 *
1773 * Reparse functions perform semantic analysis
1774 * (do not save the result, just a check) of
1775 * the expression and fill repeat indices.
1776 */
1777
1778/**
1779 * @brief Look at the next token and check its kind.
1780 *
1781 * @param[in] ctx Context for logging.
1782 * @param[in] exp Expression to use.
1783 * @param[in] exp_idx Position in the expression \p exp.
1784 * @param[in] want_tok Expected token.
1785 * @param[in] strict Whether the token is strictly required (print error if
1786 * not the next one) or we simply want to check whether it is the next or not.
1787 * @return LY_ERR
1788 */
1789static LY_ERR
1790exp_check_token(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t exp_idx, enum lyxp_token want_tok, int strict)
1791{
1792 if (exp->used == exp_idx) {
1793 if (strict) {
1794 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOF);
1795 }
1796 return LY_EINVAL;
1797 }
1798
1799 if (want_tok && (exp->tokens[exp_idx] != want_tok)) {
1800 if (strict) {
1801 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1802 print_token(exp->tokens[exp_idx]), &exp->expr[exp->tok_pos[exp_idx]]);
1803 }
1804 return LY_EINVAL;
1805 }
1806
1807 return LY_SUCCESS;
1808}
1809
1810/**
1811 * @brief Stack operation push on the repeat array.
1812 *
1813 * @param[in] exp Expression to use.
1814 * @param[in] exp_idx Position in the expresion \p exp.
1815 * @param[in] repeat_op_idx Index from \p exp of the operator token. This value is pushed.
1816 */
1817static void
1818exp_repeat_push(struct lyxp_expr *exp, uint16_t exp_idx, uint16_t repeat_op_idx)
1819{
1820 uint16_t i;
1821
1822 if (exp->repeat[exp_idx]) {
1823 for (i = 0; exp->repeat[exp_idx][i]; ++i);
1824 exp->repeat[exp_idx] = realloc(exp->repeat[exp_idx], (i + 2) * sizeof *exp->repeat[exp_idx]);
1825 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1826 exp->repeat[exp_idx][i] = repeat_op_idx;
1827 exp->repeat[exp_idx][i + 1] = 0;
1828 } else {
1829 exp->repeat[exp_idx] = calloc(2, sizeof *exp->repeat[exp_idx]);
1830 LY_CHECK_ERR_RET(!exp->repeat[exp_idx], LOGMEM(NULL), );
1831 exp->repeat[exp_idx][0] = repeat_op_idx;
1832 }
1833}
1834
1835/**
1836 * @brief Reparse Predicate. Logs directly on error.
1837 *
1838 * [7] Predicate ::= '[' Expr ']'
1839 *
1840 * @param[in] ctx Context for logging.
1841 * @param[in] exp Parsed XPath expression.
1842 * @param[in] exp_idx Position in the expression @p exp.
1843 * @return LY_ERR
1844 */
1845static LY_ERR
1846reparse_predicate(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1847{
1848 LY_ERR rc;
1849
1850 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK1, 1);
1851 LY_CHECK_RET(rc);
1852 ++(*exp_idx);
1853
1854 rc = reparse_or_expr(ctx, exp, exp_idx);
1855 LY_CHECK_RET(rc);
1856
1857 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_BRACK2, 1);
1858 LY_CHECK_RET(rc);
1859 ++(*exp_idx);
1860
1861 return LY_SUCCESS;
1862}
1863
1864/**
1865 * @brief Reparse RelativeLocationPath. Logs directly on error.
1866 *
1867 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
1868 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
1869 * [6] NodeTest ::= NameTest | NodeType '(' ')'
1870 *
1871 * @param[in] ctx Context for logging.
1872 * @param[in] exp Parsed XPath expression.
1873 * @param[in] exp_idx Position in the expression \p exp.
1874 * @return LY_ERR (LY_EINCOMPLETE on forward reference)
1875 */
1876static LY_ERR
1877reparse_relative_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1878{
1879 LY_ERR rc;
1880
1881 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1882 LY_CHECK_RET(rc);
1883
1884 goto step;
1885 do {
1886 /* '/' or '//' */
1887 ++(*exp_idx);
1888
1889 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1890 LY_CHECK_RET(rc);
1891step:
1892 /* Step */
1893 switch (exp->tokens[*exp_idx]) {
1894 case LYXP_TOKEN_DOT:
1895 ++(*exp_idx);
1896 break;
1897
1898 case LYXP_TOKEN_DDOT:
1899 ++(*exp_idx);
1900 break;
1901
1902 case LYXP_TOKEN_AT:
1903 ++(*exp_idx);
1904
1905 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
1906 LY_CHECK_RET(rc);
1907 if ((exp->tokens[*exp_idx] != LYXP_TOKEN_NAMETEST) && (exp->tokens[*exp_idx] != LYXP_TOKEN_NODETYPE)) {
1908 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1909 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1910 return LY_EVALID;
1911 }
1912 /* fall through */
1913 case LYXP_TOKEN_NAMETEST:
1914 ++(*exp_idx);
1915 goto reparse_predicate;
1916 break;
1917
1918 case LYXP_TOKEN_NODETYPE:
1919 ++(*exp_idx);
1920
1921 /* '(' */
1922 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
1923 LY_CHECK_RET(rc);
1924 ++(*exp_idx);
1925
1926 /* ')' */
1927 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
1928 LY_CHECK_RET(rc);
1929 ++(*exp_idx);
1930
1931reparse_predicate:
1932 /* Predicate* */
1933 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
1934 rc = reparse_predicate(ctx, exp, exp_idx);
1935 LY_CHECK_RET(rc);
1936 }
1937 break;
1938 default:
1939 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
1940 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
1941 return LY_EVALID;
1942 }
1943 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
1944
1945 return LY_SUCCESS;
1946}
1947
1948/**
1949 * @brief Reparse AbsoluteLocationPath. Logs directly on error.
1950 *
1951 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
1952 *
1953 * @param[in] ctx Context for logging.
1954 * @param[in] exp Parsed XPath expression.
1955 * @param[in] exp_idx Position in the expression \p exp.
1956 * @return LY_ERR
1957 */
1958static LY_ERR
1959reparse_absolute_location_path(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
1960{
1961 LY_ERR rc;
1962
1963 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_PATH, 1);
1964 LY_CHECK_RET(rc);
1965
1966 /* '/' RelativeLocationPath? */
1967 if (exp->tok_len[*exp_idx] == 1) {
1968 /* '/' */
1969 ++(*exp_idx);
1970
1971 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
1972 return LY_SUCCESS;
1973 }
1974 switch (exp->tokens[*exp_idx]) {
1975 case LYXP_TOKEN_DOT:
1976 case LYXP_TOKEN_DDOT:
1977 case LYXP_TOKEN_AT:
1978 case LYXP_TOKEN_NAMETEST:
1979 case LYXP_TOKEN_NODETYPE:
1980 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1981 LY_CHECK_RET(rc);
1982 /* fall through */
1983 default:
1984 break;
1985 }
1986
1987 /* '//' RelativeLocationPath */
1988 } else {
1989 /* '//' */
1990 ++(*exp_idx);
1991
1992 rc = reparse_relative_location_path(ctx, exp, exp_idx);
1993 LY_CHECK_RET(rc);
1994 }
1995
1996 return LY_SUCCESS;
1997}
1998
1999/**
2000 * @brief Reparse FunctionCall. Logs directly on error.
2001 *
2002 * [9] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
2003 *
2004 * @param[in] ctx Context for logging.
2005 * @param[in] exp Parsed XPath expression.
2006 * @param[in] exp_idx Position in the expression @p exp.
2007 * @return LY_ERR
2008 */
2009static LY_ERR
2010reparse_function_call(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2011{
2012 int min_arg_count = -1, max_arg_count, arg_count;
2013 uint16_t func_exp_idx;
2014 LY_ERR rc;
2015
2016 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_FUNCNAME, 1);
2017 LY_CHECK_RET(rc);
2018 func_exp_idx = *exp_idx;
2019 switch (exp->tok_len[*exp_idx]) {
2020 case 3:
2021 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
2022 min_arg_count = 1;
2023 max_arg_count = 1;
2024 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
2025 min_arg_count = 1;
2026 max_arg_count = 1;
2027 }
2028 break;
2029 case 4:
2030 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
2031 min_arg_count = 1;
2032 max_arg_count = 1;
2033 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
2034 min_arg_count = 0;
2035 max_arg_count = 0;
2036 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
2037 min_arg_count = 0;
2038 max_arg_count = 1;
2039 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
2040 min_arg_count = 0;
2041 max_arg_count = 0;
2042 }
2043 break;
2044 case 5:
2045 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
2046 min_arg_count = 1;
2047 max_arg_count = 1;
2048 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
2049 min_arg_count = 0;
2050 max_arg_count = 0;
2051 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
2052 min_arg_count = 1;
2053 max_arg_count = 1;
2054 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
2055 min_arg_count = 1;
2056 max_arg_count = 1;
2057 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
2058 min_arg_count = 1;
2059 max_arg_count = 1;
2060 }
2061 break;
2062 case 6:
2063 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
2064 min_arg_count = 2;
Michal Vaskobe2e3562019-10-15 15:35:35 +02002065 max_arg_count = INT_MAX;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002066 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
2067 min_arg_count = 0;
2068 max_arg_count = 1;
2069 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
2070 min_arg_count = 0;
2071 max_arg_count = 1;
2072 }
2073 break;
2074 case 7:
2075 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
2076 min_arg_count = 1;
2077 max_arg_count = 1;
2078 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
2079 min_arg_count = 1;
2080 max_arg_count = 1;
2081 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
2082 min_arg_count = 0;
2083 max_arg_count = 0;
2084 }
2085 break;
2086 case 8:
2087 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
2088 min_arg_count = 2;
2089 max_arg_count = 2;
2090 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
2091 min_arg_count = 0;
2092 max_arg_count = 0;
2093 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
2094 min_arg_count = 2;
2095 max_arg_count = 2;
2096 }
2097 break;
2098 case 9:
2099 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
2100 min_arg_count = 2;
2101 max_arg_count = 3;
2102 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
2103 min_arg_count = 3;
2104 max_arg_count = 3;
2105 }
2106 break;
2107 case 10:
2108 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
2109 min_arg_count = 0;
2110 max_arg_count = 1;
2111 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
2112 min_arg_count = 1;
2113 max_arg_count = 1;
2114 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
2115 min_arg_count = 2;
2116 max_arg_count = 2;
2117 }
2118 break;
2119 case 11:
2120 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
2121 min_arg_count = 2;
2122 max_arg_count = 2;
2123 }
2124 break;
2125 case 12:
2126 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
2127 min_arg_count = 2;
2128 max_arg_count = 2;
2129 }
2130 break;
2131 case 13:
2132 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
2133 min_arg_count = 0;
2134 max_arg_count = 1;
2135 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
2136 min_arg_count = 0;
2137 max_arg_count = 1;
2138 }
2139 break;
2140 case 15:
2141 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
2142 min_arg_count = 0;
2143 max_arg_count = 1;
2144 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
2145 min_arg_count = 2;
2146 max_arg_count = 2;
2147 }
2148 break;
2149 case 16:
2150 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
2151 min_arg_count = 2;
2152 max_arg_count = 2;
2153 }
2154 break;
2155 case 20:
2156 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
2157 min_arg_count = 2;
2158 max_arg_count = 2;
2159 }
2160 break;
2161 }
2162 if (min_arg_count == -1) {
2163 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INFUNC, exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
2164 return LY_EINVAL;
2165 }
2166 ++(*exp_idx);
2167
2168 /* '(' */
2169 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR1, 1);
2170 LY_CHECK_RET(rc);
2171 ++(*exp_idx);
2172
2173 /* ( Expr ( ',' Expr )* )? */
2174 arg_count = 0;
2175 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1);
2176 LY_CHECK_RET(rc);
2177 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
2178 ++arg_count;
2179 rc = reparse_or_expr(ctx, exp, exp_idx);
2180 LY_CHECK_RET(rc);
2181 }
2182 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
2183 ++(*exp_idx);
2184
2185 ++arg_count;
2186 rc = reparse_or_expr(ctx, exp, exp_idx);
2187 LY_CHECK_RET(rc);
2188 }
2189
2190 /* ')' */
2191 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2192 LY_CHECK_RET(rc);
2193 ++(*exp_idx);
2194
2195 if ((arg_count < min_arg_count) || (arg_count > max_arg_count)) {
2196 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INARGCOUNT, arg_count, exp->tok_len[func_exp_idx],
2197 &exp->expr[exp->tok_pos[func_exp_idx]]);
2198 return LY_EVALID;
2199 }
2200
2201 return LY_SUCCESS;
2202}
2203
2204/**
2205 * @brief Reparse PathExpr. Logs directly on error.
2206 *
2207 * [10] PathExpr ::= LocationPath | PrimaryExpr Predicate*
2208 * | PrimaryExpr Predicate* '/' RelativeLocationPath
2209 * | PrimaryExpr Predicate* '//' RelativeLocationPath
2210 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2211 * [8] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
2212 *
2213 * @param[in] ctx Context for logging.
2214 * @param[in] exp Parsed XPath expression.
2215 * @param[in] exp_idx Position in the expression @p exp.
2216 * @return LY_ERR
2217 */
2218static LY_ERR
2219reparse_path_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2220{
2221 LY_ERR rc;
2222
2223 if (exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_NONE, 1)) {
2224 return -1;
2225 }
2226
2227 switch (exp->tokens[*exp_idx]) {
2228 case LYXP_TOKEN_PAR1:
2229 /* '(' Expr ')' Predicate* */
2230 ++(*exp_idx);
2231
2232 rc = reparse_or_expr(ctx, exp, exp_idx);
2233 LY_CHECK_RET(rc);
2234
2235 rc = exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_PAR2, 1);
2236 LY_CHECK_RET(rc);
2237 ++(*exp_idx);
2238 goto predicate;
2239 break;
2240 case LYXP_TOKEN_DOT:
2241 case LYXP_TOKEN_DDOT:
2242 case LYXP_TOKEN_AT:
2243 case LYXP_TOKEN_NAMETEST:
2244 case LYXP_TOKEN_NODETYPE:
2245 /* RelativeLocationPath */
2246 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2247 LY_CHECK_RET(rc);
2248 break;
2249 case LYXP_TOKEN_FUNCNAME:
2250 /* FunctionCall */
2251 rc = reparse_function_call(ctx, exp, exp_idx);
2252 LY_CHECK_RET(rc);
2253 goto predicate;
2254 break;
2255 case LYXP_TOKEN_OPERATOR_PATH:
2256 /* AbsoluteLocationPath */
2257 rc = reparse_absolute_location_path(ctx, exp, exp_idx);
2258 LY_CHECK_RET(rc);
2259 break;
2260 case LYXP_TOKEN_LITERAL:
2261 /* Literal */
2262 ++(*exp_idx);
2263 goto predicate;
2264 break;
2265 case LYXP_TOKEN_NUMBER:
2266 /* Number */
2267 ++(*exp_idx);
2268 goto predicate;
2269 break;
2270 default:
2271 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK,
2272 print_token(exp->tokens[*exp_idx]), &exp->expr[exp->tok_pos[*exp_idx]]);
2273 return LY_EVALID;
2274 }
2275
2276 return LY_SUCCESS;
2277
2278predicate:
2279 /* Predicate* */
2280 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
2281 rc = reparse_predicate(ctx, exp, exp_idx);
2282 LY_CHECK_RET(rc);
2283 }
2284
2285 /* ('/' or '//') RelativeLocationPath */
2286 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
2287
2288 /* '/' or '//' */
2289 ++(*exp_idx);
2290
2291 rc = reparse_relative_location_path(ctx, exp, exp_idx);
2292 LY_CHECK_RET(rc);
2293 }
2294
2295 return LY_SUCCESS;
2296}
2297
2298/**
2299 * @brief Reparse UnaryExpr. Logs directly on error.
2300 *
2301 * [17] UnaryExpr ::= UnionExpr | '-' UnaryExpr
2302 * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
2303 *
2304 * @param[in] ctx Context for logging.
2305 * @param[in] exp Parsed XPath expression.
2306 * @param[in] exp_idx Position in the expression @p exp.
2307 * @return LY_ERR
2308 */
2309static LY_ERR
2310reparse_unary_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2311{
2312 uint16_t prev_exp;
2313 LY_ERR rc;
2314
2315 /* ('-')* */
2316 prev_exp = *exp_idx;
2317 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2318 && (exp->expr[exp->tok_pos[*exp_idx]] == '-')) {
2319 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNARY);
2320 ++(*exp_idx);
2321 }
2322
2323 /* PathExpr */
2324 prev_exp = *exp_idx;
2325 rc = reparse_path_expr(ctx, exp, exp_idx);
2326 LY_CHECK_RET(rc);
2327
2328 /* ('|' PathExpr)* */
2329 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_UNI, 0)) {
2330 exp_repeat_push(exp, prev_exp, LYXP_EXPR_UNION);
2331 ++(*exp_idx);
2332
2333 rc = reparse_path_expr(ctx, exp, exp_idx);
2334 LY_CHECK_RET(rc);
2335 }
2336
2337 return LY_SUCCESS;
2338}
2339
2340/**
2341 * @brief Reparse AdditiveExpr. Logs directly on error.
2342 *
2343 * [15] AdditiveExpr ::= MultiplicativeExpr
2344 * | AdditiveExpr '+' MultiplicativeExpr
2345 * | AdditiveExpr '-' MultiplicativeExpr
2346 * [16] MultiplicativeExpr ::= UnaryExpr
2347 * | MultiplicativeExpr '*' UnaryExpr
2348 * | MultiplicativeExpr 'div' UnaryExpr
2349 * | MultiplicativeExpr 'mod' UnaryExpr
2350 *
2351 * @param[in] ctx Context for logging.
2352 * @param[in] exp Parsed XPath expression.
2353 * @param[in] exp_idx Position in the expression @p exp.
2354 * @return LY_ERR
2355 */
2356static LY_ERR
2357reparse_additive_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2358{
2359 uint16_t prev_add_exp, prev_mul_exp;
2360 LY_ERR rc;
2361
2362 prev_add_exp = *exp_idx;
2363 goto reparse_multiplicative_expr;
2364
2365 /* ('+' / '-' MultiplicativeExpr)* */
2366 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2367 && ((exp->expr[exp->tok_pos[*exp_idx]] == '+') || (exp->expr[exp->tok_pos[*exp_idx]] == '-'))) {
2368 exp_repeat_push(exp, prev_add_exp, LYXP_EXPR_ADDITIVE);
2369 ++(*exp_idx);
2370
2371reparse_multiplicative_expr:
2372 /* UnaryExpr */
2373 prev_mul_exp = *exp_idx;
2374 rc = reparse_unary_expr(ctx, exp, exp_idx);
2375 LY_CHECK_RET(rc);
2376
2377 /* ('*' / 'div' / 'mod' UnaryExpr)* */
2378 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0)
2379 && ((exp->expr[exp->tok_pos[*exp_idx]] == '*') || (exp->tok_len[*exp_idx] == 3))) {
2380 exp_repeat_push(exp, prev_mul_exp, LYXP_EXPR_MULTIPLICATIVE);
2381 ++(*exp_idx);
2382
2383 rc = reparse_unary_expr(ctx, exp, exp_idx);
2384 LY_CHECK_RET(rc);
2385 }
2386 }
2387
2388 return LY_SUCCESS;
2389}
2390
2391/**
2392 * @brief Reparse EqualityExpr. Logs directly on error.
2393 *
2394 * [13] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
2395 * | EqualityExpr '!=' RelationalExpr
2396 * [14] RelationalExpr ::= AdditiveExpr
2397 * | RelationalExpr '<' AdditiveExpr
2398 * | RelationalExpr '>' AdditiveExpr
2399 * | RelationalExpr '<=' AdditiveExpr
2400 * | RelationalExpr '>=' AdditiveExpr
2401 *
2402 * @param[in] ctx Context for logging.
2403 * @param[in] exp Parsed XPath expression.
2404 * @param[in] exp_idx Position in the expression @p exp.
2405 * @return LY_ERR
2406 */
2407static LY_ERR
2408reparse_equality_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2409{
2410 uint16_t prev_eq_exp, prev_rel_exp;
2411 LY_ERR rc;
2412
2413 prev_eq_exp = *exp_idx;
2414 goto reparse_additive_expr;
2415
2416 /* ('=' / '!=' RelationalExpr)* */
2417 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2418 && ((exp->expr[exp->tok_pos[*exp_idx]] == '=') || (exp->expr[exp->tok_pos[*exp_idx]] == '!'))) {
2419 exp_repeat_push(exp, prev_eq_exp, LYXP_EXPR_EQUALITY);
2420 ++(*exp_idx);
2421
2422reparse_additive_expr:
2423 /* AdditiveExpr */
2424 prev_rel_exp = *exp_idx;
2425 rc = reparse_additive_expr(ctx, exp, exp_idx);
2426 LY_CHECK_RET(rc);
2427
2428 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
2429 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_COMP, 0)
2430 && ((exp->expr[exp->tok_pos[*exp_idx]] == '<') || (exp->expr[exp->tok_pos[*exp_idx]] == '>'))) {
2431 exp_repeat_push(exp, prev_rel_exp, LYXP_EXPR_RELATIONAL);
2432 ++(*exp_idx);
2433
2434 rc = reparse_additive_expr(ctx, exp, exp_idx);
2435 LY_CHECK_RET(rc);
2436 }
2437 }
2438
2439 return LY_SUCCESS;
2440}
2441
2442/**
2443 * @brief Reparse OrExpr. Logs directly on error.
2444 *
2445 * [11] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
2446 * [12] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
2447 *
2448 * @param[in] ctx Context for logging.
2449 * @param[in] exp Parsed XPath expression.
2450 * @param[in] exp_idx Position in the expression @p exp.
2451 * @return LY_ERR
2452 */
2453static LY_ERR
2454reparse_or_expr(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx)
2455{
2456 uint16_t prev_or_exp, prev_and_exp;
2457 LY_ERR rc;
2458
2459 prev_or_exp = *exp_idx;
2460 goto reparse_equality_expr;
2461
2462 /* ('or' AndExpr)* */
2463 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 2)) {
2464 exp_repeat_push(exp, prev_or_exp, LYXP_EXPR_OR);
2465 ++(*exp_idx);
2466
2467reparse_equality_expr:
2468 /* EqualityExpr */
2469 prev_and_exp = *exp_idx;
2470 rc = reparse_equality_expr(ctx, exp, exp_idx);
2471 LY_CHECK_RET(rc);
2472
2473 /* ('and' EqualityExpr)* */
2474 while (!exp_check_token(ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_LOG, 0) && (exp->tok_len[*exp_idx] == 3)) {
2475 exp_repeat_push(exp, prev_and_exp, LYXP_EXPR_AND);
2476 ++(*exp_idx);
2477
2478 rc = reparse_equality_expr(ctx, exp, exp_idx);
2479 LY_CHECK_RET(rc);
2480 }
2481 }
2482
2483 return LY_SUCCESS;
2484}
Radek Krejcib1646a92018-11-02 16:08:26 +01002485
2486/**
2487 * @brief Parse NCName.
2488 *
2489 * @param[in] ncname Name to parse.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002490 * @return Length of @p ncname valid bytes.
Radek Krejcib1646a92018-11-02 16:08:26 +01002491 */
Radek Krejcid4270262019-01-07 15:07:25 +01002492static long int
Radek Krejcib1646a92018-11-02 16:08:26 +01002493parse_ncname(const char *ncname)
2494{
2495 unsigned int uc;
Radek Krejcid4270262019-01-07 15:07:25 +01002496 size_t size;
2497 long int len = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002498
2499 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), 0);
2500 if (!is_xmlqnamestartchar(uc) || (uc == ':')) {
2501 return len;
2502 }
2503
2504 do {
2505 len += size;
Radek Krejci9a564c92019-01-07 14:53:57 +01002506 if (!*ncname) {
2507 break;
2508 }
Radek Krejcid4270262019-01-07 15:07:25 +01002509 LY_CHECK_RET(ly_getutf8(&ncname, &uc, &size), -len);
Radek Krejcib1646a92018-11-02 16:08:26 +01002510 } while (is_xmlqnamechar(uc) && (uc != ':'));
2511
2512 return len;
2513}
2514
2515/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02002516 * @brief Add @p token into the expression @p exp.
Radek Krejcib1646a92018-11-02 16:08:26 +01002517 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002518 * @param[in] ctx Context for logging.
Radek Krejcib1646a92018-11-02 16:08:26 +01002519 * @param[in] exp Expression to use.
2520 * @param[in] token Token to add.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002521 * @param[in] tok_pos Token position in the XPath expression.
Radek Krejcib1646a92018-11-02 16:08:26 +01002522 * @param[in] tok_len Token length in the XPath expression.
Michal Vasko03ff5a72019-09-11 13:49:33 +02002523 * @return LY_ERR
Radek Krejcib1646a92018-11-02 16:08:26 +01002524 */
2525static LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02002526exp_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 +01002527{
2528 uint32_t prev;
2529
2530 if (exp->used == exp->size) {
2531 prev = exp->size;
2532 exp->size += LYXP_EXPR_SIZE_STEP;
2533 if (prev > exp->size) {
2534 LOGINT(ctx);
2535 return LY_EINT;
2536 }
2537
2538 exp->tokens = ly_realloc(exp->tokens, exp->size * sizeof *exp->tokens);
2539 LY_CHECK_ERR_RET(!exp->tokens, LOGMEM(ctx), LY_EMEM);
2540 exp->tok_pos = ly_realloc(exp->tok_pos, exp->size * sizeof *exp->tok_pos);
2541 LY_CHECK_ERR_RET(!exp->tok_pos, LOGMEM(ctx), LY_EMEM);
2542 exp->tok_len = ly_realloc(exp->tok_len, exp->size * sizeof *exp->tok_len);
2543 LY_CHECK_ERR_RET(!exp->tok_len, LOGMEM(ctx), LY_EMEM);
2544 }
2545
2546 exp->tokens[exp->used] = token;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002547 exp->tok_pos[exp->used] = tok_pos;
Radek Krejcib1646a92018-11-02 16:08:26 +01002548 exp->tok_len[exp->used] = tok_len;
2549 ++exp->used;
2550 return LY_SUCCESS;
2551}
2552
2553void
2554lyxp_expr_free(struct ly_ctx *ctx, struct lyxp_expr *expr)
2555{
2556 uint16_t i;
2557
2558 if (!expr) {
2559 return;
2560 }
2561
2562 lydict_remove(ctx, expr->expr);
2563 free(expr->tokens);
2564 free(expr->tok_pos);
2565 free(expr->tok_len);
2566 if (expr->repeat) {
2567 for (i = 0; i < expr->used; ++i) {
2568 free(expr->repeat[i]);
2569 }
2570 }
2571 free(expr->repeat);
2572 free(expr);
2573}
2574
2575struct lyxp_expr *
2576lyxp_expr_parse(struct ly_ctx *ctx, const char *expr)
2577{
2578 struct lyxp_expr *ret;
Radek Krejcid4270262019-01-07 15:07:25 +01002579 size_t parsed = 0, tok_len;
2580 long int ncname_len;
Radek Krejcib1646a92018-11-02 16:08:26 +01002581 enum lyxp_token tok_type;
2582 int prev_function_check = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002583 uint16_t exp_idx = 0;
Radek Krejcib1646a92018-11-02 16:08:26 +01002584
2585 if (strlen(expr) > UINT16_MAX) {
2586 LOGERR(ctx, LY_EINVAL, "XPath expression cannot be longer than %ud characters.", UINT16_MAX);
2587 return NULL;
2588 }
2589
2590 /* init lyxp_expr structure */
2591 ret = calloc(1, sizeof *ret);
2592 LY_CHECK_ERR_GOTO(!ret, LOGMEM(ctx), error);
2593 ret->expr = lydict_insert(ctx, expr, strlen(expr));
2594 LY_CHECK_ERR_GOTO(!ret->expr, LOGMEM(ctx), error);
2595 ret->used = 0;
2596 ret->size = LYXP_EXPR_SIZE_START;
2597 ret->tokens = malloc(ret->size * sizeof *ret->tokens);
2598 LY_CHECK_ERR_GOTO(!ret->tokens, LOGMEM(ctx), error);
2599
2600 ret->tok_pos = malloc(ret->size * sizeof *ret->tok_pos);
2601 LY_CHECK_ERR_GOTO(!ret->tok_pos, LOGMEM(ctx), error);
2602
2603 ret->tok_len = malloc(ret->size * sizeof *ret->tok_len);
2604 LY_CHECK_ERR_GOTO(!ret->tok_len, LOGMEM(ctx), error);
2605
2606 while (is_xmlws(expr[parsed])) {
2607 ++parsed;
2608 }
2609
2610 do {
2611 if (expr[parsed] == '(') {
2612
2613 /* '(' */
2614 tok_len = 1;
2615 tok_type = LYXP_TOKEN_PAR1;
2616
2617 if (prev_function_check && ret->used && (ret->tokens[ret->used - 1] == LYXP_TOKEN_NAMETEST)) {
2618 /* it is a NodeType/FunctionName after all */
2619 if (((ret->tok_len[ret->used - 1] == 4)
2620 && (!strncmp(&expr[ret->tok_pos[ret->used - 1]], "node", 4)
2621 || !strncmp(&expr[ret->tok_pos[ret->used - 1]], "text", 4))) ||
2622 ((ret->tok_len[ret->used - 1] == 7)
2623 && !strncmp(&expr[ret->tok_pos[ret->used - 1]], "comment", 7))) {
2624 ret->tokens[ret->used - 1] = LYXP_TOKEN_NODETYPE;
2625 } else {
2626 ret->tokens[ret->used - 1] = LYXP_TOKEN_FUNCNAME;
2627 }
2628 prev_function_check = 0;
2629 }
2630
2631 } else if (expr[parsed] == ')') {
2632
2633 /* ')' */
2634 tok_len = 1;
2635 tok_type = LYXP_TOKEN_PAR2;
2636
2637 } else if (expr[parsed] == '[') {
2638
2639 /* '[' */
2640 tok_len = 1;
2641 tok_type = LYXP_TOKEN_BRACK1;
2642
2643 } else if (expr[parsed] == ']') {
2644
2645 /* ']' */
2646 tok_len = 1;
2647 tok_type = LYXP_TOKEN_BRACK2;
2648
2649 } else if (!strncmp(&expr[parsed], "..", 2)) {
2650
2651 /* '..' */
2652 tok_len = 2;
2653 tok_type = LYXP_TOKEN_DDOT;
2654
2655 } else if ((expr[parsed] == '.') && (!isdigit(expr[parsed + 1]))) {
2656
2657 /* '.' */
2658 tok_len = 1;
2659 tok_type = LYXP_TOKEN_DOT;
2660
2661 } else if (expr[parsed] == '@') {
2662
2663 /* '@' */
2664 tok_len = 1;
2665 tok_type = LYXP_TOKEN_AT;
2666
2667 } else if (expr[parsed] == ',') {
2668
2669 /* ',' */
2670 tok_len = 1;
2671 tok_type = LYXP_TOKEN_COMMA;
2672
2673 } else if (expr[parsed] == '\'') {
2674
2675 /* Literal with ' */
2676 for (tok_len = 1; (expr[parsed + tok_len] != '\0') && (expr[parsed + tok_len] != '\''); ++tok_len);
2677 LY_CHECK_ERR_GOTO(expr[parsed + tok_len] == '\0',
2678 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_EOE, expr[parsed], &expr[parsed]), error);
2679 ++tok_len;
2680 tok_type = LYXP_TOKEN_LITERAL;
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] == '.') || (isdigit(expr[parsed]))) {
2692
2693 /* Number */
2694 for (tok_len = 0; isdigit(expr[parsed + tok_len]); ++tok_len);
2695 if (expr[parsed + tok_len] == '.') {
2696 ++tok_len;
2697 for (; isdigit(expr[parsed + tok_len]); ++tok_len);
2698 }
2699 tok_type = LYXP_TOKEN_NUMBER;
2700
2701 } else if (expr[parsed] == '/') {
2702
2703 /* Operator '/', '//' */
2704 if (!strncmp(&expr[parsed], "//", 2)) {
2705 tok_len = 2;
2706 } else {
2707 tok_len = 1;
2708 }
2709 tok_type = LYXP_TOKEN_OPERATOR_PATH;
2710
2711 } else if (!strncmp(&expr[parsed], "!=", 2) || !strncmp(&expr[parsed], "<=", 2)
2712 || !strncmp(&expr[parsed], ">=", 2)) {
2713
2714 /* Operator '!=', '<=', '>=' */
2715 tok_len = 2;
2716 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2717
2718 } else if (expr[parsed] == '|') {
2719
2720 /* Operator '|' */
2721 tok_len = 1;
2722 tok_type = LYXP_TOKEN_OPERATOR_UNI;
2723
2724 } else if ((expr[parsed] == '+') || (expr[parsed] == '-')) {
2725
2726 /* Operator '+', '-' */
2727 tok_len = 1;
2728 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2729
2730 } else if ((expr[parsed] == '=') || (expr[parsed] == '<') || (expr[parsed] == '>')) {
2731
2732 /* Operator '=', '<', '>' */
2733 tok_len = 1;
2734 tok_type = LYXP_TOKEN_OPERATOR_COMP;
2735
2736 } else if (ret->used && (ret->tokens[ret->used - 1] != LYXP_TOKEN_AT)
2737 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_PAR1)
2738 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_BRACK1)
2739 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_COMMA)
2740 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_LOG)
2741 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_COMP)
2742 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_MATH)
2743 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_UNI)
2744 && (ret->tokens[ret->used - 1] != LYXP_TOKEN_OPERATOR_PATH)) {
2745
2746 /* Operator '*', 'or', 'and', 'mod', or 'div' */
2747 if (expr[parsed] == '*') {
2748 tok_len = 1;
2749 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2750
2751 } else if (!strncmp(&expr[parsed], "or", 2)) {
2752 tok_len = 2;
2753 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2754
2755 } else if (!strncmp(&expr[parsed], "and", 3)) {
2756 tok_len = 3;
2757 tok_type = LYXP_TOKEN_OPERATOR_LOG;
2758
2759 } else if (!strncmp(&expr[parsed], "mod", 3) || !strncmp(&expr[parsed], "div", 3)) {
2760 tok_len = 3;
2761 tok_type = LYXP_TOKEN_OPERATOR_MATH;
2762
2763 } else if (prev_function_check) {
Michal Vasko53078572019-05-24 08:50:15 +02002764 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Invalid character 0x%x ('%c'), perhaps \"%.*s\" is supposed to be a function call.",
2765 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 +01002766 goto error;
2767 } else {
Radek Krejcid4270262019-01-07 15:07:25 +01002768 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INEXPR, parsed + 1, expr);
Radek Krejcib1646a92018-11-02 16:08:26 +01002769 goto error;
2770 }
2771 } else if (expr[parsed] == '*') {
2772
2773 /* NameTest '*' */
2774 tok_len = 1;
2775 tok_type = LYXP_TOKEN_NAMETEST;
2776
2777 } else {
2778
2779 /* NameTest (NCName ':' '*' | QName) or NodeType/FunctionName */
2780 ncname_len = parse_ncname(&expr[parsed]);
Radek Krejcid4270262019-01-07 15:07:25 +01002781 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 +01002782 tok_len = ncname_len;
2783
2784 if (expr[parsed + tok_len] == ':') {
2785 ++tok_len;
2786 if (expr[parsed + tok_len] == '*') {
2787 ++tok_len;
2788 } else {
2789 ncname_len = parse_ncname(&expr[parsed + tok_len]);
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 /* remove old flag to prevent ambiguities */
2794 prev_function_check = 0;
2795 tok_type = LYXP_TOKEN_NAMETEST;
2796 } else {
2797 /* there is no prefix so it can still be NodeType/FunctionName, we can't finally decide now */
2798 prev_function_check = 1;
2799 tok_type = LYXP_TOKEN_NAMETEST;
2800 }
2801 }
2802
2803 /* store the token, move on to the next one */
2804 LY_CHECK_GOTO(exp_add_token(ctx, ret, tok_type, parsed, tok_len), error);
2805 parsed += tok_len;
2806 while (is_xmlws(expr[parsed])) {
2807 ++parsed;
2808 }
2809
2810 } while (expr[parsed]);
2811
2812 /* prealloc repeat */
2813 ret->repeat = calloc(ret->size, sizeof *ret->repeat);
2814 LY_CHECK_ERR_GOTO(!ret->repeat, LOGMEM(ctx), error);
2815
Michal Vasko03ff5a72019-09-11 13:49:33 +02002816 /* fill repeat */
2817 LY_CHECK_GOTO(reparse_or_expr(ctx, ret, &exp_idx), error);
2818 if (ret->used > exp_idx) {
2819 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_XP_INTOK, "Unknown", &ret->expr[ret->tok_pos[exp_idx]]);
2820 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of an XPath expression.",
2821 &ret->expr[ret->tok_pos[exp_idx]]);
2822 goto error;
2823 }
2824
2825 print_expr_struct_debug(ret);
2826
Radek Krejcib1646a92018-11-02 16:08:26 +01002827 return ret;
2828
2829error:
2830 lyxp_expr_free(ctx, ret);
2831 return NULL;
2832}
2833
Michal Vasko03ff5a72019-09-11 13:49:33 +02002834/*
2835 * warn functions
2836 *
2837 * Warn functions check specific reasonable conditions for schema XPath
2838 * and print a warning if they are not satisfied.
2839 */
2840
2841/**
2842 * @brief Get the last-added schema node that is currently in the context.
2843 *
2844 * @param[in] set Set to search in.
2845 * @return Last-added schema context node, NULL if no node is in context.
2846 */
2847static struct lysc_node *
2848warn_get_scnode_in_ctx(struct lyxp_set *set)
2849{
2850 uint32_t i;
2851
2852 if (!set || (set->type != LYXP_SET_SCNODE_SET)) {
2853 return NULL;
2854 }
2855
2856 i = set->used;
2857 do {
2858 --i;
2859 if (set->val.scnodes[i].in_ctx == 1) {
2860 /* if there are more, simply return the first found (last added) */
2861 return set->val.scnodes[i].scnode;
2862 }
2863 } while (i);
2864
2865 return NULL;
2866}
2867
2868/**
2869 * @brief Test whether a type is numeric - integer type or decimal64.
2870 *
2871 * @param[in] type Type to test.
2872 * @return 1 if numeric, 0 otherwise.
2873 */
2874static int
2875warn_is_numeric_type(struct lysc_type *type)
2876{
2877 struct lysc_type_union *uni;
2878 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002879 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002880
2881 switch (type->basetype) {
2882 case LY_TYPE_DEC64:
2883 case LY_TYPE_INT8:
2884 case LY_TYPE_UINT8:
2885 case LY_TYPE_INT16:
2886 case LY_TYPE_UINT16:
2887 case LY_TYPE_INT32:
2888 case LY_TYPE_UINT32:
2889 case LY_TYPE_INT64:
2890 case LY_TYPE_UINT64:
2891 return 1;
2892 case LY_TYPE_UNION:
2893 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002894 LY_ARRAY_FOR(uni->types, u) {
2895 ret = warn_is_numeric_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002896 if (ret) {
2897 /* found a suitable type */
2898 return 1;
2899 }
2900 }
2901 /* did not find any suitable type */
2902 return 0;
2903 case LY_TYPE_LEAFREF:
2904 return warn_is_numeric_type(((struct lysc_type_leafref *)type)->realtype);
2905 default:
2906 return 0;
2907 }
2908}
2909
2910/**
2911 * @brief Test whether a type is string-like - no integers, decimal64 or binary.
2912 *
2913 * @param[in] type Type to test.
2914 * @return 1 if string, 0 otherwise.
2915 */
2916static int
2917warn_is_string_type(struct lysc_type *type)
2918{
2919 struct lysc_type_union *uni;
2920 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002921 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002922
2923 switch (type->basetype) {
2924 case LY_TYPE_BITS:
2925 case LY_TYPE_ENUM:
2926 case LY_TYPE_IDENT:
2927 case LY_TYPE_INST:
2928 case LY_TYPE_STRING:
2929 return 1;
2930 case LY_TYPE_UNION:
2931 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002932 LY_ARRAY_FOR(uni->types, u) {
2933 ret = warn_is_string_type(uni->types[u]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002934 if (ret) {
2935 /* found a suitable type */
2936 return 1;
2937 }
2938 }
2939 /* did not find any suitable type */
2940 return 0;
2941 case LY_TYPE_LEAFREF:
2942 return warn_is_string_type(((struct lysc_type_leafref *)type)->realtype);
2943 default:
2944 return 0;
2945 }
2946}
2947
2948/**
2949 * @brief Test whether a type is one specific type.
2950 *
2951 * @param[in] type Type to test.
2952 * @param[in] base Expected type.
2953 * @return 1 if it is, 0 otherwise.
2954 */
2955static int
2956warn_is_specific_type(struct lysc_type *type, LY_DATA_TYPE base)
2957{
2958 struct lysc_type_union *uni;
2959 int ret;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002960 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002961
2962 if (type->basetype == base) {
2963 return 1;
2964 } else if (type->basetype == LY_TYPE_UNION) {
2965 uni = (struct lysc_type_union *)type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002966 LY_ARRAY_FOR(uni->types, u) {
2967 ret = warn_is_specific_type(uni->types[u], base);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002968 if (ret) {
2969 /* found a suitable type */
2970 return 1;
2971 }
2972 }
2973 /* did not find any suitable type */
2974 return 0;
2975 } else if (type->basetype == LY_TYPE_LEAFREF) {
2976 return warn_is_specific_type(((struct lysc_type_leafref *)type)->realtype, base);
2977 }
2978
2979 return 0;
2980}
2981
2982/**
2983 * @brief Get next type of a (union) type.
2984 *
2985 * @param[in] type Base type.
2986 * @param[in] prev_type Previously returned type.
2987 * @return Next type or NULL.
2988 */
2989static struct lysc_type *
2990warn_is_equal_type_next_type(struct lysc_type *type, struct lysc_type *prev_type)
2991{
2992 struct lysc_type_union *uni;
2993 int found = 0;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02002994 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02002995
2996 switch (type->basetype) {
2997 case LY_TYPE_UNION:
2998 uni = (struct lysc_type_union *)type;
2999 if (!prev_type) {
3000 return uni->types[0];
3001 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003002 LY_ARRAY_FOR(uni->types, u) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003003 if (found) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003004 return uni->types[u];
Michal Vasko03ff5a72019-09-11 13:49:33 +02003005 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003006 if (prev_type == uni->types[u]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003007 found = 1;
3008 }
3009 }
3010 return NULL;
3011 default:
3012 if (prev_type) {
3013 assert(type == prev_type);
3014 return NULL;
3015 } else {
3016 return type;
3017 }
3018 }
3019}
3020
3021/**
3022 * @brief Test whether 2 types have a common type.
3023 *
3024 * @param[in] type1 First type.
3025 * @param[in] type2 Second type.
3026 * @return 1 if they do, 0 otherwise.
3027 */
3028static int
3029warn_is_equal_type(struct lysc_type *type1, struct lysc_type *type2)
3030{
3031 struct lysc_type *t1, *rt1, *t2, *rt2;
3032
3033 t1 = NULL;
3034 while ((t1 = warn_is_equal_type_next_type(type1, t1))) {
3035 if (t1->basetype == LY_TYPE_LEAFREF) {
3036 rt1 = ((struct lysc_type_leafref *)t1)->realtype;
3037 } else {
3038 rt1 = t1;
3039 }
3040
3041 t2 = NULL;
3042 while ((t2 = warn_is_equal_type_next_type(type2, t2))) {
3043 if (t2->basetype == LY_TYPE_LEAFREF) {
3044 rt2 = ((struct lysc_type_leafref *)t2)->realtype;
3045 } else {
3046 rt2 = t2;
3047 }
3048
3049 if (rt2->basetype == rt1->basetype) {
3050 /* match found */
3051 return 1;
3052 }
3053 }
3054 }
3055
3056 return 0;
3057}
3058
3059/**
3060 * @brief Check both operands of comparison operators.
3061 *
3062 * @param[in] ctx Context for errors.
3063 * @param[in] set1 First operand set.
3064 * @param[in] set2 Second operand set.
3065 * @param[in] numbers_only Whether accept only numbers or other types are fine too (for '=' and '!=').
3066 * @param[in] expr Start of the expression to print with the warning.
3067 * @param[in] tok_pos Token position.
3068 */
3069static void
3070warn_operands(struct ly_ctx *ctx, struct lyxp_set *set1, struct lyxp_set *set2, int numbers_only, const char *expr, uint16_t tok_pos)
3071{
3072 struct lysc_node_leaf *node1, *node2;
3073 int leaves = 1, warning = 0;
3074
3075 node1 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set1);
3076 node2 = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set2);
3077
3078 if (!node1 && !node2) {
3079 /* no node-sets involved, nothing to do */
3080 return;
3081 }
3082
3083 if (node1) {
3084 if (!(node1->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3085 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node1->nodetype), node1->name);
3086 warning = 1;
3087 leaves = 0;
3088 } else if (numbers_only && !warn_is_numeric_type(node1->type)) {
3089 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node1->name);
3090 warning = 1;
3091 }
3092 }
3093
3094 if (node2) {
3095 if (!(node2->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3096 LOGWRN(ctx, "Node type %s \"%s\" used as operand.", lys_nodetype2str(node2->nodetype), node2->name);
3097 warning = 1;
3098 leaves = 0;
3099 } else if (numbers_only && !warn_is_numeric_type(node2->type)) {
3100 LOGWRN(ctx, "Node \"%s\" is not of a numeric type, but used where it was expected.", node2->name);
3101 warning = 1;
3102 }
3103 }
3104
3105 if (node1 && node2 && leaves && !numbers_only) {
3106 if ((warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type))
3107 || (!warn_is_numeric_type(node1->type) && warn_is_numeric_type(node2->type))
3108 || (!warn_is_numeric_type(node1->type) && !warn_is_numeric_type(node2->type)
3109 && !warn_is_equal_type(node1->type, node2->type))) {
3110 LOGWRN(ctx, "Incompatible types of operands \"%s\" and \"%s\" for comparison.", node1->name, node2->name);
3111 warning = 1;
3112 }
3113 }
3114
3115 if (warning) {
3116 LOGWRN(ctx, "Previous warning generated by XPath subexpression[%u] \"%.20s\".", tok_pos, expr + tok_pos);
3117 }
3118}
3119
3120/**
3121 * @brief Check that a value is valid for a leaf. If not applicable, does nothing.
3122 *
3123 * @param[in] exp Parsed XPath expression.
3124 * @param[in] set Set with the leaf/leaf-list.
3125 * @param[in] val_exp Index of the value (literal/number) in @p exp.
3126 * @param[in] equal_exp Index of the start of the equality expression in @p exp.
3127 * @param[in] last_equal_exp Index of the end of the equality expression in @p exp.
3128 */
3129static void
3130warn_equality_value(struct lyxp_expr *exp, struct lyxp_set *set, uint16_t val_exp, uint16_t equal_exp, uint16_t last_equal_exp)
3131{
3132 struct lysc_node *scnode;
3133 struct lysc_type *type;
3134 char *value;
3135 LY_ERR rc;
3136 struct ly_err_item *err = NULL;
3137
3138 if ((scnode = warn_get_scnode_in_ctx(set)) && (scnode->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3139 && ((exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) || (exp->tokens[val_exp] == LYXP_TOKEN_NUMBER))) {
3140 /* check that the node can have the specified value */
3141 if (exp->tokens[val_exp] == LYXP_TOKEN_LITERAL) {
3142 value = strndup(exp->expr + exp->tok_pos[val_exp] + 1, exp->tok_len[val_exp] - 2);
3143 } else {
3144 value = strndup(exp->expr + exp->tok_pos[val_exp], exp->tok_len[val_exp]);
3145 }
3146 if (!value) {
3147 LOGMEM(set->ctx);
3148 return;
3149 }
3150
3151 if ((((struct lysc_node_leaf *)scnode)->type->basetype == LY_TYPE_IDENT) && !strchr(value, ':')) {
3152 LOGWRN(set->ctx, "Identityref \"%s\" comparison with identity \"%s\" without prefix, consider adding"
3153 " a prefix or best using \"derived-from(-or-self)()\" functions.", scnode->name, value);
3154 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3155 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3156 exp->expr + exp->tok_pos[equal_exp]);
3157 }
3158
3159 type = ((struct lysc_node_leaf *)scnode)->type;
3160 if (type->basetype != LY_TYPE_IDENT) {
3161 rc = type->plugin->store(set->ctx, type, value, strlen(value), LY_TYPE_OPTS_SCHEMA,
3162 lys_resolve_prefix, (void *)type->dflt_mod, LYD_XML, NULL, NULL, NULL, NULL, &err);
3163
3164 if (err) {
3165 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type (%s).", value, err->msg);
3166 ly_err_free(err);
3167 } else if (rc != LY_SUCCESS) {
3168 LOGWRN(set->ctx, "Invalid value \"%s\" which does not fit the type.", value);
3169 }
3170 if (rc != LY_SUCCESS) {
3171 LOGWRN(set->ctx, "Previous warning generated by XPath subexpression[%u] \"%.*s\".", exp->tok_pos[equal_exp],
3172 (exp->tok_pos[last_equal_exp] - exp->tok_pos[equal_exp]) + exp->tok_len[last_equal_exp],
3173 exp->expr + exp->tok_pos[equal_exp]);
3174 }
3175 }
3176 free(value);
3177 }
3178}
3179
3180/*
3181 * XPath functions
3182 */
3183
3184/**
3185 * @brief Execute the YANG 1.1 bit-is-set(node-set, string) function. Returns LYXP_SET_BOOLEAN
3186 * depending on whether the first node bit value from the second argument is set.
3187 *
3188 * @param[in] args Array of arguments.
3189 * @param[in] arg_count Count of elements in @p args.
3190 * @param[in,out] set Context and result set at the same time.
3191 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003192 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003193 */
3194static LY_ERR
3195xpath_bit_is_set(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3196{
3197 struct lyd_node_term *leaf;
3198 struct lysc_node_leaf *sleaf;
3199 struct lysc_type_bits *bits;
3200 LY_ERR rc = LY_SUCCESS;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003201 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003202
3203 if (options & LYXP_SCNODE_ALL) {
3204 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3205 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003206 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3207 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 +02003208 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_BITS)) {
3209 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"bits\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003210 }
3211
3212 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3213 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3214 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 +02003215 } else if (!warn_is_string_type(sleaf->type)) {
3216 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003217 }
3218 }
3219 set_scnode_clear_ctx(set);
3220 return rc;
3221 }
3222
Michal Vaskod3678892020-05-21 10:06:58 +02003223 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003224 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)");
3225 return LY_EVALID;
3226 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003227 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003228 LY_CHECK_RET(rc);
3229
3230 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003231 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003232 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3233 if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))
3234 && (((struct lysc_node_leaf *)leaf->schema)->type->basetype == LY_TYPE_BITS)) {
3235 bits = (struct lysc_type_bits *)((struct lysc_node_leaf *)leaf->schema)->type;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003236 LY_ARRAY_FOR(bits->bits, u) {
3237 if (!strcmp(bits->bits[u].name, args[1]->val.str)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003238 set_fill_boolean(set, 1);
3239 break;
3240 }
3241 }
3242 }
3243 }
3244
3245 return LY_SUCCESS;
3246}
3247
3248/**
3249 * @brief Execute the XPath boolean(object) function. Returns LYXP_SET_BOOLEAN
3250 * with the argument converted to boolean.
3251 *
3252 * @param[in] args Array of arguments.
3253 * @param[in] arg_count Count of elements in @p args.
3254 * @param[in,out] set Context and result set at the same time.
3255 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003256 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003257 */
3258static LY_ERR
3259xpath_boolean(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3260{
3261 LY_ERR rc;
3262
3263 if (options & LYXP_SCNODE_ALL) {
3264 set_scnode_clear_ctx(set);
3265 return LY_SUCCESS;
3266 }
3267
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003268 rc = lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003269 LY_CHECK_RET(rc);
3270 set_fill_set(set, args[0]);
3271
3272 return LY_SUCCESS;
3273}
3274
3275/**
3276 * @brief Execute the XPath ceiling(number) function. Returns LYXP_SET_NUMBER
3277 * with the first argument rounded up to the nearest integer.
3278 *
3279 * @param[in] args Array of arguments.
3280 * @param[in] arg_count Count of elements in @p args.
3281 * @param[in,out] set Context and result set at the same time.
3282 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003283 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003284 */
3285static LY_ERR
3286xpath_ceiling(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3287{
3288 struct lysc_node_leaf *sleaf;
3289 LY_ERR rc = LY_SUCCESS;
3290
3291 if (options & LYXP_SCNODE_ALL) {
3292 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3293 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003294 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3295 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 +02003296 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
3297 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003298 }
3299 set_scnode_clear_ctx(set);
3300 return rc;
3301 }
3302
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003303 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003304 LY_CHECK_RET(rc);
3305 if ((long long)args[0]->val.num != args[0]->val.num) {
3306 set_fill_number(set, ((long long)args[0]->val.num) + 1);
3307 } else {
3308 set_fill_number(set, args[0]->val.num);
3309 }
3310
3311 return LY_SUCCESS;
3312}
3313
3314/**
3315 * @brief Execute the XPath concat(string, string, string*) function.
3316 * Returns LYXP_SET_STRING with the concatenation of all the arguments.
3317 *
3318 * @param[in] args Array of arguments.
3319 * @param[in] arg_count Count of elements in @p args.
3320 * @param[in,out] set Context and result set at the same time.
3321 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003322 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003323 */
3324static LY_ERR
3325xpath_concat(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3326{
3327 uint16_t i;
3328 char *str = NULL;
3329 size_t used = 1;
3330 LY_ERR rc = LY_SUCCESS;
3331 struct lysc_node_leaf *sleaf;
3332
3333 if (options & LYXP_SCNODE_ALL) {
3334 for (i = 0; i < arg_count; ++i) {
3335 if ((args[i]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[i]))) {
3336 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3337 LOGWRN(set->ctx, "Argument #%u of %s is a %s node \"%s\".",
3338 i + 1, __func__, lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003339 } else if (!warn_is_string_type(sleaf->type)) {
3340 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 +02003341 }
3342 }
3343 }
3344 set_scnode_clear_ctx(set);
3345 return rc;
3346 }
3347
3348 for (i = 0; i < arg_count; ++i) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003349 rc = lyxp_set_cast(args[i], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003350 if (rc != LY_SUCCESS) {
3351 free(str);
3352 return rc;
3353 }
3354
3355 str = ly_realloc(str, (used + strlen(args[i]->val.str)) * sizeof(char));
3356 LY_CHECK_ERR_RET(!str, LOGMEM(set->ctx), LY_EMEM);
3357 strcpy(str + used - 1, args[i]->val.str);
3358 used += strlen(args[i]->val.str);
3359 }
3360
3361 /* free, kind of */
Michal Vaskod3678892020-05-21 10:06:58 +02003362 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003363 set->type = LYXP_SET_STRING;
3364 set->val.str = str;
3365
3366 return LY_SUCCESS;
3367}
3368
3369/**
3370 * @brief Execute the XPath contains(string, string) function.
3371 * Returns LYXP_SET_BOOLEAN whether the second argument can
3372 * be found in the first or not.
3373 *
3374 * @param[in] args Array of arguments.
3375 * @param[in] arg_count Count of elements in @p args.
3376 * @param[in,out] set Context and result set at the same time.
3377 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003378 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003379 */
3380static LY_ERR
3381xpath_contains(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3382{
3383 struct lysc_node_leaf *sleaf;
3384 LY_ERR rc = LY_SUCCESS;
3385
3386 if (options & LYXP_SCNODE_ALL) {
3387 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3388 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3389 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 +02003390 } else if (!warn_is_string_type(sleaf->type)) {
3391 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003392 }
3393 }
3394
3395 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3396 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3397 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 +02003398 } else if (!warn_is_string_type(sleaf->type)) {
3399 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003400 }
3401 }
3402 set_scnode_clear_ctx(set);
3403 return rc;
3404 }
3405
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003406 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003407 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003408 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003409 LY_CHECK_RET(rc);
3410
3411 if (strstr(args[0]->val.str, args[1]->val.str)) {
3412 set_fill_boolean(set, 1);
3413 } else {
3414 set_fill_boolean(set, 0);
3415 }
3416
3417 return LY_SUCCESS;
3418}
3419
3420/**
3421 * @brief Execute the XPath count(node-set) function. Returns LYXP_SET_NUMBER
3422 * with the size of the node-set from the argument.
3423 *
3424 * @param[in] args Array of arguments.
3425 * @param[in] arg_count Count of elements in @p args.
3426 * @param[in,out] set Context and result set at the same time.
3427 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003428 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003429 */
3430static LY_ERR
3431xpath_count(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3432{
3433 struct lysc_node *scnode = NULL;
3434 LY_ERR rc = LY_SUCCESS;
3435
3436 if (options & LYXP_SCNODE_ALL) {
3437 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(scnode = warn_get_scnode_in_ctx(args[0]))) {
3438 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003439 }
3440 set_scnode_clear_ctx(set);
3441 return rc;
3442 }
3443
Michal Vasko03ff5a72019-09-11 13:49:33 +02003444 if (args[0]->type != LYXP_SET_NODE_SET) {
3445 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "count(node-set)");
3446 return LY_EVALID;
3447 }
3448
3449 set_fill_number(set, args[0]->used);
3450 return LY_SUCCESS;
3451}
3452
3453/**
3454 * @brief Execute the XPath current() function. Returns LYXP_SET_NODE_SET
3455 * with the context with the intial node.
3456 *
3457 * @param[in] args Array of arguments.
3458 * @param[in] arg_count Count of elements in @p args.
3459 * @param[in,out] set Context and result set at the same time.
3460 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003461 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003462 */
3463static LY_ERR
3464xpath_current(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3465{
3466 if (arg_count || args) {
3467 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGCOUNT, arg_count, "current()");
3468 return LY_EVALID;
3469 }
3470
3471 if (options & LYXP_SCNODE_ALL) {
3472 set_scnode_clear_ctx(set);
3473
Michal Vaskoecd62de2019-11-13 12:35:11 +01003474 lyxp_set_scnode_insert_node(set, set->ctx_scnode, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003475 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02003476 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003477
3478 /* position is filled later */
3479 set_insert_node(set, set->ctx_node, 0, LYXP_NODE_ELEM, 0);
3480 }
3481
3482 return LY_SUCCESS;
3483}
3484
3485/**
3486 * @brief Execute the YANG 1.1 deref(node-set) function. Returns LYXP_SET_NODE_SET with either
3487 * leafref or instance-identifier target node(s).
3488 *
3489 * @param[in] args Array of arguments.
3490 * @param[in] arg_count Count of elements in @p args.
3491 * @param[in,out] set Context and result set at the same time.
3492 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003493 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003494 */
3495static LY_ERR
3496xpath_deref(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3497{
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003498 struct lysc_ctx cctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003499 struct lyd_node_term *leaf;
Michal Vasko42e497c2020-01-06 08:38:25 +01003500 struct lysc_node_leaf *sleaf = NULL;
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003501 const struct lysc_node *target;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003502 const struct lyd_node *node;
3503 char *errmsg = NULL;
3504 const char *val;
3505 int dynamic;
3506 LY_ERR rc = LY_SUCCESS;
3507
3508 if (options & LYXP_SCNODE_ALL) {
3509 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3510 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003511 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3512 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 +02003513 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_LEAFREF) && !warn_is_specific_type(sleaf->type, LY_TYPE_INST)) {
3514 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"leafref\" nor \"instance-identifier\".",
3515 __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003516 }
3517 set_scnode_clear_ctx(set);
Michal Vasko42e497c2020-01-06 08:38:25 +01003518 if (sleaf && (sleaf->type->basetype == LY_TYPE_LEAFREF)) {
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003519 cctx.ctx = set->ctx;
3520 rc = lys_compile_leafref_validate(&cctx, (struct lysc_node *)sleaf, (struct lysc_type_leafref *)sleaf->type, &target);
3521 /* it was already validated, it must succeed */
3522 if (rc == LY_SUCCESS) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01003523 lyxp_set_scnode_insert_node(set, target, LYXP_NODE_ELEM);
Michal Vaskoae9e4cb2019-09-25 08:43:05 +02003524 }
3525 }
3526
Michal Vasko03ff5a72019-09-11 13:49:33 +02003527 return rc;
3528 }
3529
Michal Vaskod3678892020-05-21 10:06:58 +02003530 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003531 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "deref(node-set)");
3532 return LY_EVALID;
3533 }
3534
Michal Vaskod3678892020-05-21 10:06:58 +02003535 lyxp_set_free_content(set);
3536 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003537 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3538 sleaf = (struct lysc_node_leaf *)leaf->schema;
3539 if (sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
3540 if (sleaf->type->basetype == LY_TYPE_LEAFREF) {
3541 /* find leafref target */
3542 val = lyd_value2str(leaf, &dynamic);
3543 node = ly_type_find_leafref(set->ctx, sleaf->type, val, strlen(val), (struct lyd_node *)leaf,
Michal Vaskof03ed032020-03-04 13:31:44 +01003544 set->tree, &leaf->value, &errmsg);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003545 if (dynamic) {
3546 free((char *)val);
3547 }
3548 if (!node) {
3549 LOGERR(set->ctx, LY_EINVAL, errmsg);
3550 free(errmsg);
3551 return LY_EINVAL;
3552 }
3553
3554 /* insert it */
3555 set_insert_node(set, node, 0, LYXP_NODE_ELEM, 0);
3556 } else {
3557 assert(sleaf->type->basetype == LY_TYPE_INST);
Michal Vaskof03ed032020-03-04 13:31:44 +01003558 node = (struct lyd_node *)lyd_target(leaf->value.target, set->tree);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003559 if (!node) {
3560 val = lyd_value2str(leaf, &dynamic);
3561 LOGERR(set->ctx, LY_EVALID, "Invalid instance-identifier \"%s\" value - required instance not found.", val);
3562 if (dynamic) {
3563 free((char *)val);
3564 }
3565 return LY_EVALID;
3566 }
3567 }
3568 }
3569 }
3570
3571 return LY_SUCCESS;
3572}
3573
3574/**
3575 * @brief Execute the YANG 1.1 derived-from(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3576 * on whether the first argument nodes contain a node of an identity derived from the second
3577 * argument identity.
3578 *
3579 * @param[in] args Array of arguments.
3580 * @param[in] arg_count Count of elements in @p args.
3581 * @param[in,out] set Context and result set at the same time.
3582 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003583 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003584 */
3585static LY_ERR
3586xpath_derived_from(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3587{
3588 uint16_t i;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003589 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003590 struct lyd_node_term *leaf;
3591 struct lysc_node_leaf *sleaf;
3592 struct lyd_value data = {0};
3593 struct ly_err_item *err = NULL;
3594 LY_ERR rc = LY_SUCCESS;
3595 int found;
3596
3597 if (options & LYXP_SCNODE_ALL) {
3598 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3599 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003600 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3601 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 +02003602 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3603 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003604 }
3605
3606 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3607 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3608 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 +02003609 } else if (!warn_is_string_type(sleaf->type)) {
3610 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003611 }
3612 }
3613 set_scnode_clear_ctx(set);
3614 return rc;
3615 }
3616
Michal Vaskod3678892020-05-21 10:06:58 +02003617 if (args[0]->type != LYXP_SET_NODE_SET) {
3618 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
3619 "derived-from(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003620 return LY_EVALID;
3621 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003622 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003623 LY_CHECK_RET(rc);
3624
3625 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003626 found = 0;
3627 for (i = 0; i < args[0]->used; ++i) {
3628 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3629 sleaf = (struct lysc_node_leaf *)leaf->schema;
3630 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3631 /* store args[1] into ident */
3632 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3633 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3634 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
3635 if (err) {
3636 ly_err_print(err);
3637 ly_err_free(err);
3638 }
3639 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003640
Michal Vaskod3678892020-05-21 10:06:58 +02003641 LY_ARRAY_FOR(data.ident->derived, u) {
3642 if (data.ident->derived[u] == leaf->value.ident) {
3643 set_fill_boolean(set, 1);
3644 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003645 break;
3646 }
3647 }
Michal Vaskod3678892020-05-21 10:06:58 +02003648 if (found) {
3649 break;
3650 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02003651 }
3652 }
3653
3654 return LY_SUCCESS;
3655}
3656
3657/**
3658 * @brief Execute the YANG 1.1 derived-from-or-self(node-set, string) function. Returns LYXP_SET_BOOLEAN depending
3659 * on whether the first argument nodes contain a node of an identity that either is or is derived from
3660 * the second argument identity.
3661 *
3662 * @param[in] args Array of arguments.
3663 * @param[in] arg_count Count of elements in @p args.
3664 * @param[in,out] set Context and result set at the same time.
3665 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003666 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003667 */
3668static LY_ERR
3669xpath_derived_from_or_self(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3670{
3671 uint16_t i;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02003672 LY_ARRAY_SIZE_TYPE u;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003673 struct lyd_node_term *leaf;
3674 struct lysc_node_leaf *sleaf;
3675 struct lyd_value data = {0};
3676 struct ly_err_item *err = NULL;
3677 LY_ERR rc = LY_SUCCESS;
3678 int found;
3679
3680 if (options & LYXP_SCNODE_ALL) {
3681 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3682 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003683 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3684 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 +02003685 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_IDENT)) {
3686 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"identityref\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003687 }
3688
3689 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
3690 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3691 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 +02003692 } else if (!warn_is_string_type(sleaf->type)) {
3693 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003694 }
3695 }
3696 set_scnode_clear_ctx(set);
3697 return rc;
3698 }
3699
Michal Vaskod3678892020-05-21 10:06:58 +02003700 if (args[0]->type != LYXP_SET_NODE_SET) {
3701 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
3702 "derived-from-or-self(node-set, string)");
Michal Vasko03ff5a72019-09-11 13:49:33 +02003703 return LY_EVALID;
3704 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003705 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003706 LY_CHECK_RET(rc);
3707
3708 set_fill_boolean(set, 0);
Michal Vaskod3678892020-05-21 10:06:58 +02003709 found = 0;
3710 for (i = 0; i < args[0]->used; ++i) {
3711 leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
3712 sleaf = (struct lysc_node_leaf *)leaf->schema;
3713 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_IDENT)) {
3714 /* store args[1] into ident */
3715 rc = sleaf->type->plugin->store(set->ctx, sleaf->type, args[1]->val.str, strlen(args[1]->val.str),
3716 LY_TYPE_OPTS_STORE, lys_resolve_prefix, (void *)sleaf->dflt_mod, set->format,
3717 (struct lyd_node *)leaf, set->tree, &data, NULL, &err);
3718 if (err) {
3719 ly_err_print(err);
3720 ly_err_free(err);
3721 }
3722 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003723
Michal Vaskod3678892020-05-21 10:06:58 +02003724 if (data.ident == leaf->value.ident) {
3725 set_fill_boolean(set, 1);
3726 break;
3727 }
3728 LY_ARRAY_FOR(data.ident->derived, u) {
3729 if (data.ident->derived[u] == leaf->value.ident) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003730 set_fill_boolean(set, 1);
Michal Vaskod3678892020-05-21 10:06:58 +02003731 found = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003732 break;
3733 }
Michal Vaskod3678892020-05-21 10:06:58 +02003734 }
3735 if (found) {
3736 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003737 }
3738 }
3739 }
3740
3741 return LY_SUCCESS;
3742}
3743
3744/**
3745 * @brief Execute the YANG 1.1 enum-value(node-set) function. Returns LYXP_SET_NUMBER
3746 * with the integer value of the first node's enum value, otherwise NaN.
3747 *
3748 * @param[in] args Array of arguments.
3749 * @param[in] arg_count Count of elements in @p args.
3750 * @param[in,out] set Context and result set at the same time.
3751 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003752 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003753 */
3754static LY_ERR
3755xpath_enum_value(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3756{
3757 struct lyd_node_term *leaf;
3758 struct lysc_node_leaf *sleaf;
3759 LY_ERR rc = LY_SUCCESS;
3760
3761 if (options & LYXP_SCNODE_ALL) {
3762 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3763 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003764 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3765 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 +02003766 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_ENUM)) {
3767 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"enumeration\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003768 }
3769 set_scnode_clear_ctx(set);
3770 return rc;
3771 }
3772
Michal Vaskod3678892020-05-21 10:06:58 +02003773 if (args[0]->type != LYXP_SET_NODE_SET) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003774 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "enum-value(node-set)");
3775 return LY_EVALID;
3776 }
3777
3778 set_fill_number(set, NAN);
Michal Vaskod3678892020-05-21 10:06:58 +02003779 if (args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003780 leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
3781 sleaf = (struct lysc_node_leaf *)leaf->schema;
3782 if ((sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (sleaf->type->basetype == LY_TYPE_ENUM)) {
3783 set_fill_number(set, leaf->value.enum_item->value);
3784 }
3785 }
3786
3787 return LY_SUCCESS;
3788}
3789
3790/**
3791 * @brief Execute the XPath false() function. Returns LYXP_SET_BOOLEAN
3792 * with false value.
3793 *
3794 * @param[in] args Array of arguments.
3795 * @param[in] arg_count Count of elements in @p args.
3796 * @param[in,out] set Context and result set at the same time.
3797 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003798 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003799 */
3800static LY_ERR
3801xpath_false(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3802{
3803 if (options & LYXP_SCNODE_ALL) {
3804 set_scnode_clear_ctx(set);
3805 return LY_SUCCESS;
3806 }
3807
3808 set_fill_boolean(set, 0);
3809 return LY_SUCCESS;
3810}
3811
3812/**
3813 * @brief Execute the XPath floor(number) function. Returns LYXP_SET_NUMBER
3814 * with the first argument floored (truncated).
3815 *
3816 * @param[in] args Array of arguments.
3817 * @param[in] arg_count Count of elements in @p args.
3818 * @param[in,out] set Context and result set at the same time.
3819 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003820 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003821 */
3822static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003823xpath_floor(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int UNUSED(options))
Michal Vasko03ff5a72019-09-11 13:49:33 +02003824{
3825 LY_ERR rc;
3826
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003827 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003828 LY_CHECK_RET(rc);
3829 if (isfinite(args[0]->val.num)) {
3830 set_fill_number(set, (long long)args[0]->val.num);
3831 }
3832
3833 return LY_SUCCESS;
3834}
3835
3836/**
3837 * @brief Execute the XPath lang(string) function. Returns LYXP_SET_BOOLEAN
3838 * whether the language of the text matches the one from the argument.
3839 *
3840 * @param[in] args Array of arguments.
3841 * @param[in] arg_count Count of elements in @p args.
3842 * @param[in,out] set Context and result set at the same time.
3843 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003844 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003845 */
3846static LY_ERR
3847xpath_lang(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3848{
3849 const struct lyd_node *node;
3850 struct lysc_node_leaf *sleaf;
Michal Vasko9f96a052020-03-10 09:41:45 +01003851 struct lyd_meta *meta = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003852 const char *val;
3853 int i, dynamic;
3854 LY_ERR rc = LY_SUCCESS;
3855
3856 if (options & LYXP_SCNODE_ALL) {
3857 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
3858 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
3859 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 +02003860 } else if (!warn_is_string_type(sleaf->type)) {
3861 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003862 }
3863 }
3864 set_scnode_clear_ctx(set);
3865 return rc;
3866 }
3867
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003868 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003869 LY_CHECK_RET(rc);
3870
Michal Vasko03ff5a72019-09-11 13:49:33 +02003871 if (set->type != LYXP_SET_NODE_SET) {
3872 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "lang(string)");
3873 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02003874 } else if (!set->used) {
3875 set_fill_boolean(set, 0);
3876 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003877 }
3878
3879 switch (set->val.nodes[0].type) {
3880 case LYXP_NODE_ELEM:
3881 case LYXP_NODE_TEXT:
3882 node = set->val.nodes[0].node;
3883 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01003884 case LYXP_NODE_META:
3885 node = set->val.meta[0].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003886 break;
3887 default:
3888 /* nothing to do with roots */
3889 set_fill_boolean(set, 0);
3890 return LY_SUCCESS;
3891 }
3892
Michal Vasko9f96a052020-03-10 09:41:45 +01003893 /* find lang metadata */
Michal Vasko03ff5a72019-09-11 13:49:33 +02003894 for (; node; node = (struct lyd_node *)node->parent) {
Michal Vasko9f96a052020-03-10 09:41:45 +01003895 for (meta = node->meta; meta; meta = meta->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003896 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01003897 if (meta->name && !strcmp(meta->name, "lang") && !strcmp(meta->annotation->module->name, "xml")) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003898 break;
3899 }
3900 }
3901
Michal Vasko9f96a052020-03-10 09:41:45 +01003902 if (meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003903 break;
3904 }
3905 }
3906
3907 /* compare languages */
Michal Vasko9f96a052020-03-10 09:41:45 +01003908 if (!meta) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003909 set_fill_boolean(set, 0);
3910 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01003911 val = lyd_meta2str(meta, &dynamic);
Michal Vasko03ff5a72019-09-11 13:49:33 +02003912 for (i = 0; args[0]->val.str[i]; ++i) {
3913 if (tolower(args[0]->val.str[i]) != tolower(val[i])) {
3914 set_fill_boolean(set, 0);
3915 break;
3916 }
3917 }
3918 if (!args[0]->val.str[i]) {
3919 if (!val[i] || (val[i] == '-')) {
3920 set_fill_boolean(set, 1);
3921 } else {
3922 set_fill_boolean(set, 0);
3923 }
3924 }
3925 if (dynamic) {
3926 free((char *)val);
3927 }
3928 }
3929
3930 return LY_SUCCESS;
3931}
3932
3933/**
3934 * @brief Execute the XPath last() function. Returns LYXP_SET_NUMBER
3935 * with the context size.
3936 *
3937 * @param[in] args Array of arguments.
3938 * @param[in] arg_count Count of elements in @p args.
3939 * @param[in,out] set Context and result set at the same time.
3940 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003941 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003942 */
3943static LY_ERR
3944xpath_last(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
3945{
3946 if (options & LYXP_SCNODE_ALL) {
3947 set_scnode_clear_ctx(set);
3948 return LY_SUCCESS;
3949 }
3950
Michal Vasko03ff5a72019-09-11 13:49:33 +02003951 if (set->type != LYXP_SET_NODE_SET) {
3952 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "last()");
3953 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02003954 } else if (!set->used) {
3955 set_fill_number(set, 0);
3956 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003957 }
3958
3959 set_fill_number(set, set->ctx_size);
3960 return LY_SUCCESS;
3961}
3962
3963/**
3964 * @brief Execute the XPath local-name(node-set?) function. Returns LYXP_SET_STRING
3965 * with the node name without namespace from the argument or the context.
3966 *
3967 * @param[in] args Array of arguments.
3968 * @param[in] arg_count Count of elements in @p args.
3969 * @param[in,out] set Context and result set at the same time.
3970 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01003971 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02003972 */
3973static LY_ERR
3974xpath_local_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
3975{
3976 struct lyxp_set_node *item;
3977 /* suppress unused variable warning */
3978 (void)options;
3979
3980 if (options & LYXP_SCNODE_ALL) {
3981 set_scnode_clear_ctx(set);
3982 return LY_SUCCESS;
3983 }
3984
3985 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003986 if (args[0]->type != LYXP_SET_NODE_SET) {
3987 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "local-name(node-set?)");
3988 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02003989 } else if (!args[0]->used) {
3990 set_fill_string(set, "", 0);
3991 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02003992 }
3993
3994 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01003995 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02003996
3997 item = &args[0]->val.nodes[0];
3998 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02003999 if (set->type != LYXP_SET_NODE_SET) {
4000 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "local-name(node-set?)");
4001 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004002 } else if (!set->used) {
4003 set_fill_string(set, "", 0);
4004 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004005 }
4006
4007 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004008 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004009
4010 item = &set->val.nodes[0];
4011 }
4012
4013 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004014 case LYXP_NODE_NONE:
4015 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004016 case LYXP_NODE_ROOT:
4017 case LYXP_NODE_ROOT_CONFIG:
4018 case LYXP_NODE_TEXT:
4019 set_fill_string(set, "", 0);
4020 break;
4021 case LYXP_NODE_ELEM:
4022 set_fill_string(set, item->node->schema->name, strlen(item->node->schema->name));
4023 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004024 case LYXP_NODE_META:
4025 set_fill_string(set, ((struct lyd_meta *)item->node)->name, strlen(((struct lyd_meta *)item->node)->name));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004026 break;
4027 }
4028
4029 return LY_SUCCESS;
4030}
4031
4032/**
4033 * @brief Execute the XPath name(node-set?) function. Returns LYXP_SET_STRING
4034 * with the node name fully qualified (with namespace) from the argument or the context.
4035 *
4036 * @param[in] args Array of arguments.
4037 * @param[in] arg_count Count of elements in @p args.
4038 * @param[in,out] set Context and result set at the same time.
4039 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004040 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004041 */
4042static LY_ERR
4043xpath_name(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4044{
4045 struct lyxp_set_node *item;
4046 struct lys_module *mod;
4047 char *str;
4048 const char *name;
4049 int rc;
4050
4051 if (options & LYXP_SCNODE_ALL) {
4052 set_scnode_clear_ctx(set);
4053 return LY_SUCCESS;
4054 }
4055
4056 if (arg_count) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004057 if (args[0]->type != LYXP_SET_NODE_SET) {
4058 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "name(node-set?)");
4059 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004060 } else if (!args[0]->used) {
4061 set_fill_string(set, "", 0);
4062 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004063 }
4064
4065 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004066 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004067
4068 item = &args[0]->val.nodes[0];
4069 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004070 if (set->type != LYXP_SET_NODE_SET) {
4071 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "name(node-set?)");
4072 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004073 } else if (!set->used) {
4074 set_fill_string(set, "", 0);
4075 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004076 }
4077
4078 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004079 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004080
4081 item = &set->val.nodes[0];
4082 }
4083
4084 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004085 case LYXP_NODE_NONE:
4086 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004087 case LYXP_NODE_ROOT:
4088 case LYXP_NODE_ROOT_CONFIG:
4089 case LYXP_NODE_TEXT:
4090 mod = NULL;
4091 name = NULL;
4092 break;
4093 case LYXP_NODE_ELEM:
4094 mod = item->node->schema->module;
4095 name = item->node->schema->name;
4096 break;
Michal Vasko9f96a052020-03-10 09:41:45 +01004097 case LYXP_NODE_META:
4098 mod = ((struct lyd_meta *)item->node)->annotation->module;
4099 name = ((struct lyd_meta *)item->node)->name;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004100 break;
4101 }
4102
4103 if (mod && name) {
4104 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01004105 case LYD_SCHEMA:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004106 rc = asprintf(&str, "%s:%s", lys_prefix_find_module(set->local_mod, mod), name);
4107 break;
4108 case LYD_JSON:
4109 rc = asprintf(&str, "%s:%s", mod->name, name);
4110 break;
Michal Vasko52927e22020-03-16 17:26:14 +01004111 case LYD_XML:
Michal Vasko9409ef62019-09-12 11:47:17 +02004112 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004113 }
4114 LY_CHECK_ERR_RET(rc == -1, LOGMEM(set->ctx), LY_EMEM);
4115 set_fill_string(set, str, strlen(str));
4116 free(str);
4117 } else {
4118 set_fill_string(set, "", 0);
4119 }
4120
4121 return LY_SUCCESS;
4122}
4123
4124/**
4125 * @brief Execute the XPath namespace-uri(node-set?) function. Returns LYXP_SET_STRING
4126 * with the namespace of the node from the argument or the context.
4127 *
4128 * @param[in] args Array of arguments.
4129 * @param[in] arg_count Count of elements in @p args.
4130 * @param[in,out] set Context and result set at the same time.
4131 * @param[in] options XPath options.
4132 * @return LY_ERR (LY_EINVAL for wrong arguments on schema)
4133 */
4134static LY_ERR
4135xpath_namespace_uri(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4136{
4137 struct lyxp_set_node *item;
4138 struct lys_module *mod;
4139 /* suppress unused variable warning */
4140 (void)options;
4141
4142 if (options & LYXP_SCNODE_ALL) {
4143 set_scnode_clear_ctx(set);
4144 return LY_SUCCESS;
4145 }
4146
4147 if (arg_count) {
Michal Vaskod3678892020-05-21 10:06:58 +02004148 if (args[0]->type != LYXP_SET_NODE_SET) {
4149 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]),
4150 "namespace-uri(node-set?)");
4151 return LY_EVALID;
4152 } else if (!args[0]->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004153 set_fill_string(set, "", 0);
4154 return LY_SUCCESS;
4155 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02004156
4157 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004158 assert(!set_sort(args[0]));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004159
4160 item = &args[0]->val.nodes[0];
4161 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02004162 if (set->type != LYXP_SET_NODE_SET) {
4163 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "namespace-uri(node-set?)");
4164 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004165 } else if (!set->used) {
4166 set_fill_string(set, "", 0);
4167 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004168 }
4169
4170 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004171 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02004172
4173 item = &set->val.nodes[0];
4174 }
4175
4176 switch (item->type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004177 case LYXP_NODE_NONE:
4178 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004179 case LYXP_NODE_ROOT:
4180 case LYXP_NODE_ROOT_CONFIG:
4181 case LYXP_NODE_TEXT:
4182 set_fill_string(set, "", 0);
4183 break;
4184 case LYXP_NODE_ELEM:
Michal Vasko9f96a052020-03-10 09:41:45 +01004185 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004186 if (item->type == LYXP_NODE_ELEM) {
4187 mod = item->node->schema->module;
Michal Vasko9f96a052020-03-10 09:41:45 +01004188 } else { /* LYXP_NODE_META */
Michal Vasko03ff5a72019-09-11 13:49:33 +02004189 /* annotations */
Michal Vasko9f96a052020-03-10 09:41:45 +01004190 mod = ((struct lyd_meta *)item->node)->annotation->module;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004191 }
4192
4193 set_fill_string(set, mod->ns, strlen(mod->ns));
4194 break;
4195 }
4196
4197 return LY_SUCCESS;
4198}
4199
4200/**
4201 * @brief Execute the XPath node() function (node type). Returns LYXP_SET_NODE_SET
4202 * with only nodes from the context. In practice it either leaves the context
4203 * as it is or returns an empty node set.
4204 *
4205 * @param[in] args Array of arguments.
4206 * @param[in] arg_count Count of elements in @p args.
4207 * @param[in,out] set Context and result set at the same time.
4208 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004209 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004210 */
4211static LY_ERR
4212xpath_node(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4213{
4214 if (options & LYXP_SCNODE_ALL) {
4215 set_scnode_clear_ctx(set);
4216 return LY_SUCCESS;
4217 }
4218
4219 if (set->type != LYXP_SET_NODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02004220 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004221 }
4222 return LY_SUCCESS;
4223}
4224
4225/**
4226 * @brief Execute the XPath normalize-space(string?) function. Returns LYXP_SET_STRING
4227 * with normalized value (no leading, trailing, double white spaces) of the node
4228 * from the argument or the context.
4229 *
4230 * @param[in] args Array of arguments.
4231 * @param[in] arg_count Count of elements in @p args.
4232 * @param[in,out] set Context and result set at the same time.
4233 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004234 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004235 */
4236static LY_ERR
4237xpath_normalize_space(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4238{
4239 uint16_t i, new_used;
4240 char *new;
4241 int have_spaces = 0, space_before = 0;
4242 struct lysc_node_leaf *sleaf;
4243 LY_ERR rc = LY_SUCCESS;
4244
4245 if (options & LYXP_SCNODE_ALL) {
4246 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4247 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4248 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 +02004249 } else if (!warn_is_string_type(sleaf->type)) {
4250 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004251 }
4252 }
4253 set_scnode_clear_ctx(set);
4254 return rc;
4255 }
4256
4257 if (arg_count) {
4258 set_fill_set(set, args[0]);
4259 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004260 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004261 LY_CHECK_RET(rc);
4262
4263 /* is there any normalization necessary? */
4264 for (i = 0; set->val.str[i]; ++i) {
4265 if (is_xmlws(set->val.str[i])) {
4266 if ((i == 0) || space_before || (!set->val.str[i + 1])) {
4267 have_spaces = 1;
4268 break;
4269 }
4270 space_before = 1;
4271 } else {
4272 space_before = 0;
4273 }
4274 }
4275
4276 /* yep, there is */
4277 if (have_spaces) {
4278 /* it's enough, at least one character will go, makes space for ending '\0' */
4279 new = malloc(strlen(set->val.str) * sizeof(char));
4280 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4281 new_used = 0;
4282
4283 space_before = 0;
4284 for (i = 0; set->val.str[i]; ++i) {
4285 if (is_xmlws(set->val.str[i])) {
4286 if ((i == 0) || space_before) {
4287 space_before = 1;
4288 continue;
4289 } else {
4290 space_before = 1;
4291 }
4292 } else {
4293 space_before = 0;
4294 }
4295
4296 new[new_used] = (space_before ? ' ' : set->val.str[i]);
4297 ++new_used;
4298 }
4299
4300 /* at worst there is one trailing space now */
4301 if (new_used && is_xmlws(new[new_used - 1])) {
4302 --new_used;
4303 }
4304
4305 new = ly_realloc(new, (new_used + 1) * sizeof(char));
4306 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
4307 new[new_used] = '\0';
4308
4309 free(set->val.str);
4310 set->val.str = new;
4311 }
4312
4313 return LY_SUCCESS;
4314}
4315
4316/**
4317 * @brief Execute the XPath not(boolean) function. Returns LYXP_SET_BOOLEAN
4318 * with the argument converted to boolean and logically inverted.
4319 *
4320 * @param[in] args Array of arguments.
4321 * @param[in] arg_count Count of elements in @p args.
4322 * @param[in,out] set Context and result set at the same time.
4323 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004324 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004325 */
4326static LY_ERR
4327xpath_not(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4328{
4329 if (options & LYXP_SCNODE_ALL) {
4330 set_scnode_clear_ctx(set);
4331 return LY_SUCCESS;
4332 }
4333
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004334 lyxp_set_cast(args[0], LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004335 if (args[0]->val.bool) {
4336 set_fill_boolean(set, 0);
4337 } else {
4338 set_fill_boolean(set, 1);
4339 }
4340
4341 return LY_SUCCESS;
4342}
4343
4344/**
4345 * @brief Execute the XPath number(object?) function. Returns LYXP_SET_NUMBER
4346 * with the number representation of either the argument or the context.
4347 *
4348 * @param[in] args Array of arguments.
4349 * @param[in] arg_count Count of elements in @p args.
4350 * @param[in,out] set Context and result set at the same time.
4351 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004352 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004353 */
4354static LY_ERR
4355xpath_number(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4356{
4357 LY_ERR rc;
4358
4359 if (options & LYXP_SCNODE_ALL) {
4360 set_scnode_clear_ctx(set);
4361 return LY_SUCCESS;
4362 }
4363
4364 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004365 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004366 LY_CHECK_RET(rc);
4367 set_fill_set(set, args[0]);
4368 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004369 rc = lyxp_set_cast(set, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004370 LY_CHECK_RET(rc);
4371 }
4372
4373 return LY_SUCCESS;
4374}
4375
4376/**
4377 * @brief Execute the XPath position() function. Returns LYXP_SET_NUMBER
4378 * with the context position.
4379 *
4380 * @param[in] args Array of arguments.
4381 * @param[in] arg_count Count of elements in @p args.
4382 * @param[in,out] set Context and result set at the same time.
4383 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004384 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004385 */
4386static LY_ERR
4387xpath_position(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4388{
4389 if (options & LYXP_SCNODE_ALL) {
4390 set_scnode_clear_ctx(set);
4391 return LY_SUCCESS;
4392 }
4393
Michal Vasko03ff5a72019-09-11 13:49:33 +02004394 if (set->type != LYXP_SET_NODE_SET) {
4395 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "position()");
4396 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004397 } else if (!set->used) {
4398 set_fill_number(set, 0);
4399 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004400 }
4401
4402 set_fill_number(set, set->ctx_pos);
4403
4404 /* UNUSED in 'Release' build type */
4405 (void)options;
4406 return LY_SUCCESS;
4407}
4408
4409/**
4410 * @brief Execute the YANG 1.1 re-match(string, string) function. Returns LYXP_SET_BOOLEAN
4411 * depending on whether the second argument regex matches the first argument string. For details refer to
4412 * YANG 1.1 RFC section 10.2.1.
4413 *
4414 * @param[in] args Array of arguments.
4415 * @param[in] arg_count Count of elements in @p args.
4416 * @param[in,out] set Context and result set at the same time.
4417 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004418 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004419 */
4420static LY_ERR
4421xpath_re_match(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4422{
4423 struct lysc_pattern **patterns = NULL, **pattern;
4424 struct lysc_node_leaf *sleaf;
4425 char *path;
4426 LY_ERR rc = LY_SUCCESS;
4427 struct ly_err_item *err;
4428
4429 if (options & LYXP_SCNODE_ALL) {
4430 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4431 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4432 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 +02004433 } else if (!warn_is_string_type(sleaf->type)) {
4434 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004435 }
4436 }
4437
4438 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4439 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4440 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 +02004441 } else if (!warn_is_string_type(sleaf->type)) {
4442 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004443 }
4444 }
4445 set_scnode_clear_ctx(set);
4446 return rc;
4447 }
4448
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004449 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004450 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004451 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004452 LY_CHECK_RET(rc);
4453
4454 LY_ARRAY_NEW_RET(set->ctx, patterns, pattern, LY_EMEM);
4455 *pattern = malloc(sizeof **pattern);
4456 path = lyd_path(set->ctx_node, LYD_PATH_LOG, NULL, 0);
4457 rc = lys_compile_type_pattern_check(set->ctx, path, args[1]->val.str, &(*pattern)->code);
4458 free(path);
4459 if (rc != LY_SUCCESS) {
4460 LY_ARRAY_FREE(patterns);
4461 return rc;
4462 }
4463
4464 rc = ly_type_validate_patterns(patterns, args[0]->val.str, strlen(args[0]->val.str), &err);
4465 pcre2_code_free((*pattern)->code);
4466 free(*pattern);
4467 LY_ARRAY_FREE(patterns);
4468 if (rc && (rc != LY_EVALID)) {
4469 ly_err_print(err);
4470 ly_err_free(err);
4471 return rc;
4472 }
4473
4474 if (rc == LY_EVALID) {
4475 ly_err_free(err);
4476 set_fill_boolean(set, 0);
4477 } else {
4478 set_fill_boolean(set, 1);
4479 }
4480
4481 return LY_SUCCESS;
4482}
4483
4484/**
4485 * @brief Execute the XPath round(number) function. Returns LYXP_SET_NUMBER
4486 * with the rounded first argument. For details refer to
4487 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-round.
4488 *
4489 * @param[in] args Array of arguments.
4490 * @param[in] arg_count Count of elements in @p args.
4491 * @param[in,out] set Context and result set at the same time.
4492 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004493 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004494 */
4495static LY_ERR
4496xpath_round(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4497{
4498 struct lysc_node_leaf *sleaf;
4499 LY_ERR rc = LY_SUCCESS;
4500
4501 if (options & LYXP_SCNODE_ALL) {
4502 if ((args[0]->type != LYXP_SET_SCNODE_SET) || !(sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4503 LOGWRN(set->ctx, "Argument #1 of %s not a node-set as expected.", __func__);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004504 } else if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4505 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 +02004506 } else if (!warn_is_specific_type(sleaf->type, LY_TYPE_DEC64)) {
4507 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of type \"decimal64\".", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004508 }
4509 set_scnode_clear_ctx(set);
4510 return rc;
4511 }
4512
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004513 rc = lyxp_set_cast(args[0], LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004514 LY_CHECK_RET(rc);
4515
4516 /* cover only the cases where floor can't be used */
4517 if ((args[0]->val.num == -0.0f) || ((args[0]->val.num < 0) && (args[0]->val.num >= -0.5))) {
4518 set_fill_number(set, -0.0f);
4519 } else {
4520 args[0]->val.num += 0.5;
4521 rc = xpath_floor(args, 1, args[0], options);
4522 LY_CHECK_RET(rc);
4523 set_fill_number(set, args[0]->val.num);
4524 }
4525
4526 return LY_SUCCESS;
4527}
4528
4529/**
4530 * @brief Execute the XPath starts-with(string, string) function.
4531 * Returns LYXP_SET_BOOLEAN whether the second argument is
4532 * the prefix of the first or not.
4533 *
4534 * @param[in] args Array of arguments.
4535 * @param[in] arg_count Count of elements in @p args.
4536 * @param[in,out] set Context and result set at the same time.
4537 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004538 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004539 */
4540static LY_ERR
4541xpath_starts_with(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4542{
4543 struct lysc_node_leaf *sleaf;
4544 LY_ERR rc = LY_SUCCESS;
4545
4546 if (options & LYXP_SCNODE_ALL) {
4547 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4548 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4549 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 +02004550 } else if (!warn_is_string_type(sleaf->type)) {
4551 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004552 }
4553 }
4554
4555 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4556 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4557 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 +02004558 } else if (!warn_is_string_type(sleaf->type)) {
4559 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004560 }
4561 }
4562 set_scnode_clear_ctx(set);
4563 return rc;
4564 }
4565
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004566 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004567 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004568 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004569 LY_CHECK_RET(rc);
4570
4571 if (strncmp(args[0]->val.str, args[1]->val.str, strlen(args[1]->val.str))) {
4572 set_fill_boolean(set, 0);
4573 } else {
4574 set_fill_boolean(set, 1);
4575 }
4576
4577 return LY_SUCCESS;
4578}
4579
4580/**
4581 * @brief Execute the XPath string(object?) function. Returns LYXP_SET_STRING
4582 * with the string representation of either the argument or the context.
4583 *
4584 * @param[in] args Array of arguments.
4585 * @param[in] arg_count Count of elements in @p args.
4586 * @param[in,out] set Context and result set at the same time.
4587 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004588 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004589 */
4590static LY_ERR
4591xpath_string(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4592{
4593 LY_ERR rc;
4594
4595 if (options & LYXP_SCNODE_ALL) {
4596 set_scnode_clear_ctx(set);
4597 return LY_SUCCESS;
4598 }
4599
4600 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004601 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004602 LY_CHECK_RET(rc);
4603 set_fill_set(set, args[0]);
4604 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004605 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004606 LY_CHECK_RET(rc);
4607 }
4608
4609 return LY_SUCCESS;
4610}
4611
4612/**
4613 * @brief Execute the XPath string-length(string?) function. Returns LYXP_SET_NUMBER
4614 * with the length of the string in either the argument or the context.
4615 *
4616 * @param[in] args Array of arguments.
4617 * @param[in] arg_count Count of elements in @p args.
4618 * @param[in,out] set Context and result set at the same time.
4619 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004620 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004621 */
4622static LY_ERR
4623xpath_string_length(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4624{
4625 struct lysc_node_leaf *sleaf;
4626 LY_ERR rc = LY_SUCCESS;
4627
4628 if (options & LYXP_SCNODE_ALL) {
4629 if (arg_count && (args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4630 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4631 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 +02004632 } else if (!warn_is_string_type(sleaf->type)) {
4633 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004634 }
4635 }
4636 if (!arg_count && (set->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(set))) {
4637 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4638 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 +02004639 } else if (!warn_is_string_type(sleaf->type)) {
4640 LOGWRN(set->ctx, "Argument #0 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004641 }
4642 }
4643 set_scnode_clear_ctx(set);
4644 return rc;
4645 }
4646
4647 if (arg_count) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004648 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004649 LY_CHECK_RET(rc);
4650 set_fill_number(set, strlen(args[0]->val.str));
4651 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004652 rc = lyxp_set_cast(set, LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004653 LY_CHECK_RET(rc);
4654 set_fill_number(set, strlen(set->val.str));
4655 }
4656
4657 return LY_SUCCESS;
4658}
4659
4660/**
4661 * @brief Execute the XPath substring(string, number, number?) function.
4662 * Returns LYXP_SET_STRING substring of the first argument starting
4663 * on the second argument index ending on the third argument index,
4664 * indexed from 1. For exact definition refer to
4665 * http://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring.
4666 *
4667 * @param[in] args Array of arguments.
4668 * @param[in] arg_count Count of elements in @p args.
4669 * @param[in,out] set Context and result set at the same time.
4670 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004671 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004672 */
4673static LY_ERR
4674xpath_substring(struct lyxp_set **args, uint16_t arg_count, struct lyxp_set *set, int options)
4675{
4676 int start, len;
4677 uint16_t str_start, str_len, pos;
4678 struct lysc_node_leaf *sleaf;
4679 LY_ERR rc = LY_SUCCESS;
4680
4681 if (options & LYXP_SCNODE_ALL) {
4682 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4683 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4684 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 +02004685 } else if (!warn_is_string_type(sleaf->type)) {
4686 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004687 }
4688 }
4689
4690 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4691 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4692 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 +02004693 } else if (!warn_is_numeric_type(sleaf->type)) {
4694 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004695 }
4696 }
4697
4698 if ((arg_count == 3) && (args[2]->type == LYXP_SET_SCNODE_SET)
4699 && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
4700 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4701 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 +02004702 } else if (!warn_is_numeric_type(sleaf->type)) {
4703 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004704 }
4705 }
4706 set_scnode_clear_ctx(set);
4707 return rc;
4708 }
4709
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004710 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004711 LY_CHECK_RET(rc);
4712
4713 /* start */
4714 if (xpath_round(&args[1], 1, args[1], options)) {
4715 return -1;
4716 }
4717 if (isfinite(args[1]->val.num)) {
4718 start = args[1]->val.num - 1;
4719 } else if (isinf(args[1]->val.num) && signbit(args[1]->val.num)) {
4720 start = INT_MIN;
4721 } else {
4722 start = INT_MAX;
4723 }
4724
4725 /* len */
4726 if (arg_count == 3) {
4727 rc = xpath_round(&args[2], 1, args[2], options);
4728 LY_CHECK_RET(rc);
4729 if (isfinite(args[2]->val.num)) {
4730 len = args[2]->val.num;
4731 } else if (isnan(args[2]->val.num) || signbit(args[2]->val.num)) {
4732 len = 0;
4733 } else {
4734 len = INT_MAX;
4735 }
4736 } else {
4737 len = INT_MAX;
4738 }
4739
4740 /* find matching character positions */
4741 str_start = 0;
4742 str_len = 0;
4743 for (pos = 0; args[0]->val.str[pos]; ++pos) {
4744 if (pos < start) {
4745 ++str_start;
4746 } else if (pos < start + len) {
4747 ++str_len;
4748 } else {
4749 break;
4750 }
4751 }
4752
4753 set_fill_string(set, args[0]->val.str + str_start, str_len);
4754 return LY_SUCCESS;
4755}
4756
4757/**
4758 * @brief Execute the XPath substring-after(string, string) function.
4759 * Returns LYXP_SET_STRING with the string succeeding the occurance
4760 * of the second argument in the first or an empty string.
4761 *
4762 * @param[in] args Array of arguments.
4763 * @param[in] arg_count Count of elements in @p args.
4764 * @param[in,out] set Context and result set at the same time.
4765 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004766 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004767 */
4768static LY_ERR
4769xpath_substring_after(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4770{
4771 char *ptr;
4772 struct lysc_node_leaf *sleaf;
4773 LY_ERR rc = LY_SUCCESS;
4774
4775 if (options & LYXP_SCNODE_ALL) {
4776 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4777 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4778 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 +02004779 } else if (!warn_is_string_type(sleaf->type)) {
4780 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004781 }
4782 }
4783
4784 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4785 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4786 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 +02004787 } else if (!warn_is_string_type(sleaf->type)) {
4788 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004789 }
4790 }
4791 set_scnode_clear_ctx(set);
4792 return rc;
4793 }
4794
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004795 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004796 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004797 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004798 LY_CHECK_RET(rc);
4799
4800 ptr = strstr(args[0]->val.str, args[1]->val.str);
4801 if (ptr) {
4802 set_fill_string(set, ptr + strlen(args[1]->val.str), strlen(ptr + strlen(args[1]->val.str)));
4803 } else {
4804 set_fill_string(set, "", 0);
4805 }
4806
4807 return LY_SUCCESS;
4808}
4809
4810/**
4811 * @brief Execute the XPath substring-before(string, string) function.
4812 * Returns LYXP_SET_STRING with the string preceding the occurance
4813 * of the second argument in the first or an empty string.
4814 *
4815 * @param[in] args Array of arguments.
4816 * @param[in] arg_count Count of elements in @p args.
4817 * @param[in,out] set Context and result set at the same time.
4818 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004819 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004820 */
4821static LY_ERR
4822xpath_substring_before(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4823{
4824 char *ptr;
4825 struct lysc_node_leaf *sleaf;
4826 LY_ERR rc = LY_SUCCESS;
4827
4828 if (options & LYXP_SCNODE_ALL) {
4829 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
4830 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4831 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 +02004832 } else if (!warn_is_string_type(sleaf->type)) {
4833 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004834 }
4835 }
4836
4837 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
4838 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4839 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 +02004840 } else if (!warn_is_string_type(sleaf->type)) {
4841 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004842 }
4843 }
4844 set_scnode_clear_ctx(set);
4845 return rc;
4846 }
4847
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004848 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004849 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004850 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004851 LY_CHECK_RET(rc);
4852
4853 ptr = strstr(args[0]->val.str, args[1]->val.str);
4854 if (ptr) {
4855 set_fill_string(set, args[0]->val.str, ptr - args[0]->val.str);
4856 } else {
4857 set_fill_string(set, "", 0);
4858 }
4859
4860 return LY_SUCCESS;
4861}
4862
4863/**
4864 * @brief Execute the XPath sum(node-set) function. Returns LYXP_SET_NUMBER
4865 * with the sum of all the nodes in the context.
4866 *
4867 * @param[in] args Array of arguments.
4868 * @param[in] arg_count Count of elements in @p args.
4869 * @param[in,out] set Context and result set at the same time.
4870 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004871 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004872 */
4873static LY_ERR
4874xpath_sum(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4875{
4876 long double num;
4877 char *str;
4878 uint16_t i;
4879 struct lyxp_set set_item;
4880 struct lysc_node_leaf *sleaf;
4881 LY_ERR rc = LY_SUCCESS;
4882
4883 if (options & LYXP_SCNODE_ALL) {
4884 if (args[0]->type == LYXP_SET_SCNODE_SET) {
4885 for (i = 0; i < args[0]->used; ++i) {
4886 if (args[0]->val.scnodes[i].in_ctx == 1) {
4887 sleaf = (struct lysc_node_leaf *)args[0]->val.scnodes[i].scnode;
4888 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
4889 LOGWRN(set->ctx, "Argument #1 of %s is a %s node \"%s\".", __func__,
4890 lys_nodetype2str(sleaf->nodetype), sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004891 } else if (!warn_is_numeric_type(sleaf->type)) {
4892 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of numeric type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004893 }
4894 }
4895 }
4896 }
4897 set_scnode_clear_ctx(set);
4898 return rc;
4899 }
4900
4901 set_fill_number(set, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004902
4903 if (args[0]->type != LYXP_SET_NODE_SET) {
4904 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INARGTYPE, 1, print_set_type(args[0]), "sum(node-set)");
4905 return LY_EVALID;
Michal Vaskod3678892020-05-21 10:06:58 +02004906 } else if (!args[0]->used) {
4907 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02004908 }
4909
Michal Vasko5c4e5892019-11-14 12:31:38 +01004910 set_init(&set_item, set);
4911
Michal Vasko03ff5a72019-09-11 13:49:33 +02004912 set_item.type = LYXP_SET_NODE_SET;
4913 set_item.val.nodes = malloc(sizeof *set_item.val.nodes);
4914 LY_CHECK_ERR_RET(!set_item.val.nodes, LOGMEM(set->ctx), LY_EMEM);
4915
4916 set_item.used = 1;
4917 set_item.size = 1;
4918
4919 for (i = 0; i < args[0]->used; ++i) {
4920 set_item.val.nodes[0] = args[0]->val.nodes[i];
4921
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01004922 rc = cast_node_set_to_string(&set_item, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004923 LY_CHECK_RET(rc);
4924 num = cast_string_to_number(str);
4925 free(str);
4926 set->val.num += num;
4927 }
4928
4929 free(set_item.val.nodes);
4930
4931 return LY_SUCCESS;
4932}
4933
4934/**
4935 * @brief Execute the XPath text() function (node type). Returns LYXP_SET_NODE_SET
4936 * with the text content of the nodes in the context.
4937 *
4938 * @param[in] args Array of arguments.
4939 * @param[in] arg_count Count of elements in @p args.
4940 * @param[in,out] set Context and result set at the same time.
4941 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004942 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004943 */
4944static LY_ERR
4945xpath_text(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4946{
4947 uint32_t i;
4948
4949 if (options & LYXP_SCNODE_ALL) {
4950 set_scnode_clear_ctx(set);
4951 return LY_SUCCESS;
4952 }
4953
Michal Vasko03ff5a72019-09-11 13:49:33 +02004954 if (set->type != LYXP_SET_NODE_SET) {
4955 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INCTX, print_set_type(set), "text()");
4956 return LY_EVALID;
4957 }
4958
4959 for (i = 0; i < set->used;) {
4960 switch (set->val.nodes[i].type) {
Michal Vasko2caefc12019-11-14 16:07:56 +01004961 case LYXP_NODE_NONE:
4962 LOGINT_RET(set->ctx);
Michal Vasko03ff5a72019-09-11 13:49:33 +02004963 case LYXP_NODE_ELEM:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004964 if (set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4965 set->val.nodes[i].type = LYXP_NODE_TEXT;
4966 ++i;
4967 break;
4968 }
4969 /* fall through */
4970 case LYXP_NODE_ROOT:
4971 case LYXP_NODE_ROOT_CONFIG:
4972 case LYXP_NODE_TEXT:
Michal Vasko9f96a052020-03-10 09:41:45 +01004973 case LYXP_NODE_META:
Michal Vasko03ff5a72019-09-11 13:49:33 +02004974 set_remove_node(set, i);
4975 break;
4976 }
4977 }
4978
4979 return LY_SUCCESS;
4980}
4981
4982/**
4983 * @brief Execute the XPath translate(string, string, string) function.
4984 * Returns LYXP_SET_STRING with the first argument with the characters
4985 * from the second argument replaced by those on the corresponding
4986 * positions in the third argument.
4987 *
4988 * @param[in] args Array of arguments.
4989 * @param[in] arg_count Count of elements in @p args.
4990 * @param[in,out] set Context and result set at the same time.
4991 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01004992 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02004993 */
4994static LY_ERR
4995xpath_translate(struct lyxp_set **args, uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
4996{
4997 uint16_t i, j, new_used;
4998 char *new;
4999 int found, have_removed;
5000 struct lysc_node_leaf *sleaf;
5001 LY_ERR rc = LY_SUCCESS;
5002
5003 if (options & LYXP_SCNODE_ALL) {
5004 if ((args[0]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[0]))) {
5005 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5006 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 +02005007 } else if (!warn_is_string_type(sleaf->type)) {
5008 LOGWRN(set->ctx, "Argument #1 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005009 }
5010 }
5011
5012 if ((args[1]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[1]))) {
5013 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5014 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 +02005015 } else if (!warn_is_string_type(sleaf->type)) {
5016 LOGWRN(set->ctx, "Argument #2 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005017 }
5018 }
5019
5020 if ((args[2]->type == LYXP_SET_SCNODE_SET) && (sleaf = (struct lysc_node_leaf *)warn_get_scnode_in_ctx(args[2]))) {
5021 if (!(sleaf->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
5022 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 +02005023 } else if (!warn_is_string_type(sleaf->type)) {
5024 LOGWRN(set->ctx, "Argument #3 of %s is node \"%s\", not of string-type.", __func__, sleaf->name);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005025 }
5026 }
5027 set_scnode_clear_ctx(set);
5028 return rc;
5029 }
5030
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005031 rc = lyxp_set_cast(args[0], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005032 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005033 rc = lyxp_set_cast(args[1], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005034 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005035 rc = lyxp_set_cast(args[2], LYXP_SET_STRING);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005036 LY_CHECK_RET(rc);
5037
5038 new = malloc((strlen(args[0]->val.str) + 1) * sizeof(char));
5039 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5040 new_used = 0;
5041
5042 have_removed = 0;
5043 for (i = 0; args[0]->val.str[i]; ++i) {
5044 found = 0;
5045
5046 for (j = 0; args[1]->val.str[j]; ++j) {
5047 if (args[0]->val.str[i] == args[1]->val.str[j]) {
5048 /* removing this char */
5049 if (j >= strlen(args[2]->val.str)) {
5050 have_removed = 1;
5051 found = 1;
5052 break;
5053 }
5054 /* replacing this char */
5055 new[new_used] = args[2]->val.str[j];
5056 ++new_used;
5057 found = 1;
5058 break;
5059 }
5060 }
5061
5062 /* copying this char */
5063 if (!found) {
5064 new[new_used] = args[0]->val.str[i];
5065 ++new_used;
5066 }
5067 }
5068
5069 if (have_removed) {
5070 new = ly_realloc(new, (new_used + 1) * sizeof(char));
5071 LY_CHECK_ERR_RET(!new, LOGMEM(set->ctx), LY_EMEM);
5072 }
5073 new[new_used] = '\0';
5074
Michal Vaskod3678892020-05-21 10:06:58 +02005075 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005076 set->type = LYXP_SET_STRING;
5077 set->val.str = new;
5078
5079 return LY_SUCCESS;
5080}
5081
5082/**
5083 * @brief Execute the XPath true() function. Returns LYXP_SET_BOOLEAN
5084 * with true value.
5085 *
5086 * @param[in] args Array of arguments.
5087 * @param[in] arg_count Count of elements in @p args.
5088 * @param[in,out] set Context and result set at the same time.
5089 * @param[in] options XPath options.
Michal Vasko0cbf54f2019-12-16 10:01:06 +01005090 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005091 */
5092static LY_ERR
5093xpath_true(struct lyxp_set **UNUSED(args), uint16_t UNUSED(arg_count), struct lyxp_set *set, int options)
5094{
5095 if (options & LYXP_SCNODE_ALL) {
5096 set_scnode_clear_ctx(set);
5097 return LY_SUCCESS;
5098 }
5099
5100 set_fill_boolean(set, 1);
5101 return LY_SUCCESS;
5102}
5103
5104/*
5105 * moveto functions
5106 *
5107 * They and only they actually change the context (set).
5108 */
5109
5110/**
Michal Vasko6346ece2019-09-24 13:12:53 +02005111 * @brief Skip prefix and return corresponding model if there is a prefix. Logs directly.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005112 *
Michal Vasko2104e9f2020-03-06 08:23:25 +01005113 * XPath @p set is expected to be a (sc)node set!
5114 *
Michal Vasko6346ece2019-09-24 13:12:53 +02005115 * @param[in,out] qname Qualified node name. If includes prefix, it is skipped.
5116 * @param[in,out] qname_len Length of @p qname, is updated accordingly.
5117 * @param[in] set Set with XPath context.
5118 * @param[out] moveto_mod Expected module of a matching node.
5119 * @return LY_ERR
Michal Vasko03ff5a72019-09-11 13:49:33 +02005120 */
Michal Vasko6346ece2019-09-24 13:12:53 +02005121static LY_ERR
5122moveto_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 +02005123{
Michal Vasko6346ece2019-09-24 13:12:53 +02005124 const struct lys_module *mod;
5125 const char *ptr;
5126 int pref_len;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005127 char *str;
5128
Michal Vasko2104e9f2020-03-06 08:23:25 +01005129 assert((set->type == LYXP_SET_NODE_SET) || (set->type == LYXP_SET_SCNODE_SET));
5130
Michal Vasko6346ece2019-09-24 13:12:53 +02005131 if ((ptr = ly_strnchr(*qname, ':', *qname_len))) {
5132 /* specific module */
5133 pref_len = ptr - *qname;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005134
Michal Vasko6346ece2019-09-24 13:12:53 +02005135 switch (set->format) {
Michal Vasko52927e22020-03-16 17:26:14 +01005136 case LYD_SCHEMA:
Michal Vasko6346ece2019-09-24 13:12:53 +02005137 /* schema, search all local module imports */
5138 mod = lys_module_find_prefix(set->local_mod, *qname, pref_len);
5139 break;
5140 case LYD_JSON:
5141 /* JSON data, search in context */
5142 str = strndup(*qname, pref_len);
5143 mod = ly_ctx_get_module(set->ctx, str, NULL);
5144 free(str);
5145 break;
Michal Vasko52927e22020-03-16 17:26:14 +01005146 case LYD_XML:
Michal Vasko6346ece2019-09-24 13:12:53 +02005147 LOGINT_RET(set->ctx);
5148 }
5149
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005150 /* Check for errors and non-implemented modules, as they are not valid */
5151 if (!mod || !mod->implemented) {
Michal Vasko2104e9f2020-03-06 08:23:25 +01005152 if (set->type == LYXP_SET_SCNODE_SET) {
5153 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INMOD, pref_len, *qname);
5154 } else {
5155 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INMOD, pref_len, *qname);
5156 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005157 return LY_EVALID;
5158 }
Juraj Vijtiukd75faa62019-11-26 14:10:10 +01005159
Michal Vasko6346ece2019-09-24 13:12:53 +02005160 *qname += pref_len + 1;
5161 *qname_len -= pref_len + 1;
5162 } else if (((*qname)[0] == '*') && (*qname_len == 1)) {
5163 /* all modules - special case */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005164 mod = NULL;
Michal Vasko6346ece2019-09-24 13:12:53 +02005165 } else {
5166 /* local module */
5167 mod = set->local_mod;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005168 }
5169
Michal Vasko6346ece2019-09-24 13:12:53 +02005170 *moveto_mod = mod;
5171 return LY_SUCCESS;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005172}
5173
5174/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005175 * @brief Move context @p set to the root. Handles absolute path.
5176 * Result is LYXP_SET_NODE_SET.
5177 *
5178 * @param[in,out] set Set to use.
5179 * @param[in] options Xpath options.
5180 */
5181static void
5182moveto_root(struct lyxp_set *set, int options)
5183{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005184 if (!set) {
5185 return;
5186 }
5187
5188 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005189 set_scnode_clear_ctx(set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01005190 lyxp_set_scnode_insert_node(set, NULL, set->root_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005191 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02005192 set->type = LYXP_SET_NODE_SET;
5193 set->used = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005194 set_insert_node(set, NULL, 0, set->root_type, 0);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005195 }
5196}
5197
5198/**
Michal Vaskoa1424542019-11-14 16:08:52 +01005199 * @brief Check whether a node has some unresolved "when".
5200 *
5201 * @param[in] node Node to check.
5202 * @return LY_ERR value (LY_EINCOMPLETE if there are some unresolved "when")
5203 */
5204static LY_ERR
5205moveto_when_check(const struct lyd_node *node)
5206{
5207 const struct lysc_node *schema;
5208
5209 if (!node) {
5210 return LY_SUCCESS;
5211 }
5212
5213 schema = node->schema;
5214 do {
5215 if (schema->when && !(node->flags & LYD_WHEN_TRUE)) {
5216 return LY_EINCOMPLETE;
5217 }
5218 schema = schema->parent;
5219 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
5220
5221 return LY_SUCCESS;
5222}
5223
5224/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02005225 * @brief Check @p node as a part of NameTest processing.
5226 *
5227 * @param[in] node Node to check.
5228 * @param[in] root_type XPath root node type.
Michal Vaskod3678892020-05-21 10:06:58 +02005229 * @param[in] node_name Node name in the dictionary to move to, NULL for any node.
5230 * @param[in] moveto_mod Expected module of the node, NULL for any.
Michal Vasko6346ece2019-09-24 13:12:53 +02005231 * @return LY_ERR (LY_ENOT if node does not match, LY_EINCOMPLETE on unresolved when,
5232 * LY_EINVAL if netither node nor any children match)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005233 */
5234static LY_ERR
5235moveto_node_check(const struct lyd_node *node, enum lyxp_node_type root_type, const char *node_name,
5236 const struct lys_module *moveto_mod)
5237{
5238 /* module check */
5239 if (moveto_mod && (node->schema->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005240 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005241 }
5242
Michal Vasko5c4e5892019-11-14 12:31:38 +01005243 /* context check */
5244 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005245 return LY_EINVAL;
5246 }
5247
5248 /* name check */
Michal Vaskod3678892020-05-21 10:06:58 +02005249 if (node_name && (node->schema->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005250 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005251 }
5252
Michal Vaskoa1424542019-11-14 16:08:52 +01005253 /* when check */
5254 if (moveto_when_check(node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005255 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005256 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005257
5258 /* match */
5259 return LY_SUCCESS;
5260}
5261
5262/**
5263 * @brief Check @p node as a part of schema NameTest processing.
5264 *
5265 * @param[in] node Schema node to check.
5266 * @param[in] root_type XPath root node type.
Michal Vaskod3678892020-05-21 10:06:58 +02005267 * @param[in] node_name Node name in the dictionary to move to, NULL for any nodes.
5268 * @param[in] moveto_mod Expected module of the node, NULL for any.
Michal Vasko6346ece2019-09-24 13:12:53 +02005269 * @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 +02005270 */
5271static LY_ERR
5272moveto_scnode_check(const struct lysc_node *node, enum lyxp_node_type root_type, const char *node_name,
Michal Vaskocafad9d2019-11-07 15:20:03 +01005273 const struct lys_module *moveto_mod)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005274{
Michal Vasko03ff5a72019-09-11 13:49:33 +02005275 /* module check */
Michal Vaskod3678892020-05-21 10:06:58 +02005276 if (moveto_mod && (node->module != moveto_mod)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005277 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005278 }
5279
5280 /* context check */
5281 if ((root_type == LYXP_NODE_ROOT_CONFIG) && (node->flags & LYS_CONFIG_R)) {
5282 return LY_EINVAL;
5283 }
5284
5285 /* name check */
Michal Vaskod3678892020-05-21 10:06:58 +02005286 if (node_name && (node->name != node_name)) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005287 return LY_ENOT;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005288 }
5289
5290 /* match */
5291 return LY_SUCCESS;
5292}
5293
5294/**
Michal Vaskod3678892020-05-21 10:06:58 +02005295 * @brief Move context @p set to a node. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY). Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005296 *
5297 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005298 * @param[in] mod Matching node module, NULL for any.
5299 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005300 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5301 */
5302static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005303moveto_node(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005304{
Michal Vaskof03ed032020-03-04 13:31:44 +01005305 uint32_t i;
Michal Vasko6346ece2019-09-24 13:12:53 +02005306 int replaced;
Michal Vaskod3678892020-05-21 10:06:58 +02005307 const struct lyd_node *siblings, *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005308 LY_ERR rc;
5309
Michal Vaskod3678892020-05-21 10:06:58 +02005310 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005311 return LY_SUCCESS;
5312 }
5313
5314 if (set->type != LYXP_SET_NODE_SET) {
5315 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5316 return LY_EVALID;
5317 }
5318
Michal Vasko03ff5a72019-09-11 13:49:33 +02005319 for (i = 0; i < set->used; ) {
5320 replaced = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02005321 siblings = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005322
5323 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 +01005324 assert(!set->val.nodes[i].node);
Michal Vaskod3678892020-05-21 10:06:58 +02005325
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005326 /* search in all the trees */
Michal Vaskod3678892020-05-21 10:06:58 +02005327 siblings = set->tree;
Michal Vasko5c4e5892019-11-14 12:31:38 +01005328 } else if (!(set->val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskod3678892020-05-21 10:06:58 +02005329 /* search in children */
5330 siblings = lyd_node_children(set->val.nodes[i].node);
5331 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005332
Michal Vaskod3678892020-05-21 10:06:58 +02005333 for (sub = siblings; sub; sub = sub->next) {
5334 rc = moveto_node_check(sub, set->root_type, ncname, mod);
5335 if (rc == LY_SUCCESS) {
5336 if (!replaced) {
5337 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5338 replaced = 1;
5339 } else {
5340 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005341 }
Michal Vaskod3678892020-05-21 10:06:58 +02005342 ++i;
5343 } else if (rc == LY_EINCOMPLETE) {
5344 return rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005345 }
5346 }
5347
5348 if (!replaced) {
5349 /* no match */
5350 set_remove_node(set, i);
5351 }
5352 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005353
5354 return LY_SUCCESS;
5355}
5356
5357/**
Michal Vaskod3678892020-05-21 10:06:58 +02005358 * @brief Move context @p set to a node using hashes. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
5359 * Context position aware.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005360 *
5361 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005362 * @param[in] scnode Matching node schema.
5363 * @param[in] list_inst If @p scnode is ::LYS_LIST, the matching list instance. Ignored otherwise.
5364 * @param[in] llist_val If @p scnode is ::LYS_LEAFLIST, the matching leaf-list value. Ignored otherwise.
5365 * @param[in] llist_val_len Length of @p llist_val.
5366 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5367 */
5368static LY_ERR
5369moveto_node_hash(struct lyxp_set *set, const struct lysc_node *scnode, const struct lyd_node *list_inst,
5370 const char *llist_val, uint16_t llist_val_len)
5371{
5372 uint32_t i;
5373 int replaced;
5374 const struct lyd_node *siblings;
5375 struct lyd_node *sub;
5376
5377 assert(scnode && ((scnode->nodetype != LYS_LIST) || list_inst) && ((scnode->nodetype != LYS_LEAFLIST) || llist_val));
5378
5379 if (!set) {
5380 return LY_SUCCESS;
5381 }
5382
5383 if (set->type != LYXP_SET_NODE_SET) {
5384 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5385 return LY_EVALID;
5386 }
5387
5388 /* context check for all the nodes since we have the schema node */
5389 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (scnode->flags & LYS_CONFIG_R)) {
5390 lyxp_set_free_content(set);
5391 return LY_SUCCESS;
5392 }
5393
5394 for (i = 0; i < set->used; ) {
5395 replaced = 0;
5396 siblings = NULL;
5397
5398 if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
5399 assert(!set->val.nodes[i].node);
5400
5401 /* search in all the trees */
5402 siblings = set->tree;
5403 } else if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
5404 /* search in children */
5405 siblings = lyd_node_children(set->val.nodes[i].node);
5406 }
5407
5408 /* find the node using hashes */
5409 if (scnode->nodetype == LYS_LIST) {
5410 lyd_find_sibling_first(siblings, list_inst, &sub);
5411 } else {
5412 lyd_find_sibling_val(siblings, scnode, llist_val, llist_val_len, &sub);
5413 }
5414
5415 /* when check */
5416 if (sub && moveto_when_check(sub)) {
5417 return LY_EINCOMPLETE;
5418 }
5419
5420 if (sub) {
5421 /* pos filled later */
5422 if (!replaced) {
5423 set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
5424 replaced = 1;
5425 } else {
5426 set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
5427 }
5428 ++i;
5429 }
5430
5431 if (!replaced) {
5432 /* no match */
5433 set_remove_node(set, i);
5434 }
5435 }
5436
5437 return LY_SUCCESS;
5438}
5439
5440/**
5441 * @brief Move context @p set to a schema node. Result is LYXP_SET_SCNODE_SET (or LYXP_SET_EMPTY).
5442 *
5443 * @param[in,out] set Set to use.
5444 * @param[in] mod Matching node module, NULL for any.
5445 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005446 * @param[in] options XPath options.
5447 * @return LY_ERR
5448 */
5449static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005450moveto_scnode(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005451{
Michal Vaskocafad9d2019-11-07 15:20:03 +01005452 int i, orig_used, idx, temp_ctx = 0, getnext_opts;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005453 uint32_t mod_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005454 const struct lysc_node *sub, *start_parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005455
Michal Vaskod3678892020-05-21 10:06:58 +02005456 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005457 return LY_SUCCESS;
5458 }
5459
5460 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005461 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 +02005462 return LY_EVALID;
5463 }
5464
Michal Vaskocafad9d2019-11-07 15:20:03 +01005465 /* getnext opts */
5466 getnext_opts = LYS_GETNEXT_NOSTATECHECK;
5467 if (options & LYXP_SCNODE_OUTPUT) {
5468 getnext_opts |= LYS_GETNEXT_OUTPUT;
5469 }
5470
Michal Vasko03ff5a72019-09-11 13:49:33 +02005471 orig_used = set->used;
5472 for (i = 0; i < orig_used; ++i) {
5473 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005474 if (set->val.scnodes[i].in_ctx != -2) {
5475 continue;
5476 }
5477
5478 /* remember context node */
5479 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005480 } else {
5481 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005482 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005483
5484 start_parent = set->val.scnodes[i].scnode;
5485
5486 if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
Michal Vaskod3678892020-05-21 10:06:58 +02005487 /* it can actually be in any module, it's all <running>, but we know it's mod (if set),
Michal Vasko03ff5a72019-09-11 13:49:33 +02005488 * so use it directly (root node itself is useless in this case) */
5489 mod_idx = 0;
Michal Vaskod3678892020-05-21 10:06:58 +02005490 while (mod || (mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005491 sub = NULL;
Michal Vasko509de4d2019-12-10 14:51:30 +01005492 /* module may not be implemented */
Michal Vaskod3678892020-05-21 10:06:58 +02005493 while (mod->implemented && (sub = lys_getnext(sub, NULL, mod->compiled, getnext_opts))) {
5494 if (!moveto_scnode_check(sub, set->root_type, ncname, mod)) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005495 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005496 /* we need to prevent these nodes from being considered in this moveto */
5497 if ((idx < orig_used) && (idx > i)) {
5498 set->val.scnodes[idx].in_ctx = 2;
5499 temp_ctx = 1;
5500 }
5501 }
5502 }
5503
5504 if (!mod_idx) {
Michal Vaskod3678892020-05-21 10:06:58 +02005505 /* mod was specified, we are not going through the whole context */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005506 break;
5507 }
5508 /* next iteration */
Michal Vaskod3678892020-05-21 10:06:58 +02005509 mod = NULL;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005510 }
5511
5512 /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
5513 } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5514 sub = NULL;
Michal Vaskocafad9d2019-11-07 15:20:03 +01005515 while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
Michal Vaskod3678892020-05-21 10:06:58 +02005516 if (!moveto_scnode_check(sub, set->root_type, ncname, (mod ? mod : set->local_mod))) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005517 idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005518 if ((idx < orig_used) && (idx > i)) {
5519 set->val.scnodes[idx].in_ctx = 2;
5520 temp_ctx = 1;
5521 }
5522 }
5523 }
5524 }
5525 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005526
5527 /* correct temporary in_ctx values */
5528 if (temp_ctx) {
5529 for (i = 0; i < orig_used; ++i) {
5530 if (set->val.scnodes[i].in_ctx == 2) {
5531 set->val.scnodes[i].in_ctx = 1;
5532 }
5533 }
5534 }
5535
5536 return LY_SUCCESS;
5537}
5538
5539/**
Michal Vaskod3678892020-05-21 10:06:58 +02005540 * @brief Move context @p set to a node and all its descendants. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
Michal Vasko03ff5a72019-09-11 13:49:33 +02005541 * Context position aware.
5542 *
5543 * @param[in] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005544 * @param[in] mod Matching node module, NULL for any.
5545 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005546 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5547 */
5548static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005549moveto_node_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005550{
5551 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005552 const struct lyd_node *next, *elem, *start;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005553 struct lyxp_set ret_set;
5554 LY_ERR rc;
5555
Michal Vaskod3678892020-05-21 10:06:58 +02005556 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005557 return LY_SUCCESS;
5558 }
5559
5560 if (set->type != LYXP_SET_NODE_SET) {
5561 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5562 return LY_EVALID;
5563 }
5564
Michal Vasko9f96a052020-03-10 09:41:45 +01005565 /* replace the original nodes (and throws away all text and meta nodes, root is replaced by a child) */
Michal Vaskod3678892020-05-21 10:06:58 +02005566 rc = moveto_node(set, NULL, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005567 LY_CHECK_RET(rc);
5568
Michal Vasko6346ece2019-09-24 13:12:53 +02005569 /* this loop traverses all the nodes in the set and adds/keeps only those that match qname */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005570 set_init(&ret_set, set);
5571 for (i = 0; i < set->used; ++i) {
5572
5573 /* TREE DFS */
5574 start = set->val.nodes[i].node;
5575 for (elem = next = start; elem; elem = next) {
Michal Vaskod3678892020-05-21 10:06:58 +02005576 rc = moveto_node_check(elem, set->root_type, ncname, mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005577 if (!rc) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005578 /* add matching node into result set */
5579 set_insert_node(&ret_set, elem, 0, LYXP_NODE_ELEM, ret_set.used);
5580 if (set_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) {
5581 /* the node is a duplicate, we'll process it later in the set */
5582 goto skip_children;
5583 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005584 } else if (rc == LY_EINCOMPLETE) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005585 return rc;
5586 } else if (rc == LY_EINVAL) {
5587 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005588 }
5589
5590 /* TREE DFS NEXT ELEM */
5591 /* select element for the next run - children first */
Michal Vaskod3678892020-05-21 10:06:58 +02005592 next = lyd_node_children(elem);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005593 if (!next) {
5594skip_children:
5595 /* no children, so try siblings, but only if it's not the start,
5596 * that is considered to be the root and it's siblings are not traversed */
5597 if (elem != start) {
5598 next = elem->next;
5599 } else {
5600 break;
5601 }
5602 }
5603 while (!next) {
5604 /* no siblings, go back through the parents */
5605 if ((struct lyd_node *)elem->parent == start) {
5606 /* we are done, no next element to process */
5607 break;
5608 }
5609 /* parent is already processed, go to its sibling */
5610 elem = (struct lyd_node *)elem->parent;
5611 next = elem->next;
5612 }
5613 }
5614 }
5615
5616 /* make the temporary set the current one */
5617 ret_set.ctx_pos = set->ctx_pos;
5618 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02005619 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005620 memcpy(set, &ret_set, sizeof *set);
5621
5622 return LY_SUCCESS;
5623}
5624
5625/**
Michal Vaskod3678892020-05-21 10:06:58 +02005626 * @brief Move context @p set to a schema node and all its descendants. Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
Michal Vasko03ff5a72019-09-11 13:49:33 +02005627 *
5628 * @param[in] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005629 * @param[in] mod Matching node module, NULL for any.
5630 * @param[in] ncname Matching node name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005631 * @param[in] options XPath options.
5632 * @return LY_ERR
5633 */
5634static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005635moveto_scnode_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005636{
Michal Vasko6346ece2019-09-24 13:12:53 +02005637 int i, orig_used, idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005638 const struct lysc_node *next, *elem, *start;
Michal Vasko6346ece2019-09-24 13:12:53 +02005639 LY_ERR rc;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005640
Michal Vaskod3678892020-05-21 10:06:58 +02005641 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005642 return LY_SUCCESS;
5643 }
5644
5645 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01005646 LOGVAL(set->ctx, LY_VLOG_LYSC, set->ctx_scnode, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005647 return LY_EVALID;
5648 }
5649
Michal Vasko03ff5a72019-09-11 13:49:33 +02005650 orig_used = set->used;
5651 for (i = 0; i < orig_used; ++i) {
5652 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01005653 if (set->val.scnodes[i].in_ctx != -2) {
5654 continue;
5655 }
5656
5657 /* remember context node */
5658 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01005659 } else {
5660 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005661 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005662
5663 /* TREE DFS */
5664 start = set->val.scnodes[i].scnode;
5665 for (elem = next = start; elem; elem = next) {
Michal Vasko6346ece2019-09-24 13:12:53 +02005666 if ((elem == start) || (elem->nodetype & (LYS_CHOICE | LYS_CASE))) {
5667 /* schema-only nodes, skip root */
Michal Vasko03ff5a72019-09-11 13:49:33 +02005668 goto next_iter;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005669 }
5670
Michal Vaskod3678892020-05-21 10:06:58 +02005671 rc = moveto_scnode_check(elem, set->root_type, ncname, mod);
Michal Vasko6346ece2019-09-24 13:12:53 +02005672 if (!rc) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005673 if ((idx = lyxp_set_scnode_dup_node_check(set, elem, LYXP_NODE_ELEM, i)) > -1) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005674 set->val.scnodes[idx].in_ctx = 1;
5675 if (idx > i) {
5676 /* we will process it later in the set */
5677 goto skip_children;
5678 }
5679 } else {
Michal Vaskoecd62de2019-11-13 12:35:11 +01005680 lyxp_set_scnode_insert_node(set, elem, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005681 }
Michal Vasko6346ece2019-09-24 13:12:53 +02005682 } else if (rc == LY_EINVAL) {
5683 goto skip_children;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005684 }
5685
5686next_iter:
5687 /* TREE DFS NEXT ELEM */
5688 /* select element for the next run - children first */
5689 next = lysc_node_children(elem, options & LYXP_SCNODE_OUTPUT ? LYS_CONFIG_R : LYS_CONFIG_W);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005690 if (!next) {
5691skip_children:
5692 /* no children, so try siblings, but only if it's not the start,
5693 * that is considered to be the root and it's siblings are not traversed */
5694 if (elem != start) {
5695 next = elem->next;
5696 } else {
5697 break;
5698 }
5699 }
5700 while (!next) {
5701 /* no siblings, go back through the parents */
5702 if (elem->parent == start) {
5703 /* we are done, no next element to process */
5704 break;
5705 }
5706 /* parent is already processed, go to its sibling */
5707 elem = elem->parent;
5708 next = elem->next;
5709 }
5710 }
5711 }
5712
5713 return LY_SUCCESS;
5714}
5715
5716/**
Michal Vaskod3678892020-05-21 10:06:58 +02005717 * @brief Move context @p set to an attribute.
5718 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
Michal Vasko03ff5a72019-09-11 13:49:33 +02005719 * Indirectly context position aware.
5720 *
5721 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005722 * @param[in] mod Matching metadata module, NULL for any.
5723 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005724 * @return LY_ERR
5725 */
5726static LY_ERR
Michal Vaskod3678892020-05-21 10:06:58 +02005727moveto_attr(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005728{
5729 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02005730 int replaced;
Michal Vasko9f96a052020-03-10 09:41:45 +01005731 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005732
Michal Vaskod3678892020-05-21 10:06:58 +02005733 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005734 return LY_SUCCESS;
5735 }
5736
5737 if (set->type != LYXP_SET_NODE_SET) {
5738 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5739 return LY_EVALID;
5740 }
5741
Michal Vasko03ff5a72019-09-11 13:49:33 +02005742 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 Vasko9f96a052020-03-10 09:41:45 +01005748 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005749
5750 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02005751 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005752 continue;
5753 }
5754
Michal Vaskod3678892020-05-21 10:06:58 +02005755 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005756 /* match */
5757 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005758 set->val.meta[i].meta = sub;
5759 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005760 /* pos does not change */
5761 replaced = 1;
5762 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005763 set_insert_node(set, (struct lyd_node *)sub, set->val.nodes[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005764 }
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
Michal Vaskod3678892020-05-21 10:06:58 +02005792 if ((set1->type != LYXP_SET_NODE_SET) || (set2->type != LYXP_SET_NODE_SET)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005793 LOGVAL(set1->ctx, LY_VLOG_LYD, set1->ctx_node, LY_VCODE_XP_INOP_2, "union", print_set_type(set1), print_set_type(set2));
5794 return LY_EVALID;
5795 }
5796
5797 /* set2 is empty or both set1 and set2 */
Michal Vaskod3678892020-05-21 10:06:58 +02005798 if (!set2->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005799 return LY_SUCCESS;
5800 }
5801
Michal Vaskod3678892020-05-21 10:06:58 +02005802 if (!set1->used) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005803 memcpy(set1, set2, sizeof *set1);
5804 /* dynamic memory belongs to set1 now, do not free */
Michal Vaskod3678892020-05-21 10:06:58 +02005805 memset(set2, 0, sizeof *set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005806 return LY_SUCCESS;
5807 }
5808
5809 /* we assume sets are sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005810 assert(!set_sort(set1) && !set_sort(set2));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005811
5812 /* sort, remove duplicates */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005813 rc = set_sorted_merge(set1, set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005814 LY_CHECK_RET(rc);
5815
5816 /* final set must be sorted */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005817 assert(!set_sort(set1));
Michal Vasko03ff5a72019-09-11 13:49:33 +02005818
5819 return LY_SUCCESS;
5820}
5821
5822/**
Michal Vaskod3678892020-05-21 10:06:58 +02005823 * @brief Move context @p set to an attribute in any of the descendants.
5824 * Result is LYXP_SET_NODE_SET (or LYXP_SET_EMPTY).
Michal Vasko03ff5a72019-09-11 13:49:33 +02005825 * Context position aware.
5826 *
5827 * @param[in,out] set Set to use.
Michal Vaskod3678892020-05-21 10:06:58 +02005828 * @param[in] mod Matching metadata module, NULL for any.
5829 * @param[in] ncname Matching metadata name in the dictionary, NULL for any.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005830 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5831 */
5832static int
Michal Vaskod3678892020-05-21 10:06:58 +02005833moveto_attr_alldesc(struct lyxp_set *set, const struct lys_module *mod, const char *ncname)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005834{
5835 uint32_t i;
Michal Vaskod3678892020-05-21 10:06:58 +02005836 int replaced;
Michal Vasko9f96a052020-03-10 09:41:45 +01005837 struct lyd_meta *sub;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005838 struct lyxp_set *set_all_desc = NULL;
5839 LY_ERR rc;
5840
Michal Vaskod3678892020-05-21 10:06:58 +02005841 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005842 return LY_SUCCESS;
5843 }
5844
5845 if (set->type != LYXP_SET_NODE_SET) {
5846 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
5847 return LY_EVALID;
5848 }
5849
Michal Vasko03ff5a72019-09-11 13:49:33 +02005850 /* can be optimized similarly to moveto_node_alldesc() and save considerable amount of memory,
5851 * but it likely won't be used much, so it's a waste of time */
5852 /* copy the context */
5853 set_all_desc = set_copy(set);
5854 /* get all descendant nodes (the original context nodes are removed) */
Michal Vaskod3678892020-05-21 10:06:58 +02005855 rc = moveto_node_alldesc(set_all_desc, NULL, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005856 if (rc != LY_SUCCESS) {
5857 lyxp_set_free(set_all_desc);
5858 return rc;
5859 }
5860 /* prepend the original context nodes */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005861 rc = moveto_union(set, set_all_desc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005862 if (rc != LY_SUCCESS) {
5863 lyxp_set_free(set_all_desc);
5864 return rc;
5865 }
5866 lyxp_set_free(set_all_desc);
5867
Michal Vasko03ff5a72019-09-11 13:49:33 +02005868 for (i = 0; i < set->used; ) {
5869 replaced = 0;
5870
5871 /* only attributes of an elem can be in the result, skip all the rest,
5872 * we have all attributes qualified in lyd tree */
5873 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005874 for (sub = set->val.nodes[i].node->meta; sub; sub = sub->next) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005875 /* check "namespace" */
Michal Vaskod3678892020-05-21 10:06:58 +02005876 if (mod && (sub->annotation->module != mod)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005877 continue;
5878 }
5879
Michal Vaskod3678892020-05-21 10:06:58 +02005880 if (!ncname || (sub->name == ncname)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005881 /* match */
5882 if (!replaced) {
Michal Vasko9f96a052020-03-10 09:41:45 +01005883 set->val.meta[i].meta = sub;
5884 set->val.meta[i].type = LYXP_NODE_META;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005885 /* pos does not change */
5886 replaced = 1;
5887 } else {
Michal Vasko9f96a052020-03-10 09:41:45 +01005888 set_insert_node(set, (struct lyd_node *)sub, set->val.meta[i].pos, LYXP_NODE_META, i + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005889 }
5890 ++i;
5891 }
5892 }
5893 }
5894
5895 if (!replaced) {
5896 /* no match */
5897 set_remove_node(set, i);
5898 }
5899 }
5900
5901 return LY_SUCCESS;
5902}
5903
5904/**
5905 * @brief Move context @p set to self and al chilren, recursively. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5906 * (or LYXP_SET_EMPTY). Context position aware.
5907 *
5908 * @param[in] parent Current parent.
5909 * @param[in] parent_pos Position of @p parent.
5910 * @param[in] parent_type Node type of @p parent.
5911 * @param[in,out] to_set Set to use.
5912 * @param[in] dup_check_set Set for checking duplicities.
Michal Vasko03ff5a72019-09-11 13:49:33 +02005913 * @param[in] options XPath options.
5914 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5915 */
5916static LY_ERR
5917moveto_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 +01005918 struct lyxp_set *to_set, const struct lyxp_set *dup_check_set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02005919{
5920 const struct lyd_node *sub;
5921 LY_ERR rc;
5922
5923 switch (parent_type) {
5924 case LYXP_NODE_ROOT:
5925 case LYXP_NODE_ROOT_CONFIG:
5926 /* add the same node but as an element */
5927 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_ELEM, -1)) {
5928 set_insert_node(to_set, parent, 0, LYXP_NODE_ELEM, to_set->used);
5929
5930 /* skip anydata/anyxml and dummy nodes */
Michal Vasko5c4e5892019-11-14 12:31:38 +01005931 if (!(parent->schema->nodetype & LYS_ANYDATA)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005932 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005933 rc = moveto_self_add_children_r(parent, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005934 LY_CHECK_RET(rc);
5935 }
5936 }
5937 break;
5938 case LYXP_NODE_ELEM:
5939 /* add all the children ... */
5940 if (!(parent->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
5941 for (sub = lyd_node_children(parent); sub; sub = sub->next) {
5942 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005943 if ((to_set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->schema->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005944 continue;
5945 }
5946
Michal Vaskoa1424542019-11-14 16:08:52 +01005947 /* when check */
5948 if (moveto_when_check(sub)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005949 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01005950 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02005951
5952 if (!set_dup_node_check(dup_check_set, sub, LYXP_NODE_ELEM, -1)) {
5953 set_insert_node(to_set, sub, 0, LYXP_NODE_ELEM, to_set->used);
5954
Michal Vasko5c4e5892019-11-14 12:31:38 +01005955 /* skip anydata/anyxml nodes */
5956 if (sub->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005957 continue;
5958 }
5959
5960 /* also add all the children of this node, recursively */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01005961 rc = moveto_self_add_children_r(sub, 0, LYXP_NODE_ELEM, to_set, dup_check_set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02005962 LY_CHECK_RET(rc);
5963 }
5964 }
5965
5966 /* ... or add their text node, ... */
5967 } else {
5968 if (!set_dup_node_check(dup_check_set, parent, LYXP_NODE_TEXT, -1)) {
5969 set_insert_node(to_set, parent, parent_pos, LYXP_NODE_TEXT, to_set->used);
5970 }
5971 }
5972 break;
5973 default:
5974 LOGINT_RET(parent->schema->module->ctx);
5975 }
5976
5977 return LY_SUCCESS;
5978}
5979
5980/**
5981 * @brief Move context @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_NODE_SET
5982 * (or LYXP_SET_EMPTY). Context position aware.
5983 *
5984 * @param[in,out] set Set to use.
5985 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
5986 * @param[in] options XPath options.
5987 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
5988 */
5989static LY_ERR
5990moveto_self(struct lyxp_set *set, int all_desc, int options)
5991{
5992 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02005993 struct lyxp_set ret_set;
5994 LY_ERR rc;
5995
Michal Vaskod3678892020-05-21 10:06:58 +02005996 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02005997 return LY_SUCCESS;
5998 }
5999
6000 if (set->type != LYXP_SET_NODE_SET) {
6001 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6002 return LY_EVALID;
6003 }
6004
6005 /* nothing to do */
6006 if (!all_desc) {
6007 return LY_SUCCESS;
6008 }
6009
Michal Vasko03ff5a72019-09-11 13:49:33 +02006010 /* add all the children, they get added recursively */
6011 set_init(&ret_set, set);
6012 for (i = 0; i < set->used; ++i) {
6013 /* copy the current node to tmp */
6014 set_insert_node(&ret_set, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, ret_set.used);
6015
6016 /* do not touch attributes and text nodes */
Michal Vasko9f96a052020-03-10 09:41:45 +01006017 if ((set->val.nodes[i].type == LYXP_NODE_TEXT) || (set->val.nodes[i].type == LYXP_NODE_META)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006018 continue;
6019 }
6020
Michal Vasko5c4e5892019-11-14 12:31:38 +01006021 /* skip anydata/anyxml nodes */
6022 if (set->val.nodes[i].node->schema->nodetype & LYS_ANYDATA) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006023 continue;
6024 }
6025
6026 /* add all the children */
6027 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 +01006028 set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006029 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006030 lyxp_set_free_content(&ret_set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006031 return rc;
6032 }
6033 }
6034
6035 /* use the temporary set as the current one */
6036 ret_set.ctx_pos = set->ctx_pos;
6037 ret_set.ctx_size = set->ctx_size;
Michal Vaskod3678892020-05-21 10:06:58 +02006038 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006039 memcpy(set, &ret_set, sizeof *set);
6040
6041 return LY_SUCCESS;
6042}
6043
6044/**
6045 * @brief Move context schema @p set to self. Handles '/' or '//' and '.'. Result is LYXP_SET_SCNODE_SET
6046 * (or LYXP_SET_EMPTY).
6047 *
6048 * @param[in,out] set Set to use.
6049 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6050 * @param[in] options XPath options.
6051 * @return LY_ERR
6052 */
6053static LY_ERR
6054moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
6055{
6056 const struct lysc_node *sub;
6057 uint32_t i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006058
Michal Vaskod3678892020-05-21 10:06:58 +02006059 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006060 return LY_SUCCESS;
6061 }
6062
6063 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006064 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 +02006065 return LY_EVALID;
6066 }
6067
6068 /* nothing to do */
6069 if (!all_desc) {
6070 return LY_SUCCESS;
6071 }
6072
Michal Vasko03ff5a72019-09-11 13:49:33 +02006073 /* add all the children, they get added recursively */
6074 for (i = 0; i < set->used; ++i) {
6075 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006076 if (set->val.scnodes[i].in_ctx != -2) {
6077 continue;
6078 }
6079
6080 /* remember context node (it was traversed again so it changes to a normal node) */
6081 set->val.scnodes[i].in_ctx = 1;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006082 }
6083
6084 /* add all the children */
6085 if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
6086 sub = NULL;
6087 while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
6088 /* RPC input/output check */
6089 if (options & LYXP_SCNODE_OUTPUT) {
6090 if (sub->parent->nodetype == LYS_INPUT) {
6091 continue;
6092 }
6093 } else {
6094 if (sub->parent->nodetype == LYS_OUTPUT) {
6095 continue;
6096 }
6097 }
6098
6099 /* context check */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006100 if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006101 continue;
6102 }
6103
Michal Vaskoecd62de2019-11-13 12:35:11 +01006104 lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006105 /* throw away the insert index, we want to consider that node again, recursively */
6106 }
6107 }
6108 }
6109
6110 return LY_SUCCESS;
6111}
6112
6113/**
6114 * @brief Move context @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_NODE_SET
6115 * (or LYXP_SET_EMPTY). Context position aware.
6116 *
6117 * @param[in] set Set to use.
6118 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6119 * @param[in] options XPath options.
6120 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6121 */
6122static LY_ERR
6123moveto_parent(struct lyxp_set *set, int all_desc, int options)
6124{
6125 LY_ERR rc;
6126 uint32_t i;
6127 struct lyd_node *node, *new_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006128 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006129
Michal Vaskod3678892020-05-21 10:06:58 +02006130 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006131 return LY_SUCCESS;
6132 }
6133
6134 if (set->type != LYXP_SET_NODE_SET) {
6135 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INOP_1, "path operator", print_set_type(set));
6136 return LY_EVALID;
6137 }
6138
6139 if (all_desc) {
6140 /* <path>//.. == <path>//./.. */
6141 rc = moveto_self(set, 1, options);
6142 LY_CHECK_RET(rc);
6143 }
6144
Michal Vasko57eab132019-09-24 11:46:26 +02006145 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006146 node = set->val.nodes[i].node;
6147
6148 if (set->val.nodes[i].type == LYXP_NODE_ELEM) {
6149 new_node = (struct lyd_node *)node->parent;
6150 } else if (set->val.nodes[i].type == LYXP_NODE_TEXT) {
6151 new_node = node;
Michal Vasko9f96a052020-03-10 09:41:45 +01006152 } else if (set->val.nodes[i].type == LYXP_NODE_META) {
6153 new_node = set->val.meta[i].meta->parent;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006154 if (!new_node) {
6155 LOGINT_RET(set->ctx);
6156 }
6157 } else {
6158 /* root does not have a parent */
Michal Vasko2caefc12019-11-14 16:07:56 +01006159 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006160 continue;
6161 }
6162
Michal Vaskoa1424542019-11-14 16:08:52 +01006163 /* when check */
6164 if (moveto_when_check(new_node)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006165 return LY_EINCOMPLETE;
Michal Vaskoa1424542019-11-14 16:08:52 +01006166 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006167
6168 /* node already there can also be the root */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006169 if (!new_node) {
6170 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006171
6172 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6173 } else {
6174 new_type = LYXP_NODE_ELEM;
6175 }
6176
Michal Vasko03ff5a72019-09-11 13:49:33 +02006177 if (set_dup_node_check(set, new_node, new_type, -1)) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006178 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006179 } else {
6180 set_replace_node(set, new_node, 0, new_type, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006181 }
6182 }
6183
Michal Vasko2caefc12019-11-14 16:07:56 +01006184 set_remove_nodes_none(set);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006185 assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006186
6187 return LY_SUCCESS;
6188}
6189
6190/**
6191 * @brief Move context schema @p set to parent. Handles '/' or '//' and '..'. Result is LYXP_SET_SCNODE_SET
6192 * (or LYXP_SET_EMPTY).
6193 *
6194 * @param[in] set Set to use.
6195 * @param[in] all_desc Whether to go to all descendants ('//') or not ('/').
6196 * @param[in] options XPath options.
6197 * @return LY_ERR
6198 */
6199static LY_ERR
6200moveto_scnode_parent(struct lyxp_set *set, int all_desc, int options)
6201{
6202 int idx, i, orig_used, temp_ctx = 0;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006203 const struct lysc_node *node, *new_node;
6204 enum lyxp_node_type new_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006205 LY_ERR rc;
6206
Michal Vaskod3678892020-05-21 10:06:58 +02006207 if (!set) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006208 return LY_SUCCESS;
6209 }
6210
6211 if (set->type != LYXP_SET_SCNODE_SET) {
Michal Vaskof6e51882019-12-16 09:59:45 +01006212 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 +02006213 return LY_EVALID;
6214 }
6215
6216 if (all_desc) {
6217 /* <path>//.. == <path>//./.. */
6218 rc = moveto_scnode_self(set, 1, options);
6219 LY_CHECK_RET(rc);
6220 }
6221
Michal Vasko03ff5a72019-09-11 13:49:33 +02006222 orig_used = set->used;
6223 for (i = 0; i < orig_used; ++i) {
6224 if (set->val.scnodes[i].in_ctx != 1) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01006225 if (set->val.scnodes[i].in_ctx != -2) {
6226 continue;
6227 }
6228
6229 /* remember context node */
6230 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoec4df482019-12-16 10:02:18 +01006231 } else {
6232 set->val.scnodes[i].in_ctx = 0;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006233 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02006234
6235 node = set->val.scnodes[i].scnode;
6236
6237 if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vaskod3678892020-05-21 10:06:58 +02006238 new_node = lysc_data_parent(node);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006239 } else {
6240 /* root does not have a parent */
6241 continue;
6242 }
6243
Michal Vasko03ff5a72019-09-11 13:49:33 +02006244 /* node has no parent */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006245 if (!new_node) {
6246 new_type = set->root_type;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006247
6248 /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
6249 } else {
6250 new_type = LYXP_NODE_ELEM;
6251 }
6252
Michal Vaskoecd62de2019-11-13 12:35:11 +01006253 idx = lyxp_set_scnode_insert_node(set, new_node, new_type);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006254 if ((idx < orig_used) && (idx > i)) {
6255 set->val.scnodes[idx].in_ctx = 2;
6256 temp_ctx = 1;
6257 }
6258 }
6259
6260 if (temp_ctx) {
6261 for (i = 0; i < orig_used; ++i) {
6262 if (set->val.scnodes[i].in_ctx == 2) {
6263 set->val.scnodes[i].in_ctx = 1;
6264 }
6265 }
6266 }
6267
6268 return LY_SUCCESS;
6269}
6270
6271/**
6272 * @brief Move context @p set to the result of a comparison. Handles '=', '!=', '<=', '<', '>=', or '>'.
6273 * Result is LYXP_SET_BOOLEAN. Indirectly context position aware.
6274 *
6275 * @param[in,out] set1 Set to use for the result.
6276 * @param[in] set2 Set acting as the second operand for @p op.
6277 * @param[in] op Comparison operator to process.
6278 * @param[in] options XPath options.
6279 * @return LY_ERR
6280 */
6281static LY_ERR
6282moveto_op_comp(struct lyxp_set *set1, struct lyxp_set *set2, const char *op, int options)
6283{
6284 /*
6285 * NODE SET + NODE SET = NODE SET + STRING /(1 NODE SET) 2 STRING
6286 * NODE SET + STRING = STRING + STRING /1 STRING (2 STRING)
6287 * NODE SET + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6288 * NODE SET + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6289 * STRING + NODE SET = STRING + STRING /(1 STRING) 2 STRING
6290 * NUMBER + NODE SET = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6291 * BOOLEAN + NODE SET = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6292 *
6293 * '=' or '!='
6294 * BOOLEAN + BOOLEAN
6295 * BOOLEAN + STRING = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6296 * BOOLEAN + NUMBER = BOOLEAN + BOOLEAN /(1 BOOLEAN) 2 BOOLEAN
6297 * STRING + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6298 * NUMBER + BOOLEAN = BOOLEAN + BOOLEAN /1 BOOLEAN (2 BOOLEAN)
6299 * NUMBER + NUMBER
6300 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6301 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6302 * STRING + STRING
6303 *
6304 * '<=', '<', '>=', '>'
6305 * NUMBER + NUMBER
6306 * BOOLEAN + BOOLEAN = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6307 * BOOLEAN + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6308 * BOOLEAN + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6309 * NUMBER + STRING = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6310 * STRING + STRING = NUMBER + NUMBER /1 NUMBER, 2 NUMBER
6311 * STRING + NUMBER = NUMBER + NUMBER /1 NUMBER (2 NUMBER)
6312 * NUMBER + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6313 * STRING + BOOLEAN = NUMBER + NUMBER /(1 NUMBER) 2 NUMBER
6314 */
6315 struct lyxp_set iter1, iter2;
6316 int result;
6317 int64_t i;
6318 LY_ERR rc;
6319
Michal Vaskod3678892020-05-21 10:06:58 +02006320 iter1.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006321
6322 /* iterative evaluation with node-sets */
6323 if ((set1->type == LYXP_SET_NODE_SET) || (set2->type == LYXP_SET_NODE_SET)) {
6324 if (set1->type == LYXP_SET_NODE_SET) {
6325 for (i = 0; i < set1->used; ++i) {
6326 switch (set2->type) {
6327 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006328 rc = set_comp_cast(&iter1, set1, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006329 break;
6330 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006331 rc = set_comp_cast(&iter1, set1, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006332 break;
6333 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006334 rc = set_comp_cast(&iter1, set1, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006335 break;
6336 }
6337 LY_CHECK_RET(rc);
6338
6339 rc = moveto_op_comp(&iter1, set2, op, options);
6340 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006341 lyxp_set_free_content(&iter1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006342 return rc;
6343 }
6344
6345 /* lazy evaluation until true */
6346 if (iter1.val.bool) {
6347 set_fill_boolean(set1, 1);
6348 return LY_SUCCESS;
6349 }
6350 }
6351 } else {
6352 for (i = 0; i < set2->used; ++i) {
6353 switch (set1->type) {
6354 case LYXP_SET_NUMBER:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006355 rc = set_comp_cast(&iter2, set2, LYXP_SET_NUMBER, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006356 break;
6357 case LYXP_SET_BOOLEAN:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006358 rc = set_comp_cast(&iter2, set2, LYXP_SET_BOOLEAN, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006359 break;
6360 default:
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006361 rc = set_comp_cast(&iter2, set2, LYXP_SET_STRING, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006362 break;
6363 }
6364 LY_CHECK_RET(rc);
6365
6366 set_fill_set(&iter1, set1);
6367
6368 rc = moveto_op_comp(&iter1, &iter2, op, options);
6369 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006370 lyxp_set_free_content(&iter1);
6371 lyxp_set_free_content(&iter2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006372 return rc;
6373 }
Michal Vaskod3678892020-05-21 10:06:58 +02006374 lyxp_set_free_content(&iter2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006375
6376 /* lazy evaluation until true */
6377 if (iter1.val.bool) {
6378 set_fill_boolean(set1, 1);
6379 return LY_SUCCESS;
6380 }
6381 }
6382 }
6383
6384 /* false for all nodes */
6385 set_fill_boolean(set1, 0);
6386 return LY_SUCCESS;
6387 }
6388
6389 /* first convert properly */
6390 if ((op[0] == '=') || (op[0] == '!')) {
6391 if ((set1->type == LYXP_SET_BOOLEAN) || (set2->type == LYXP_SET_BOOLEAN)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006392 lyxp_set_cast(set1, LYXP_SET_BOOLEAN);
6393 lyxp_set_cast(set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006394 } else if ((set1->type == LYXP_SET_NUMBER) || (set2->type == LYXP_SET_NUMBER)) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006395 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006396 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006397 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006398 LY_CHECK_RET(rc);
6399 } /* else we have 2 strings */
6400 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006401 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006402 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006403 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006404 LY_CHECK_RET(rc);
6405 }
6406
6407 assert(set1->type == set2->type);
6408
6409 /* compute result */
6410 if (op[0] == '=') {
6411 if (set1->type == LYXP_SET_BOOLEAN) {
6412 result = (set1->val.bool == set2->val.bool);
6413 } else if (set1->type == LYXP_SET_NUMBER) {
6414 result = (set1->val.num == set2->val.num);
6415 } else {
6416 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006417 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006418 }
6419 } else if (op[0] == '!') {
6420 if (set1->type == LYXP_SET_BOOLEAN) {
6421 result = (set1->val.bool != set2->val.bool);
6422 } else if (set1->type == LYXP_SET_NUMBER) {
6423 result = (set1->val.num != set2->val.num);
6424 } else {
6425 assert(set1->type == LYXP_SET_STRING);
Michal Vaskoac6c72f2019-11-14 16:09:34 +01006426 result = !strcmp(set1->val.str, set2->val.str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006427 }
6428 } else {
6429 assert(set1->type == LYXP_SET_NUMBER);
6430 if (op[0] == '<') {
6431 if (op[1] == '=') {
6432 result = (set1->val.num <= set2->val.num);
6433 } else {
6434 result = (set1->val.num < set2->val.num);
6435 }
6436 } else {
6437 if (op[1] == '=') {
6438 result = (set1->val.num >= set2->val.num);
6439 } else {
6440 result = (set1->val.num > set2->val.num);
6441 }
6442 }
6443 }
6444
6445 /* assign result */
6446 if (result) {
6447 set_fill_boolean(set1, 1);
6448 } else {
6449 set_fill_boolean(set1, 0);
6450 }
6451
6452 return LY_SUCCESS;
6453}
6454
6455/**
6456 * @brief Move context @p set to the result of a basic operation. Handles '+', '-', unary '-', '*', 'div',
6457 * or 'mod'. Result is LYXP_SET_NUMBER. Indirectly context position aware.
6458 *
6459 * @param[in,out] set1 Set to use for the result.
6460 * @param[in] set2 Set acting as the second operand for @p op.
6461 * @param[in] op Operator to process.
Michal Vasko03ff5a72019-09-11 13:49:33 +02006462 * @return LY_ERR
6463 */
6464static LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006465moveto_op_math(struct lyxp_set *set1, struct lyxp_set *set2, const char *op)
Michal Vasko03ff5a72019-09-11 13:49:33 +02006466{
6467 LY_ERR rc;
6468
6469 /* unary '-' */
6470 if (!set2 && (op[0] == '-')) {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006471 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006472 LY_CHECK_RET(rc);
6473 set1->val.num *= -1;
6474 lyxp_set_free(set2);
6475 return LY_SUCCESS;
6476 }
6477
6478 assert(set1 && set2);
6479
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006480 rc = lyxp_set_cast(set1, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006481 LY_CHECK_RET(rc);
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006482 rc = lyxp_set_cast(set2, LYXP_SET_NUMBER);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006483 LY_CHECK_RET(rc);
6484
6485 switch (op[0]) {
6486 /* '+' */
6487 case '+':
6488 set1->val.num += set2->val.num;
6489 break;
6490
6491 /* '-' */
6492 case '-':
6493 set1->val.num -= set2->val.num;
6494 break;
6495
6496 /* '*' */
6497 case '*':
6498 set1->val.num *= set2->val.num;
6499 break;
6500
6501 /* 'div' */
6502 case 'd':
6503 set1->val.num /= set2->val.num;
6504 break;
6505
6506 /* 'mod' */
6507 case 'm':
6508 set1->val.num = ((long long)set1->val.num) % ((long long)set2->val.num);
6509 break;
6510
6511 default:
6512 LOGINT_RET(set1->ctx);
6513 }
6514
6515 return LY_SUCCESS;
6516}
6517
6518/*
6519 * eval functions
6520 *
6521 * They execute a parsed XPath expression on some data subtree.
6522 */
6523
6524/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02006525 * @brief Evaluate Predicate. Logs directly on error.
6526 *
Michal Vaskod3678892020-05-21 10:06:58 +02006527 * [9] Predicate ::= '[' Expr ']'
Michal Vasko03ff5a72019-09-11 13:49:33 +02006528 *
6529 * @param[in] exp Parsed XPath expression.
6530 * @param[in] exp_idx Position in the expression @p exp.
6531 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6532 * @param[in] options XPath options.
6533 * @param[in] parent_pos_pred Whether parent predicate was a positional one.
6534 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
6535 */
6536static LY_ERR
6537eval_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options, int parent_pos_pred)
6538{
6539 LY_ERR rc;
Michal Vasko57eab132019-09-24 11:46:26 +02006540 uint16_t i, orig_exp;
Michal Vasko5c4e5892019-11-14 12:31:38 +01006541 uint32_t orig_pos, orig_size;
6542 int32_t pred_in_ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006543 struct lyxp_set set2;
6544 struct lyd_node *orig_parent;
6545
6546 /* '[' */
6547 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6548 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6549 ++(*exp_idx);
6550
6551 if (!set) {
6552only_parse:
6553 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
6554 LY_CHECK_RET(rc);
6555 } else if (set->type == LYXP_SET_NODE_SET) {
6556 /* 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 +01006557 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02006558
6559 /* empty set, nothing to evaluate */
6560 if (!set->used) {
6561 goto only_parse;
6562 }
6563
6564 orig_exp = *exp_idx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006565 orig_pos = 0;
6566 orig_size = set->used;
6567 orig_parent = NULL;
Michal Vasko39dbf352020-05-21 10:08:59 +02006568 for (i = 0; i < set->used; ++i) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02006569 set_init(&set2, set);
6570 set_insert_node(&set2, set->val.nodes[i].node, set->val.nodes[i].pos, set->val.nodes[i].type, 0);
6571 /* remember the node context position for position() and context size for last(),
6572 * predicates should always be evaluated with respect to the child axis (since we do
6573 * not support explicit axes) so we assign positions based on their parents */
6574 if (parent_pos_pred && ((struct lyd_node *)set->val.nodes[i].node->parent != orig_parent)) {
6575 orig_parent = (struct lyd_node *)set->val.nodes[i].node->parent;
6576 orig_pos = 1;
6577 } else {
6578 ++orig_pos;
6579 }
6580
6581 set2.ctx_pos = orig_pos;
6582 set2.ctx_size = orig_size;
6583 *exp_idx = orig_exp;
6584
6585 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6586 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006587 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006588 return rc;
6589 }
6590
6591 /* number is a position */
6592 if (set2.type == LYXP_SET_NUMBER) {
6593 if ((long long)set2.val.num == orig_pos) {
6594 set2.val.num = 1;
6595 } else {
6596 set2.val.num = 0;
6597 }
6598 }
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006599 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006600
6601 /* predicate satisfied or not? */
Michal Vasko57eab132019-09-24 11:46:26 +02006602 if (!set2.val.bool) {
Michal Vasko2caefc12019-11-14 16:07:56 +01006603 set_remove_node_none(set, i);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006604 }
6605 }
Michal Vasko2caefc12019-11-14 16:07:56 +01006606 set_remove_nodes_none(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006607
6608 } else if (set->type == LYXP_SET_SCNODE_SET) {
6609 for (i = 0; i < set->used; ++i) {
6610 if (set->val.scnodes[i].in_ctx == 1) {
6611 /* there is a currently-valid node */
6612 break;
6613 }
6614 }
6615 /* empty set, nothing to evaluate */
6616 if (i == set->used) {
6617 goto only_parse;
6618 }
6619
6620 orig_exp = *exp_idx;
6621
Michal Vasko03ff5a72019-09-11 13:49:33 +02006622 /* set special in_ctx to all the valid snodes */
6623 pred_in_ctx = set_scnode_new_in_ctx(set);
6624
6625 /* use the valid snodes one-by-one */
6626 for (i = 0; i < set->used; ++i) {
6627 if (set->val.scnodes[i].in_ctx != pred_in_ctx) {
6628 continue;
6629 }
6630 set->val.scnodes[i].in_ctx = 1;
6631
6632 *exp_idx = orig_exp;
6633
6634 rc = eval_expr_select(exp, exp_idx, 0, set, options);
6635 LY_CHECK_RET(rc);
6636
6637 set->val.scnodes[i].in_ctx = pred_in_ctx;
6638 }
6639
6640 /* restore the state as it was before the predicate */
6641 for (i = 0; i < set->used; ++i) {
6642 if (set->val.scnodes[i].in_ctx == 1) {
6643 set->val.scnodes[i].in_ctx = 0;
6644 } else if (set->val.scnodes[i].in_ctx == pred_in_ctx) {
6645 set->val.scnodes[i].in_ctx = 1;
6646 }
6647 }
6648
6649 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02006650 set2.type = LYXP_SET_NODE_SET;
Michal Vasko03ff5a72019-09-11 13:49:33 +02006651 set_fill_set(&set2, set);
6652
6653 rc = eval_expr_select(exp, exp_idx, 0, &set2, options);
6654 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02006655 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006656 return rc;
6657 }
6658
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01006659 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006660 if (!set2.val.bool) {
Michal Vaskod3678892020-05-21 10:06:58 +02006661 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006662 }
Michal Vaskod3678892020-05-21 10:06:58 +02006663 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02006664 }
6665
6666 /* ']' */
6667 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK2);
6668 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6669 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6670 ++(*exp_idx);
6671
6672 return LY_SUCCESS;
6673}
6674
6675/**
Michal Vaskod3678892020-05-21 10:06:58 +02006676 * @brief Evaluate Literal. Logs directly on error.
6677 *
6678 * @param[in] exp Parsed XPath expression.
6679 * @param[in] exp_idx Position in the expression @p exp.
6680 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
6681 */
6682static void
6683eval_literal(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
6684{
6685 if (set) {
6686 if (exp->tok_len[*exp_idx] == 2) {
6687 set_fill_string(set, "", 0);
6688 } else {
6689 set_fill_string(set, &exp->expr[exp->tok_pos[*exp_idx] + 1], exp->tok_len[*exp_idx] - 2);
6690 }
6691 }
6692 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6693 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6694 ++(*exp_idx);
6695}
6696
6697/**
6698 * @brief Check and parse a predicate following a leaf-list to extract its value.
6699 * On success all the used tokens are skipped.
6700 *
6701 * @param[in] exp Parsed XPath expression.
6702 * @param[in] exp_idx Position in the expression @p exp.
6703 * @param[out] val Leaf-list value on success.
6704 * @param[out] val_len Length of @p val.
6705 * @return LY_ERR
6706 */
6707static LY_ERR
6708eval_name_test_parse_leaflist_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, const char **val, uint16_t *val_len)
6709{
6710 uint16_t cur_idx;
6711
6712 cur_idx = *exp_idx;
6713
6714 /* '[' */
6715 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK1)) {
6716 return LY_EINVAL;
6717 }
6718 ++cur_idx;
6719
6720 /* '.' */
6721 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_DOT)) {
6722 return LY_EINVAL;
6723 }
6724 ++cur_idx;
6725
6726 /* '=' */
6727 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_OPERATOR_COMP)
6728 || (exp->expr[exp->tok_pos[cur_idx]] != '=')) {
6729 return LY_EINVAL;
6730 }
6731 ++cur_idx;
6732
6733 /* value */
6734 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_LITERAL)) {
6735 return LY_EINVAL;
6736 }
6737 ++cur_idx;
6738
6739 /* ']' */
6740 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK2)) {
6741 return LY_EINVAL;
6742 }
6743 ++cur_idx;
6744
6745 /* success */
6746 *val = &exp->expr[exp->tok_pos[cur_idx - 2] + 1];
6747 *val_len = exp->tok_len[cur_idx - 2] - 2;
6748 *exp_idx = cur_idx;
6749 return LY_SUCCESS;
6750}
6751
6752/**
6753 * @brief Check and parse a predicate following a list to make sure all the tokens are as expected (all key values defined).
6754 * On success all the used tokens are skipped.
6755 *
6756 * @param[in] exp Parsed XPath expression.
6757 * @param[in] exp_idx Position in the expression @p exp.
6758 * @param[in] slist Schema node of the list.
6759 * @param[out] val Leaf-list value on success.
6760 * @param[out] val_len Length of @p val.
6761 * @return LY_ERR
6762 */
6763static LY_ERR
6764eval_name_test_parse_list_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, const struct lysc_node *slist,
6765 const char **keys, uint16_t *keys_len)
6766{
6767 uint16_t key_count, i, cur_idx;
6768 const struct lysc_node *key;
6769
6770 if (slist->flags & LYS_KEYLESS) {
6771 /* invalid */
6772 return LY_EINVAL;
6773 }
6774
6775 /* get key count */
6776 key_count = 0;
6777 for (key = lysc_node_children(slist, 0); key && (key->flags & LYS_KEY); key = key->next) {
6778 ++key_count;
6779 }
6780
6781 /* briefly check the predicate for each key */
6782 cur_idx = *exp_idx;
6783 for (i = 0; i < key_count; ++i) {
6784 /* '[' */
6785 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK1)) {
6786 return LY_EINVAL;
6787 }
6788 ++cur_idx;
6789
6790 /* key-name */
6791 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_NAMETEST)) {
6792 return LY_EINVAL;
6793 }
6794 ++cur_idx;
6795
6796 /* '=' */
6797 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_OPERATOR_COMP)
6798 || (exp->expr[exp->tok_pos[cur_idx]] != '=')) {
6799 return LY_EINVAL;
6800 }
6801 ++cur_idx;
6802
6803 /* key-value */
6804 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_LITERAL)) {
6805 return LY_EINVAL;
6806 }
6807 ++cur_idx;
6808
6809 /* ']' */
6810 if ((exp->used == cur_idx) || (exp->tokens[cur_idx] != LYXP_TOKEN_BRACK2)) {
6811 return LY_EINVAL;
6812 }
6813 ++cur_idx;
6814 }
6815
6816 /* success */
6817 *keys = &exp->expr[exp->tok_pos[*exp_idx]];
6818 *keys_len = (exp->expr + exp->tok_pos[cur_idx - 1] + exp->tok_len[cur_idx - 1]) - *keys;
6819 *exp_idx = cur_idx;
6820 return LY_SUCCESS;
6821}
6822
6823/**
6824 * @brief Evaluate NameTest and any following Predicates. Logs directly on error.
6825 *
6826 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6827 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6828 * [7] NameTest ::= '*' | NCName ':' '*' | QName
6829 *
6830 * @param[in] exp Parsed XPath expression.
6831 * @param[in] exp_idx Position in the expression @p exp.
6832 * @param[in] attr_axis Whether to search attributes or standard nodes.
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 (LY_EINCOMPLETE on unresolved when)
6837 */
6838static LY_ERR
6839eval_name_test_with_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc, struct lyxp_set *set,
6840 int options)
6841{
6842 int i;
6843 char *path;
6844 const char *ncname = NULL, *key_val = NULL;
6845 uint16_t ncname_len, key_val_len, prev_exp_idx;
6846 const struct lys_module *moveto_mod;
6847 const struct lysc_node *scnode = NULL, *tmp;
6848 struct lyd_node *list_inst = NULL;
6849 LY_ERR rc = LY_SUCCESS;
6850
6851 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
6852 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
6853 ++(*exp_idx);
6854
6855 if (!set) {
6856 goto moveto;
6857 }
6858
6859 ncname = &exp->expr[exp->tok_pos[*exp_idx - 1]];
6860 ncname_len = exp->tok_len[*exp_idx - 1];
6861
6862 /* parse (and skip) module name */
6863 rc = moveto_resolve_model(&ncname, &ncname_len, set, &moveto_mod);
6864 LY_CHECK_GOTO(rc, cleanup);
6865
6866 if (moveto_mod && !attr_axis && !all_desc && (set->type == LYXP_SET_NODE_SET)) {
6867 /* find the matching schema node in some parent in the context */
6868 for (i = 0; i < (signed)set->used; ++i) {
6869 if (set->val.nodes[i].type == set->root_type) {
6870 tmp = lys_find_child(NULL, moveto_mod, ncname, ncname_len, 0, 0);
6871 } else if ((set->val.nodes[i].type == LYXP_NODE_ELEM)
6872 && (!scnode || (lysc_data_parent(scnode) != set->val.nodes[i].node->schema))) {
6873 /* do not repeat the same search */
6874 tmp = lys_find_child(set->val.nodes[i].node->schema, moveto_mod, ncname, ncname_len, 0, 0);
6875 }
6876
6877 /* additional context check */
6878 if (tmp && (set->root_type == LYXP_NODE_ROOT_CONFIG) && (tmp->flags & LYS_CONFIG_R)) {
6879 tmp = NULL;
6880 }
6881
6882 if (tmp) {
6883 if (scnode) {
6884 /* we found a schema node with the same name but at different level, give up, too complicated */
6885 scnode = NULL;
6886 break;
6887 } else {
6888 /* remember the found schema node and continue to make sure it can be used */
6889 scnode = tmp;
6890 }
6891 tmp = NULL;
6892 }
6893 }
6894
6895 if (scnode && (scnode->nodetype == LYS_LIST)) {
6896 /* make sure all the tokens are right */
6897 prev_exp_idx = *exp_idx;
6898 if (eval_name_test_parse_list_predicate(exp, exp_idx, scnode, &key_val, &key_val_len)) {
6899 scnode = NULL;
6900 }
6901
6902 /* try to create a list instance */
6903 if (scnode && lyd_create_list(scnode, key_val, key_val_len, set->format, 0, &list_inst)) {
6904 /* for whatever reason the list failed to be created, just use standard name comparison and
6905 * parse predicate normally */
6906 *exp_idx = prev_exp_idx;
6907 scnode = NULL;
6908 }
6909 } else if (scnode && (scnode->nodetype == LYS_LEAFLIST)) {
6910 /* make sure we know the leaf-list value */
6911 if (eval_name_test_parse_leaflist_predicate(exp, exp_idx, &key_val, &key_val_len)) {
6912 /* value could not be recognized, use standard name comparison */
6913 scnode = NULL;
6914 }
6915 }
6916 }
6917
6918 if (!scnode) {
6919 /* we are not able to match based on a schema node */
6920 if (!moveto_mod) {
6921 /* '*', all nodes match */
6922 ncname = NULL;
6923 } else {
6924 /* insert name into dictionary for efficient comparison */
6925 ncname = lydict_insert(set->ctx, ncname, ncname_len);
6926 }
6927 }
6928
6929moveto:
6930 /* move to the attribute(s), data node(s), or schema node(s) */
6931 if (attr_axis) {
6932 if (set && (options & LYXP_SCNODE_ALL)) {
6933 set_scnode_clear_ctx(set);
6934 } else {
6935 if (all_desc) {
6936 rc = moveto_attr_alldesc(set, moveto_mod, ncname);
6937 } else {
6938 rc = moveto_attr(set, moveto_mod, ncname);
6939 }
6940 LY_CHECK_GOTO(rc, cleanup);
6941 }
6942 } else {
6943 if (set && (options & LYXP_SCNODE_ALL)) {
6944 if (all_desc) {
6945 rc = moveto_scnode_alldesc(set, moveto_mod, ncname, options);
6946 } else {
6947 rc = moveto_scnode(set, moveto_mod, ncname, options);
6948 }
6949 LY_CHECK_GOTO(rc, cleanup);
6950
6951 for (i = set->used - 1; i > -1; --i) {
6952 if (set->val.scnodes[i].in_ctx > 0) {
6953 break;
6954 }
6955 }
6956 if (i == -1) {
6957 path = lysc_path(set->ctx_scnode, LYSC_PATH_LOG, NULL, 0);
6958 LOGWRN(set->ctx, "Schema node \"%.*s\" not found (%.*s) with context node \"%s\".",
6959 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]],
6960 exp->tok_pos[*exp_idx] + exp->tok_len[*exp_idx], exp->expr, path);
6961 free(path);
6962 }
6963 } else {
6964 if (all_desc) {
6965 rc = moveto_node_alldesc(set, moveto_mod, ncname);
6966 } else {
6967 if (scnode) {
6968 /* we can find the nodes using hashes */
6969 rc = moveto_node_hash(set, scnode, list_inst, key_val, key_val_len);
6970 } else {
6971 rc = moveto_node(set, moveto_mod, ncname);
6972 }
6973 }
6974 LY_CHECK_GOTO(rc, cleanup);
6975 }
6976 }
6977
6978 /* Predicate* */
6979 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
6980 rc = eval_predicate(exp, exp_idx, set, options, 1);
6981 LY_CHECK_RET(rc);
6982 }
6983
6984cleanup:
6985 lydict_remove(set->ctx, ncname);
6986 lyd_free_tree(list_inst);
6987 return rc;
6988}
6989
6990/**
6991 * @brief Evaluate NodeType and any following Predicates. Logs directly on error.
6992 *
6993 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
6994 * [6] NodeTest ::= NameTest | NodeType '(' ')'
6995 * [8] NodeType ::= 'text' | 'node'
6996 *
6997 * @param[in] exp Parsed XPath expression.
6998 * @param[in] exp_idx Position in the expression @p exp.
6999 * @param[in] attr_axis Whether to search attributes or standard nodes.
7000 * @param[in] all_desc Whether to search all the descendants or children only.
7001 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7002 * @param[in] options XPath options.
7003 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7004 */
7005static LY_ERR
7006eval_node_type_with_predicate(struct lyxp_expr *exp, uint16_t *exp_idx, int attr_axis, int all_desc,
7007 struct lyxp_set *set, int options)
7008{
7009 LY_ERR rc;
7010
7011 /* TODO */
7012 (void)attr_axis;
7013 (void)all_desc;
7014
7015 if (set) {
7016 assert(exp->tok_len[*exp_idx] == 4);
7017 if (set->type == LYXP_SET_SCNODE_SET) {
7018 set_scnode_clear_ctx(set);
7019 /* just for the debug message below */
7020 set = NULL;
7021 } else {
7022 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "node", 4)) {
7023 rc = xpath_node(NULL, 0, set, options);
7024 } else {
7025 assert(!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "text", 4));
7026 rc = xpath_text(NULL, 0, set, options);
7027 }
7028 LY_CHECK_RET(rc);
7029 }
7030 }
7031 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7032 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7033 ++(*exp_idx);
7034
7035 /* '(' */
7036 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7037 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7038 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7039 ++(*exp_idx);
7040
7041 /* ')' */
7042 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7043 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7044 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7045 ++(*exp_idx);
7046
7047 /* Predicate* */
7048 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7049 rc = eval_predicate(exp, exp_idx, set, options, 1);
7050 LY_CHECK_RET(rc);
7051 }
7052
7053 return LY_SUCCESS;
7054}
7055
7056/**
Michal Vasko03ff5a72019-09-11 13:49:33 +02007057 * @brief Evaluate RelativeLocationPath. Logs directly on error.
7058 *
7059 * [4] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
7060 * [5] Step ::= '@'? NodeTest Predicate* | '.' | '..'
Michal Vaskod3678892020-05-21 10:06:58 +02007061 * [6] NodeTest ::= NameTest | NodeType '(' ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007062 *
7063 * @param[in] exp Parsed XPath expression.
7064 * @param[in] exp_idx Position in the expression @p exp.
7065 * @param[in] all_desc Whether to search all the descendants or children only.
7066 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7067 * @param[in] options XPath options.
7068 * @return LY_ERR (YL_EINCOMPLETE on unresolved when)
7069 */
7070static LY_ERR
7071eval_relative_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, int all_desc, struct lyxp_set *set, int options)
7072{
7073 int attr_axis;
7074 LY_ERR rc;
7075
7076 goto step;
7077 do {
7078 /* evaluate '/' or '//' */
7079 if (exp->tok_len[*exp_idx] == 1) {
7080 all_desc = 0;
7081 } else {
7082 assert(exp->tok_len[*exp_idx] == 2);
7083 all_desc = 1;
7084 }
7085 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7086 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7087 ++(*exp_idx);
7088
7089step:
Michal Vaskod3678892020-05-21 10:06:58 +02007090 /* evaluate abbreviated axis '@'? if any */
7091 if (exp->tokens[*exp_idx] == LYXP_TOKEN_AT) {
7092 attr_axis = 1;
7093
7094 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7095 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7096 ++(*exp_idx);
7097 } else {
7098 attr_axis = 0;
7099 }
7100
Michal Vasko03ff5a72019-09-11 13:49:33 +02007101 /* Step */
Michal Vasko03ff5a72019-09-11 13:49:33 +02007102 switch (exp->tokens[*exp_idx]) {
7103 case LYXP_TOKEN_DOT:
7104 /* evaluate '.' */
7105 if (set && (options & LYXP_SCNODE_ALL)) {
7106 rc = moveto_scnode_self(set, all_desc, options);
7107 } else {
7108 rc = moveto_self(set, all_desc, options);
7109 }
7110 LY_CHECK_RET(rc);
7111 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7112 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7113 ++(*exp_idx);
7114 break;
7115
7116 case LYXP_TOKEN_DDOT:
7117 /* evaluate '..' */
7118 if (set && (options & LYXP_SCNODE_ALL)) {
7119 rc = moveto_scnode_parent(set, all_desc, options);
7120 } else {
7121 rc = moveto_parent(set, all_desc, options);
7122 }
7123 LY_CHECK_RET(rc);
7124 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7125 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7126 ++(*exp_idx);
7127 break;
7128
Michal Vasko03ff5a72019-09-11 13:49:33 +02007129 case LYXP_TOKEN_NAMETEST:
Michal Vaskod3678892020-05-21 10:06:58 +02007130 /* evaluate NameTest Predicate* */
7131 rc = eval_name_test_with_predicate(exp, exp_idx, attr_axis, all_desc, set, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007132 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02007133 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007134
Michal Vaskod3678892020-05-21 10:06:58 +02007135 case LYXP_TOKEN_NODETYPE:
7136 /* evaluate NodeType Predicate* */
7137 rc = eval_node_type_with_predicate(exp, exp_idx, attr_axis, all_desc, set, options);
7138 LY_CHECK_RET(rc);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007139 break;
7140
7141 default:
Michal Vasko02a77382019-09-12 11:47:35 +02007142 LOGINT_RET(set ? set->ctx : NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007143 }
7144 } while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH));
7145
7146 return LY_SUCCESS;
7147}
7148
7149/**
7150 * @brief Evaluate AbsoluteLocationPath. Logs directly on error.
7151 *
7152 * [3] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
7153 *
7154 * @param[in] exp Parsed XPath expression.
7155 * @param[in] exp_idx Position in the expression @p exp.
7156 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7157 * @param[in] options XPath options.
7158 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7159 */
7160static LY_ERR
7161eval_absolute_location_path(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7162{
7163 int all_desc;
7164 LY_ERR rc;
7165
7166 if (set) {
7167 /* no matter what tokens follow, we need to be at the root */
7168 moveto_root(set, options);
7169 }
7170
7171 /* '/' RelativeLocationPath? */
7172 if (exp->tok_len[*exp_idx] == 1) {
7173 /* evaluate '/' - deferred */
7174 all_desc = 0;
7175 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7176 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7177 ++(*exp_idx);
7178
Michal Vasko4b9e1052019-09-13 11:25:37 +02007179 if (exp_check_token(set ? set->ctx : NULL, exp, *exp_idx, LYXP_TOKEN_NONE, 0)) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007180 return LY_SUCCESS;
7181 }
7182 switch (exp->tokens[*exp_idx]) {
7183 case LYXP_TOKEN_DOT:
7184 case LYXP_TOKEN_DDOT:
7185 case LYXP_TOKEN_AT:
7186 case LYXP_TOKEN_NAMETEST:
7187 case LYXP_TOKEN_NODETYPE:
7188 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7189 LY_CHECK_RET(rc);
7190 break;
7191 default:
7192 break;
7193 }
7194
7195 /* '//' RelativeLocationPath */
7196 } else {
7197 /* evaluate '//' - deferred so as not to waste memory by remembering all the nodes */
7198 all_desc = 1;
7199 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7200 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7201 ++(*exp_idx);
7202
7203 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7204 LY_CHECK_RET(rc);
7205 }
7206
7207 return LY_SUCCESS;
7208}
7209
7210/**
7211 * @brief Evaluate FunctionCall. Logs directly on error.
7212 *
Michal Vaskod3678892020-05-21 10:06:58 +02007213 * [11] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
Michal Vasko03ff5a72019-09-11 13:49:33 +02007214 *
7215 * @param[in] exp Parsed XPath expression.
7216 * @param[in] exp_idx Position in the expression @p exp.
7217 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7218 * @param[in] options XPath options.
7219 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7220 */
7221static LY_ERR
7222eval_function_call(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7223{
7224 LY_ERR rc;
7225 LY_ERR (*xpath_func)(struct lyxp_set **, uint16_t, struct lyxp_set *, int) = NULL;
Michal Vasko0cbf54f2019-12-16 10:01:06 +01007226 uint16_t arg_count = 0, i;
Michal Vasko03ff5a72019-09-11 13:49:33 +02007227 struct lyxp_set **args = NULL, **args_aux;
7228
7229 if (set) {
7230 /* FunctionName */
7231 switch (exp->tok_len[*exp_idx]) {
7232 case 3:
7233 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "not", 3)) {
7234 xpath_func = &xpath_not;
7235 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "sum", 3)) {
7236 xpath_func = &xpath_sum;
7237 }
7238 break;
7239 case 4:
7240 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "lang", 4)) {
7241 xpath_func = &xpath_lang;
7242 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "last", 4)) {
7243 xpath_func = &xpath_last;
7244 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "name", 4)) {
7245 xpath_func = &xpath_name;
7246 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "true", 4)) {
7247 xpath_func = &xpath_true;
7248 }
7249 break;
7250 case 5:
7251 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "count", 5)) {
7252 xpath_func = &xpath_count;
7253 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "false", 5)) {
7254 xpath_func = &xpath_false;
7255 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "floor", 5)) {
7256 xpath_func = &xpath_floor;
7257 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "round", 5)) {
7258 xpath_func = &xpath_round;
7259 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "deref", 5)) {
7260 xpath_func = &xpath_deref;
7261 }
7262 break;
7263 case 6:
7264 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "concat", 6)) {
7265 xpath_func = &xpath_concat;
7266 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "number", 6)) {
7267 xpath_func = &xpath_number;
7268 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string", 6)) {
7269 xpath_func = &xpath_string;
7270 }
7271 break;
7272 case 7:
7273 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "boolean", 7)) {
7274 xpath_func = &xpath_boolean;
7275 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "ceiling", 7)) {
7276 xpath_func = &xpath_ceiling;
7277 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "current", 7)) {
7278 xpath_func = &xpath_current;
7279 }
7280 break;
7281 case 8:
7282 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "contains", 8)) {
7283 xpath_func = &xpath_contains;
7284 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "position", 8)) {
7285 xpath_func = &xpath_position;
7286 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "re-match", 8)) {
7287 xpath_func = &xpath_re_match;
7288 }
7289 break;
7290 case 9:
7291 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring", 9)) {
7292 xpath_func = &xpath_substring;
7293 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "translate", 9)) {
7294 xpath_func = &xpath_translate;
7295 }
7296 break;
7297 case 10:
7298 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "local-name", 10)) {
7299 xpath_func = &xpath_local_name;
7300 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "enum-value", 10)) {
7301 xpath_func = &xpath_enum_value;
7302 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "bit-is-set", 10)) {
7303 xpath_func = &xpath_bit_is_set;
7304 }
7305 break;
7306 case 11:
7307 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "starts-with", 11)) {
7308 xpath_func = &xpath_starts_with;
7309 }
7310 break;
7311 case 12:
7312 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from", 12)) {
7313 xpath_func = &xpath_derived_from;
7314 }
7315 break;
7316 case 13:
7317 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "namespace-uri", 13)) {
7318 xpath_func = &xpath_namespace_uri;
7319 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "string-length", 13)) {
7320 xpath_func = &xpath_string_length;
7321 }
7322 break;
7323 case 15:
7324 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "normalize-space", 15)) {
7325 xpath_func = &xpath_normalize_space;
7326 } else if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-after", 15)) {
7327 xpath_func = &xpath_substring_after;
7328 }
7329 break;
7330 case 16:
7331 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "substring-before", 16)) {
7332 xpath_func = &xpath_substring_before;
7333 }
7334 break;
7335 case 20:
7336 if (!strncmp(&exp->expr[exp->tok_pos[*exp_idx]], "derived-from-or-self", 20)) {
7337 xpath_func = &xpath_derived_from_or_self;
7338 }
7339 break;
7340 }
7341
7342 if (!xpath_func) {
7343 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7344 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]]);
7345 return LY_EVALID;
7346 }
7347 }
7348
7349 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7350 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7351 ++(*exp_idx);
7352
7353 /* '(' */
7354 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR1);
7355 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7356 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7357 ++(*exp_idx);
7358
7359 /* ( Expr ( ',' Expr )* )? */
7360 if (exp->tokens[*exp_idx] != LYXP_TOKEN_PAR2) {
7361 if (set) {
7362 args = malloc(sizeof *args);
7363 LY_CHECK_ERR_GOTO(!args, LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7364 arg_count = 1;
7365 args[0] = set_copy(set);
7366 if (!args[0]) {
7367 rc = LY_EMEM;
7368 goto cleanup;
7369 }
7370
7371 rc = eval_expr_select(exp, exp_idx, 0, args[0], options);
7372 LY_CHECK_GOTO(rc, cleanup);
7373 } else {
7374 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7375 LY_CHECK_GOTO(rc, cleanup);
7376 }
7377 }
7378 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_COMMA)) {
7379 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7380 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7381 ++(*exp_idx);
7382
7383 if (set) {
7384 ++arg_count;
7385 args_aux = realloc(args, arg_count * sizeof *args);
7386 LY_CHECK_ERR_GOTO(!args_aux, arg_count--; LOGMEM(set->ctx); rc = LY_EMEM, cleanup);
7387 args = args_aux;
7388 args[arg_count - 1] = set_copy(set);
7389 if (!args[arg_count - 1]) {
7390 rc = LY_EMEM;
7391 goto cleanup;
7392 }
7393
7394 rc = eval_expr_select(exp, exp_idx, 0, args[arg_count - 1], options);
7395 LY_CHECK_GOTO(rc, cleanup);
7396 } else {
7397 rc = eval_expr_select(exp, exp_idx, 0, NULL, options);
7398 LY_CHECK_GOTO(rc, cleanup);
7399 }
7400 }
7401
7402 /* ')' */
7403 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7404 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7405 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7406 ++(*exp_idx);
7407
7408 if (set) {
7409 /* evaluate function */
7410 rc = xpath_func(args, arg_count, set, options);
7411
7412 if (options & LYXP_SCNODE_ALL) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007413 /* merge all nodes from arg evaluations */
7414 for (i = 0; i < arg_count; ++i) {
7415 set_scnode_clear_ctx(args[i]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007416 lyxp_set_scnode_merge(set, args[i]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007417 }
7418 }
7419 } else {
7420 rc = LY_SUCCESS;
7421 }
7422
7423cleanup:
7424 for (i = 0; i < arg_count; ++i) {
7425 lyxp_set_free(args[i]);
7426 }
7427 free(args);
7428
7429 return rc;
7430}
7431
7432/**
7433 * @brief Evaluate Number. Logs directly on error.
7434 *
7435 * @param[in] ctx Context for errors.
7436 * @param[in] exp Parsed XPath expression.
7437 * @param[in] exp_idx Position in the expression @p exp.
7438 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7439 * @return LY_ERR
7440 */
7441static LY_ERR
7442eval_number(struct ly_ctx *ctx, struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set)
7443{
7444 long double num;
7445 char *endptr;
7446
7447 if (set) {
7448 errno = 0;
7449 num = strtold(&exp->expr[exp->tok_pos[*exp_idx]], &endptr);
7450 if (errno) {
7451 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7452 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double (%s).",
7453 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]], strerror(errno));
7454 return LY_EVALID;
7455 } else if (endptr - &exp->expr[exp->tok_pos[*exp_idx]] != exp->tok_len[*exp_idx]) {
7456 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, "Unknown", &exp->expr[exp->tok_pos[*exp_idx]]);
7457 LOGVAL(ctx, LY_VLOG_LYD, set->ctx_node, LYVE_XPATH, "Failed to convert \"%.*s\" into a long double.",
7458 exp->tok_len[*exp_idx], &exp->expr[exp->tok_pos[*exp_idx]]);
7459 return LY_EVALID;
7460 }
7461
7462 set_fill_number(set, num);
7463 }
7464
7465 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7466 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7467 ++(*exp_idx);
7468 return LY_SUCCESS;
7469}
7470
7471/**
7472 * @brief Evaluate PathExpr. Logs directly on error.
7473 *
Michal Vaskod3678892020-05-21 10:06:58 +02007474 * [12] PathExpr ::= LocationPath | PrimaryExpr Predicate*
Michal Vasko03ff5a72019-09-11 13:49:33 +02007475 * | PrimaryExpr Predicate* '/' RelativeLocationPath
7476 * | PrimaryExpr Predicate* '//' RelativeLocationPath
7477 * [2] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
Michal Vaskod3678892020-05-21 10:06:58 +02007478 * [10] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
Michal Vasko03ff5a72019-09-11 13:49:33 +02007479 *
7480 * @param[in] exp Parsed XPath expression.
7481 * @param[in] exp_idx Position in the expression @p exp.
7482 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7483 * @param[in] options XPath options.
7484 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7485 */
7486static LY_ERR
7487eval_path_expr(struct lyxp_expr *exp, uint16_t *exp_idx, struct lyxp_set *set, int options)
7488{
7489 int all_desc, parent_pos_pred;
7490 LY_ERR rc;
7491
7492 switch (exp->tokens[*exp_idx]) {
7493 case LYXP_TOKEN_PAR1:
7494 /* '(' Expr ')' */
7495
7496 /* '(' */
7497 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7498 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7499 ++(*exp_idx);
7500
7501 /* Expr */
7502 rc = eval_expr_select(exp, exp_idx, 0, set, options);
7503 LY_CHECK_RET(rc);
7504
7505 /* ')' */
7506 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_PAR2);
7507 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7508 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7509 ++(*exp_idx);
7510
7511 parent_pos_pred = 0;
7512 goto predicate;
7513
7514 case LYXP_TOKEN_DOT:
7515 case LYXP_TOKEN_DDOT:
7516 case LYXP_TOKEN_AT:
7517 case LYXP_TOKEN_NAMETEST:
7518 case LYXP_TOKEN_NODETYPE:
7519 /* RelativeLocationPath */
7520 rc = eval_relative_location_path(exp, exp_idx, 0, set, options);
7521 LY_CHECK_RET(rc);
7522 break;
7523
7524 case LYXP_TOKEN_FUNCNAME:
7525 /* FunctionCall */
7526 if (!set) {
7527 rc = eval_function_call(exp, exp_idx, NULL, options);
7528 } else {
7529 rc = eval_function_call(exp, exp_idx, set, options);
7530 }
7531 LY_CHECK_RET(rc);
7532
7533 parent_pos_pred = 1;
7534 goto predicate;
7535
7536 case LYXP_TOKEN_OPERATOR_PATH:
7537 /* AbsoluteLocationPath */
7538 rc = eval_absolute_location_path(exp, exp_idx, set, options);
7539 LY_CHECK_RET(rc);
7540 break;
7541
7542 case LYXP_TOKEN_LITERAL:
7543 /* Literal */
7544 if (!set || (options & LYXP_SCNODE_ALL)) {
7545 if (set) {
7546 set_scnode_clear_ctx(set);
7547 }
7548 eval_literal(exp, exp_idx, NULL);
7549 } else {
7550 eval_literal(exp, exp_idx, set);
7551 }
7552
7553 parent_pos_pred = 1;
7554 goto predicate;
7555
7556 case LYXP_TOKEN_NUMBER:
7557 /* Number */
7558 if (!set || (options & LYXP_SCNODE_ALL)) {
7559 if (set) {
7560 set_scnode_clear_ctx(set);
7561 }
Michal Vasko02a77382019-09-12 11:47:35 +02007562 rc = eval_number(NULL, exp, exp_idx, NULL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007563 } else {
7564 rc = eval_number(set->ctx, exp, exp_idx, set);
7565 }
7566 LY_CHECK_RET(rc);
7567
7568 parent_pos_pred = 1;
7569 goto predicate;
7570
7571 default:
7572 LOGVAL(set->ctx, LY_VLOG_LYD, set->ctx_node, LY_VCODE_XP_INTOK, print_token(exp->tokens[*exp_idx]),
7573 &exp->expr[exp->tok_pos[*exp_idx]]);
7574 return LY_EVALID;
7575 }
7576
7577 return LY_SUCCESS;
7578
7579predicate:
7580 /* Predicate* */
7581 while ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_BRACK1)) {
7582 rc = eval_predicate(exp, exp_idx, set, options, parent_pos_pred);
7583 LY_CHECK_RET(rc);
7584 }
7585
7586 /* ('/' or '//') RelativeLocationPath */
7587 if ((exp->used > *exp_idx) && (exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_PATH)) {
7588
7589 /* evaluate '/' or '//' */
7590 if (exp->tok_len[*exp_idx] == 1) {
7591 all_desc = 0;
7592 } else {
7593 assert(exp->tok_len[*exp_idx] == 2);
7594 all_desc = 1;
7595 }
7596
7597 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7598 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7599 ++(*exp_idx);
7600
7601 rc = eval_relative_location_path(exp, exp_idx, all_desc, set, options);
7602 LY_CHECK_RET(rc);
7603 }
7604
7605 return LY_SUCCESS;
7606}
7607
7608/**
7609 * @brief Evaluate UnionExpr. Logs directly on error.
7610 *
Michal Vaskod3678892020-05-21 10:06:58 +02007611 * [20] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007612 *
7613 * @param[in] exp Parsed XPath expression.
7614 * @param[in] exp_idx Position in the expression @p exp.
7615 * @param[in] repeat How many times this expression is repeated.
7616 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7617 * @param[in] options XPath options.
7618 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7619 */
7620static LY_ERR
7621eval_union_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7622{
7623 LY_ERR rc = LY_SUCCESS;
7624 struct lyxp_set orig_set, set2;
7625 uint16_t i;
7626
7627 assert(repeat);
7628
7629 set_init(&orig_set, set);
7630 set_init(&set2, set);
7631
7632 set_fill_set(&orig_set, set);
7633
7634 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, set, options);
7635 LY_CHECK_GOTO(rc, cleanup);
7636
7637 /* ('|' PathExpr)* */
7638 for (i = 0; i < repeat; ++i) {
7639 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_UNI);
7640 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7641 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7642 ++(*exp_idx);
7643
7644 if (!set) {
7645 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, NULL, options);
7646 LY_CHECK_GOTO(rc, cleanup);
7647 continue;
7648 }
7649
7650 set_fill_set(&set2, &orig_set);
7651 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNION, &set2, options);
7652 LY_CHECK_GOTO(rc, cleanup);
7653
7654 /* eval */
7655 if (options & LYXP_SCNODE_ALL) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007656 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007657 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007658 rc = moveto_union(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007659 LY_CHECK_GOTO(rc, cleanup);
7660 }
7661 }
7662
7663cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007664 lyxp_set_free_content(&orig_set);
7665 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007666 return rc;
7667}
7668
7669/**
7670 * @brief Evaluate UnaryExpr. Logs directly on error.
7671 *
Michal Vaskod3678892020-05-21 10:06:58 +02007672 * [19] UnaryExpr ::= UnionExpr | '-' UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007673 *
7674 * @param[in] exp Parsed XPath expression.
7675 * @param[in] exp_idx Position in the expression @p exp.
7676 * @param[in] repeat How many times this expression is repeated.
7677 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7678 * @param[in] options XPath options.
7679 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7680 */
7681static LY_ERR
7682eval_unary_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7683{
7684 LY_ERR rc;
7685 uint16_t this_op, i;
7686
7687 assert(repeat);
7688
7689 /* ('-')+ */
7690 this_op = *exp_idx;
7691 for (i = 0; i < repeat; ++i) {
7692 assert(!exp_check_token(set->ctx, exp, *exp_idx, LYXP_TOKEN_OPERATOR_MATH, 0) && (exp->expr[exp->tok_pos[*exp_idx]] == '-'));
7693
7694 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7695 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7696 ++(*exp_idx);
7697 }
7698
7699 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_UNARY, set, options);
7700 LY_CHECK_RET(rc);
7701
7702 if (set && (repeat % 2)) {
7703 if (options & LYXP_SCNODE_ALL) {
7704 warn_operands(set->ctx, set, NULL, 1, exp->expr, exp->tok_pos[this_op]);
7705 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007706 rc = moveto_op_math(set, NULL, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007707 LY_CHECK_RET(rc);
7708 }
7709 }
7710
7711 return LY_SUCCESS;
7712}
7713
7714/**
7715 * @brief Evaluate MultiplicativeExpr. Logs directly on error.
7716 *
Michal Vaskod3678892020-05-21 10:06:58 +02007717 * [18] MultiplicativeExpr ::= UnaryExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007718 * | MultiplicativeExpr '*' UnaryExpr
7719 * | MultiplicativeExpr 'div' UnaryExpr
7720 * | MultiplicativeExpr 'mod' UnaryExpr
7721 *
7722 * @param[in] exp Parsed XPath expression.
7723 * @param[in] exp_idx Position in the expression @p exp.
7724 * @param[in] repeat How many times this expression is repeated.
7725 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7726 * @param[in] options XPath options.
7727 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7728 */
7729static LY_ERR
7730eval_multiplicative_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7731{
7732 LY_ERR rc;
7733 uint16_t this_op;
7734 struct lyxp_set orig_set, set2;
7735 uint16_t i;
7736
7737 assert(repeat);
7738
7739 set_init(&orig_set, set);
7740 set_init(&set2, set);
7741
7742 set_fill_set(&orig_set, set);
7743
7744 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, set, options);
7745 LY_CHECK_GOTO(rc, cleanup);
7746
7747 /* ('*' / 'div' / 'mod' UnaryExpr)* */
7748 for (i = 0; i < repeat; ++i) {
7749 this_op = *exp_idx;
7750
7751 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7752 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7753 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7754 ++(*exp_idx);
7755
7756 if (!set) {
7757 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, NULL, options);
7758 LY_CHECK_GOTO(rc, cleanup);
7759 continue;
7760 }
7761
7762 set_fill_set(&set2, &orig_set);
7763 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_MULTIPLICATIVE, &set2, options);
7764 LY_CHECK_GOTO(rc, cleanup);
7765
7766 /* eval */
7767 if (options & LYXP_SCNODE_ALL) {
7768 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007769 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007770 set_scnode_clear_ctx(set);
7771 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007772 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007773 LY_CHECK_GOTO(rc, cleanup);
7774 }
7775 }
7776
7777cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007778 lyxp_set_free_content(&orig_set);
7779 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007780 return rc;
7781}
7782
7783/**
7784 * @brief Evaluate AdditiveExpr. Logs directly on error.
7785 *
Michal Vaskod3678892020-05-21 10:06:58 +02007786 * [17] AdditiveExpr ::= MultiplicativeExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007787 * | AdditiveExpr '+' MultiplicativeExpr
7788 * | AdditiveExpr '-' MultiplicativeExpr
7789 *
7790 * @param[in] exp Parsed XPath expression.
7791 * @param[in] exp_idx Position in the expression @p exp.
7792 * @param[in] repeat How many times this expression is repeated.
7793 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7794 * @param[in] options XPath options.
7795 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7796 */
7797static LY_ERR
7798eval_additive_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7799{
7800 LY_ERR rc;
7801 uint16_t this_op;
7802 struct lyxp_set orig_set, set2;
7803 uint16_t i;
7804
7805 assert(repeat);
7806
7807 set_init(&orig_set, set);
7808 set_init(&set2, set);
7809
7810 set_fill_set(&orig_set, set);
7811
7812 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, set, options);
7813 LY_CHECK_GOTO(rc, cleanup);
7814
7815 /* ('+' / '-' MultiplicativeExpr)* */
7816 for (i = 0; i < repeat; ++i) {
7817 this_op = *exp_idx;
7818
7819 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_MATH);
7820 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7821 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7822 ++(*exp_idx);
7823
7824 if (!set) {
7825 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, NULL, options);
7826 LY_CHECK_GOTO(rc, cleanup);
7827 continue;
7828 }
7829
7830 set_fill_set(&set2, &orig_set);
7831 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_ADDITIVE, &set2, options);
7832 LY_CHECK_GOTO(rc, cleanup);
7833
7834 /* eval */
7835 if (options & LYXP_SCNODE_ALL) {
7836 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007837 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007838 set_scnode_clear_ctx(set);
7839 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01007840 rc = moveto_op_math(set, &set2, &exp->expr[exp->tok_pos[this_op]]);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007841 LY_CHECK_GOTO(rc, cleanup);
7842 }
7843 }
7844
7845cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007846 lyxp_set_free_content(&orig_set);
7847 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007848 return rc;
7849}
7850
7851/**
7852 * @brief Evaluate RelationalExpr. Logs directly on error.
7853 *
Michal Vaskod3678892020-05-21 10:06:58 +02007854 * [16] RelationalExpr ::= AdditiveExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007855 * | RelationalExpr '<' AdditiveExpr
7856 * | RelationalExpr '>' AdditiveExpr
7857 * | RelationalExpr '<=' AdditiveExpr
7858 * | RelationalExpr '>=' AdditiveExpr
7859 *
7860 * @param[in] exp Parsed XPath expression.
7861 * @param[in] exp_idx Position in the expression @p exp.
7862 * @param[in] repeat How many times this expression is repeated.
7863 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7864 * @param[in] options XPath options.
7865 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7866 */
7867static LY_ERR
7868eval_relational_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7869{
7870 LY_ERR rc;
7871 uint16_t this_op;
7872 struct lyxp_set orig_set, set2;
7873 uint16_t i;
7874
7875 assert(repeat);
7876
7877 set_init(&orig_set, set);
7878 set_init(&set2, set);
7879
7880 set_fill_set(&orig_set, set);
7881
7882 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, set, options);
7883 LY_CHECK_GOTO(rc, cleanup);
7884
7885 /* ('<' / '>' / '<=' / '>=' AdditiveExpr)* */
7886 for (i = 0; i < repeat; ++i) {
7887 this_op = *exp_idx;
7888
7889 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7890 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7891 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7892 ++(*exp_idx);
7893
7894 if (!set) {
7895 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, NULL, options);
7896 LY_CHECK_GOTO(rc, cleanup);
7897 continue;
7898 }
7899
7900 set_fill_set(&set2, &orig_set);
7901 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_RELATIONAL, &set2, options);
7902 LY_CHECK_GOTO(rc, cleanup);
7903
7904 /* eval */
7905 if (options & LYXP_SCNODE_ALL) {
7906 warn_operands(set->ctx, set, &set2, 1, exp->expr, exp->tok_pos[this_op - 1]);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007907 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007908 set_scnode_clear_ctx(set);
7909 } else {
7910 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7911 LY_CHECK_GOTO(rc, cleanup);
7912 }
7913 }
7914
7915cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007916 lyxp_set_free_content(&orig_set);
7917 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007918 return rc;
7919}
7920
7921/**
7922 * @brief Evaluate EqualityExpr. Logs directly on error.
7923 *
Michal Vaskod3678892020-05-21 10:06:58 +02007924 * [15] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007925 * | EqualityExpr '!=' RelationalExpr
7926 *
7927 * @param[in] exp Parsed XPath expression.
7928 * @param[in] exp_idx Position in the expression @p exp.
7929 * @param[in] repeat How many times this expression is repeated.
7930 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7931 * @param[in] options XPath options.
7932 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
7933 */
7934static LY_ERR
7935eval_equality_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
7936{
7937 LY_ERR rc;
7938 uint16_t this_op;
7939 struct lyxp_set orig_set, set2;
7940 uint16_t i;
7941
7942 assert(repeat);
7943
7944 set_init(&orig_set, set);
7945 set_init(&set2, set);
7946
7947 set_fill_set(&orig_set, set);
7948
7949 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, set, options);
7950 LY_CHECK_GOTO(rc, cleanup);
7951
7952 /* ('=' / '!=' RelationalExpr)* */
7953 for (i = 0; i < repeat; ++i) {
7954 this_op = *exp_idx;
7955
7956 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_COMP);
7957 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
7958 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
7959 ++(*exp_idx);
7960
7961 if (!set) {
7962 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, NULL, options);
7963 LY_CHECK_GOTO(rc, cleanup);
7964 continue;
7965 }
7966
7967 set_fill_set(&set2, &orig_set);
7968 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_EQUALITY, &set2, options);
7969 LY_CHECK_GOTO(rc, cleanup);
7970
7971 /* eval */
7972 if (options & LYXP_SCNODE_ALL) {
7973 warn_operands(set->ctx, set, &set2, 0, exp->expr, exp->tok_pos[this_op - 1]);
7974 warn_equality_value(exp, set, *exp_idx - 1, this_op - 1, *exp_idx - 1);
7975 warn_equality_value(exp, &set2, this_op - 1, this_op - 1, *exp_idx - 1);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007976 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007977 set_scnode_clear_ctx(set);
7978 } else {
Michal Vasko03ff5a72019-09-11 13:49:33 +02007979 rc = moveto_op_comp(set, &set2, &exp->expr[exp->tok_pos[this_op]], options);
7980 LY_CHECK_GOTO(rc, cleanup);
7981 }
7982 }
7983
7984cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007985 lyxp_set_free_content(&orig_set);
7986 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02007987 return rc;
7988}
7989
7990/**
7991 * @brief Evaluate AndExpr. Logs directly on error.
7992 *
Michal Vaskod3678892020-05-21 10:06:58 +02007993 * [14] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02007994 *
7995 * @param[in] exp Parsed XPath expression.
7996 * @param[in] exp_idx Position in the expression @p exp.
7997 * @param[in] repeat How many times this expression is repeated.
7998 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
7999 * @param[in] options XPath options.
8000 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8001 */
8002static LY_ERR
8003eval_and_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
8004{
8005 LY_ERR rc;
8006 struct lyxp_set orig_set, set2;
8007 uint16_t i;
8008
8009 assert(repeat);
8010
8011 set_init(&orig_set, set);
8012 set_init(&set2, set);
8013
8014 set_fill_set(&orig_set, set);
8015
8016 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, set, options);
8017 LY_CHECK_GOTO(rc, cleanup);
8018
8019 /* cast to boolean, we know that will be the final result */
8020 if (set && (options & LYXP_SCNODE_ALL)) {
8021 set_scnode_clear_ctx(set);
8022 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008023 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008024 }
8025
8026 /* ('and' EqualityExpr)* */
8027 for (i = 0; i < repeat; ++i) {
8028 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
8029 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || !set->val.bool ? "skipped" : "parsed"),
8030 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
8031 ++(*exp_idx);
8032
8033 /* lazy evaluation */
8034 if (!set || ((set->type == LYXP_SET_BOOLEAN) && !set->val.bool)) {
8035 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, NULL, options);
8036 LY_CHECK_GOTO(rc, cleanup);
8037 continue;
8038 }
8039
8040 set_fill_set(&set2, &orig_set);
8041 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_AND, &set2, options);
8042 LY_CHECK_GOTO(rc, cleanup);
8043
8044 /* eval - just get boolean value actually */
8045 if (set->type == LYXP_SET_SCNODE_SET) {
8046 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008047 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008048 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008049 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008050 set_fill_set(set, &set2);
8051 }
8052 }
8053
8054cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008055 lyxp_set_free_content(&orig_set);
8056 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008057 return rc;
8058}
8059
8060/**
8061 * @brief Evaluate OrExpr. Logs directly on error.
8062 *
Michal Vaskod3678892020-05-21 10:06:58 +02008063 * [13] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
Michal Vasko03ff5a72019-09-11 13:49:33 +02008064 *
8065 * @param[in] exp Parsed XPath expression.
8066 * @param[in] exp_idx Position in the expression @p exp.
8067 * @param[in] repeat How many times this expression is repeated.
8068 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8069 * @param[in] options XPath options.
8070 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8071 */
8072static LY_ERR
8073eval_or_expr(struct lyxp_expr *exp, uint16_t *exp_idx, uint16_t repeat, struct lyxp_set *set, int options)
8074{
8075 LY_ERR rc;
8076 struct lyxp_set orig_set, set2;
8077 uint16_t i;
8078
8079 assert(repeat);
8080
8081 set_init(&orig_set, set);
8082 set_init(&set2, set);
8083
8084 set_fill_set(&orig_set, set);
8085
8086 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, set, options);
8087 LY_CHECK_GOTO(rc, cleanup);
8088
8089 /* cast to boolean, we know that will be the final result */
8090 if (set && (options & LYXP_SCNODE_ALL)) {
8091 set_scnode_clear_ctx(set);
8092 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008093 lyxp_set_cast(set, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008094 }
8095
8096 /* ('or' AndExpr)* */
8097 for (i = 0; i < repeat; ++i) {
8098 assert(exp->tokens[*exp_idx] == LYXP_TOKEN_OPERATOR_LOG);
8099 LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (!set || set->val.bool ? "skipped" : "parsed"),
8100 print_token(exp->tokens[*exp_idx]), exp->tok_pos[*exp_idx]);
8101 ++(*exp_idx);
8102
8103 /* lazy evaluation */
8104 if (!set || ((set->type == LYXP_SET_BOOLEAN) && set->val.bool)) {
8105 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, NULL, options);
8106 LY_CHECK_GOTO(rc, cleanup);
8107 continue;
8108 }
8109
8110 set_fill_set(&set2, &orig_set);
8111 /* expr_type cound have been LYXP_EXPR_NONE in all these later calls (except for the first one),
8112 * but it does not matter */
8113 rc = eval_expr_select(exp, exp_idx, LYXP_EXPR_OR, &set2, options);
8114 LY_CHECK_GOTO(rc, cleanup);
8115
8116 /* eval - just get boolean value actually */
8117 if (set->type == LYXP_SET_SCNODE_SET) {
8118 set_scnode_clear_ctx(&set2);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008119 lyxp_set_scnode_merge(set, &set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008120 } else {
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008121 lyxp_set_cast(&set2, LYXP_SET_BOOLEAN);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008122 set_fill_set(set, &set2);
8123 }
8124 }
8125
8126cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02008127 lyxp_set_free_content(&orig_set);
8128 lyxp_set_free_content(&set2);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008129 return rc;
8130}
8131
8132/**
8133 * @brief Decide what expression is at the pointer @p exp_idx and evaluate it accordingly.
8134 *
8135 * @param[in] exp Parsed XPath expression.
8136 * @param[in] exp_idx Position in the expression @p exp.
8137 * @param[in] etype Expression type to evaluate.
8138 * @param[in,out] set Context and result set. On NULL the rule is only parsed.
8139 * @param[in] options XPath options.
8140 * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
8141 */
8142static LY_ERR
8143eval_expr_select(struct lyxp_expr *exp, uint16_t *exp_idx, enum lyxp_expr_type etype, struct lyxp_set *set, int options)
8144{
8145 uint16_t i, count;
8146 enum lyxp_expr_type next_etype;
8147 LY_ERR rc;
8148
8149 /* process operator repeats */
8150 if (!exp->repeat[*exp_idx]) {
8151 next_etype = LYXP_EXPR_NONE;
8152 } else {
8153 /* find etype repeat */
8154 for (i = 0; exp->repeat[*exp_idx][i] > etype; ++i);
8155
8156 /* select one-priority lower because etype expression called us */
8157 if (i) {
8158 next_etype = exp->repeat[*exp_idx][i - 1];
8159 /* count repeats for that expression */
8160 for (count = 0; i && exp->repeat[*exp_idx][i - 1] == next_etype; ++count, --i);
8161 } else {
8162 next_etype = LYXP_EXPR_NONE;
8163 }
8164 }
8165
8166 /* decide what expression are we parsing based on the repeat */
8167 switch (next_etype) {
8168 case LYXP_EXPR_OR:
8169 rc = eval_or_expr(exp, exp_idx, count, set, options);
8170 break;
8171 case LYXP_EXPR_AND:
8172 rc = eval_and_expr(exp, exp_idx, count, set, options);
8173 break;
8174 case LYXP_EXPR_EQUALITY:
8175 rc = eval_equality_expr(exp, exp_idx, count, set, options);
8176 break;
8177 case LYXP_EXPR_RELATIONAL:
8178 rc = eval_relational_expr(exp, exp_idx, count, set, options);
8179 break;
8180 case LYXP_EXPR_ADDITIVE:
8181 rc = eval_additive_expr(exp, exp_idx, count, set, options);
8182 break;
8183 case LYXP_EXPR_MULTIPLICATIVE:
8184 rc = eval_multiplicative_expr(exp, exp_idx, count, set, options);
8185 break;
8186 case LYXP_EXPR_UNARY:
8187 rc = eval_unary_expr(exp, exp_idx, count, set, options);
8188 break;
8189 case LYXP_EXPR_UNION:
8190 rc = eval_union_expr(exp, exp_idx, count, set, options);
8191 break;
8192 case LYXP_EXPR_NONE:
8193 rc = eval_path_expr(exp, exp_idx, set, options);
8194 break;
8195 default:
8196 LOGINT_RET(set->ctx);
8197 }
8198
8199 return rc;
8200}
8201
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008202/**
8203 * @brief Get root type.
8204 *
8205 * @param[in] ctx_node Context node.
8206 * @param[in] ctx_scnode Schema context node.
8207 * @param[in] options XPath options.
8208 * @return Root type.
8209 */
8210static enum lyxp_node_type
8211lyxp_get_root_type(const struct lyd_node *ctx_node, const struct lysc_node *ctx_scnode, int options)
8212{
8213 if (options & LYXP_SCNODE_ALL) {
8214 if (options & LYXP_SCNODE) {
8215 /* general root that can access everything */
8216 return LYXP_NODE_ROOT;
8217 } else if (!ctx_scnode || (ctx_scnode->flags & LYS_CONFIG_W)) {
8218 /* root context node can access only config data (because we said so, it is unspecified) */
8219 return LYXP_NODE_ROOT_CONFIG;
8220 } else {
8221 return LYXP_NODE_ROOT;
8222 }
8223 }
8224
8225 if (!ctx_node || (ctx_node->schema->flags & LYS_CONFIG_W)) {
8226 /* root context node can access only config data (because we said so, it is unspecified) */
8227 return LYXP_NODE_ROOT_CONFIG;
8228 }
8229
8230 return LYXP_NODE_ROOT;
8231}
8232
Michal Vasko03ff5a72019-09-11 13:49:33 +02008233LY_ERR
Michal Vaskoecd62de2019-11-13 12:35:11 +01008234lyxp_eval(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lyd_node *ctx_node,
Michal Vaskof03ed032020-03-04 13:31:44 +01008235 enum lyxp_node_type ctx_node_type, const struct lyd_node *tree, struct lyxp_set *set, int options)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008236{
Michal Vasko03ff5a72019-09-11 13:49:33 +02008237 uint16_t exp_idx = 0;
8238 LY_ERR rc;
8239
Michal Vaskoecd62de2019-11-13 12:35:11 +01008240 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008241
8242 /* prepare set for evaluation */
8243 exp_idx = 0;
8244 memset(set, 0, sizeof *set);
Michal Vaskod3678892020-05-21 10:06:58 +02008245 set->type = LYXP_SET_NODE_SET;
Michal Vasko9b368d32020-02-14 13:53:31 +01008246 set_insert_node(set, (struct lyd_node *)ctx_node, 0, ctx_node_type, 0);
Michal Vaskoecd62de2019-11-13 12:35:11 +01008247 set->ctx = local_mod->ctx;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008248 set->ctx_node = ctx_node;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008249 set->root_type = lyxp_get_root_type(ctx_node, NULL, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008250 set->local_mod = local_mod;
Michal Vaskof03ed032020-03-04 13:31:44 +01008251 set->tree = tree;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008252 set->format = format;
8253
8254 /* evaluate */
8255 rc = eval_expr_select(exp, &exp_idx, 0, set, options);
8256 if (rc != LY_SUCCESS) {
Michal Vaskod3678892020-05-21 10:06:58 +02008257 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008258 }
8259
Michal Vasko03ff5a72019-09-11 13:49:33 +02008260 return rc;
8261}
8262
8263#if 0
8264
8265/* full xml printing of set elements, not used currently */
8266
8267void
8268lyxp_set_print_xml(FILE *f, struct lyxp_set *set)
8269{
8270 uint32_t i;
8271 char *str_num;
8272 struct lyout out;
8273
8274 memset(&out, 0, sizeof out);
8275
8276 out.type = LYOUT_STREAM;
8277 out.method.f = f;
8278
8279 switch (set->type) {
8280 case LYXP_SET_EMPTY:
8281 ly_print(&out, "Empty XPath set\n\n");
8282 break;
8283 case LYXP_SET_BOOLEAN:
8284 ly_print(&out, "Boolean XPath set:\n");
8285 ly_print(&out, "%s\n\n", set->value.bool ? "true" : "false");
8286 break;
8287 case LYXP_SET_STRING:
8288 ly_print(&out, "String XPath set:\n");
8289 ly_print(&out, "\"%s\"\n\n", set->value.str);
8290 break;
8291 case LYXP_SET_NUMBER:
8292 ly_print(&out, "Number XPath set:\n");
8293
8294 if (isnan(set->value.num)) {
8295 str_num = strdup("NaN");
8296 } else if ((set->value.num == 0) || (set->value.num == -0.0f)) {
8297 str_num = strdup("0");
8298 } else if (isinf(set->value.num) && !signbit(set->value.num)) {
8299 str_num = strdup("Infinity");
8300 } else if (isinf(set->value.num) && signbit(set->value.num)) {
8301 str_num = strdup("-Infinity");
8302 } else if ((long long)set->value.num == set->value.num) {
8303 if (asprintf(&str_num, "%lld", (long long)set->value.num) == -1) {
8304 str_num = NULL;
8305 }
8306 } else {
8307 if (asprintf(&str_num, "%03.1Lf", set->value.num) == -1) {
8308 str_num = NULL;
8309 }
8310 }
8311 if (!str_num) {
8312 LOGMEM;
8313 return;
8314 }
8315 ly_print(&out, "%s\n\n", str_num);
8316 free(str_num);
8317 break;
8318 case LYXP_SET_NODE_SET:
8319 ly_print(&out, "Node XPath set:\n");
8320
8321 for (i = 0; i < set->used; ++i) {
8322 ly_print(&out, "%d. ", i + 1);
8323 switch (set->node_type[i]) {
8324 case LYXP_NODE_ROOT_ALL:
8325 ly_print(&out, "ROOT all\n\n");
8326 break;
8327 case LYXP_NODE_ROOT_CONFIG:
8328 ly_print(&out, "ROOT config\n\n");
8329 break;
8330 case LYXP_NODE_ROOT_STATE:
8331 ly_print(&out, "ROOT state\n\n");
8332 break;
8333 case LYXP_NODE_ROOT_NOTIF:
8334 ly_print(&out, "ROOT notification \"%s\"\n\n", set->value.nodes[i]->schema->name);
8335 break;
8336 case LYXP_NODE_ROOT_RPC:
8337 ly_print(&out, "ROOT rpc \"%s\"\n\n", set->value.nodes[i]->schema->name);
8338 break;
8339 case LYXP_NODE_ROOT_OUTPUT:
8340 ly_print(&out, "ROOT output \"%s\"\n\n", set->value.nodes[i]->schema->name);
8341 break;
8342 case LYXP_NODE_ELEM:
8343 ly_print(&out, "ELEM \"%s\"\n", set->value.nodes[i]->schema->name);
8344 xml_print_node(&out, 1, set->value.nodes[i], 1, LYP_FORMAT);
8345 ly_print(&out, "\n");
8346 break;
8347 case LYXP_NODE_TEXT:
8348 ly_print(&out, "TEXT \"%s\"\n\n", ((struct lyd_node_leaf_list *)set->value.nodes[i])->value_str);
8349 break;
8350 case LYXP_NODE_ATTR:
8351 ly_print(&out, "ATTR \"%s\" = \"%s\"\n\n", set->value.attrs[i]->name, set->value.attrs[i]->value);
8352 break;
8353 }
8354 }
8355 break;
8356 }
8357}
8358
8359#endif
8360
8361LY_ERR
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008362lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target)
Michal Vasko03ff5a72019-09-11 13:49:33 +02008363{
8364 long double num;
8365 char *str;
8366 LY_ERR rc;
8367
8368 if (!set || (set->type == target)) {
8369 return LY_SUCCESS;
8370 }
8371
8372 /* it's not possible to convert anything into a node set */
Michal Vaskod3678892020-05-21 10:06:58 +02008373 assert(target != LYXP_SET_NODE_SET);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008374
8375 if (set->type == LYXP_SET_SCNODE_SET) {
Michal Vaskod3678892020-05-21 10:06:58 +02008376 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008377 return LY_EINVAL;
8378 }
8379
8380 /* to STRING */
Michal Vaskod3678892020-05-21 10:06:58 +02008381 if ((target == LYXP_SET_STRING) || ((target == LYXP_SET_NUMBER) && (set->type == LYXP_SET_NODE_SET))) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02008382 switch (set->type) {
8383 case LYXP_SET_NUMBER:
8384 if (isnan(set->val.num)) {
8385 set->val.str = strdup("NaN");
8386 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8387 } else if ((set->val.num == 0) || (set->val.num == -0.0f)) {
8388 set->val.str = strdup("0");
8389 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8390 } else if (isinf(set->val.num) && !signbit(set->val.num)) {
8391 set->val.str = strdup("Infinity");
8392 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8393 } else if (isinf(set->val.num) && signbit(set->val.num)) {
8394 set->val.str = strdup("-Infinity");
8395 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), -1);
8396 } else if ((long long)set->val.num == set->val.num) {
8397 if (asprintf(&str, "%lld", (long long)set->val.num) == -1) {
8398 LOGMEM_RET(set->ctx);
8399 }
8400 set->val.str = str;
8401 } else {
8402 if (asprintf(&str, "%03.1Lf", set->val.num) == -1) {
8403 LOGMEM_RET(set->ctx);
8404 }
8405 set->val.str = str;
8406 }
8407 break;
8408 case LYXP_SET_BOOLEAN:
8409 if (set->val.bool) {
8410 set->val.str = strdup("true");
8411 } else {
8412 set->val.str = strdup("false");
8413 }
8414 LY_CHECK_ERR_RET(!set->val.str, LOGMEM(set->ctx), LY_EMEM);
8415 break;
8416 case LYXP_SET_NODE_SET:
8417 assert(set->used);
8418
8419 /* we need the set sorted, it affects the result */
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008420 assert(!set_sort(set));
Michal Vasko03ff5a72019-09-11 13:49:33 +02008421
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008422 rc = cast_node_set_to_string(set, &str);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008423 LY_CHECK_RET(rc);
Michal Vaskod3678892020-05-21 10:06:58 +02008424 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008425 set->val.str = str;
8426 break;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008427 default:
8428 LOGINT_RET(set->ctx);
8429 }
8430 set->type = LYXP_SET_STRING;
8431 }
8432
8433 /* to NUMBER */
8434 if (target == LYXP_SET_NUMBER) {
8435 switch (set->type) {
8436 case LYXP_SET_STRING:
8437 num = cast_string_to_number(set->val.str);
Michal Vaskod3678892020-05-21 10:06:58 +02008438 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008439 set->val.num = num;
8440 break;
8441 case LYXP_SET_BOOLEAN:
8442 if (set->val.bool) {
8443 set->val.num = 1;
8444 } else {
8445 set->val.num = 0;
8446 }
8447 break;
8448 default:
8449 LOGINT_RET(set->ctx);
8450 }
8451 set->type = LYXP_SET_NUMBER;
8452 }
8453
8454 /* to BOOLEAN */
8455 if (target == LYXP_SET_BOOLEAN) {
8456 switch (set->type) {
8457 case LYXP_SET_NUMBER:
8458 if ((set->val.num == 0) || (set->val.num == -0.0f) || isnan(set->val.num)) {
8459 set->val.bool = 0;
8460 } else {
8461 set->val.bool = 1;
8462 }
8463 break;
8464 case LYXP_SET_STRING:
8465 if (set->val.str[0]) {
Michal Vaskod3678892020-05-21 10:06:58 +02008466 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008467 set->val.bool = 1;
8468 } else {
Michal Vaskod3678892020-05-21 10:06:58 +02008469 lyxp_set_free_content(set);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008470 set->val.bool = 0;
8471 }
8472 break;
8473 case LYXP_SET_NODE_SET:
Michal Vaskod3678892020-05-21 10:06:58 +02008474 if (set->used) {
8475 lyxp_set_free_content(set);
8476 set->val.bool = 1;
8477 } else {
8478 lyxp_set_free_content(set);
8479 set->val.bool = 0;
8480 }
Michal Vasko03ff5a72019-09-11 13:49:33 +02008481 break;
8482 default:
8483 LOGINT_RET(set->ctx);
8484 }
8485 set->type = LYXP_SET_BOOLEAN;
8486 }
8487
Michal Vasko03ff5a72019-09-11 13:49:33 +02008488 return LY_SUCCESS;
8489}
8490
8491LY_ERR
8492lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
8493 enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options)
8494{
8495 struct ly_ctx *ctx;
8496 uint16_t exp_idx = 0;
8497
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008498 LY_CHECK_ARG_RET(NULL, exp, local_mod, set, LY_EINVAL);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008499
8500 ctx = local_mod->ctx;
8501
8502 /* prepare set for evaluation */
8503 exp_idx = 0;
8504 memset(set, 0, sizeof *set);
8505 set->type = LYXP_SET_SCNODE_SET;
Michal Vaskoecd62de2019-11-13 12:35:11 +01008506 lyxp_set_scnode_insert_node(set, ctx_scnode, ctx_scnode_type);
Michal Vasko5c4e5892019-11-14 12:31:38 +01008507 set->val.scnodes[0].in_ctx = -2;
Michal Vasko03ff5a72019-09-11 13:49:33 +02008508 set->ctx = ctx;
8509 set->ctx_scnode = ctx_scnode;
Michal Vasko5e0e6eb2019-11-06 15:47:50 +01008510 set->root_type = lyxp_get_root_type(NULL, ctx_scnode, options);
Michal Vasko03ff5a72019-09-11 13:49:33 +02008511 set->local_mod = local_mod;
8512 set->format = format;
8513
8514 /* evaluate */
8515 return eval_expr_select(exp, &exp_idx, 0, set, options);
8516}