Coverage Report

Created: 2025-12-05 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/tree_schema.c
Line
Count
Source
1
/**
2
 * @file tree_schema.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief Schema tree implementation
5
 *
6
 * Copyright (c) 2015 - 2018 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
15
#define _GNU_SOURCE /* asprintf, strdup */
16
#include <sys/cdefs.h>
17
18
#include "tree_schema.h"
19
20
#include <assert.h>
21
#include <ctype.h>
22
#include <dirent.h>
23
#include <errno.h>
24
#include <stdint.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <sys/stat.h>
29
#include <unistd.h>
30
31
#include "common.h"
32
#include "compat.h"
33
#include "context.h"
34
#include "dict.h"
35
#include "in.h"
36
#include "in_internal.h"
37
#include "log.h"
38
#include "parser_internal.h"
39
#include "parser_schema.h"
40
#include "path.h"
41
#include "schema_compile.h"
42
#include "schema_features.h"
43
#include "set.h"
44
#include "tree.h"
45
#include "tree_edit.h"
46
#include "tree_schema_internal.h"
47
#include "xpath.h"
48
49
/**
50
 * @brief information about YANG statements
51
 */
52
struct stmt_info_s stmt_attr_info[] = {
53
    [LY_STMT_NONE] = {NULL, NULL, 0},
54
    [LY_STMT_ACTION] = {"action", "name", STMT_FLAG_ID},
55
    [LY_STMT_ANYDATA] = {"anydata", "name", STMT_FLAG_ID},
56
    [LY_STMT_ANYXML] = {"anyxml", "name", STMT_FLAG_ID},
57
    [LY_STMT_ARGUMENT] = {"argument", "name", STMT_FLAG_ID},
58
    [LY_STMT_ARG_TEXT] = {"text", NULL, 0},
59
    [LY_STMT_ARG_VALUE] = {"value", NULL, 0},
60
    [LY_STMT_AUGMENT] = {"augment", "target-node", STMT_FLAG_ID},
61
    [LY_STMT_BASE] = {"base", "name", STMT_FLAG_ID},
62
    [LY_STMT_BELONGS_TO] = {"belongs-to", "module", STMT_FLAG_ID},
63
    [LY_STMT_BIT] = {"bit", "name", STMT_FLAG_ID},
64
    [LY_STMT_CASE] = {"case", "name", STMT_FLAG_ID},
65
    [LY_STMT_CHOICE] = {"choice", "name", STMT_FLAG_ID},
66
    [LY_STMT_CONFIG] = {"config", "value", STMT_FLAG_ID},
67
    [LY_STMT_CONTACT] = {"contact", "text", STMT_FLAG_YIN},
68
    [LY_STMT_CONTAINER] = {"container", "name", STMT_FLAG_ID},
69
    [LY_STMT_DEFAULT] = {"default", "value", 0},
70
    [LY_STMT_DESCRIPTION] = {"description", "text", STMT_FLAG_YIN},
71
    [LY_STMT_DEVIATE] = {"deviate", "value", STMT_FLAG_ID},
72
    [LY_STMT_DEVIATION] = {"deviation", "target-node", STMT_FLAG_ID},
73
    [LY_STMT_ENUM] = {"enum", "name", STMT_FLAG_ID},
74
    [LY_STMT_ERROR_APP_TAG] = {"error-app-tag", "value", 0},
75
    [LY_STMT_ERROR_MESSAGE] = {"error-message", "value", STMT_FLAG_YIN},
76
    [LY_STMT_EXTENSION] = {"extension", "name", STMT_FLAG_ID},
77
    [LY_STMT_EXTENSION_INSTANCE] = {NULL, NULL, 0},
78
    [LY_STMT_FEATURE] = {"feature", "name", STMT_FLAG_ID},
79
    [LY_STMT_FRACTION_DIGITS] = {"fraction-digits", "value", STMT_FLAG_ID},
80
    [LY_STMT_GROUPING] = {"grouping", "name", STMT_FLAG_ID},
81
    [LY_STMT_IDENTITY] = {"identity", "name", STMT_FLAG_ID},
82
    [LY_STMT_IF_FEATURE] = {"if-feature", "name", 0},
83
    [LY_STMT_IMPORT] = {"import", "module", STMT_FLAG_ID},
84
    [LY_STMT_INCLUDE] = {"include", "module", STMT_FLAG_ID},
85
    [LY_STMT_INPUT] = {"input", NULL, 0},
86
    [LY_STMT_KEY] = {"key", "value", 0},
87
    [LY_STMT_LEAF] = {"leaf", "name", STMT_FLAG_ID},
88
    [LY_STMT_LEAF_LIST] = {"leaf-list", "name", STMT_FLAG_ID},
89
    [LY_STMT_LENGTH] = {"length", "value", 0},
90
    [LY_STMT_LIST] = {"list", "name", STMT_FLAG_ID},
91
    [LY_STMT_MANDATORY] = {"mandatory", "value", STMT_FLAG_ID},
92
    [LY_STMT_MAX_ELEMENTS] = {"max-elements", "value", STMT_FLAG_ID},
93
    [LY_STMT_MIN_ELEMENTS] = {"min-elements", "value", STMT_FLAG_ID},
94
    [LY_STMT_MODIFIER] = {"modifier", "value", STMT_FLAG_ID},
95
    [LY_STMT_MODULE] = {"module", "name", STMT_FLAG_ID},
96
    [LY_STMT_MUST] = {"must", "condition", 0},
97
    [LY_STMT_NAMESPACE] = {"namespace", "uri", 0},
98
    [LY_STMT_NOTIFICATION] = {"notification", "name", STMT_FLAG_ID},
99
    [LY_STMT_ORDERED_BY] = {"ordered-by", "value", STMT_FLAG_ID},
100
    [LY_STMT_ORGANIZATION] = {"organization", "text", STMT_FLAG_YIN},
101
    [LY_STMT_OUTPUT] = {"output", NULL, 0},
102
    [LY_STMT_PATH] = {"path", "value", 0},
103
    [LY_STMT_PATTERN] = {"pattern", "value", 0},
104
    [LY_STMT_POSITION] = {"position", "value", STMT_FLAG_ID},
105
    [LY_STMT_PREFIX] = {"prefix", "value", STMT_FLAG_ID},
106
    [LY_STMT_PRESENCE] = {"presence", "value", 0},
107
    [LY_STMT_RANGE] = {"range", "value", 0},
108
    [LY_STMT_REFERENCE] = {"reference", "text", STMT_FLAG_YIN},
109
    [LY_STMT_REFINE] = {"refine", "target-node", STMT_FLAG_ID},
110
    [LY_STMT_REQUIRE_INSTANCE] = {"require-instance", "value", STMT_FLAG_ID},
111
    [LY_STMT_REVISION] = {"revision", "date", STMT_FLAG_ID},
112
    [LY_STMT_REVISION_DATE] = {"revision-date", "date", STMT_FLAG_ID},
113
    [LY_STMT_RPC] = {"rpc", "name", STMT_FLAG_ID},
114
    [LY_STMT_STATUS] = {"status", "value", STMT_FLAG_ID},
115
    [LY_STMT_SUBMODULE] = {"submodule", "name", STMT_FLAG_ID},
116
    [LY_STMT_SYNTAX_LEFT_BRACE] = {"{", NULL, 0},
117
    [LY_STMT_SYNTAX_RIGHT_BRACE] = {"}", NULL, 0},
118
    [LY_STMT_SYNTAX_SEMICOLON] = {";", NULL, 0},
119
    [LY_STMT_TYPE] = {"type", "name", STMT_FLAG_ID},
120
    [LY_STMT_TYPEDEF] = {"typedef", "name", STMT_FLAG_ID},
121
    [LY_STMT_UNIQUE] = {"unique", "tag", 0},
122
    [LY_STMT_UNITS] = {"units", "name", 0},
123
    [LY_STMT_USES] = {"uses", "name", STMT_FLAG_ID},
124
    [LY_STMT_VALUE] = {"value", "value", STMT_FLAG_ID},
125
    [LY_STMT_WHEN] = {"when", "condition", 0},
126
    [LY_STMT_YANG_VERSION] = {"yang-version", "value", STMT_FLAG_ID},
127
    [LY_STMT_YIN_ELEMENT] = {"yin-element", "value", STMT_FLAG_ID},
128
};
129
130
API const char *
131
ly_stmt2str(enum ly_stmt stmt)
132
0
{
133
0
    return stmt_attr_info[stmt].name;
134
0
}
135
136
const char * const ly_devmod_list[] = {
137
    [LYS_DEV_NOT_SUPPORTED] = "not-supported",
138
    [LYS_DEV_ADD] = "add",
139
    [LYS_DEV_DELETE] = "delete",
140
    [LYS_DEV_REPLACE] = "replace",
141
};
142
143
API LY_ERR
144
lysc_tree_dfs_full(const struct lysc_node *root, lysc_dfs_clb dfs_clb, void *data)
145
0
{
146
0
    struct lysc_node *elem, *elem2;
147
0
    const struct lysc_node_action *action;
148
0
    const struct lysc_node_notif *notif;
149
150
0
    LY_CHECK_ARG_RET(NULL, root, dfs_clb, LY_EINVAL);
151
152
0
    LYSC_TREE_DFS_BEGIN(root, elem) {
153
        /* schema node */
154
0
        LY_CHECK_RET(dfs_clb(elem, data, &LYSC_TREE_DFS_continue));
155
156
0
        LY_LIST_FOR(lysc_node_actions(elem), action) {
157
0
            LYSC_TREE_DFS_BEGIN(action, elem2) {
158
                /* action subtree */
159
0
                LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
160
161
0
                LYSC_TREE_DFS_END(action, elem2);
162
0
            }
163
0
        }
164
165
0
        LY_LIST_FOR(lysc_node_notifs(elem), notif) {
166
0
            LYSC_TREE_DFS_BEGIN(notif, elem2) {
167
                /* notification subtree */
168
0
                LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
169
170
0
                LYSC_TREE_DFS_END(notif, elem2);
171
0
            }
172
0
        }
173
174
0
        LYSC_TREE_DFS_END(root, elem);
175
0
    }
176
177
0
    return LY_SUCCESS;
178
0
}
179
180
API LY_ERR
181
lysc_module_dfs_full(const struct lys_module *mod, lysc_dfs_clb dfs_clb, void *data)
182
0
{
183
0
    const struct lysc_node *root;
184
185
0
    LY_CHECK_ARG_RET(NULL, mod, mod->compiled, dfs_clb, LY_EINVAL);
186
187
    /* schema nodes */
188
0
    LY_LIST_FOR(mod->compiled->data, root) {
189
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
190
0
    }
191
192
    /* RPCs */
193
0
    LY_LIST_FOR((const struct lysc_node *)mod->compiled->rpcs, root) {
194
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
195
0
    }
196
197
    /* notifications */
198
0
    LY_LIST_FOR((const struct lysc_node *)mod->compiled->notifs, root) {
199
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
200
0
    }
201
202
0
    return LY_SUCCESS;
203
0
}
204
205
static void
206
lys_getnext_into_case(const struct lysc_node_case *first_case, const struct lysc_node **last, const struct lysc_node **next)
207
0
{
208
0
    for ( ; first_case; first_case = (const struct lysc_node_case *)first_case->next) {
209
0
        if (first_case->child) {
210
            /* there is something to return */
211
0
            (*next) = first_case->child;
212
0
            return;
213
0
        }
214
0
    }
215
216
    /* no children in choice's cases, so go to the choice's sibling instead of into it */
217
0
    (*last) = (*next);
218
0
    (*next) = (*next)->next;
219
0
}
220
221
/**
222
 * @brief Generic getnext function for ::lys_getnext() and ::lys_getnext_ext().
223
 *
224
 * Gets next schema tree (sibling) node element that can be instantiated in a data tree. Returned node can
225
 * be from an augment. If the @p ext is provided, the function is locked inside the schema tree defined in the
226
 * extension instance.
227
 *
228
 * ::lys_getnext_() is supposed to be called sequentially. In the first call, the \p last parameter is usually NULL
229
 * and function starts returning i) the first \p parent's child or ii) the first top level element specified in the
230
 * given extension (if provided) or iii) the first top level element of the \p module.
231
 * Consequent calls suppose to provide the previously returned node as the \p last parameter and still the same
232
 * \p parent and \p module parameters.
233
 *
234
 * Without options, the function is used to traverse only the schema nodes that can be paired with corresponding
235
 * data nodes in a data tree. By setting some \p options the behavior can be modified to the extent that
236
 * all the schema nodes are iteratively returned.
237
 *
238
 * @param[in] last Previously returned schema tree node, or NULL in case of the first call.
239
 * @param[in] parent Parent of the subtree where the function starts processing.
240
 * @param[in] module In case of iterating on top level elements, the \p parent is NULL and
241
 * module must be specified.
242
 * @param[in] ext The extension instance to provide a separate schema tree. To consider the top level elements in the tree,
243
 * the \p parent must be NULL. Anyway, at least one of @p parent, @p module and @p ext parameters must be specified.
244
 * @param[in] options [ORed options](@ref sgetnextflags).
245
 * @return Next schema tree node that can be instantiated in a data tree, NULL in case there is no such element.
246
 */
247
static const struct lysc_node *
248
lys_getnext_(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module,
249
        const struct lysc_ext_instance *ext, uint32_t options)
250
0
{
251
0
    const struct lysc_node *next = NULL;
252
0
    ly_bool action_flag = 0, notif_flag = 0;
253
0
    struct lysc_node **data_p = NULL;
254
255
0
    LY_CHECK_ARG_RET(NULL, parent || module || ext, NULL);
256
257
0
next:
258
0
    if (!last) {
259
        /* first call */
260
261
        /* get know where to start */
262
0
        if (parent) {
263
            /* schema subtree */
264
0
            next = last = lysc_node_child(parent);
265
0
        } else {
266
            /* top level data */
267
0
            if (ext) {
268
0
                lysc_ext_substmt(ext, LY_STMT_CONTAINER /* matches all nodes */, (void **)&data_p, NULL);
269
0
                next = last = data_p ? *data_p : NULL;
270
0
            } else {
271
0
                next = last = module->data;
272
0
            }
273
0
        }
274
0
        if (!next) {
275
            /* try to get action or notification */
276
0
            goto repeat;
277
0
        }
278
        /* test if the next can be returned */
279
0
        goto check;
280
281
0
    } else if (last->nodetype & (LYS_RPC | LYS_ACTION)) {
282
0
        action_flag = 1;
283
0
        next = last->next;
284
0
    } else if (last->nodetype == LYS_NOTIF) {
285
0
        action_flag = notif_flag = 1;
286
0
        next = last->next;
287
0
    } else {
288
0
        next = last->next;
289
0
    }
290
291
0
repeat:
292
0
    if (!next) {
293
        /* possibly go back to parent */
294
0
        data_p = NULL;
295
0
        if (last && (last->parent != parent)) {
296
0
            last = last->parent;
297
0
            goto next;
298
0
        } else if (!action_flag) {
299
0
            action_flag = 1;
300
0
            if (ext) {
301
0
                lysc_ext_substmt(ext, LY_STMT_RPC /* matches also actions */, (void **)&data_p, NULL);
302
0
                next = data_p ? *data_p : NULL;
303
0
            } else if (parent) {
304
0
                next = (struct lysc_node *)lysc_node_actions(parent);
305
0
            } else {
306
0
                next = (struct lysc_node *)module->rpcs;
307
0
            }
308
0
        } else if (!notif_flag) {
309
0
            notif_flag = 1;
310
0
            if (ext) {
311
0
                lysc_ext_substmt(ext, LY_STMT_NOTIFICATION, (void **)&data_p, NULL);
312
0
                next = data_p ? *data_p : NULL;
313
0
            } else if (parent) {
314
0
                next = (struct lysc_node *)lysc_node_notifs(parent);
315
0
            } else {
316
0
                next = (struct lysc_node *)module->notifs;
317
0
            }
318
0
        } else {
319
0
            return NULL;
320
0
        }
321
0
        goto repeat;
322
0
    }
323
0
check:
324
0
    switch (next->nodetype) {
325
0
    case LYS_RPC:
326
0
    case LYS_ACTION:
327
0
    case LYS_NOTIF:
328
0
    case LYS_LEAF:
329
0
    case LYS_ANYXML:
330
0
    case LYS_ANYDATA:
331
0
    case LYS_LIST:
332
0
    case LYS_LEAFLIST:
333
0
        break;
334
0
    case LYS_CASE:
335
0
        if (options & LYS_GETNEXT_WITHCASE) {
336
0
            break;
337
0
        } else {
338
            /* go into */
339
0
            lys_getnext_into_case((const struct lysc_node_case *)next, &last, &next);
340
0
        }
341
0
        goto repeat;
342
0
    case LYS_CONTAINER:
343
0
        if (!(next->flags & LYS_PRESENCE) && (options & LYS_GETNEXT_INTONPCONT)) {
344
0
            if (lysc_node_child(next)) {
345
                /* go into */
346
0
                next = lysc_node_child(next);
347
0
            } else {
348
0
                last = next;
349
0
                next = next->next;
350
0
            }
351
0
            goto repeat;
352
0
        }
353
0
        break;
354
0
    case LYS_CHOICE:
355
0
        if (options & LYS_GETNEXT_WITHCHOICE) {
356
0
            break;
357
0
        } else if ((options & LYS_GETNEXT_NOCHOICE) || !lysc_node_child(next)) {
358
0
            next = next->next;
359
0
        } else {
360
0
            if (options & LYS_GETNEXT_WITHCASE) {
361
0
                next = lysc_node_child(next);
362
0
            } else {
363
                /* go into */
364
0
                lys_getnext_into_case(((struct lysc_node_choice *)next)->cases, &last, &next);
365
0
            }
366
0
        }
367
0
        goto repeat;
368
0
    case LYS_INPUT:
369
0
        if (options & LYS_GETNEXT_OUTPUT) {
370
            /* skip */
371
0
            next = next->next;
372
0
        } else {
373
            /* go into */
374
0
            next = lysc_node_child(next);
375
0
        }
376
0
        goto repeat;
377
0
    case LYS_OUTPUT:
378
0
        if (!(options & LYS_GETNEXT_OUTPUT)) {
379
            /* skip */
380
0
            next = next->next;
381
0
        } else {
382
            /* go into */
383
0
            next = lysc_node_child(next);
384
0
        }
385
0
        goto repeat;
386
0
    default:
387
        /* we should not be here */
388
0
        LOGINT(module ? module->mod->ctx : parent ? parent->module->ctx : ext->module->ctx);
389
0
        return NULL;
390
0
    }
391
392
0
    return next;
393
0
}
394
395
API const struct lysc_node *
396
lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, uint32_t options)
397
0
{
398
0
    return lys_getnext_(last, parent, module, NULL, options);
399
0
}
400
401
API const struct lysc_node *
402
lys_getnext_ext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_ext_instance *ext, uint32_t options)
403
0
{
404
0
    return lys_getnext_(last, parent, NULL, ext, options);
405
0
}
406
407
const struct lysc_node *
408
lysc_ext_find_node(const struct lysc_ext_instance *ext, const struct lys_module *module, const char *name, size_t name_len,
409
        uint16_t nodetype, uint32_t options)
410
0
{
411
0
    const struct lysc_node *node = NULL;
412
413
0
    LY_CHECK_ARG_RET(NULL, ext, name, NULL);
414
0
    if (!nodetype) {
415
0
        nodetype = LYS_NODETYPE_MASK;
416
0
    }
417
418
0
    if (module && (module != ext->module)) {
419
0
        return NULL;
420
0
    }
421
422
0
    while ((node = lys_getnext_ext(node, NULL, ext, options))) {
423
0
        if (!(node->nodetype & nodetype)) {
424
0
            continue;
425
0
        }
426
427
0
        if (name_len) {
428
0
            if (!ly_strncmp(node->name, name, name_len)) {
429
0
                return node;
430
0
            }
431
0
        } else {
432
0
            if (!strcmp(node->name, name)) {
433
0
                return node;
434
0
            }
435
0
        }
436
0
    }
437
0
    return NULL;
438
0
}
439
440
API const struct lysc_node *
441
lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
442
        uint16_t nodetype, uint32_t options)
443
0
{
444
0
    const struct lysc_node *node = NULL;
445
446
0
    LY_CHECK_ARG_RET(NULL, module, name, NULL);
447
0
    if (!nodetype) {
448
0
        nodetype = LYS_NODETYPE_MASK;
449
0
    }
450
451
0
    while ((node = lys_getnext(node, parent, module->compiled, options))) {
452
0
        if (!(node->nodetype & nodetype)) {
453
0
            continue;
454
0
        }
455
0
        if (node->module != module) {
456
0
            continue;
457
0
        }
458
459
0
        if (name_len) {
460
0
            if (!ly_strncmp(node->name, name, name_len)) {
461
0
                return node;
462
0
            }
463
0
        } else {
464
0
            if (!strcmp(node->name, name)) {
465
0
                return node;
466
0
            }
467
0
        }
468
0
    }
469
0
    return NULL;
470
0
}
471
472
API LY_ERR
473
lys_find_xpath_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
474
        struct ly_set **set)
475
0
{
476
0
    LY_ERR ret = LY_SUCCESS;
477
0
    struct lyxp_set xp_set;
478
0
    struct lyxp_expr *exp = NULL;
479
0
    uint32_t i;
480
481
0
    LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
482
0
    if (!(options & LYXP_SCNODE_ALL)) {
483
0
        options = LYXP_SCNODE;
484
0
    }
485
0
    if (!ctx) {
486
0
        ctx = ctx_node->module->ctx;
487
0
    }
488
489
0
    memset(&xp_set, 0, sizeof xp_set);
490
491
    /* compile expression */
492
0
    ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
493
0
    LY_CHECK_GOTO(ret, cleanup);
494
495
    /* atomize expression */
496
0
    ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, &xp_set, options);
497
0
    LY_CHECK_GOTO(ret, cleanup);
498
499
    /* allocate return set */
500
0
    ret = ly_set_new(set);
501
0
    LY_CHECK_GOTO(ret, cleanup);
502
503
    /* transform into ly_set */
504
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
505
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
506
0
    (*set)->size = xp_set.used;
507
508
0
    for (i = 0; i < xp_set.used; ++i) {
509
0
        if (xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
510
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
511
0
            LY_CHECK_GOTO(ret, cleanup);
512
0
        }
513
0
    }
514
515
0
cleanup:
516
0
    lyxp_set_free_content(&xp_set);
517
0
    lyxp_expr_free(ctx, exp);
518
0
    return ret;
519
0
}
520
521
API LY_ERR
522
lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
523
        const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
524
0
{
525
0
    LY_ERR ret = LY_SUCCESS;
526
0
    struct lyxp_set xp_set = {0};
527
0
    uint32_t i;
528
529
0
    LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
530
0
    if (!(options & LYXP_SCNODE_ALL)) {
531
0
        options = LYXP_SCNODE;
532
0
    }
533
534
    /* atomize expression */
535
0
    ret = lyxp_atomize(cur_mod->ctx, expr, cur_mod, LY_VALUE_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, &xp_set, options);
536
0
    LY_CHECK_GOTO(ret, cleanup);
537
538
    /* allocate return set */
539
0
    ret = ly_set_new(set);
540
0
    LY_CHECK_GOTO(ret, cleanup);
541
542
    /* transform into ly_set */
543
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
544
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
545
0
    (*set)->size = xp_set.used;
546
547
0
    for (i = 0; i < xp_set.used; ++i) {
548
0
        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx >= LYXP_SET_SCNODE_ATOM_NODE)) {
549
0
            assert((xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NODE) ||
550
0
                    (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_VAL) ||
551
0
                    (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX));
552
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
553
0
            LY_CHECK_GOTO(ret, cleanup);
554
0
        }
555
0
    }
556
557
0
cleanup:
558
0
    lyxp_set_free_content(&xp_set);
559
0
    if (ret) {
560
0
        ly_set_free(*set, NULL);
561
0
        *set = NULL;
562
0
    }
563
0
    return ret;
564
0
}
565
566
API LY_ERR
567
lys_find_xpath(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
568
        struct ly_set **set)
569
0
{
570
0
    LY_ERR ret = LY_SUCCESS;
571
0
    struct lyxp_set xp_set = {0};
572
0
    struct lyxp_expr *exp = NULL;
573
0
    uint32_t i;
574
575
0
    LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
576
0
    if (!(options & LYXP_SCNODE_ALL)) {
577
0
        options = LYXP_SCNODE;
578
0
    }
579
0
    if (!ctx) {
580
0
        ctx = ctx_node->module->ctx;
581
0
    }
582
583
    /* compile expression */
584
0
    ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
585
0
    LY_CHECK_GOTO(ret, cleanup);
586
587
    /* atomize expression */
588
0
    ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, &xp_set, options);
589
0
    LY_CHECK_GOTO(ret, cleanup);
590
591
    /* allocate return set */
592
0
    ret = ly_set_new(set);
593
0
    LY_CHECK_GOTO(ret, cleanup);
594
595
    /* transform into ly_set */
596
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
597
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
598
0
    (*set)->size = xp_set.used;
599
600
0
    for (i = 0; i < xp_set.used; ++i) {
601
0
        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX)) {
602
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
603
0
            LY_CHECK_GOTO(ret, cleanup);
604
0
        }
605
0
    }
606
607
0
cleanup:
608
0
    lyxp_set_free_content(&xp_set);
609
0
    lyxp_expr_free(ctx, exp);
610
0
    if (ret) {
611
0
        ly_set_free(*set, NULL);
612
0
        *set = NULL;
613
0
    }
614
0
    return ret;
615
0
}
616
617
API LY_ERR
618
lys_find_lypath_atoms(const struct ly_path *path, struct ly_set **set)
619
0
{
620
0
    LY_ERR ret = LY_SUCCESS;
621
0
    LY_ARRAY_COUNT_TYPE u, v;
622
623
0
    LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
624
625
    /* allocate return set */
626
0
    LY_CHECK_RET(ly_set_new(set));
627
628
0
    LY_ARRAY_FOR(path, u) {
629
        /* add nodes from the path */
630
0
        LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
631
0
        if (path[u].pred_type == LY_PATH_PREDTYPE_LIST) {
632
0
            LY_ARRAY_FOR(path[u].predicates, v) {
633
                /* add all the keys in a predicate */
634
0
                LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
635
0
            }
636
0
        }
637
0
    }
638
639
0
cleanup:
640
0
    if (ret) {
641
0
        ly_set_free(*set, NULL);
642
0
        *set = NULL;
643
0
    }
644
0
    return ret;
645
0
}
646
647
API LY_ERR
648
lys_find_path_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output,
649
        struct ly_set **set)
650
0
{
651
0
    LY_ERR ret = LY_SUCCESS;
652
0
    uint8_t oper;
653
0
    struct lyxp_expr *expr = NULL;
654
0
    struct ly_path *p = NULL;
655
656
0
    LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
657
658
0
    if (!ctx) {
659
0
        ctx = ctx_node->module->ctx;
660
0
    }
661
662
    /* parse */
663
0
    ret = lyxp_expr_parse(ctx, path, strlen(path), 0, &expr);
664
0
    LY_CHECK_GOTO(ret, cleanup);
665
666
    /* compile */
667
0
    oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
668
0
    ret = ly_path_compile(ctx, NULL, ctx_node, NULL, expr, LY_PATH_LREF_FALSE, oper, LY_PATH_TARGET_MANY,
669
0
            LY_VALUE_JSON, NULL, NULL, &p);
670
0
    LY_CHECK_GOTO(ret, cleanup);
671
672
    /* resolve */
673
0
    ret = lys_find_lypath_atoms(p, set);
674
675
0
cleanup:
676
0
    ly_path_free(ctx, p);
677
0
    lyxp_expr_free(ctx, expr);
678
0
    return ret;
679
0
}
680
681
API const struct lysc_node *
682
lys_find_path(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output)
683
0
{
684
0
    const struct lysc_node *snode = NULL;
685
0
    struct lyxp_expr *exp = NULL;
686
0
    struct ly_path *p = NULL;
687
0
    LY_ERR ret;
688
0
    uint8_t oper;
689
690
0
    LY_CHECK_ARG_RET(ctx, ctx || ctx_node, NULL);
691
692
0
    if (!ctx) {
693
0
        ctx = ctx_node->module->ctx;
694
0
    }
695
696
    /* parse */
697
0
    ret = lyxp_expr_parse(ctx, path, strlen(path), 0, &exp);
698
0
    LY_CHECK_GOTO(ret, cleanup);
699
700
    /* compile */
701
0
    oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
702
0
    ret = ly_path_compile(ctx, NULL, ctx_node, NULL, exp, LY_PATH_LREF_FALSE, oper, LY_PATH_TARGET_MANY,
703
0
            LY_VALUE_JSON, NULL, NULL, &p);
704
0
    LY_CHECK_GOTO(ret, cleanup);
705
706
    /* get last node */
707
0
    snode = p[LY_ARRAY_COUNT(p) - 1].node;
708
709
0
cleanup:
710
0
    ly_path_free(ctx, p);
711
0
    lyxp_expr_free(ctx, exp);
712
0
    return snode;
713
0
}
714
715
char *
716
lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
717
        size_t buflen)
718
0
{
719
0
    const struct lysc_node *iter;
720
0
    char *path = NULL;
721
0
    int len = 0;
722
723
0
    if (buffer) {
724
0
        LY_CHECK_ARG_RET(node->module->ctx, buflen > 1, NULL);
725
0
        buffer[0] = '\0';
726
0
    }
727
728
0
    switch (pathtype) {
729
0
    case LYSC_PATH_LOG:
730
0
    case LYSC_PATH_DATA:
731
0
        for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
732
0
            char *s, *id;
733
0
            const char *slash;
734
735
0
            if ((pathtype == LYSC_PATH_DATA) && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT))) {
736
                /* schema-only node */
737
0
                continue;
738
0
            }
739
740
0
            s = buffer ? strdup(buffer) : path;
741
0
            id = strdup(iter->name);
742
0
            if (parent && (iter->parent == parent)) {
743
0
                slash = "";
744
0
            } else {
745
0
                slash = "/";
746
0
            }
747
0
            if (!iter->parent || (iter->parent->module != iter->module)) {
748
                /* print prefix */
749
0
                if (buffer) {
750
0
                    len = snprintf(buffer, buflen, "%s%s:%s%s", slash, iter->module->name, id, s ? s : "");
751
0
                } else {
752
0
                    len = asprintf(&path, "%s%s:%s%s", slash, iter->module->name, id, s ? s : "");
753
0
                }
754
0
            } else {
755
                /* prefix is the same as in parent */
756
0
                if (buffer) {
757
0
                    len = snprintf(buffer, buflen, "%s%s%s", slash, id, s ? s : "");
758
0
                } else {
759
0
                    len = asprintf(&path, "%s%s%s", slash, id, s ? s : "");
760
0
                }
761
0
            }
762
0
            free(s);
763
0
            free(id);
764
765
0
            if (buffer && (buflen <= (size_t)len)) {
766
                /* not enough space in buffer */
767
0
                break;
768
0
            }
769
0
        }
770
771
0
        if (len < 0) {
772
0
            free(path);
773
0
            path = NULL;
774
0
        } else if (len == 0) {
775
0
            if (buffer) {
776
0
                strcpy(buffer, "/");
777
0
            } else {
778
0
                path = strdup("/");
779
0
            }
780
0
        }
781
0
        break;
782
0
    }
783
784
0
    if (buffer) {
785
0
        return buffer;
786
0
    } else {
787
0
        return path;
788
0
    }
789
0
}
790
791
API char *
792
lysc_path(const struct lysc_node *node, LYSC_PATH_TYPE pathtype, char *buffer, size_t buflen)
793
0
{
794
0
    return lysc_path_until(node, NULL, pathtype, buffer, buflen);
795
0
}
796
797
LY_ERR
798
lys_set_implemented_r(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
799
0
{
800
0
    struct lys_module *m;
801
802
0
    assert(!mod->implemented);
803
804
    /* we have module from the current context */
805
0
    m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
806
0
    if (m) {
807
0
        assert(m != mod);
808
809
        /* check collision with other implemented revision */
810
0
        LOGERR(mod->ctx, LY_EDENIED, "Module \"%s%s%s\" is present in the context in other implemented revision (%s).",
811
0
                mod->name, mod->revision ? "@" : "", mod->revision ? mod->revision : "", m->revision ? m->revision : "none");
812
0
        return LY_EDENIED;
813
0
    }
814
815
    /* enable features */
816
0
    LY_CHECK_RET(lys_enable_features(mod->parsed, features));
817
818
0
    if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
819
        /* do not compile the module yet */
820
0
        mod->to_compile = 1;
821
0
        return LY_SUCCESS;
822
0
    }
823
824
    /* add the module into newly implemented module set */
825
0
    LY_CHECK_RET(ly_set_add(&unres->implementing, mod, 1, NULL));
826
827
    /* mark the module implemented, check for collision was already done */
828
0
    mod->implemented = 1;
829
830
    /* compile the schema */
831
0
    LY_CHECK_RET(lys_compile(mod, 0, unres));
832
833
    /* new module is implemented and compiled */
834
0
    unres->full_compilation = 0;
835
836
0
    return LY_SUCCESS;
837
0
}
838
839
API LY_ERR
840
lys_set_implemented(struct lys_module *mod, const char **features)
841
0
{
842
0
    LY_ERR ret = LY_SUCCESS, r;
843
0
    struct lys_glob_unres unres = {0};
844
845
0
    LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
846
847
0
    if (mod->implemented) {
848
        /* mod is already implemented, set the features */
849
0
        r = lys_set_features(mod->parsed, features);
850
0
        if (r == LY_EEXIST) {
851
            /* no changes */
852
0
            return LY_SUCCESS;
853
0
        } else if (r) {
854
            /* error */
855
0
            return r;
856
0
        }
857
858
0
        if (mod->ctx->flags & LY_CTX_EXPLICIT_COMPILE) {
859
            /* just mark the module as changed */
860
0
            mod->to_compile = 1;
861
0
            return LY_SUCCESS;
862
0
        } else {
863
            /* full recompilation */
864
0
            return lys_recompile(mod->ctx, 1);
865
0
        }
866
0
    }
867
868
    /* implement this module and any other required modules, recursively */
869
0
    ret = lys_set_implemented_r(mod, features, &unres);
870
871
    /* the first module being implemented is finished, resolve global unres, consolidate the set */
872
0
    if (!ret) {
873
0
        ret = lys_compile_unres_glob(mod->ctx, &unres);
874
0
    }
875
0
    if (ret) {
876
        /* failure, full compile revert */
877
0
        lys_compile_unres_glob_revert(mod->ctx, &unres);
878
0
    }
879
880
0
    lys_compile_unres_glob_erase(mod->ctx, &unres);
881
0
    return ret;
882
0
}
883
884
static LY_ERR
885
lys_resolve_import_include(struct lys_parser_ctx *pctx, struct lysp_module *pmod)
886
0
{
887
0
    struct lysp_import *imp;
888
0
    LY_ARRAY_COUNT_TYPE u, v;
889
890
0
    pmod->parsing = 1;
891
0
    LY_ARRAY_FOR(pmod->imports, u) {
892
0
        imp = &pmod->imports[u];
893
0
        if (!imp->module) {
894
0
            LY_CHECK_RET(lys_load_module(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, 0, NULL,
895
0
                    pctx->unres, &imp->module));
896
0
        }
897
        /* check for importing the same module twice */
898
0
        for (v = 0; v < u; ++v) {
899
0
            if (imp->module == pmod->imports[v].module) {
900
0
                LOGWRN(PARSER_CTX(pctx), "Single revision of the module \"%s\" imported twice.", imp->name);
901
0
            }
902
0
        }
903
0
    }
904
0
    LY_CHECK_RET(lysp_load_submodules(pctx, pmod));
905
906
0
    pmod->parsing = 0;
907
908
0
    return LY_SUCCESS;
909
0
}
910
911
LY_ERR
912
lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
913
        LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
914
        void *check_data, struct lysp_submodule **submodule)
915
0
{
916
0
    LY_ERR ret;
917
0
    struct lysp_submodule *submod = NULL, *latest_sp;
918
0
    struct lys_yang_parser_ctx *yangctx = NULL;
919
0
    struct lys_yin_parser_ctx *yinctx = NULL;
920
0
    struct lys_parser_ctx *pctx;
921
922
0
    LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
923
924
0
    switch (format) {
925
0
    case LYS_IN_YIN:
926
0
        ret = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
927
0
        pctx = (struct lys_parser_ctx *)yinctx;
928
0
        break;
929
0
    case LYS_IN_YANG:
930
0
        ret = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
931
0
        pctx = (struct lys_parser_ctx *)yangctx;
932
0
        break;
933
0
    default:
934
0
        LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
935
0
        ret = LY_EINVAL;
936
0
        break;
937
0
    }
938
0
    LY_CHECK_GOTO(ret, error);
939
0
    assert(submod);
940
941
    /* make sure that the newest revision is at position 0 */
942
0
    lysp_sort_revisions(submod->revs);
943
944
    /* decide the latest revision */
945
0
    latest_sp = (struct lysp_submodule *)ly_ctx_get_submodule2_latest(submod->mod, submod->name);
946
0
    if (latest_sp) {
947
0
        if (submod->revs) {
948
0
            if (!latest_sp->revs) {
949
                /* latest has no revision, so mod is anyway newer */
950
0
                submod->latest_revision = latest_sp->latest_revision;
951
                /* the latest_sp is zeroed later when the new module is being inserted into the context */
952
0
            } else if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
953
0
                submod->latest_revision = latest_sp->latest_revision;
954
                /* the latest_sp is zeroed later when the new module is being inserted into the context */
955
0
            } else {
956
0
                latest_sp = NULL;
957
0
            }
958
0
        } else {
959
0
            latest_sp = NULL;
960
0
        }
961
0
    } else {
962
0
        submod->latest_revision = 1;
963
0
    }
964
965
0
    if (custom_check) {
966
0
        LY_CHECK_GOTO(ret = custom_check(ctx, NULL, submod, check_data), error);
967
0
    }
968
969
0
    if (latest_sp) {
970
0
        latest_sp->latest_revision = 0;
971
0
    }
972
973
0
    lys_parser_fill_filepath(ctx, in, &submod->filepath);
974
975
    /* resolve imports and includes */
976
0
    LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, (struct lysp_module *)submod), error);
977
978
    /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
979
0
    memcpy(&main_ctx->tpdfs_nodes, &pctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
980
0
    memcpy(&main_ctx->grps_nodes, &pctx->grps_nodes, sizeof main_ctx->grps_nodes);
981
982
0
    if (format == LYS_IN_YANG) {
983
0
        yang_parser_ctx_free(yangctx);
984
0
    } else {
985
0
        yin_parser_ctx_free(yinctx);
986
0
    }
987
0
    *submodule = submod;
988
0
    return LY_SUCCESS;
989
990
0
error:
991
0
    lysp_module_free((struct lysp_module *)submod);
992
0
    if (format == LYS_IN_YANG) {
993
0
        yang_parser_ctx_free(yangctx);
994
0
    } else {
995
0
        yin_parser_ctx_free(yinctx);
996
0
    }
997
0
    return ret;
998
0
}
999
1000
/**
1001
 * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
1002
 *
1003
 * @param[in] mod Parsed module to add to.
1004
 * @return LY_SUCCESS on success.
1005
 * @return LY_ERR on error.
1006
 */
1007
static LY_ERR
1008
lys_parsed_add_internal_ietf_netconf(struct lysp_module *mod)
1009
0
{
1010
0
    struct lysp_ext_instance *ext_p;
1011
0
    struct lysp_stmt *stmt;
1012
0
    struct lysp_import *imp;
1013
1014
    /*
1015
     * 1) edit-config's operation
1016
     */
1017
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
1018
0
    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
1019
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
1020
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation", 0, &ext_p->argument));
1021
0
    ext_p->format = LY_VALUE_SCHEMA;
1022
0
    ext_p->prefix_data = mod;
1023
0
    ext_p->flags = LYS_INTERNAL;
1024
0
    ext_p->parent_stmt = LY_STMT_MODULE;
1025
0
    ext_p->parent_stmt_index = 0;
1026
1027
0
    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
1028
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1029
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1030
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
1031
0
    stmt->format = LY_VALUE_SCHEMA;
1032
0
    stmt->prefix_data = mod;
1033
0
    stmt->kw = LY_STMT_TYPE;
1034
1035
0
    stmt->child = calloc(1, sizeof *stmt->child);
1036
0
    stmt = stmt->child;
1037
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1038
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1039
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "merge", 0, &stmt->arg));
1040
0
    stmt->format = LY_VALUE_SCHEMA;
1041
0
    stmt->prefix_data = mod;
1042
0
    stmt->kw = LY_STMT_ENUM;
1043
1044
0
    stmt->next = calloc(1, sizeof *stmt->child);
1045
0
    stmt = stmt->next;
1046
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1047
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1048
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "replace", 0, &stmt->arg));
1049
0
    stmt->format = LY_VALUE_SCHEMA;
1050
0
    stmt->prefix_data = mod;
1051
0
    stmt->kw = LY_STMT_ENUM;
1052
1053
0
    stmt->next = calloc(1, sizeof *stmt->child);
1054
0
    stmt = stmt->next;
1055
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1056
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1057
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "create", 0, &stmt->arg));
1058
0
    stmt->format = LY_VALUE_SCHEMA;
1059
0
    stmt->prefix_data = mod;
1060
0
    stmt->kw = LY_STMT_ENUM;
1061
1062
0
    stmt->next = calloc(1, sizeof *stmt->child);
1063
0
    stmt = stmt->next;
1064
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1065
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1066
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "delete", 0, &stmt->arg));
1067
0
    stmt->format = LY_VALUE_SCHEMA;
1068
0
    stmt->prefix_data = mod;
1069
0
    stmt->kw = LY_STMT_ENUM;
1070
1071
0
    stmt->next = calloc(1, sizeof *stmt->child);
1072
0
    stmt = stmt->next;
1073
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1074
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1075
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "remove", 0, &stmt->arg));
1076
0
    stmt->format = LY_VALUE_SCHEMA;
1077
0
    stmt->prefix_data = mod;
1078
0
    stmt->kw = LY_STMT_ENUM;
1079
1080
    /*
1081
     * 2) filter's type
1082
     */
1083
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
1084
0
    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
1085
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
1086
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &ext_p->argument));
1087
0
    ext_p->format = LY_VALUE_SCHEMA;
1088
0
    ext_p->prefix_data = mod;
1089
0
    ext_p->flags = LYS_INTERNAL;
1090
0
    ext_p->parent_stmt = LY_STMT_MODULE;
1091
0
    ext_p->parent_stmt_index = 0;
1092
1093
0
    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
1094
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1095
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1096
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
1097
0
    stmt->format = LY_VALUE_SCHEMA;
1098
0
    stmt->prefix_data = mod;
1099
0
    stmt->kw = LY_STMT_TYPE;
1100
1101
0
    stmt->child = calloc(1, sizeof *stmt->child);
1102
0
    stmt = stmt->child;
1103
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1104
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1105
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "subtree", 0, &stmt->arg));
1106
0
    stmt->format = LY_VALUE_SCHEMA;
1107
0
    stmt->prefix_data = mod;
1108
0
    stmt->kw = LY_STMT_ENUM;
1109
1110
0
    stmt->next = calloc(1, sizeof *stmt->child);
1111
0
    stmt = stmt->next;
1112
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1113
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
1114
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
1115
0
    stmt->format = LY_VALUE_SCHEMA;
1116
0
    stmt->prefix_data = mod;
1117
0
    stmt->kw = LY_STMT_ENUM;
1118
1119
    /* if-feature for enum allowed only for YANG 1.1 modules */
1120
0
    if (mod->version >= LYS_VERSION_1_1) {
1121
0
        stmt->child = calloc(1, sizeof *stmt->child);
1122
0
        stmt = stmt->child;
1123
0
        LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1124
0
        LY_CHECK_RET(lydict_insert(mod->mod->ctx, "if-feature", 0, &stmt->stmt));
1125
0
        LY_CHECK_RET(lydict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
1126
0
        stmt->format = LY_VALUE_SCHEMA;
1127
0
        stmt->prefix_data = mod;
1128
0
        stmt->kw = LY_STMT_IF_FEATURE;
1129
0
    }
1130
1131
    /*
1132
     * 3) filter's select
1133
     */
1134
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
1135
0
    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
1136
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
1137
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "select", 0, &ext_p->argument));
1138
0
    ext_p->format = LY_VALUE_SCHEMA;
1139
0
    ext_p->prefix_data = mod;
1140
0
    ext_p->flags = LYS_INTERNAL;
1141
0
    ext_p->parent_stmt = LY_STMT_MODULE;
1142
0
    ext_p->parent_stmt_index = 0;
1143
1144
0
    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
1145
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1146
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1147
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
1148
0
    stmt->format = LY_VALUE_SCHEMA;
1149
0
    stmt->prefix_data = mod;
1150
0
    stmt->kw = LY_STMT_TYPE;
1151
1152
    /* create new imports for the used prefixes */
1153
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
1154
1155
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1156
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1157
0
    imp->flags = LYS_INTERNAL;
1158
1159
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
1160
1161
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
1162
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
1163
0
    imp->flags = LYS_INTERNAL;
1164
1165
0
    return LY_SUCCESS;
1166
0
}
1167
1168
/**
1169
 * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
1170
 *
1171
 * @param[in] mod Parsed module to add to.
1172
 * @return LY_SUCCESS on success.
1173
 * @return LY_ERR on error.
1174
 */
1175
static LY_ERR
1176
lys_parsed_add_internal_ietf_netconf_with_defaults(struct lysp_module *mod)
1177
0
{
1178
0
    struct lysp_ext_instance *ext_p;
1179
0
    struct lysp_stmt *stmt;
1180
0
    struct lysp_import *imp;
1181
1182
    /* add new extension instance */
1183
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, ext_p, LY_EMEM);
1184
1185
    /* fill in the extension instance fields */
1186
0
    LY_CHECK_ERR_RET(!ext_p, LOGMEM(mod->mod->ctx), LY_EMEM);
1187
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_:annotation", 0, &ext_p->name));
1188
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "default", 0, &ext_p->argument));
1189
0
    ext_p->format = LY_VALUE_SCHEMA;
1190
0
    ext_p->prefix_data = mod;
1191
0
    ext_p->flags = LYS_INTERNAL;
1192
0
    ext_p->parent_stmt = LY_STMT_MODULE;
1193
0
    ext_p->parent_stmt_index = 0;
1194
1195
0
    ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
1196
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
1197
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
1198
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
1199
0
    stmt->format = LY_VALUE_SCHEMA;
1200
0
    stmt->prefix_data = mod;
1201
0
    stmt->kw = LY_STMT_TYPE;
1202
1203
    /* create new import for the used prefix */
1204
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
1205
1206
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
1207
0
    LY_CHECK_RET(lydict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
1208
0
    imp->flags = LYS_INTERNAL;
1209
1210
0
    return LY_SUCCESS;
1211
0
}
1212
1213
LY_ERR
1214
lys_create_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, ly_bool need_implemented,
1215
        LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
1216
        void *check_data, const char **features, struct lys_glob_unres *unres, struct lys_module **module)
1217
0
{
1218
0
    struct lys_module *mod = NULL, *latest, *mod_dup, *mod_impl;
1219
0
    struct lysp_submodule *submod;
1220
0
    LY_ERR ret;
1221
0
    LY_ARRAY_COUNT_TYPE u;
1222
0
    struct lys_yang_parser_ctx *yangctx = NULL;
1223
0
    struct lys_yin_parser_ctx *yinctx = NULL;
1224
0
    struct lys_parser_ctx *pctx = NULL;
1225
0
    char *filename, *rev, *dot;
1226
0
    size_t len;
1227
0
    ly_bool implement;
1228
1229
0
    assert(ctx && in && (!features || need_implemented) && unres);
1230
1231
0
    if (module) {
1232
0
        *module = NULL;
1233
0
    }
1234
1235
0
    if (ctx->flags & LY_CTX_ALL_IMPLEMENTED) {
1236
0
        implement = 1;
1237
0
    } else {
1238
0
        implement = need_implemented;
1239
0
    }
1240
1241
0
    mod = calloc(1, sizeof *mod);
1242
0
    LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
1243
0
    mod->ctx = ctx;
1244
1245
    /* parse */
1246
0
    switch (format) {
1247
0
    case LYS_IN_YIN:
1248
0
        ret = yin_parse_module(&yinctx, in, mod, unres);
1249
0
        pctx = (struct lys_parser_ctx *)yinctx;
1250
0
        break;
1251
0
    case LYS_IN_YANG:
1252
0
        ret = yang_parse_module(&yangctx, in, mod, unres);
1253
0
        pctx = (struct lys_parser_ctx *)yangctx;
1254
0
        break;
1255
0
    default:
1256
0
        LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1257
0
        ret = LY_EINVAL;
1258
0
        break;
1259
0
    }
1260
0
    LY_CHECK_GOTO(ret, free_mod_cleanup);
1261
1262
    /* make sure that the newest revision is at position 0 */
1263
0
    lysp_sort_revisions(mod->parsed->revs);
1264
0
    if (mod->parsed->revs) {
1265
0
        LY_CHECK_GOTO(ret = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), free_mod_cleanup);
1266
0
    }
1267
1268
    /* decide the latest revision */
1269
0
    latest = (struct lys_module *)ly_ctx_get_module_latest(ctx, mod->name);
1270
0
    if (latest) {
1271
0
        if (mod->revision) {
1272
0
            if (!latest->revision) {
1273
                /* latest has no revision, so mod is anyway newer */
1274
0
                mod->latest_revision = latest->latest_revision;
1275
                /* the latest is zeroed later when the new module is being inserted into the context */
1276
0
            } else if (strcmp(mod->revision, latest->revision) > 0) {
1277
0
                mod->latest_revision = latest->latest_revision;
1278
                /* the latest is zeroed later when the new module is being inserted into the context */
1279
0
            } else {
1280
0
                latest = NULL;
1281
0
            }
1282
0
        } else {
1283
0
            latest = NULL;
1284
0
        }
1285
0
    } else {
1286
0
        mod->latest_revision = 1;
1287
0
    }
1288
1289
0
    if (custom_check) {
1290
0
        LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), free_mod_cleanup);
1291
0
    }
1292
1293
    /* check whether it is not already in the context in the same revision */
1294
0
    mod_dup = (struct lys_module *)ly_ctx_get_module(ctx, mod->name, mod->revision);
1295
0
    if (implement) {
1296
0
        mod_impl = ly_ctx_get_module_implemented(ctx, mod->name);
1297
0
        if (mod_impl && (mod_impl != mod_dup)) {
1298
0
            LOGERR(ctx, LY_EDENIED, "Module \"%s@%s\" is already implemented in the context.", mod_impl->name,
1299
0
                    mod_impl->revision ? mod_impl->revision : "<none>");
1300
0
            ret = LY_EDENIED;
1301
0
            goto free_mod_cleanup;
1302
0
        }
1303
0
    }
1304
0
    if (mod_dup) {
1305
0
        if (implement) {
1306
0
            if (!mod_dup->implemented) {
1307
                /* just implement it */
1308
0
                LY_CHECK_GOTO(ret = lys_set_implemented_r(mod_dup, features, unres), free_mod_cleanup);
1309
0
                goto free_mod_cleanup;
1310
0
            }
1311
1312
            /* nothing to do */
1313
0
            LOGVRB("Module \"%s@%s\" is already implemented in the context.", mod_dup->name,
1314
0
                    mod_dup->revision ? mod_dup->revision : "<none>");
1315
0
            goto free_mod_cleanup;
1316
0
        }
1317
1318
        /* nothing to do */
1319
0
        LOGVRB("Module \"%s@%s\" is already present in the context.", mod_dup->name,
1320
0
                mod_dup->revision ? mod_dup->revision : "<none>");
1321
0
        goto free_mod_cleanup;
1322
0
    }
1323
1324
0
    switch (in->type) {
1325
0
    case LY_IN_FILEPATH:
1326
        /* check that name and revision match filename */
1327
0
        filename = strrchr(in->method.fpath.filepath, '/');
1328
0
        if (!filename) {
1329
0
            filename = in->method.fpath.filepath;
1330
0
        } else {
1331
0
            filename++;
1332
0
        }
1333
0
        rev = strchr(filename, '@');
1334
0
        dot = strrchr(filename, '.');
1335
1336
        /* name */
1337
0
        len = strlen(mod->name);
1338
0
        if (strncmp(filename, mod->name, len) ||
1339
0
                ((rev && (rev != &filename[len])) || (!rev && (dot != &filename[len])))) {
1340
0
            LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
1341
0
        }
1342
0
        if (rev) {
1343
0
            len = dot - ++rev;
1344
0
            if (!mod->parsed->revs || (len != LY_REV_SIZE - 1) || strncmp(mod->parsed->revs[0].date, rev, len)) {
1345
0
                LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1346
0
                        mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1347
0
            }
1348
0
        }
1349
1350
0
        break;
1351
0
    case LY_IN_FD:
1352
0
    case LY_IN_FILE:
1353
0
    case LY_IN_MEMORY:
1354
        /* nothing special to do */
1355
0
        break;
1356
0
    case LY_IN_ERROR:
1357
0
        LOGINT(ctx);
1358
0
        ret = LY_EINT;
1359
0
        goto free_mod_cleanup;
1360
0
    }
1361
0
    lys_parser_fill_filepath(ctx, in, &mod->filepath);
1362
1363
0
    if (latest) {
1364
0
        latest->latest_revision = 0;
1365
0
    }
1366
1367
    /* add internal data in case specific modules were parsed */
1368
0
    if (!strcmp(mod->name, "ietf-netconf")) {
1369
0
        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf(mod->parsed), free_mod_cleanup);
1370
0
    } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
1371
0
        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf_with_defaults(mod->parsed), free_mod_cleanup);
1372
0
    }
1373
1374
    /* add the module into newly created module set, will also be freed from there on any error */
1375
0
    LY_CHECK_GOTO(ret = ly_set_add(&unres->creating, mod, 1, NULL), free_mod_cleanup);
1376
1377
    /* add into context */
1378
0
    ret = ly_set_add(&ctx->list, mod, 1, NULL);
1379
0
    LY_CHECK_GOTO(ret, cleanup);
1380
0
    ctx->change_count++;
1381
1382
    /* resolve includes and all imports */
1383
0
    LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, mod->parsed), cleanup);
1384
1385
    /* check name collisions */
1386
0
    LY_CHECK_GOTO(ret = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
1387
    /* TODO groupings */
1388
0
    LY_CHECK_GOTO(ret = lysp_check_dup_features(pctx, mod->parsed), cleanup);
1389
0
    LY_CHECK_GOTO(ret = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
1390
1391
    /* compile features */
1392
0
    LY_CHECK_GOTO(ret = lys_compile_feature_iffeatures(mod->parsed), cleanup);
1393
1394
    /* pre-compile identities of the module and any submodules */
1395
0
    LY_CHECK_GOTO(ret = lys_identity_precompile(NULL, ctx, mod->parsed, mod->parsed->identities, &mod->identities), cleanup);
1396
0
    LY_ARRAY_FOR(mod->parsed->includes, u) {
1397
0
        submod = mod->parsed->includes[u].submodule;
1398
0
        ret = lys_identity_precompile(NULL, ctx, (struct lysp_module *)submod, submod->identities, &mod->identities);
1399
0
        LY_CHECK_GOTO(ret, cleanup);
1400
0
    }
1401
1402
0
    if (implement) {
1403
        /* implement (compile) */
1404
0
        LY_CHECK_GOTO(ret = lys_set_implemented_r(mod, features, unres), cleanup);
1405
0
    }
1406
1407
    /* success */
1408
0
    goto cleanup;
1409
1410
0
free_mod_cleanup:
1411
0
    lys_module_free(mod);
1412
0
    if (ret) {
1413
0
        mod = NULL;
1414
0
    } else {
1415
        /* return the existing module */
1416
0
        assert(mod_dup);
1417
0
        mod = mod_dup;
1418
0
    }
1419
1420
0
cleanup:
1421
0
    if (pctx) {
1422
0
        ly_set_erase(&pctx->tpdfs_nodes, NULL);
1423
0
    }
1424
0
    if (format == LYS_IN_YANG) {
1425
0
        yang_parser_ctx_free(yangctx);
1426
0
    } else {
1427
0
        yin_parser_ctx_free(yinctx);
1428
0
    }
1429
1430
0
    if (!ret && module) {
1431
0
        *module = mod;
1432
0
    }
1433
0
    return ret;
1434
0
}
1435
1436
static LYS_INFORMAT
1437
lys_parse_get_format(const struct ly_in *in, LYS_INFORMAT format)
1438
0
{
1439
0
    if (!format && (in->type == LY_IN_FILEPATH)) {
1440
        /* unknown format - try to detect it from filename's suffix */
1441
0
        const char *path = in->method.fpath.filepath;
1442
0
        size_t len = strlen(path);
1443
1444
        /* ignore trailing whitespaces */
1445
0
        for ( ; len > 0 && isspace(path[len - 1]); len--) {}
1446
1447
0
        if ((len >= LY_YANG_SUFFIX_LEN + 1) &&
1448
0
                !strncmp(&path[len - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX, LY_YANG_SUFFIX_LEN)) {
1449
0
            format = LYS_IN_YANG;
1450
0
        } else if ((len >= LY_YIN_SUFFIX_LEN + 1) &&
1451
0
                !strncmp(&path[len - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX, LY_YIN_SUFFIX_LEN)) {
1452
0
            format = LYS_IN_YIN;
1453
0
        } /* else still unknown */
1454
0
    }
1455
1456
0
    return format;
1457
0
}
1458
1459
API LY_ERR
1460
lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char **features, const struct lys_module **module)
1461
0
{
1462
0
    LY_ERR ret;
1463
0
    struct lys_glob_unres unres = {0};
1464
1465
0
    if (module) {
1466
0
        *module = NULL;
1467
0
    }
1468
0
    LY_CHECK_ARG_RET(NULL, ctx, in, LY_EINVAL);
1469
1470
0
    format = lys_parse_get_format(in, format);
1471
0
    LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
1472
1473
    /* remember input position */
1474
0
    in->func_start = in->current;
1475
1476
0
    ret = lys_create_module(ctx, in, format, 1, NULL, NULL, features, &unres, (struct lys_module **)module);
1477
0
    LY_CHECK_GOTO(ret, cleanup);
1478
1479
    /* resolve global unres */
1480
0
    ret = lys_compile_unres_glob(ctx, &unres);
1481
0
    LY_CHECK_GOTO(ret, cleanup);
1482
1483
0
cleanup:
1484
0
    if (ret) {
1485
0
        lys_compile_unres_glob_revert(ctx, &unres);
1486
0
    }
1487
0
    lys_compile_unres_glob_erase(ctx, &unres);
1488
0
    if (ret && module) {
1489
0
        *module = NULL;
1490
0
    }
1491
0
    return ret;
1492
0
}
1493
1494
API LY_ERR
1495
lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const struct lys_module **module)
1496
0
{
1497
0
    LY_ERR ret;
1498
0
    struct ly_in *in = NULL;
1499
1500
0
    LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, LY_EINVAL);
1501
1502
0
    LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
1503
1504
0
    ret = lys_parse(ctx, in, format, NULL, module);
1505
0
    ly_in_free(in, 0);
1506
1507
0
    return ret;
1508
0
}
1509
1510
API LY_ERR
1511
lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const struct lys_module **module)
1512
0
{
1513
0
    LY_ERR ret;
1514
0
    struct ly_in *in = NULL;
1515
1516
0
    LY_CHECK_ARG_RET(ctx, fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
1517
1518
0
    LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
1519
1520
0
    ret = lys_parse(ctx, in, format, NULL, module);
1521
0
    ly_in_free(in, 0);
1522
1523
0
    return ret;
1524
0
}
1525
1526
API LY_ERR
1527
lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const struct lys_module **module)
1528
0
{
1529
0
    LY_ERR ret;
1530
0
    struct ly_in *in = NULL;
1531
1532
0
    LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, LY_EINVAL);
1533
1534
0
    LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
1535
0
            LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
1536
1537
0
    ret = lys_parse(ctx, in, format, NULL, module);
1538
0
    ly_in_free(in, 0);
1539
1540
0
    return ret;
1541
0
}
1542
1543
API LY_ERR
1544
lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *name, const char *revision,
1545
        char **localfile, LYS_INFORMAT *format)
1546
0
{
1547
0
    LY_ERR ret = LY_EMEM;
1548
0
    size_t len, flen, match_len = 0, dir_len;
1549
0
    ly_bool implicit_cwd = 0;
1550
0
    char *wd, *wn = NULL;
1551
0
    DIR *dir = NULL;
1552
0
    struct dirent *file;
1553
0
    char *match_name = NULL;
1554
0
    LYS_INFORMAT format_aux, match_format = 0;
1555
0
    struct ly_set *dirs;
1556
0
    struct stat st;
1557
1558
0
    LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1559
1560
    /* start to fill the dir fifo with the context's search path (if set)
1561
     * and the current working directory */
1562
0
    LY_CHECK_RET(ly_set_new(&dirs));
1563
1564
0
    len = strlen(name);
1565
0
    if (cwd) {
1566
0
        wd = get_current_dir_name();
1567
0
        if (!wd) {
1568
0
            LOGMEM(NULL);
1569
0
            goto cleanup;
1570
0
        } else {
1571
            /* add implicit current working directory (./) to be searched,
1572
             * this directory is not searched recursively */
1573
0
            ret = ly_set_add(dirs, wd, 0, NULL);
1574
0
            LY_CHECK_GOTO(ret, cleanup);
1575
0
            implicit_cwd = 1;
1576
0
        }
1577
0
    }
1578
0
    if (searchpaths) {
1579
0
        for (uint64_t i = 0; searchpaths[i]; i++) {
1580
            /* check for duplicities with the implicit current working directory */
1581
0
            if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1582
0
                implicit_cwd = 0;
1583
0
                continue;
1584
0
            }
1585
0
            wd = strdup(searchpaths[i]);
1586
0
            if (!wd) {
1587
0
                LOGMEM(NULL);
1588
0
                goto cleanup;
1589
0
            } else {
1590
0
                ret = ly_set_add(dirs, wd, 0, NULL);
1591
0
                LY_CHECK_GOTO(ret, cleanup);
1592
0
            }
1593
0
        }
1594
0
    }
1595
0
    wd = NULL;
1596
1597
    /* start searching */
1598
0
    while (dirs->count) {
1599
0
        free(wd);
1600
0
        free(wn); wn = NULL;
1601
1602
0
        dirs->count--;
1603
0
        wd = (char *)dirs->objs[dirs->count];
1604
0
        dirs->objs[dirs->count] = NULL;
1605
0
        LOGVRB("Searching for \"%s\" in \"%s\".", name, wd);
1606
1607
0
        if (dir) {
1608
0
            closedir(dir);
1609
0
        }
1610
0
        dir = opendir(wd);
1611
0
        dir_len = strlen(wd);
1612
0
        if (!dir) {
1613
0
            LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1614
0
        } else {
1615
0
            while ((file = readdir(dir))) {
1616
0
                if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1617
                    /* skip . and .. */
1618
0
                    continue;
1619
0
                }
1620
0
                free(wn);
1621
0
                if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1622
0
                    LOGMEM(NULL);
1623
0
                    goto cleanup;
1624
0
                }
1625
0
                if (stat(wn, &st) == -1) {
1626
0
                    LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1627
0
                            file->d_name, wd, strerror(errno));
1628
0
                    continue;
1629
0
                }
1630
0
                if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1631
                    /* we have another subdirectory in searchpath to explore,
1632
                     * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1633
0
                    ret = ly_set_add(dirs, wn, 0, NULL);
1634
0
                    LY_CHECK_GOTO(ret, cleanup);
1635
1636
                    /* continue with the next item in current directory */
1637
0
                    wn = NULL;
1638
0
                    continue;
1639
0
                } else if (!S_ISREG(st.st_mode)) {
1640
                    /* not a regular file (note that we see the target of symlinks instead of symlinks */
1641
0
                    continue;
1642
0
                }
1643
1644
                /* here we know that the item is a file which can contain a module */
1645
0
                if (strncmp(name, file->d_name, len) ||
1646
0
                        ((file->d_name[len] != '.') && (file->d_name[len] != '@'))) {
1647
                    /* different filename than the module we search for */
1648
0
                    continue;
1649
0
                }
1650
1651
                /* get type according to filename suffix */
1652
0
                flen = strlen(file->d_name);
1653
0
                if ((flen >= LY_YANG_SUFFIX_LEN + 1) &&
1654
0
                        !strcmp(&file->d_name[flen - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX)) {
1655
0
                    format_aux = LYS_IN_YANG;
1656
0
                } else if ((flen >= LY_YIN_SUFFIX_LEN + 1) &&
1657
0
                        !strcmp(&file->d_name[flen - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX)) {
1658
0
                    format_aux = LYS_IN_YIN;
1659
0
                } else {
1660
                    /* not supportde suffix/file format */
1661
0
                    continue;
1662
0
                }
1663
1664
0
                if (revision) {
1665
                    /* we look for the specific revision, try to get it from the filename */
1666
0
                    if (file->d_name[len] == '@') {
1667
                        /* check revision from the filename */
1668
0
                        if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1669
                            /* another revision */
1670
0
                            continue;
1671
0
                        } else {
1672
                            /* exact revision */
1673
0
                            free(match_name);
1674
0
                            match_name = wn;
1675
0
                            wn = NULL;
1676
0
                            match_len = dir_len + 1 + len;
1677
0
                            match_format = format_aux;
1678
0
                            goto success;
1679
0
                        }
1680
0
                    } else {
1681
                        /* continue trying to find exact revision match, use this only if not found */
1682
0
                        free(match_name);
1683
0
                        match_name = wn;
1684
0
                        wn = NULL;
1685
0
                        match_len = dir_len + 1 + len;
1686
0
                        match_format = format_aux;
1687
0
                        continue;
1688
0
                    }
1689
0
                } else {
1690
                    /* remember the revision and try to find the newest one */
1691
0
                    if (match_name) {
1692
0
                        if ((file->d_name[len] != '@') ||
1693
0
                                lysp_check_date(NULL, &file->d_name[len + 1],
1694
0
                                flen - ((format_aux == LYS_IN_YANG) ? LY_YANG_SUFFIX_LEN : LY_YIN_SUFFIX_LEN) - len - 1, NULL)) {
1695
0
                            continue;
1696
0
                        } else if ((match_name[match_len] == '@') &&
1697
0
                                (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1698
0
                            continue;
1699
0
                        }
1700
0
                        free(match_name);
1701
0
                    }
1702
1703
0
                    match_name = wn;
1704
0
                    wn = NULL;
1705
0
                    match_len = dir_len + 1 + len;
1706
0
                    match_format = format_aux;
1707
0
                    continue;
1708
0
                }
1709
0
            }
1710
0
        }
1711
0
    }
1712
1713
0
success:
1714
0
    (*localfile) = match_name;
1715
0
    match_name = NULL;
1716
0
    if (format) {
1717
0
        (*format) = match_format;
1718
0
    }
1719
0
    ret = LY_SUCCESS;
1720
1721
0
cleanup:
1722
0
    free(wn);
1723
0
    free(wd);
1724
0
    if (dir) {
1725
0
        closedir(dir);
1726
0
    }
1727
0
    free(match_name);
1728
0
    ly_set_free(dirs, free);
1729
1730
0
    return ret;
1731
0
}