Coverage Report

Created: 2025-10-08 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/path.c
Line
Count
Source
1
/**
2
 * @file path.c
3
 * @author Michal Vasko <mvasko@cesnet.cz>
4
 * @brief Path functions
5
 *
6
 * Copyright (c) 2020 CESNET, z.s.p.o.
7
 *
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
 */
14
#define _ISOC99_SOURCE /* strtoull */
15
16
#include "path.h"
17
18
#include <assert.h>
19
#include <ctype.h>
20
#include <stdlib.h>
21
#include <string.h>
22
23
#include "common.h"
24
#include "compat.h"
25
#include "log.h"
26
#include "plugins_types.h"
27
#include "schema_compile.h"
28
#include "set.h"
29
#include "tree.h"
30
#include "tree_data_internal.h"
31
#include "tree_edit.h"
32
#include "tree_schema.h"
33
#include "tree_schema_internal.h"
34
#include "xpath.h"
35
36
#define LOGVAL_P(CTX, CUR_NODE, CODE, ...) ly_vlog(CTX, (CUR_NODE) ? LY_VLOG_LYSC : LY_VLOG_NONE, CUR_NODE, CODE, ##__VA_ARGS__)
37
38
/**
39
 * @brief Check predicate syntax.
40
 *
41
 * @param[in] ctx libyang context.
42
 * @param[in] cur_node Current (original context) node.
43
 * @param[in] exp Parsed predicate.
44
 * @param[in,out] tok_idx Index in @p exp, is adjusted.
45
 * @param[in] prefix Prefix option.
46
 * @param[in] pred Predicate option.
47
 * @return LY_ERR value.
48
 */
49
static LY_ERR
50
ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp,
51
        uint16_t *tok_idx, uint8_t prefix, uint8_t pred)
52
0
{
53
0
    LY_ERR ret = LY_SUCCESS;
54
0
    struct ly_set *set = NULL;
55
0
    uint32_t i;
56
0
    const char *name;
57
0
    size_t name_len;
58
59
0
    LOG_LOCSET(cur_node, NULL, NULL, NULL);
60
61
0
    if (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1)) {
62
        /* '[' */
63
64
0
        if (((pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_KEYS)) &&
65
0
                !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
66
0
            ret = ly_set_new(&set);
67
0
            LY_CHECK_GOTO(ret, cleanup);
68
69
0
            do {
70
                /* NameTest is always expected here */
71
0
                LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
72
73
                /* check prefix based on the options */
74
0
                name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
75
0
                if ((prefix == LY_PATH_PREFIX_MANDATORY) && !name) {
76
0
                    LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", exp->tok_len[*tok_idx],
77
0
                            exp->expr + exp->tok_pos[*tok_idx]);
78
0
                    goto token_error;
79
0
                } else if ((prefix == LY_PATH_PREFIX_STRICT_INHERIT) && name) {
80
0
                    LOGVAL(ctx, LYVE_XPATH, "Redundant prefix for \"%.*s\" in path.", exp->tok_len[*tok_idx],
81
0
                            exp->expr + exp->tok_pos[*tok_idx]);
82
0
                    goto token_error;
83
0
                }
84
0
                if (!name) {
85
0
                    name = exp->expr + exp->tok_pos[*tok_idx];
86
0
                    name_len = exp->tok_len[*tok_idx];
87
0
                } else {
88
0
                    ++name;
89
0
                    name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
90
0
                }
91
92
                /* check whether it was not already specified */
93
0
                for (i = 0; i < set->count; ++i) {
94
                    /* all the keys must be from the same module so this comparison should be fine */
95
0
                    if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
96
0
                        LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
97
0
                        goto token_error;
98
0
                    }
99
0
                }
100
101
                /* add it into the set */
102
0
                ret = ly_set_add(set, (void *)name, 1, NULL);
103
0
                LY_CHECK_GOTO(ret, cleanup);
104
105
                /* NameTest */
106
0
                ++(*tok_idx);
107
108
                /* '=' */
109
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
110
111
                /* Literal */
112
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
113
114
                /* ']' */
115
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
116
117
                /* '[' */
118
0
            } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
119
120
0
        } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DOT)) {
121
            /* '.' */
122
123
            /* '=' */
124
0
            LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
125
126
            /* Literal */
127
0
            LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL), token_error);
128
129
            /* ']' */
130
0
            LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
131
132
0
        } else if ((pred == LY_PATH_PRED_SIMPLE) && !lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER)) {
133
            /* Number */
134
135
            /* ']' */
136
0
            LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
137
138
0
        } else if ((pred == LY_PATH_PRED_LEAFREF) && !lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_NAMETEST)) {
139
0
            assert(prefix == LY_PATH_PREFIX_OPTIONAL);
140
0
            ret = ly_set_new(&set);
141
0
            LY_CHECK_GOTO(ret, cleanup);
142
143
0
            do {
144
                /* NameTest is always expected here */
145
0
                LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_NAMETEST), token_error);
146
147
0
                name = strnstr(exp->expr + exp->tok_pos[*tok_idx], ":", exp->tok_len[*tok_idx]);
148
0
                if (!name) {
149
0
                    name = exp->expr + exp->tok_pos[*tok_idx];
150
0
                    name_len = exp->tok_len[*tok_idx];
151
0
                } else {
152
0
                    ++name;
153
0
                    name_len = exp->tok_len[*tok_idx] - (name - (exp->expr + exp->tok_pos[*tok_idx]));
154
0
                }
155
156
                /* check whether it was not already specified */
157
0
                for (i = 0; i < set->count; ++i) {
158
                    /* all the keys must be from the same module so this comparison should be fine */
159
0
                    if (!strncmp(set->objs[i], name, name_len) && !isalpha(((char *)set->objs[i])[name_len])) {
160
0
                        LOGVAL(ctx, LYVE_XPATH, "Duplicate predicate key \"%.*s\" in path.", (int)name_len, name);
161
0
                        goto token_error;
162
0
                    }
163
0
                }
164
165
                /* add it into the set */
166
0
                ret = ly_set_add(set, (void *)name, 1, NULL);
167
0
                LY_CHECK_GOTO(ret, cleanup);
168
169
                /* NameTest */
170
0
                ++(*tok_idx);
171
172
                /* '=' */
173
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error);
174
175
                /* FuncName */
176
0
                LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error);
177
0
                if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) ||
178
0
                        strncmp(exp->expr + exp->tok_pos[*tok_idx], "current", ly_strlen_const("current"))) {
179
0
                    LOGVAL(ctx, LYVE_XPATH, "Invalid function \"%.*s\" invocation in path.",
180
0
                            exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]);
181
0
                    goto token_error;
182
0
                }
183
0
                ++(*tok_idx);
184
185
                /* '(' */
186
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), token_error);
187
188
                /* ')' */
189
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), token_error);
190
191
                /* '/' */
192
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
193
194
                /* '..' */
195
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_DDOT), token_error);
196
0
                do {
197
                    /* '/' */
198
0
                    LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_PATH), token_error);
199
0
                } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_DDOT));
200
201
                /* NameTest */
202
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
203
204
                /* '/' */
205
0
                while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_OPER_PATH)) {
206
                    /* NameTest */
207
0
                    LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), token_error);
208
0
                }
209
210
                /* ']' */
211
0
                LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error);
212
213
                /* '[' */
214
0
            } while (!lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_BRACK1));
215
216
0
        } else {
217
0
            LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(exp->tokens[*tok_idx]), exp->expr + exp->tok_pos[*tok_idx]);
218
0
            goto token_error;
219
0
        }
220
0
    }
221
222
0
cleanup:
223
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
224
0
    ly_set_free(set, NULL);
225
0
    return ret;
226
227
0
token_error:
228
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
229
0
    ly_set_free(set, NULL);
230
0
    return LY_EVALID;
231
0
}
232
233
LY_ERR
234
ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len,
235
        uint8_t begin, uint8_t lref, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
236
0
{
237
0
    LY_ERR ret = LY_SUCCESS;
238
0
    struct lyxp_expr *exp = NULL;
239
0
    uint16_t tok_idx, cur_len;
240
0
    const char *cur_node, *prev_prefix = NULL, *ptr;
241
242
0
    assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER));
243
0
    assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
244
0
    assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) ||
245
0
            (prefix == LY_PATH_PREFIX_STRICT_INHERIT));
246
0
    assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
247
248
0
    LOG_LOCSET(ctx_node, NULL, NULL, NULL);
249
250
    /* parse as a generic XPath expression */
251
0
    LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error);
252
0
    tok_idx = 0;
253
254
0
    if (begin == LY_PATH_BEGIN_EITHER) {
255
        /* is the path relative? */
256
0
        if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) {
257
            /* relative path check specific to leafref */
258
0
            if (lref == LY_PATH_LREF_TRUE) {
259
                /* mandatory '..' */
260
0
                LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error);
261
262
0
                do {
263
                    /* '/' */
264
0
                    LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
265
266
                    /* optional '..' */
267
0
                } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT));
268
0
            }
269
0
        }
270
0
    } else {
271
        /* '/' */
272
0
        LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error);
273
0
    }
274
275
0
    do {
276
        /* NameTest */
277
0
        LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, exp, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, error);
278
279
        /* check prefix based on the options */
280
0
        cur_node = exp->expr + exp->tok_pos[tok_idx];
281
0
        cur_len = exp->tok_len[tok_idx];
282
0
        if (prefix == LY_PATH_PREFIX_MANDATORY) {
283
0
            if (!strnstr(cur_node, ":", cur_len)) {
284
0
                LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
285
0
                ret = LY_EVALID;
286
0
                goto error;
287
0
            }
288
0
        } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) {
289
0
            if (!prev_prefix) {
290
                /* the first node must have a prefix */
291
0
                if (!strnstr(cur_node, ":", cur_len)) {
292
0
                    LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node);
293
0
                    ret = LY_EVALID;
294
0
                    goto error;
295
0
                }
296
297
                /* remember the first prefix */
298
0
                prev_prefix = cur_node;
299
0
            } else {
300
                /* the prefix must be different, if any */
301
0
                ptr = strnstr(cur_node, ":", cur_len);
302
0
                if (ptr) {
303
0
                    if (!strncmp(prev_prefix, cur_node, ptr - cur_node) && (prev_prefix[ptr - cur_node] == ':')) {
304
0
                        LOGVAL(ctx, LYVE_XPATH, "Duplicate prefix for \"%.*s\" in path.", cur_len, cur_node);
305
0
                        ret = LY_EVALID;
306
0
                        goto error;
307
0
                    }
308
309
                    /* remember this next prefix */
310
0
                    prev_prefix = cur_node;
311
0
                }
312
0
            }
313
0
        }
314
315
0
        ++tok_idx;
316
317
        /* Predicate* */
318
0
        LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, ctx_node, exp, &tok_idx, prefix, pred), error);
319
320
        /* '/' */
321
0
    } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH));
322
323
    /* trailing token check */
324
0
    if (exp->used > tok_idx) {
325
0
        LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of path.", exp->expr + exp->tok_pos[tok_idx]);
326
0
        ret = LY_EVALID;
327
0
        goto error;
328
0
    }
329
330
0
    *expr = exp;
331
332
0
    LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
333
0
    return LY_SUCCESS;
334
335
0
error:
336
0
    lyxp_expr_free(ctx, exp);
337
0
    LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
338
0
    return ret;
339
0
}
340
341
LY_ERR
342
ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path,
343
        size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr)
344
0
{
345
0
    LY_ERR ret = LY_SUCCESS;
346
0
    struct lyxp_expr *exp = NULL;
347
0
    uint16_t tok_idx;
348
349
0
    assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY));
350
0
    assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF));
351
352
0
    LOG_LOCSET(cur_node, NULL, NULL, NULL);
353
354
    /* parse as a generic XPath expression */
355
0
    LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
356
0
    tok_idx = 0;
357
358
0
    LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error);
359
360
    /* trailing token check */
361
0
    if (exp->used > tok_idx) {
362
0
        LOGVAL(ctx, LYVE_XPATH, "Unparsed characters \"%s\" left at the end of predicate.",
363
0
                exp->expr + exp->tok_pos[tok_idx]);
364
0
        ret = LY_EVALID;
365
0
        goto error;
366
0
    }
367
368
0
    *expr = exp;
369
370
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
371
0
    return LY_SUCCESS;
372
373
0
error:
374
0
    lyxp_expr_free(ctx, exp);
375
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
376
0
    return ret;
377
0
}
378
379
/**
380
 * @brief Parse prefix from a NameTest, if any, and node name, and return expected module of the node.
381
 *
382
 * @param[in] ctx libyang context.
383
 * @param[in] cur_node Optional current (original context) node.
384
 * @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA*.
385
 * @param[in] prev_ctx_node Previous context node. Needed for ::LY_VALUE_JSON.
386
 * @param[in] expr Parsed path.
387
 * @param[in] tok_idx Index in @p expr.
388
 * @param[in] lref Lref option.
389
 * @param[in] format Format of the path.
390
 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
391
 * @param[out] mod Resolved module.
392
 * @param[out] name Parsed node name.
393
 * @param[out] name_len Length of @p name.
394
 * @return LY_ERR value.
395
 */
396
static LY_ERR
397
ly_path_compile_prefix(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
398
        const struct lysc_node *prev_ctx_node, const struct lyxp_expr *expr, uint16_t tok_idx, uint8_t lref,
399
        LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, const struct lys_module **mod,
400
        const char **name, size_t *name_len)
401
0
{
402
0
    LY_ERR ret;
403
0
    const char *pref;
404
0
    size_t len;
405
406
0
    assert(expr->tokens[tok_idx] == LYXP_TOKEN_NAMETEST);
407
408
    /* get prefix */
409
0
    if ((pref = strnstr(expr->expr + expr->tok_pos[tok_idx], ":", expr->tok_len[tok_idx]))) {
410
0
        len = pref - (expr->expr + expr->tok_pos[tok_idx]);
411
0
        pref = expr->expr + expr->tok_pos[tok_idx];
412
0
    } else {
413
0
        len = 0;
414
0
    }
415
416
    /* find next node module */
417
0
    if (pref) {
418
0
        LOG_LOCSET(cur_node, NULL, NULL, NULL);
419
420
0
        *mod = ly_resolve_prefix(ctx, pref, len, format, prefix_data);
421
0
        if (!*mod) {
422
0
            LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
423
0
                    (int)len, pref, ly_format2str(format));
424
0
            ret = LY_EVALID;
425
0
            goto error;
426
0
        } else if (!(*mod)->implemented) {
427
0
            if (lref == LY_PATH_LREF_FALSE) {
428
0
                LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
429
0
                ret = LY_EVALID;
430
0
                goto error;
431
0
            }
432
433
0
            assert(unres);
434
0
            LY_CHECK_GOTO(ret = lys_set_implemented_r((struct lys_module *)*mod, NULL, unres), error);
435
0
            if (unres->recompile) {
436
0
                return LY_ERECOMPILE;
437
0
            }
438
0
        }
439
440
0
        LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
441
0
    } else {
442
0
        switch (format) {
443
0
        case LY_VALUE_SCHEMA:
444
0
        case LY_VALUE_SCHEMA_RESOLVED:
445
0
            if (!cur_mod) {
446
0
                LOGINT_RET(ctx);
447
0
            }
448
            /* use current module */
449
0
            *mod = cur_mod;
450
0
            break;
451
0
        case LY_VALUE_JSON:
452
0
            if (!prev_ctx_node) {
453
0
                LOGINT_RET(ctx);
454
0
            }
455
            /* inherit module of the previous node */
456
0
            *mod = prev_ctx_node->module;
457
0
            break;
458
0
        case LY_VALUE_CANON:
459
0
        case LY_VALUE_XML:
460
0
        case LY_VALUE_LYB:
461
            /* not really defined or accepted */
462
0
            LOGINT_RET(ctx);
463
0
        }
464
0
    }
465
466
    /* set name */
467
0
    if (pref) {
468
0
        *name = pref + len + 1;
469
0
        *name_len = expr->tok_len[tok_idx] - len - 1;
470
0
    } else {
471
0
        *name = expr->expr + expr->tok_pos[tok_idx];
472
0
        *name_len = expr->tok_len[tok_idx];
473
0
    }
474
475
0
    return LY_SUCCESS;
476
477
0
error:
478
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
479
0
    return ret;
480
0
}
481
482
LY_ERR
483
ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod,
484
        const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format,
485
        void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type)
486
0
{
487
0
    LY_ERR ret = LY_SUCCESS;
488
0
    struct ly_path_predicate *p;
489
0
    const struct lysc_node *key;
490
0
    const struct lys_module *mod = NULL;
491
0
    const char *name;
492
0
    size_t name_len, key_count;
493
494
0
    assert(ctx && ctx_node);
495
496
0
    LOG_LOCSET(cur_node, NULL, NULL, NULL);
497
498
0
    *pred_type = 0;
499
500
0
    if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
501
        /* '[', no predicate */
502
0
        goto cleanup; /* LY_SUCCESS */
503
0
    }
504
505
0
    if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
506
0
        if (ctx_node->nodetype != LYS_LIST) {
507
0
            LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
508
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
509
0
            ret = LY_EVALID;
510
0
            goto cleanup;
511
0
        } else if (ctx_node->flags & LYS_KEYLESS) {
512
0
            LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
513
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
514
0
            ret = LY_EVALID;
515
0
            goto cleanup;
516
0
        }
517
518
0
        do {
519
            /* NameTest, find the key */
520
0
            LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, LY_PATH_LREF_FALSE,
521
0
                    format, prefix_data, NULL, &mod, &name, &name_len));
522
0
            key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
523
0
            if (!key) {
524
0
                LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
525
0
                ret = LY_ENOTFOUND;
526
0
                goto cleanup;
527
0
            } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
528
0
                LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
529
0
                        key->name);
530
0
                ret = LY_EVALID;
531
0
                goto cleanup;
532
0
            }
533
0
            ++(*tok_idx);
534
535
0
            if (!*pred_type) {
536
                /* new predicate */
537
0
                *pred_type = LY_PATH_PREDTYPE_LIST;
538
0
            }
539
0
            assert(*pred_type == LY_PATH_PREDTYPE_LIST);
540
0
            LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
541
0
            p->key = key;
542
543
            /* '=' */
544
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
545
0
            ++(*tok_idx);
546
547
            /* Literal */
548
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
549
0
            LOG_LOCSET(key, NULL, NULL, NULL);
550
0
            ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type,
551
0
                    expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
552
0
                    LYD_HINT_DATA, key, NULL);
553
0
            LOG_LOCBACK(key ? 1 : 0, 0, 0, 0);
554
0
            LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
555
0
            ++(*tok_idx);
556
557
            /* "allocate" the type to avoid problems when freeing the value after the type was freed */
558
0
            ++((struct lysc_type *)p->value.realtype)->refcount;
559
560
            /* ']' */
561
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
562
0
            ++(*tok_idx);
563
564
            /* another predicate follows? */
565
0
        } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
566
567
        /* check that all keys were set */
568
0
        key_count = 0;
569
0
        for (key = lysc_node_child(ctx_node); key && (key->flags & LYS_KEY); key = key->next) {
570
0
            ++key_count;
571
0
        }
572
0
        if (LY_ARRAY_COUNT(*predicates) != key_count) {
573
            /* names (keys) are unique - it was checked when parsing */
574
0
            LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
575
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
576
0
            ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates);
577
0
            *predicates = NULL;
578
0
            ret = LY_EVALID;
579
0
            goto cleanup;
580
0
        }
581
582
0
    } else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
583
0
        if (ctx_node->nodetype != LYS_LEAFLIST) {
584
0
            LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
585
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
586
0
            ret = LY_EVALID;
587
0
            goto cleanup;
588
0
        }
589
0
        ++(*tok_idx);
590
591
        /* new predicate */
592
0
        *pred_type = LY_PATH_PREDTYPE_LEAFLIST;
593
0
        LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
594
595
        /* '=' */
596
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
597
0
        ++(*tok_idx);
598
599
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL);
600
        /* store the value */
601
0
        LOG_LOCSET(ctx_node, NULL, NULL, NULL);
602
0
        ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type,
603
0
                expr->expr + expr->tok_pos[*tok_idx] + 1, expr->tok_len[*tok_idx] - 2, NULL, format, prefix_data,
604
0
                LYD_HINT_DATA, ctx_node, NULL);
605
0
        LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0);
606
0
        LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
607
0
        ++(*tok_idx);
608
609
        /* "allocate" the type to avoid problems when freeing the value after the type was freed */
610
0
        ++((struct lysc_type *)p->value.realtype)->refcount;
611
612
        /* ']' */
613
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
614
0
        ++(*tok_idx);
615
0
    } else {
616
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
617
0
        if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
618
0
            ret = LY_EVALID;
619
0
            LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
620
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
621
0
            goto cleanup;
622
0
        } else if (ctx_node->flags & LYS_CONFIG_W) {
623
0
            ret = LY_EVALID;
624
0
            LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
625
0
                    lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
626
0
            goto cleanup;
627
0
        }
628
629
        /* new predicate */
630
0
        *pred_type = LY_PATH_PREDTYPE_POSITION;
631
0
        LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
632
633
        /* syntax was already checked */
634
0
        p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&name, LY_BASE_DEC);
635
0
        ++(*tok_idx);
636
637
        /* ']' */
638
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
639
0
        ++(*tok_idx);
640
0
    }
641
642
0
cleanup:
643
0
    LOG_LOCBACK(cur_node ? 1 : 0, 0, 0, 0);
644
0
    return ret;
645
0
}
646
647
/**
648
 * @brief Compile leafref predicate. Actually, it is only checked.
649
 *
650
 * @param[in] ctx_node Context node, node for which the predicate is defined.
651
 * @param[in] cur_node Current (original context) node.
652
 * @param[in] expr Parsed path.
653
 * @param[in,out] tok_idx Index in @p expr, is adjusted for parsed tokens.
654
 * @param[in] format Format of the path.
655
 * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
656
 * @param[in,out] unres Global unres structure for newly implemented modules.
657
 * @return LY_ERR value.
658
 */
659
static LY_ERR
660
ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
661
        const struct lyxp_expr *expr, uint16_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data,
662
        struct lys_glob_unres *unres)
663
0
{
664
0
    LY_ERR ret = LY_SUCCESS;
665
0
    const struct lysc_node *key, *node, *node2;
666
0
    const struct lys_module *mod;
667
0
    const char *name;
668
0
    size_t name_len;
669
0
    struct ly_ctx *ctx = cur_node->module->ctx;
670
671
0
    LOG_LOCSET(cur_node, NULL, NULL, NULL);
672
673
0
    if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
674
        /* '[', no predicate */
675
0
        goto cleanup; /* LY_SUCCESS */
676
0
    }
677
678
0
    if (ctx_node->nodetype != LYS_LIST) {
679
0
        LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
680
0
                lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
681
0
        ret = LY_EVALID;
682
0
        goto cleanup;
683
0
    } else if (ctx_node->flags & LYS_KEYLESS) {
684
0
        LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
685
0
                lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
686
0
        ret = LY_EVALID;
687
0
        goto cleanup;
688
0
    }
689
690
0
    do {
691
        /* NameTest, find the key */
692
0
        ret = ly_path_compile_prefix(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx,
693
0
                LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len);
694
0
        LY_CHECK_GOTO(ret, cleanup);
695
0
        key = lys_find_child(ctx_node, mod, name, name_len, 0, 0);
696
0
        if (!key) {
697
0
            LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
698
0
            ret = LY_EVALID;
699
0
            goto cleanup;
700
0
        } else if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
701
0
            LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
702
0
                    lys_nodetype2str(key->nodetype), key->name);
703
0
            ret = LY_EVALID;
704
0
            goto cleanup;
705
0
        }
706
0
        ++(*tok_idx);
707
708
        /* we are not actually compiling, throw the key away */
709
0
        (void)key;
710
711
        /* '=' */
712
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL);
713
0
        ++(*tok_idx);
714
715
        /* FuncName */
716
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_FUNCNAME);
717
0
        ++(*tok_idx);
718
719
        /* evaluating from the "current()" node */
720
0
        node = cur_node;
721
722
        /* '(' */
723
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR1);
724
0
        ++(*tok_idx);
725
726
        /* ')' */
727
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_PAR2);
728
0
        ++(*tok_idx);
729
730
0
        do {
731
            /* '/' */
732
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
733
0
            ++(*tok_idx);
734
735
            /* go to parent */
736
0
            if (!node) {
737
0
                LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
738
0
                ret = LY_EVALID;
739
0
                goto cleanup;
740
0
            }
741
0
            node = lysc_data_parent(node);
742
743
            /* '..' */
744
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_DDOT);
745
0
            ++(*tok_idx);
746
0
        } while (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_DDOT);
747
748
0
        do {
749
            /* '/' */
750
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_PATH);
751
0
            ++(*tok_idx);
752
753
            /* NameTest */
754
0
            assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
755
0
            LY_CHECK_RET(ly_path_compile_prefix(ctx, cur_node, cur_node->module, node, expr, *tok_idx,
756
0
                    LY_PATH_LREF_TRUE, format, prefix_data, unres, &mod, &name, &name_len));
757
0
            node2 = lys_find_child(node, mod, name, name_len, 0, 0);
758
0
            if (!node2) {
759
0
                LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
760
0
                ret = LY_EVALID;
761
0
                goto cleanup;
762
0
            }
763
0
            node = node2;
764
0
            ++(*tok_idx);
765
0
        } while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
766
767
        /* check the last target node */
768
0
        if (node->nodetype != LYS_LEAF) {
769
0
            LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
770
0
                    lys_nodetype2str(node->nodetype), node->name);
771
0
            ret = LY_EVALID;
772
0
            goto cleanup;
773
0
        }
774
775
        /* we are not actually compiling, throw the rightside node away */
776
0
        (void)node;
777
778
        /* ']' */
779
0
        assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
780
0
        ++(*tok_idx);
781
782
        /* another predicate follows? */
783
0
    } while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
784
785
0
cleanup:
786
0
    LOG_LOCBACK(1, 0, 0, 0);
787
0
    return ret;
788
0
}
789
790
LY_ERR
791
ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node,
792
        const struct lysc_ext_instance *ext, const struct lyxp_expr *expr, uint8_t lref, uint8_t oper, uint8_t target,
793
        LY_VALUE_FORMAT format, void *prefix_data, struct lys_glob_unres *unres, struct ly_path **path)
794
0
{
795
0
    LY_ERR ret = LY_SUCCESS;
796
0
    uint16_t tok_idx = 0;
797
0
    const struct lys_module *mod = NULL;
798
0
    const struct lysc_node *node2, *cur_node, *op;
799
0
    struct ly_path *p = NULL;
800
0
    uint32_t getnext_opts;
801
0
    const char *name;
802
0
    size_t name_len;
803
804
0
    assert(ctx);
805
0
    assert((lref == LY_PATH_LREF_FALSE) || ctx_node);
806
0
    assert((lref == LY_PATH_LREF_TRUE) || (lref == LY_PATH_LREF_FALSE));
807
0
    assert((oper == LY_PATH_OPER_INPUT) || (oper == LY_PATH_OPER_OUTPUT));
808
0
    assert((target == LY_PATH_TARGET_SINGLE) || (target == LY_PATH_TARGET_MANY));
809
810
    /* find operation, if we are in any */
811
0
    for (op = ctx_node; op && !(op->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); op = op->parent) {}
812
813
0
    *path = NULL;
814
815
    /* remember original context node */
816
0
    cur_node = ctx_node;
817
0
    LOG_LOCINIT(cur_node, NULL, NULL, NULL);
818
819
0
    if (oper == LY_PATH_OPER_OUTPUT) {
820
0
        getnext_opts = LYS_GETNEXT_OUTPUT;
821
0
    } else {
822
0
        getnext_opts = 0;
823
0
    }
824
825
0
    if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
826
        /* absolute path */
827
0
        ctx_node = NULL;
828
829
0
        ++tok_idx;
830
0
    } else {
831
        /* relative path */
832
0
        while ((lref == LY_PATH_LREF_TRUE) && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
833
0
            if (!ctx_node) {
834
0
                LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
835
0
                ret = LY_EVALID;
836
0
                goto cleanup;
837
0
            }
838
839
            /* get parent */
840
0
            ctx_node = lysc_data_parent(ctx_node);
841
842
0
            ++tok_idx;
843
844
0
            assert(expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH);
845
0
            ++tok_idx;
846
0
        }
847
848
        /* we are not storing the parent */
849
0
        (void)ctx_node;
850
0
    }
851
852
0
    do {
853
        /* check last compiled inner node, whether it is uniquely identified (even key-less list) */
854
0
        if (p && (lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
855
0
                (p->node->nodetype == LYS_LIST) && !p->predicates) {
856
0
            LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
857
0
                    lys_nodetype2str(p->node->nodetype), p->node->name);
858
0
            ret = LY_EVALID;
859
0
            goto cleanup;
860
0
        }
861
862
        /* NameTest */
863
0
        LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
864
865
        /* get module and node name */
866
0
        LY_CHECK_GOTO(ret = ly_path_compile_prefix(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, lref, format,
867
0
                prefix_data, unres, &mod, &name, &name_len), cleanup);
868
0
        ++tok_idx;
869
870
        /* find the next node */
871
0
        if (!ctx_node && ext) {
872
0
            node2 = lysc_ext_find_node(ext, mod, name, name_len, 0, getnext_opts);
873
0
        } else {
874
0
            node2 = lys_find_child(ctx_node, mod, name, name_len, 0, getnext_opts);
875
0
        }
876
0
        if (!node2 || (op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
877
0
            LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
878
0
            ret = LY_EVALID;
879
0
            goto cleanup;
880
0
        }
881
0
        ctx_node = node2;
882
883
        /* new path segment */
884
0
        LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
885
0
        p->node = ctx_node;
886
887
        /* compile any predicates */
888
0
        if (lref == LY_PATH_LREF_TRUE) {
889
0
            ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data, unres);
890
0
        } else {
891
0
            ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
892
0
                    &p->predicates, &p->pred_type);
893
0
        }
894
0
        LY_CHECK_GOTO(ret, cleanup);
895
0
    } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
896
897
    /* check leftover tokens */
898
0
    if (tok_idx < expr->used) {
899
0
        LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_print_token(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
900
0
        ret = LY_EVALID;
901
0
        goto cleanup;
902
0
    }
903
904
    /* check last compiled node */
905
0
    if ((lref == LY_PATH_LREF_FALSE) && (target == LY_PATH_TARGET_SINGLE) &&
906
0
            (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
907
0
        LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
908
0
                lys_nodetype2str(p->node->nodetype), p->node->name);
909
0
        ret = LY_EVALID;
910
0
        goto cleanup;
911
0
    }
912
913
0
cleanup:
914
0
    if (ret) {
915
0
        ly_path_free(ctx, *path);
916
0
        *path = NULL;
917
0
    }
918
0
    LOG_LOCBACK(1, 0, 0, 0);
919
0
    return ret;
920
0
}
921
922
LY_ERR
923
ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx,
924
        struct lyd_node **match)
925
0
{
926
0
    LY_ARRAY_COUNT_TYPE u;
927
0
    struct lyd_node *prev_node = NULL, *node = NULL, *target;
928
0
    uint64_t pos;
929
930
0
    assert(path && start);
931
932
0
    if (lysc_data_parent(path[0].node)) {
933
        /* relative path, start from the parent children */
934
0
        start = lyd_child(start);
935
0
    } else {
936
        /* absolute path, start from the first top-level sibling */
937
0
        while (start->parent) {
938
0
            start = lyd_parent(start);
939
0
        }
940
0
        while (start->prev->next) {
941
0
            start = start->prev;
942
0
        }
943
0
    }
944
945
0
    LY_ARRAY_FOR(path, u) {
946
0
        switch (path[u].pred_type) {
947
0
        case LY_PATH_PREDTYPE_POSITION:
948
            /* we cannot use hashes and want an instance on a specific position */
949
0
            pos = 1;
950
0
            LYD_LIST_FOR_INST(start, path[u].node, node) {
951
0
                if (pos == path[u].predicates[0].position) {
952
0
                    break;
953
0
                }
954
0
                ++pos;
955
0
            }
956
0
            break;
957
0
        case LY_PATH_PREDTYPE_LEAFLIST:
958
            /* we will use hashes to find one leaf-list instance */
959
0
            LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target));
960
0
            lyd_find_sibling_first(start, target, &node);
961
0
            lyd_free_tree(target);
962
0
            break;
963
0
        case LY_PATH_PREDTYPE_LIST:
964
            /* we will use hashes to find one list instance */
965
0
            LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target));
966
0
            lyd_find_sibling_first(start, target, &node);
967
0
            lyd_free_tree(target);
968
0
            break;
969
0
        case LY_PATH_PREDTYPE_NONE:
970
            /* we will use hashes to find one any/container/leaf instance */
971
0
            lyd_find_sibling_val(start, path[u].node, NULL, 0, &node);
972
0
            break;
973
0
        }
974
975
0
        if (!node) {
976
            /* no matching nodes */
977
0
            break;
978
0
        }
979
980
        /* rememeber previous node */
981
0
        prev_node = node;
982
983
        /* next path segment, if any */
984
0
        start = lyd_child(node);
985
0
    }
986
987
0
    if (node) {
988
        /* we have found the full path */
989
0
        if (path_idx) {
990
0
            *path_idx = u;
991
0
        }
992
0
        if (match) {
993
0
            *match = node;
994
0
        }
995
0
        return LY_SUCCESS;
996
997
0
    } else if (prev_node) {
998
        /* we have found only some partial match */
999
0
        if (path_idx) {
1000
0
            *path_idx = u - 1;
1001
0
        }
1002
0
        if (match) {
1003
0
            *match = prev_node;
1004
0
        }
1005
0
        return LY_EINCOMPLETE;
1006
0
    }
1007
1008
    /* we have not found any nodes */
1009
0
    if (path_idx) {
1010
0
        *path_idx = 0;
1011
0
    }
1012
0
    if (match) {
1013
0
        *match = NULL;
1014
0
    }
1015
0
    return LY_ENOTFOUND;
1016
0
}
1017
1018
LY_ERR
1019
ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match)
1020
0
{
1021
0
    LY_ERR ret;
1022
0
    struct lyd_node *m;
1023
1024
0
    ret = ly_path_eval_partial(path, start, NULL, &m);
1025
1026
0
    if (ret == LY_SUCCESS) {
1027
        /* last node was found */
1028
0
        if (match) {
1029
0
            *match = m;
1030
0
        }
1031
0
        return LY_SUCCESS;
1032
0
    }
1033
1034
    /* not a full match */
1035
0
    if (match) {
1036
0
        *match = NULL;
1037
0
    }
1038
0
    return LY_ENOTFOUND;
1039
0
}
1040
1041
LY_ERR
1042
ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup)
1043
0
{
1044
0
    LY_ARRAY_COUNT_TYPE u, v;
1045
1046
0
    if (!path) {
1047
0
        return LY_SUCCESS;
1048
0
    }
1049
1050
0
    LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(path), LY_EMEM);
1051
0
    LY_ARRAY_FOR(path, u) {
1052
0
        LY_ARRAY_INCREMENT(*dup);
1053
0
        (*dup)[u].node = path[u].node;
1054
0
        if (path[u].predicates) {
1055
0
            LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM);
1056
0
            (*dup)[u].pred_type = path[u].pred_type;
1057
0
            LY_ARRAY_FOR(path[u].predicates, v) {
1058
0
                struct ly_path_predicate *pred = &path[u].predicates[v];
1059
1060
0
                LY_ARRAY_INCREMENT((*dup)[u].predicates);
1061
0
                switch (path[u].pred_type) {
1062
0
                case LY_PATH_PREDTYPE_POSITION:
1063
                    /* position-predicate */
1064
0
                    (*dup)[u].predicates[v].position = pred->position;
1065
0
                    break;
1066
0
                case LY_PATH_PREDTYPE_LIST:
1067
0
                case LY_PATH_PREDTYPE_LEAFLIST:
1068
                    /* key-predicate or leaf-list-predicate */
1069
0
                    (*dup)[u].predicates[v].key = pred->key;
1070
0
                    pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
1071
0
                    ++((struct lysc_type *)pred->value.realtype)->refcount;
1072
0
                    break;
1073
0
                case LY_PATH_PREDTYPE_NONE:
1074
0
                    break;
1075
0
                }
1076
0
            }
1077
0
        }
1078
0
    }
1079
1080
0
    return LY_SUCCESS;
1081
0
}
1082
1083
void
1084
ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates)
1085
0
{
1086
0
    LY_ARRAY_COUNT_TYPE u;
1087
1088
0
    if (!predicates) {
1089
0
        return;
1090
0
    }
1091
1092
0
    LY_ARRAY_FOR(predicates, u) {
1093
0
        switch (pred_type) {
1094
0
        case LY_PATH_PREDTYPE_POSITION:
1095
0
        case LY_PATH_PREDTYPE_NONE:
1096
            /* nothing to free */
1097
0
            break;
1098
0
        case LY_PATH_PREDTYPE_LIST:
1099
0
        case LY_PATH_PREDTYPE_LEAFLIST:
1100
0
            if (predicates[u].value.realtype) {
1101
0
                predicates[u].value.realtype->plugin->free(ctx, &predicates[u].value);
1102
0
                lysc_type_free((struct ly_ctx *)ctx, (struct lysc_type *)predicates[u].value.realtype);
1103
0
            }
1104
0
            break;
1105
0
        }
1106
0
    }
1107
0
    LY_ARRAY_FREE(predicates);
1108
0
}
1109
1110
void
1111
ly_path_free(const struct ly_ctx *ctx, struct ly_path *path)
1112
0
{
1113
0
    LY_ARRAY_COUNT_TYPE u;
1114
1115
0
    if (!path) {
1116
0
        return;
1117
0
    }
1118
1119
0
    LY_ARRAY_FOR(path, u) {
1120
0
        ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates);
1121
0
    }
1122
0
    LY_ARRAY_FREE(path);
1123
0
}