Coverage Report

Created: 2026-04-12 06:40

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
 * @author Michal Vasko <mvasko@cesnet.cz>
5
 * @brief Schema tree implementation
6
 *
7
 * Copyright (c) 2015 - 2026 CESNET, z.s.p.o.
8
 *
9
 * This source code is licensed under BSD 3-Clause License (the "License").
10
 * You may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     https://opensource.org/licenses/BSD-3-Clause
14
 */
15
16
#define _GNU_SOURCE /* asprintf, strdup */
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 "compat.h"
32
#include "context.h"
33
#include "dict.h"
34
#include "in.h"
35
#include "in_internal.h"
36
#include "log.h"
37
#include "ly_common.h"
38
#include "parser_internal.h"
39
#include "parser_schema.h"
40
#include "path.h"
41
#include "plugins_exts.h"
42
#include "plugins_internal.h"
43
#include "schema_compile.h"
44
#include "schema_compile_amend.h"
45
#include "schema_features.h"
46
#include "set.h"
47
#include "tree.h"
48
#include "tree_edit.h"
49
#include "tree_schema_free.h"
50
#include "tree_schema_internal.h"
51
#include "xml.h"
52
#include "xpath.h"
53
54
const char * const ly_devmod_list[] = {
55
    [LYS_DEV_NOT_SUPPORTED] = "not-supported",
56
    [LYS_DEV_ADD] = "add",
57
    [LYS_DEV_DELETE] = "delete",
58
    [LYS_DEV_REPLACE] = "replace",
59
};
60
61
LIBYANG_API_DEF LY_ERR
62
lysc_tree_dfs_full(const struct lysc_node *root, lysc_dfs_clb dfs_clb, void *data)
63
0
{
64
0
    struct lysc_node *elem, *elem2;
65
0
    const struct lysc_node_action *action;
66
0
    const struct lysc_node_notif *notif;
67
68
0
    LY_CHECK_ARG_RET(NULL, root, dfs_clb, LY_EINVAL);
69
70
0
    LYSC_TREE_DFS_BEGIN(root, elem) {
71
        /* schema node */
72
0
        LY_CHECK_RET(dfs_clb(elem, data, &LYSC_TREE_DFS_continue));
73
74
0
        LY_LIST_FOR(lysc_node_actions(elem), action) {
75
0
            LYSC_TREE_DFS_BEGIN(action, elem2) {
76
                /* action subtree */
77
0
                LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
78
79
0
                LYSC_TREE_DFS_END(action, elem2);
80
0
            }
81
0
        }
82
83
0
        LY_LIST_FOR(lysc_node_notifs(elem), notif) {
84
0
            LYSC_TREE_DFS_BEGIN(notif, elem2) {
85
                /* notification subtree */
86
0
                LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
87
88
0
                LYSC_TREE_DFS_END(notif, elem2);
89
0
            }
90
0
        }
91
92
0
        LYSC_TREE_DFS_END(root, elem);
93
0
    }
94
95
0
    return LY_SUCCESS;
96
0
}
97
98
LIBYANG_API_DEF LY_ERR
99
lysc_module_dfs_full(const struct lys_module *mod, lysc_dfs_clb dfs_clb, void *data)
100
0
{
101
0
    const struct lysc_node *root;
102
103
0
    LY_CHECK_ARG_RET(NULL, mod, mod->compiled, dfs_clb, LY_EINVAL);
104
105
    /* schema nodes */
106
0
    LY_LIST_FOR(mod->compiled->data, root) {
107
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
108
0
    }
109
110
    /* RPCs */
111
0
    LY_LIST_FOR((const struct lysc_node *)mod->compiled->rpcs, root) {
112
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
113
0
    }
114
115
    /* notifications */
116
0
    LY_LIST_FOR((const struct lysc_node *)mod->compiled->notifs, root) {
117
0
        LY_CHECK_RET(lysc_tree_dfs_full(root, dfs_clb, data));
118
0
    }
119
120
0
    return LY_SUCCESS;
121
0
}
122
123
/**
124
 * @brief Find import prefix in imports.
125
 */
126
static const struct lys_module *
127
ly_schema_resolve_prefix(const struct ly_ctx *UNUSED(ctx), const char *prefix, uint32_t prefix_len, const void *prefix_data)
128
2.07M
{
129
2.07M
    const struct lysp_module *prefix_mod = prefix_data;
130
2.07M
    LY_ARRAY_COUNT_TYPE u;
131
2.07M
    const char *local_prefix;
132
133
2.07M
    local_prefix = prefix_mod->is_submod ? ((struct lysp_submodule *)prefix_mod)->prefix : prefix_mod->mod->prefix;
134
2.07M
    if (!prefix_len || !ly_strncmp(local_prefix, prefix, prefix_len)) {
135
        /* it is the prefix of the module itself */
136
55.6k
        return prefix_mod->mod;
137
55.6k
    }
138
139
    /* search in imports */
140
2.49M
    LY_ARRAY_FOR(prefix_mod->imports, u) {
141
2.49M
        if (!ly_strncmp(prefix_mod->imports[u].prefix, prefix, prefix_len)) {
142
1.93M
            return prefix_mod->imports[u].module;
143
1.93M
        }
144
2.49M
    }
145
146
81.1k
    return NULL;
147
2.01M
}
148
149
/**
150
 * @brief Find resolved module for a prefix in prefix - module pairs.
151
 */
152
static const struct lys_module *
153
ly_schema_resolved_resolve_prefix(const struct ly_ctx *UNUSED(ctx), const char *prefix, uint32_t prefix_len,
154
        const void *prefix_data)
155
1.02M
{
156
1.02M
    const struct lysc_prefix *prefixes = prefix_data;
157
1.02M
    LY_ARRAY_COUNT_TYPE u;
158
159
1.44M
    LY_ARRAY_FOR(prefixes, u) {
160
1.44M
        if ((!prefixes[u].prefix && !prefix_len) || (prefixes[u].prefix && !ly_strncmp(prefixes[u].prefix, prefix, prefix_len))) {
161
861k
            return prefixes[u].mod;
162
861k
        }
163
1.44M
    }
164
165
162k
    return NULL;
166
1.02M
}
167
168
/**
169
 * @brief Find XML namespace prefix in XML namespaces, which are then mapped to modules.
170
 */
171
static const struct lys_module *
172
ly_xml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, uint32_t prefix_len, const void *prefix_data)
173
671k
{
174
671k
    const struct lys_module *mod;
175
671k
    const struct lyxml_ns *ns;
176
671k
    const struct ly_set *ns_set = prefix_data;
177
178
671k
    ns = lyxml_ns_get(ns_set, prefix, prefix_len);
179
671k
    if (!ns) {
180
2.02k
        return NULL;
181
2.02k
    }
182
183
669k
    mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
184
669k
    if (!mod) {
185
        /* for YIN extension prefix resolution */
186
18.5k
        mod = ly_ctx_get_module_latest_ns(ctx, ns->uri);
187
18.5k
    }
188
669k
    return mod;
189
671k
}
190
191
/**
192
 * @brief Find module name.
193
 */
194
static const struct lys_module *
195
ly_json_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, uint32_t prefix_len, const void *UNUSED(prefix_data))
196
325k
{
197
325k
    return ly_ctx_get_module_implemented2(ctx, prefix, prefix_len);
198
325k
}
199
200
const struct lys_module *
201
ly_resolve_prefix(const struct ly_ctx *ctx, const void *prefix, uint32_t prefix_len, LY_VALUE_FORMAT format,
202
        const void *prefix_data)
203
2.97M
{
204
2.97M
    const struct lys_module *mod = NULL;
205
206
2.97M
    LY_CHECK_ARG_RET(ctx, prefix, prefix_len, NULL);
207
208
2.97M
    switch (format) {
209
2.07M
    case LY_VALUE_SCHEMA:
210
2.07M
        mod = ly_schema_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
211
2.07M
        break;
212
573k
    case LY_VALUE_SCHEMA_RESOLVED:
213
573k
        mod = ly_schema_resolved_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
214
573k
        break;
215
5.80k
    case LY_VALUE_XML:
216
5.80k
    case LY_VALUE_STR_NS:
217
5.80k
        mod = ly_xml_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
218
5.80k
        break;
219
0
    case LY_VALUE_CANON:
220
325k
    case LY_VALUE_JSON:
221
325k
    case LY_VALUE_LYB:
222
325k
        mod = ly_json_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
223
325k
        break;
224
2.97M
    }
225
226
2.97M
    return mod;
227
2.97M
}
228
229
LIBYANG_API_DEF const struct lys_module *
230
lys_find_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix, uint32_t prefix_len,
231
        LY_VALUE_FORMAT format, const void *prefix_data)
232
2.02M
{
233
2.02M
    if (prefix_len) {
234
561k
        return ly_resolve_prefix(ctx, prefix, prefix_len, format, prefix_data);
235
1.46M
    } else {
236
1.46M
        switch (format) {
237
0
        case LY_VALUE_SCHEMA:
238
            /* use local module */
239
0
            return ly_schema_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
240
450k
        case LY_VALUE_SCHEMA_RESOLVED:
241
            /* use local module */
242
450k
            return ly_schema_resolved_resolve_prefix(ctx, prefix, prefix_len, prefix_data);
243
0
        case LY_VALUE_CANON:
244
347k
        case LY_VALUE_JSON:
245
347k
        case LY_VALUE_LYB:
246
347k
        case LY_VALUE_STR_NS:
247
            /* use context node module (as specified) */
248
347k
            return ctx_node ? ctx_node->module : NULL;
249
665k
        case LY_VALUE_XML:
250
            /* use the default namespace */
251
665k
            return ly_xml_resolve_prefix(ctx, NULL, 0, prefix_data);
252
1.46M
        }
253
1.46M
    }
254
255
0
    return NULL;
256
2.02M
}
257
258
static void
259
lys_getnext_into_case(const struct lysc_node_case *first_case, const struct lysc_node **last, const struct lysc_node **next)
260
102k
{
261
103k
    for ( ; first_case; first_case = (const struct lysc_node_case *)first_case->next) {
262
103k
        if (first_case->child) {
263
            /* there is something to return */
264
102k
            (*next) = first_case->child;
265
102k
            return;
266
102k
        }
267
103k
    }
268
269
    /* no children in choice's cases, so go to the choice's sibling instead of into it */
270
396
    (*last) = (*next);
271
396
    (*next) = (*next)->next;
272
396
}
273
274
LIBYANG_API_DEF const struct lysc_node *
275
lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, uint32_t options)
276
30.5M
{
277
30.5M
    const struct lysc_node *next = NULL;
278
30.5M
    ly_bool action_flag = 0, notif_flag = 0;
279
280
30.5M
    LY_CHECK_ARG_RET(NULL, last || parent || module, NULL);
281
282
30.7M
next:
283
30.7M
    if (!last) {
284
        /* first call */
285
286
        /* learn where to start */
287
9.18M
        if (parent) {
288
            /* schema subtree */
289
5.63M
            next = last = lysc_node_child(parent);
290
5.63M
        } else {
291
            /* top level data */
292
3.54M
            next = last = module->data;
293
3.54M
        }
294
9.18M
        if (!next) {
295
            /* try to get action or notification */
296
1.60M
            goto repeat;
297
1.60M
        }
298
        /* test if the next can be returned */
299
7.58M
        goto check;
300
301
21.5M
    } else if (last->nodetype & (LYS_RPC | LYS_ACTION)) {
302
325k
        action_flag = 1;
303
325k
        next = last->next;
304
21.2M
    } else if (last->nodetype == LYS_NOTIF) {
305
855k
        action_flag = notif_flag = 1;
306
855k
        next = last->next;
307
20.3M
    } else {
308
20.3M
        next = last->next;
309
20.3M
    }
310
311
36.7M
repeat:
312
36.7M
    if (!next) {
313
19.4M
        if (last && (last->parent != parent)) {
314
            /* go back to parent */
315
183k
            last = last->parent;
316
183k
            goto next;
317
19.2M
        } else if (!action_flag) {
318
6.46M
            action_flag = 1;
319
6.46M
            if (parent) {
320
3.34M
                next = (struct lysc_node *)lysc_node_actions(parent);
321
3.34M
            } else if (module) {
322
3.11M
                next = (struct lysc_node *)module->rpcs;
323
3.11M
            }
324
12.8M
        } else if (!notif_flag) {
325
6.44M
            notif_flag = 1;
326
6.44M
            if (parent) {
327
3.34M
                next = (struct lysc_node *)lysc_node_notifs(parent);
328
3.34M
            } else if (module) {
329
3.10M
                next = (struct lysc_node *)module->notifs;
330
3.10M
            }
331
6.44M
        } else {
332
6.38M
            return NULL;
333
6.38M
        }
334
12.9M
        goto repeat;
335
19.4M
    }
336
24.8M
check:
337
24.8M
    switch (next->nodetype) {
338
337k
    case LYS_RPC:
339
337k
    case LYS_ACTION:
340
1.25M
    case LYS_NOTIF:
341
16.6M
    case LYS_LEAF:
342
16.6M
    case LYS_ANYXML:
343
16.6M
    case LYS_ANYDATA:
344
19.9M
    case LYS_LIST:
345
21.6M
    case LYS_LEAFLIST:
346
21.6M
        break;
347
90.3k
    case LYS_CASE:
348
90.3k
        if (options & LYS_GETNEXT_WITHCASE) {
349
183
            break;
350
90.1k
        } else {
351
            /* go into */
352
90.1k
            lys_getnext_into_case((const struct lysc_node_case *)next, &last, &next);
353
90.1k
        }
354
90.1k
        goto repeat;
355
2.45M
    case LYS_CONTAINER:
356
2.45M
        if (!(next->flags & LYS_PRESENCE) && (options & LYS_GETNEXT_INTONPCONT)) {
357
0
            if (lysc_node_child(next)) {
358
                /* go into */
359
0
                next = lysc_node_child(next);
360
0
            } else {
361
0
                last = next;
362
0
                next = next->next;
363
0
            }
364
0
            goto repeat;
365
0
        }
366
2.45M
        break;
367
2.45M
    case LYS_CHOICE:
368
468k
        if (options & LYS_GETNEXT_WITHCHOICE) {
369
90.6k
            break;
370
378k
        } else if ((options & LYS_GETNEXT_NOCHOICE) || !lysc_node_child(next)) {
371
365k
            next = next->next;
372
365k
        } else {
373
12.5k
            if (options & LYS_GETNEXT_WITHCASE) {
374
0
                next = lysc_node_child(next);
375
12.5k
            } else {
376
                /* go into */
377
12.5k
                lys_getnext_into_case(((struct lysc_node_choice *)next)->cases, &last, &next);
378
12.5k
            }
379
12.5k
        }
380
378k
        goto repeat;
381
378k
    case LYS_INPUT:
382
214k
        if (options & LYS_GETNEXT_OUTPUT) {
383
            /* skip */
384
0
            next = next->next;
385
214k
        } else {
386
            /* go into */
387
214k
            next = lysc_node_child(next);
388
214k
        }
389
214k
        goto repeat;
390
14.8k
    case LYS_OUTPUT:
391
14.8k
        if (!(options & LYS_GETNEXT_OUTPUT)) {
392
            /* skip */
393
14.8k
            next = next->next;
394
14.8k
        } else {
395
            /* go into */
396
0
            next = lysc_node_child(next);
397
0
        }
398
14.8k
        goto repeat;
399
0
    default:
400
        /* we should not be here */
401
0
        LOGINT(NULL);
402
0
        return NULL;
403
24.8M
    }
404
405
24.1M
    return next;
406
24.8M
}
407
408
/**
409
 * @brief Get schema node in extension instance according to the given parameters.
410
 *
411
 * @param[in] ext Extension instance which top-level schema node is being searched.
412
 * @param[in] parent Parsed parent data node.
413
 * @param[in] sparent Schema parent node.
414
 * @param[in] module Optional parameter to match the extension instance's (and its data) module.
415
 * @param[in] name Name of the schema node to find, if the string is not NULL-terminated, the @p name_len must be set.
416
 * @param[in] name_len Length of the @p name string, use in case the @p name is not NULL-terminated string.
417
 * @param[in] nodetype Allowed [type of the node](@ref schemanodetypes).
418
 * @param[in] is_xpath Set if searching for nodes in an XPath expression.
419
 * @param[out] snode Found schema node, NULL if no suitable was found.
420
 * @return Found schema node if there is some satisfy the provided requirements.
421
 */
422
static LY_ERR
423
lys_ext_find_node(const struct lysc_ext_instance *ext, const struct lyd_node *parent, const struct lysc_node *sparent,
424
        const char *prefix, uint32_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name,
425
        uint32_t name_len, ly_bool is_xpath, const struct lysc_node **snode)
426
244k
{
427
244k
    LY_ERR rc = LY_SUCCESS;
428
244k
    struct lyplg_ext *plg_ext;
429
244k
    const struct lys_module *mod;
430
244k
    const struct lysc_node *node;
431
432
244k
    plg_ext = LYSC_GET_EXT_PLG(ext->def->plugin_ref);
433
244k
    if (!plg_ext) {
434
0
        return LY_ENOT;
435
0
    }
436
437
    /* standard nodes */
438
244k
    if (is_xpath && plg_ext->snode_xpath) {
439
0
        rc = plg_ext->snode_xpath((struct lysc_ext_instance *)ext, prefix, prefix_len, format, prefix_data, name,
440
0
                name_len, snode);
441
244k
    } else if (!is_xpath && plg_ext->snode) {
442
0
        rc = plg_ext->snode((struct lysc_ext_instance *)ext, parent, sparent, prefix, prefix_len, format,
443
0
                prefix_data, name, name_len, snode);
444
244k
    } else {
445
244k
        lyplg_ext_get_storage(ext, LY_STMT_DATA_NODE_MASK, sizeof node, (const void **)&node);
446
244k
        if (node) {
447
            /* find the module */
448
0
            mod = lys_find_module((*snode)->module->ctx, parent ? parent->schema : sparent, prefix, prefix_len, format,
449
0
                    prefix_data);
450
0
        }
451
244k
        if (node && mod && mod->implemented) {
452
0
            while ((node = lys_getnext(node, node->parent, NULL, 0))) {
453
0
                if (node->module != mod) {
454
0
                    continue;
455
0
                }
456
0
                if (ly_strncmp(node->name, name, name_len)) {
457
0
                    continue;
458
0
                }
459
460
0
                break;
461
0
            }
462
0
            if (node) {
463
                /* matching node */
464
0
                *snode = node;
465
0
            }
466
0
        }
467
244k
        if (!*snode) {
468
244k
            rc = LY_ENOT;
469
244k
        }
470
244k
    }
471
472
244k
    return rc;
473
244k
}
474
475
LY_ERR
476
lys_find_child_node_ext(const struct ly_ctx *ctx, const struct lys_module *mod, const struct lyd_node *parent,
477
        const struct lysc_node *sparent, const char *prefix, uint32_t prefix_len, LY_VALUE_FORMAT format,
478
        void *prefix_data, const char *name, uint32_t name_len, ly_bool is_xpath, const struct lysc_node **snode,
479
        struct lysc_ext_instance **ext)
480
649k
{
481
649k
    LY_ERR r;
482
649k
    LY_ARRAY_COUNT_TYPE u;
483
649k
    struct lysc_ext_instance *exts;
484
485
649k
    *snode = NULL;
486
649k
    if (ext) {
487
211k
        *ext = NULL;
488
211k
    }
489
490
    /* check if there are any nested parent extension instances */
491
649k
    if (parent && parent->schema) {
492
0
        exts = parent->schema->exts;
493
649k
    } else if (sparent) {
494
360k
        exts = sparent->exts;
495
360k
    } else {
496
288k
        exts = NULL;
497
288k
    }
498
649k
    LY_ARRAY_FOR(exts, u) {
499
0
        r = lys_ext_find_node(&exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len,
500
0
                is_xpath, snode);
501
0
        if (!r) {
502
0
            if (ext) {
503
                /* schema node found, remember the ext instance */
504
0
                *ext = &exts[u];
505
0
            }
506
0
            return LY_SUCCESS;
507
0
        } else if (r != LY_ENOT) {
508
0
            return r;
509
0
        }
510
511
        /* data was not from this ext instance, continue */
512
0
    }
513
514
    /* check if there are global module ext instances */
515
649k
    if (!mod) {
516
156k
        mod = lys_find_module(ctx, parent ? parent->schema : sparent, prefix, prefix_len, format, prefix_data);
517
156k
    }
518
649k
    if (mod && mod->implemented) {
519
493k
        exts = mod->compiled->exts;
520
493k
    } else {
521
156k
        exts = NULL;
522
156k
    }
523
649k
    LY_ARRAY_FOR(exts, u) {
524
244k
        r = lys_ext_find_node(&exts[u], parent, sparent, prefix, prefix_len, format, prefix_data, name, name_len,
525
244k
                is_xpath, snode);
526
244k
        if (!r) {
527
0
            if (ext) {
528
0
                *ext = &exts[u];
529
0
            }
530
0
            return LY_SUCCESS;
531
244k
        } else if (r != LY_ENOT) {
532
0
            return r;
533
0
        }
534
244k
    }
535
536
    /* no extensions or none matched */
537
649k
    return LY_ENOT;
538
649k
}
539
540
LY_ERR
541
lys_find_child_node(const struct ly_ctx *ctx, const struct lysc_node *parent, const struct lys_module *mod,
542
        const char *prefix, uint32_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name,
543
        uint32_t name_len, uint32_t options, const struct lysc_node **snode, struct lysc_ext_instance **ext)
544
1.56M
{
545
1.56M
    const struct lysc_node *node = NULL;
546
547
1.56M
    assert(name);
548
549
1.56M
    *snode = NULL;
550
1.56M
    if (ext) {
551
1.02M
        *ext = NULL;
552
1.02M
    }
553
554
1.56M
    if (prefix && !prefix_len) {
555
0
        prefix_len = strlen(prefix);
556
0
    }
557
1.56M
    if (!name_len) {
558
1.07k
        name_len = strlen(name);
559
1.07k
    }
560
561
    /* find the module */
562
1.56M
    if (!mod) {
563
1.04M
        mod = lys_find_module(ctx, parent, prefix, prefix_len, format, prefix_data);
564
1.04M
    }
565
566
    /* look for a standard schema node */
567
1.56M
    if (mod && mod->implemented) {
568
5.24M
        while ((node = lys_getnext(node, parent, mod->compiled, options))) {
569
            /* check module */
570
5.18M
            if (node->module != mod) {
571
2.59k
                continue;
572
2.59k
            }
573
574
            /* check name */
575
5.18M
            if (!ly_strncmp(node->name, name, name_len)) {
576
1.35M
                *snode = node;
577
1.35M
                return LY_SUCCESS;
578
1.35M
            }
579
5.18M
        }
580
1.41M
    }
581
582
    /* look for an ext instance node */
583
209k
    return lys_find_child_node_ext(ctx, mod, NULL, parent, prefix, prefix_len, format, prefix_data, name, name_len,
584
209k
            0, snode, ext);
585
1.56M
}
586
587
LIBYANG_API_DEF const struct lysc_node *
588
lys_find_child(const struct ly_ctx *ctx, const struct lysc_node *parent, const struct lys_module *mod,
589
        const char *mod_name, uint32_t mod_len, const char *name, uint32_t name_len, uint32_t options)
590
525k
{
591
525k
    const struct lysc_node *snode = NULL;
592
593
1.05M
    LY_CHECK_ARG_RET(NULL, ctx || parent || mod, (mod || mod_name) && (!mod || !mod_name), name, NULL);
594
595
525k
    if (parent) {
596
525k
        ctx = parent->module->ctx;
597
525k
    } else if (mod) {
598
0
        ctx = mod->ctx;
599
0
    }
600
601
525k
    if (mod) {
602
525k
        mod_name = mod->name;
603
525k
    }
604
605
525k
    if (mod_name && !mod_len) {
606
525k
        mod_len = strlen(mod_name);
607
525k
    }
608
525k
    if (!name_len) {
609
37
        name_len = strlen(name);
610
37
    }
611
612
525k
    lys_find_child_node(ctx, parent, mod, mod_name, mod_len, LY_VALUE_JSON, NULL, name, name_len, options, &snode, NULL);
613
525k
    return snode;
614
1.05M
}
615
616
LIBYANG_API_DEF LY_ERR
617
lys_find_xpath_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
618
        struct ly_set **set)
619
0
{
620
0
    LY_ERR ret = LY_SUCCESS;
621
0
    struct lyxp_set xp_set = {0};
622
0
    struct lyxp_expr *exp = NULL;
623
0
    uint32_t i;
624
625
0
    LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
626
0
    LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
627
0
    if (!(options & LYXP_SCNODE_ALL)) {
628
0
        options |= LYXP_SCNODE;
629
0
    }
630
0
    if (!ctx) {
631
0
        ctx = ctx_node->module->ctx;
632
0
    }
633
634
    /* allocate return set */
635
0
    ret = ly_set_new(set);
636
0
    LY_CHECK_GOTO(ret, cleanup);
637
638
    /* compile expression */
639
0
    ret = lyxp_expr_parse(ctx, NULL, xpath, 0, 1, &exp);
640
0
    LY_CHECK_GOTO(ret, cleanup);
641
642
    /* atomize expression */
643
0
    ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
644
0
    LY_CHECK_GOTO(ret, cleanup);
645
646
    /* transform into ly_set */
647
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
648
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
649
0
    (*set)->size = xp_set.used;
650
651
0
    for (i = 0; i < xp_set.used; ++i) {
652
0
        if (xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
653
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
654
0
            LY_CHECK_GOTO(ret, cleanup);
655
0
        }
656
0
    }
657
658
0
cleanup:
659
0
    lyxp_set_free_content(&xp_set);
660
0
    lyxp_expr_free(exp);
661
0
    return ret;
662
0
}
663
664
LIBYANG_API_DEF LY_ERR
665
lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
666
        const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
667
0
{
668
0
    LY_ERR ret = LY_SUCCESS;
669
0
    struct lyxp_set xp_set = {0};
670
0
    uint32_t i;
671
672
0
    LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
673
0
    LY_CHECK_CTX_EQUAL_RET(__func__, ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
674
0
    if (!(options & LYXP_SCNODE_ALL)) {
675
0
        options = LYXP_SCNODE;
676
0
    }
677
678
    /* allocate return set */
679
0
    ret = ly_set_new(set);
680
0
    LY_CHECK_GOTO(ret, cleanup);
681
682
    /* atomize expression */
683
0
    ret = lyxp_atomize(cur_mod->ctx, expr, cur_mod, LY_VALUE_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, ctx_node,
684
0
            &xp_set, options);
685
0
    LY_CHECK_GOTO(ret, cleanup);
686
687
    /* transform into ly_set */
688
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
689
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
690
0
    (*set)->size = xp_set.used;
691
692
0
    for (i = 0; i < xp_set.used; ++i) {
693
0
        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx >= LYXP_SET_SCNODE_ATOM_NODE)) {
694
0
            assert((xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_NODE) ||
695
0
                    (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_VAL) ||
696
0
                    (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX));
697
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
698
0
            LY_CHECK_GOTO(ret, cleanup);
699
0
        }
700
0
    }
701
702
0
cleanup:
703
0
    lyxp_set_free_content(&xp_set);
704
0
    if (ret) {
705
0
        ly_set_free(*set, NULL);
706
0
        *set = NULL;
707
0
    }
708
0
    return ret;
709
0
}
710
711
LIBYANG_API_DEF LY_ERR
712
lys_find_xpath(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *xpath, uint32_t options,
713
        struct ly_set **set)
714
0
{
715
0
    LY_ERR ret = LY_SUCCESS;
716
0
    struct lyxp_set xp_set = {0};
717
0
    struct lyxp_expr *exp = NULL;
718
0
    uint32_t i;
719
720
0
    LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
721
0
    LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
722
0
    if (!(options & LYXP_SCNODE_ALL)) {
723
0
        options |= LYXP_SCNODE;
724
0
    }
725
0
    if (!ctx) {
726
0
        ctx = ctx_node->module->ctx;
727
0
    }
728
729
    /* allocate return set */
730
0
    ret = ly_set_new(set);
731
0
    LY_CHECK_GOTO(ret, cleanup);
732
733
    /* compile expression */
734
0
    ret = lyxp_expr_parse(ctx, NULL, xpath, 0, 1, &exp);
735
0
    LY_CHECK_GOTO(ret, cleanup);
736
737
    /* atomize expression */
738
0
    ret = lyxp_atomize(ctx, exp, NULL, LY_VALUE_JSON, NULL, ctx_node, ctx_node, &xp_set, options);
739
0
    LY_CHECK_GOTO(ret, cleanup);
740
741
    /* transform into ly_set */
742
0
    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
743
0
    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx); ret = LY_EMEM, cleanup);
744
0
    (*set)->size = xp_set.used;
745
746
0
    for (i = 0; i < xp_set.used; ++i) {
747
0
        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX)) {
748
0
            ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
749
0
            LY_CHECK_GOTO(ret, cleanup);
750
0
        }
751
0
    }
752
753
0
cleanup:
754
0
    lyxp_set_free_content(&xp_set);
755
0
    lyxp_expr_free(exp);
756
0
    if (ret) {
757
0
        ly_set_free(*set, NULL);
758
0
        *set = NULL;
759
0
    }
760
0
    return ret;
761
0
}
762
763
LIBYANG_API_DEF LY_ERR
764
lys_find_lypath_atoms(const struct ly_path *path, struct ly_set **set)
765
0
{
766
0
    LY_ERR ret = LY_SUCCESS;
767
0
    LY_ARRAY_COUNT_TYPE u, v;
768
769
0
    LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
770
771
    /* allocate return set */
772
0
    LY_CHECK_RET(ly_set_new(set));
773
774
0
    LY_ARRAY_FOR(path, u) {
775
        /* add nodes from the path */
776
0
        LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
777
0
        LY_ARRAY_FOR(path[u].predicates, v) {
778
0
            if ((path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST) || (path[u].predicates[v].type == LY_PATH_PREDTYPE_LIST_VAR)) {
779
                /* add all the keys in a predicate */
780
0
                LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
781
0
            }
782
0
        }
783
0
    }
784
785
0
cleanup:
786
0
    if (ret) {
787
0
        ly_set_free(*set, NULL);
788
0
        *set = NULL;
789
0
    }
790
0
    return ret;
791
0
}
792
793
LIBYANG_API_DEF LY_ERR
794
lys_find_path_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output,
795
        struct ly_set **set)
796
0
{
797
0
    LY_ERR ret = LY_SUCCESS;
798
0
    uint8_t oper;
799
0
    struct lyxp_expr *expr = NULL;
800
0
    struct ly_path *p = NULL;
801
802
0
    LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
803
0
    LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
804
805
0
    if (!ctx) {
806
0
        ctx = ctx_node->module->ctx;
807
0
    }
808
809
    /* parse */
810
0
    ret = ly_path_parse(ctx, ctx_node, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
811
0
            LY_PATH_PRED_SIMPLE, &expr);
812
0
    LY_CHECK_GOTO(ret, cleanup);
813
814
    /* compile */
815
0
    oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
816
0
    ret = ly_path_compile(ctx, ctx_node, expr, oper, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p);
817
0
    LY_CHECK_GOTO(ret, cleanup);
818
819
    /* resolve */
820
0
    ret = lys_find_lypath_atoms(p, set);
821
822
0
cleanup:
823
0
    ly_path_free(p);
824
0
    lyxp_expr_free(expr);
825
0
    return ret;
826
0
}
827
828
LIBYANG_API_DEF const struct lysc_node *
829
lys_find_path(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *path, ly_bool output)
830
0
{
831
0
    const struct lysc_node *snode = NULL;
832
0
    struct lyxp_expr *expr = NULL;
833
0
    struct ly_path *p = NULL;
834
0
    LY_ERR ret;
835
0
    uint8_t oper;
836
837
0
    LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, NULL);
838
0
    LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
839
840
0
    if (!ctx) {
841
0
        ctx = ctx_node->module->ctx;
842
0
    }
843
844
    /* parse */
845
0
    ret = ly_path_parse(ctx, ctx_node, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
846
0
            LY_PATH_PRED_SIMPLE, &expr);
847
0
    LY_CHECK_GOTO(ret, cleanup);
848
849
    /* compile */
850
0
    oper = output ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT;
851
0
    ret = ly_path_compile(ctx, ctx_node, expr, oper, LY_PATH_TARGET_MANY, 0, LY_VALUE_JSON, NULL, &p);
852
0
    LY_CHECK_GOTO(ret, cleanup);
853
854
    /* get last node */
855
0
    snode = p[LY_ARRAY_COUNT(p) - 1].node;
856
857
0
cleanup:
858
0
    ly_path_free(p);
859
0
    lyxp_expr_free(expr);
860
0
    return snode;
861
0
}
862
863
char *
864
lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
865
        size_t buflen)
866
1.41M
{
867
1.41M
    const struct lysc_node *iter, *par, *key;
868
1.41M
    char *path = NULL;
869
1.41M
    int len = 0;
870
1.41M
    ly_bool skip_schema;
871
872
1.41M
    if (buffer) {
873
190k
        LY_CHECK_ARG_RET(node->module->ctx, buflen > 1, NULL);
874
190k
        buffer[0] = '\0';
875
190k
    }
876
877
1.41M
    if ((pathtype == LYSC_PATH_DATA) || (pathtype == LYSC_PATH_DATA_PATTERN)) {
878
        /* skip schema-only nodes */
879
0
        skip_schema = 1;
880
1.41M
    } else {
881
1.41M
        skip_schema = 0;
882
1.41M
    }
883
884
2.48M
    for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
885
1.07M
        char *s;
886
1.07M
        const char *slash;
887
888
1.07M
        if (skip_schema && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT))) {
889
            /* schema-only node */
890
0
            continue;
891
0
        }
892
893
1.07M
        if ((pathtype == LYSC_PATH_DATA_PATTERN) && (iter->nodetype == LYS_LIST)) {
894
0
            char *predicates = NULL;
895
896
0
            key = NULL;
897
0
            while ((key = lys_getnext(key, iter, NULL, 0)) && lysc_is_key(key)) {
898
0
                s = predicates;
899
900
                /* print key predicate */
901
0
                if (asprintf(&predicates, "%s[%s='%%s']", s ? s : "", key->name) == -1) {
902
0
                    free(s);
903
0
                    free(path);
904
0
                    return NULL;
905
0
                }
906
0
                free(s);
907
0
            }
908
0
            s = buffer ? strdup(buffer) : path;
909
0
            if (buffer) {
910
0
                len = snprintf(buffer, buflen, "%s%s", predicates ? predicates : "", s ? s : "");
911
0
            } else {
912
0
                len = asprintf(&path, "%s%s", predicates ? predicates : "", s ? s : "");
913
0
            }
914
0
            free(predicates);
915
0
            free(s);
916
917
0
            if (buffer && (buflen <= (size_t)len)) {
918
                /* not enough space in buffer */
919
0
                break;
920
0
            }
921
0
        }
922
923
1.07M
        s = buffer ? strdup(buffer) : path;
924
1.07M
        if (parent && (iter->parent == parent)) {
925
0
            slash = "";
926
1.07M
        } else {
927
1.07M
            slash = "/";
928
1.07M
        }
929
930
1.07M
        if (skip_schema) {
931
0
            par = lysc_data_parent(iter);
932
1.07M
        } else {
933
1.07M
            par = iter->parent;
934
1.07M
        }
935
936
1.07M
        if (!par || (par->module != iter->module)) {
937
            /* print prefix */
938
571k
            if (buffer) {
939
190k
                len = snprintf(buffer, buflen, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
940
380k
            } else {
941
380k
                len = asprintf(&path, "%s%s:%s%s", slash, iter->module->name, iter->name, s ? s : "");
942
380k
            }
943
571k
        } else {
944
            /* prefix is the same as in parent */
945
501k
            if (buffer) {
946
330k
                len = snprintf(buffer, buflen, "%s%s%s", slash, iter->name, s ? s : "");
947
330k
            } else {
948
170k
                len = asprintf(&path, "%s%s%s", slash, iter->name, s ? s : "");
949
170k
            }
950
501k
        }
951
1.07M
        free(s);
952
953
1.07M
        if (buffer && (buflen <= (size_t)len)) {
954
            /* not enough space in buffer */
955
171
            break;
956
171
        }
957
1.07M
    }
958
959
1.41M
    if (len < 0) {
960
0
        free(path);
961
0
        path = NULL;
962
1.41M
    } else if (len == 0) {
963
841k
        if (buffer) {
964
0
            strcpy(buffer, "/");
965
841k
        } else {
966
841k
            free(path);
967
841k
            path = strdup("/");
968
841k
        }
969
841k
    }
970
971
1.41M
    if (buffer) {
972
190k
        return buffer;
973
1.22M
    } else {
974
1.22M
        return path;
975
1.22M
    }
976
1.41M
}
977
978
LIBYANG_API_DEF char *
979
lysc_path(const struct lysc_node *node, LYSC_PATH_TYPE pathtype, char *buffer, size_t buflen)
980
1.41M
{
981
1.41M
    return lysc_path_until(node, NULL, pathtype, buffer, buflen);
982
1.41M
}
983
984
LY_ERR
985
_lys_set_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
986
26.5k
{
987
26.5k
    LY_ERR ret = LY_SUCCESS, r;
988
26.5k
    struct lys_module *mod_iter;
989
26.5k
    const char **imp_f, *all_f[] = {"*", NULL};
990
26.5k
    uint32_t i;
991
992
26.5k
    if (mod->implemented) {
993
        /* mod is already implemented, set the features */
994
1
        r = lys_set_features(mod->parsed, features);
995
1
        if (r == LY_EEXIST) {
996
            /* no changes */
997
1
            return LY_SUCCESS;
998
1
        } else if (!r) {
999
            /* mark the module as changed */
1000
0
            mod->to_compile = 1;
1001
0
        }
1002
1003
0
        return r;
1004
1
    }
1005
1006
    /* implement, ignore recompilation because it must always take place later */
1007
26.5k
    r = lys_implement(mod, features, unres);
1008
26.5k
    LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
1009
1010
26.4k
    if (mod->ctx->opts & LY_CTX_ALL_IMPLEMENTED) {
1011
        /* implement all the imports as well */
1012
0
        for (i = 0; i < unres->creating.count; ++i) {
1013
0
            mod = unres->creating.objs[i];
1014
0
            if (mod->implemented) {
1015
0
                continue;
1016
0
            }
1017
1018
0
            imp_f = (mod->ctx->opts & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
1019
0
            r = lys_implement(mod, imp_f, unres);
1020
0
            LY_CHECK_ERR_GOTO(r && (r != LY_ERECOMPILE), ret = r, cleanup);
1021
0
        }
1022
0
    }
1023
1024
    /* try to find module with LYS_MOD_IMPORTED_REV flag */
1025
26.4k
    i = 0;
1026
301k
    while ((mod_iter = ly_ctx_get_module_iter(mod->ctx, &i))) {
1027
274k
        if (!strcmp(mod_iter->name, mod->name) && (mod_iter != mod) && (mod_iter->latest_revision & LYS_MOD_IMPORTED_REV)) {
1028
3
            LOGVRB("Implemented module \"%s@%s\" was not and will not be imported if the revision-date is missing"
1029
3
                    " in the import statement. Instead, the revision \"%s\" is imported.", mod->name, mod->revision,
1030
3
                    mod_iter->revision);
1031
3
            break;
1032
3
        }
1033
274k
    }
1034
1035
26.5k
cleanup:
1036
26.5k
    return ret;
1037
26.4k
}
1038
1039
/**
1040
 * @brief Check whether it may be needed to (re)compile a module from a particular dependency set
1041
 * and if so, add it into its dep set.
1042
 *
1043
 * Dependency set includes all modules that need to be (re)compiled in case any of the module(s)
1044
 * in the dep set are (re)compiled.
1045
 *
1046
 * The reason for recompilation is possible disabled nodes and updating
1047
 * leafref targets to point to the newly compiled modules. Using the import relation, the
1048
 * dependency is reflexive because of possible foreign augments and deviations, which are compiled
1049
 * during the target module compilation.
1050
 *
1051
 * - every module must belong to exactly one dep set
1052
 * - implement flag must be ignored because it can be changed during dep set compilation
1053
 *
1054
 * @param[in] mod Module to process.
1055
 * @param[in,out] ctx_set Set with all not-yet-processed modules.
1056
 * @param[in,out] dep_set Current dependency set to update.
1057
 * @param[in] aux_set Set of traversed non-compiled modules, should be empty on first call.
1058
 * @return LY_ERR value.
1059
 */
1060
static LY_ERR
1061
lys_unres_dep_sets_create_mod_r(struct lys_module *mod, struct ly_set *ctx_set, struct ly_set *dep_set,
1062
        struct ly_set *aux_set)
1063
356k
{
1064
356k
    struct lys_module *mod2;
1065
356k
    struct lysp_import *imports;
1066
356k
    uint32_t i;
1067
356k
    LY_ARRAY_COUNT_TYPE u, v;
1068
356k
    ly_bool found;
1069
1070
356k
    if (LYS_IS_SINGLE_DEP_SET(mod)) {
1071
        /* is already in a separate dep set */
1072
230k
        if (!lys_has_dep_mods(mod)) {
1073
            /* break the dep set here, no modules depend on this one */
1074
230k
            return LY_SUCCESS;
1075
230k
        }
1076
1077
0
        if (ly_set_contains(aux_set, mod, NULL)) {
1078
            /* it was traversed */
1079
0
            return LY_SUCCESS;
1080
0
        }
1081
1082
        /* add a new auxiliary module */
1083
0
        LY_CHECK_RET(ly_set_add(aux_set, mod, 1, NULL));
1084
125k
    } else {
1085
125k
        if (!ly_set_contains(ctx_set, mod, &i)) {
1086
            /* it was already processed */
1087
0
            return LY_SUCCESS;
1088
0
        }
1089
1090
        /* remove it from the set, we are processing it now */
1091
125k
        ly_set_rm_index(ctx_set, i, NULL);
1092
1093
        /* add a new dependent module into the dep set */
1094
125k
        LY_CHECK_RET(ly_set_add(dep_set, mod, 1, NULL));
1095
125k
    }
1096
1097
    /* process imports of the module and submodules */
1098
125k
    imports = mod->parsed->imports;
1099
230k
    LY_ARRAY_FOR(imports, u) {
1100
230k
        mod2 = imports[u].module;
1101
230k
        LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
1102
230k
    }
1103
125k
    LY_ARRAY_FOR(mod->parsed->includes, v) {
1104
0
        imports = mod->parsed->includes[v].submodule->imports;
1105
0
        LY_ARRAY_FOR(imports, u) {
1106
0
            mod2 = imports[u].module;
1107
0
            if (LYS_IS_SINGLE_DEP_SET(mod2) && !lys_has_dep_mods(mod2)) {
1108
                /* break the dep set here, no modules depend on this one */
1109
0
                continue;
1110
0
            }
1111
1112
0
            LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(imports[u].module, ctx_set, dep_set, aux_set));
1113
0
        }
1114
0
    }
1115
1116
    /* process modules and submodules importing this module */
1117
1.28M
    for (i = 0; i < mod->ctx->modules.count; ++i) {
1118
1.15M
        mod2 = mod->ctx->modules.objs[i];
1119
1.15M
        found = 0;
1120
1121
1.15M
        imports = mod2->parsed->imports;
1122
1.15M
        LY_ARRAY_FOR(imports, u) {
1123
1.01M
            if (imports[u].module == mod) {
1124
0
                found = 1;
1125
0
                break;
1126
0
            }
1127
1.01M
        }
1128
1129
1.15M
        if (!found) {
1130
1.15M
            LY_ARRAY_FOR(mod2->parsed->includes, v) {
1131
0
                imports = mod2->parsed->includes[v].submodule->imports;
1132
0
                LY_ARRAY_FOR(imports, u) {
1133
0
                    if (imports[u].module == mod) {
1134
0
                        found = 1;
1135
0
                        break;
1136
0
                    }
1137
0
                }
1138
1139
0
                if (found) {
1140
0
                    break;
1141
0
                }
1142
0
            }
1143
1.15M
        }
1144
1145
1.15M
        if (found) {
1146
0
            LY_CHECK_RET(lys_unres_dep_sets_create_mod_r(mod2, ctx_set, dep_set, aux_set));
1147
0
        }
1148
1.15M
    }
1149
1150
125k
    return LY_SUCCESS;
1151
125k
}
1152
1153
/**
1154
 * @brief Add all simple modules (that have nothing to (re)compile) into separate dep sets.
1155
 *
1156
 * @param[in,out] ctx_set Set with all not-yet-processed modules.
1157
 * @param[in,out] main_set Set of dependency module sets.
1158
 * @return LY_ERR value.
1159
 */
1160
static LY_ERR
1161
lys_unres_dep_sets_create_single(struct ly_set *ctx_set, struct ly_set *main_set)
1162
53.7k
{
1163
53.7k
    LY_ERR ret = LY_SUCCESS;
1164
53.7k
    struct lys_module *m;
1165
53.7k
    uint32_t i = 0;
1166
53.7k
    struct ly_set *dep_set = NULL;
1167
1168
574k
    while (i < ctx_set->count) {
1169
520k
        m = ctx_set->objs[i];
1170
520k
        if (LYS_IS_SINGLE_DEP_SET(m)) {
1171
            /* remove it from the set, we are processing it now */
1172
289k
            ly_set_rm_index(ctx_set, i, NULL);
1173
1174
            /* this module can be in a separate dep set (but there still may be modules importing this one
1175
             * that depend on imports of this one in case it defines groupings) */
1176
289k
            LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
1177
289k
            LY_CHECK_GOTO(ret = ly_set_add(dep_set, m, 1, NULL), cleanup);
1178
289k
            LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
1179
289k
            dep_set = NULL;
1180
289k
        } else {
1181
231k
            ++i;
1182
231k
        }
1183
520k
    }
1184
1185
53.7k
cleanup:
1186
53.7k
    ly_set_free(dep_set, NULL);
1187
53.7k
    return ret;
1188
53.7k
}
1189
1190
LY_ERR
1191
lys_unres_dep_sets_create(struct ly_ctx *ctx, struct ly_set *main_set, struct lys_module *mod)
1192
53.7k
{
1193
53.7k
    LY_ERR ret = LY_SUCCESS;
1194
53.7k
    struct lys_module *m;
1195
53.7k
    struct ly_set *dep_set = NULL, *ctx_set = NULL, aux_set = {0};
1196
53.7k
    uint32_t i;
1197
53.7k
    ly_bool found;
1198
1199
53.7k
    assert(!main_set->count);
1200
1201
    /* start with a duplicate set of modules that we will remove from */
1202
53.7k
    LY_CHECK_GOTO(ret = ly_set_dup(&ctx->modules, NULL, &ctx_set), cleanup);
1203
1204
    /* first create all dep sets with single modules */
1205
53.7k
    LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_single(ctx_set, main_set), cleanup);
1206
1207
53.7k
    if (mod && !ly_set_contains(ctx_set, mod, NULL)) {
1208
        /* dep set for this module has already been created, nothing else to do */
1209
10.2k
        goto cleanup;
1210
10.2k
    }
1211
1212
152k
    while (ctx_set->count) {
1213
        /* create new dep set */
1214
125k
        LY_CHECK_GOTO(ret = ly_set_new(&dep_set), cleanup);
1215
1216
125k
        if (mod) {
1217
            /* use the module create a dep set with the rest of its dependent modules */
1218
16.2k
            LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_mod_r(mod, ctx_set, dep_set, &aux_set), cleanup);
1219
109k
        } else {
1220
            /* use first ctx mod to create a dep set with the rest of its dependent modules */
1221
109k
            LY_CHECK_GOTO(ret = lys_unres_dep_sets_create_mod_r(ctx_set->objs[0], ctx_set, dep_set, &aux_set), cleanup);
1222
109k
        }
1223
125k
        ly_set_erase(&aux_set, NULL);
1224
125k
        assert(dep_set->count);
1225
1226
        /* check whether there is any module that will be (re)compiled */
1227
125k
        found = 0;
1228
125k
        for (i = 0; i < dep_set->count; ++i) {
1229
125k
            m = dep_set->objs[i];
1230
125k
            if (m->to_compile) {
1231
125k
                found = 1;
1232
125k
                break;
1233
125k
            }
1234
125k
        }
1235
1236
125k
        if (found) {
1237
            /* if there is, all the implemented modules need to be recompiled */
1238
250k
            for (i = 0; i < dep_set->count; ++i) {
1239
125k
                m = dep_set->objs[i];
1240
125k
                if (m->implemented) {
1241
125k
                    m->to_compile = 1;
1242
125k
                }
1243
125k
            }
1244
125k
        }
1245
1246
        /* add the dep set into main set */
1247
125k
        LY_CHECK_GOTO(ret = ly_set_add(main_set, dep_set, 1, NULL), cleanup);
1248
125k
        dep_set = NULL;
1249
1250
125k
        if (mod) {
1251
            /* we need dep set only for this module */
1252
16.2k
            break;
1253
16.2k
        }
1254
125k
    }
1255
1256
43.5k
#ifndef NDEBUG
1257
43.5k
    LOGDBG(LY_LDGDEPSETS, "dep sets created (%" PRIu32 "):", main_set->count);
1258
396k
    for (i = 0; i < main_set->count; ++i) {
1259
353k
        struct ly_set *iter_set = main_set->objs[i];
1260
1261
353k
        LOGDBG(LY_LDGDEPSETS, "dep set #%" PRIu32 ":", i);
1262
706k
        for (uint32_t j = 0; j < iter_set->count; ++j) {
1263
353k
            m = iter_set->objs[j];
1264
353k
            LOGDBG(LY_LDGDEPSETS, "\t%s", m->name);
1265
353k
        }
1266
353k
    }
1267
43.5k
#endif
1268
1269
53.7k
cleanup:
1270
53.7k
    assert(ret || main_set->objs);
1271
53.7k
    ly_set_erase(&aux_set, NULL);
1272
53.7k
    ly_set_free(dep_set, NULL);
1273
53.7k
    ly_set_free(ctx_set, NULL);
1274
53.7k
    return ret;
1275
53.7k
}
1276
1277
void
1278
lys_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres)
1279
13.6k
{
1280
13.6k
    uint32_t i, j, idx, *prev_lo, temp_lo = 0;
1281
13.6k
    struct lys_module *mod;
1282
13.6k
    struct ly_set *dep_set;
1283
13.6k
    LY_ERR ret;
1284
1285
16.4k
    for (i = 0; i < unres->implementing.count; ++i) {
1286
2.74k
        mod = unres->implementing.objs[i];
1287
2.74k
        assert(mod->implemented);
1288
1289
        /* make the module correctly non-implemented again */
1290
2.74k
        mod->implemented = 0;
1291
2.74k
        lys_precompile_augments_deviations_revert(ctx, mod);
1292
2.74k
        lysc_module_free(ctx, mod->compiled);
1293
2.74k
        mod->compiled = NULL;
1294
1295
        /* should not be made implemented */
1296
2.74k
        mod->to_compile = 0;
1297
2.74k
    }
1298
1299
16.6k
    for (i = 0; i < unres->creating.count; ++i) {
1300
2.99k
        mod = unres->creating.objs[i];
1301
1302
        /* remove the module from the context */
1303
2.99k
        ly_set_rm(&ctx->modules, mod, NULL);
1304
1305
        /* remove it also from dep sets */
1306
16.4k
        for (j = 0; j < unres->dep_sets.count; ++j) {
1307
16.1k
            dep_set = unres->dep_sets.objs[j];
1308
16.1k
            if (ly_set_contains(dep_set, mod, &idx)) {
1309
2.69k
                ly_set_rm_index(dep_set, idx, NULL);
1310
2.69k
                break;
1311
2.69k
            }
1312
16.1k
        }
1313
1314
        /* free the module */
1315
2.99k
        lys_module_free(ctx, mod, 1);
1316
2.99k
    }
1317
1318
13.6k
    if (unres->implementing.count) {
1319
        /* recompile previous context because some implemented modules are no longer implemented,
1320
         * we can reuse the current to_compile flags */
1321
2.74k
        prev_lo = ly_temp_log_options(&temp_lo);
1322
2.74k
        ret = lys_compile_depset_all(ctx, &ctx->unres);
1323
2.74k
        ly_temp_log_options(prev_lo);
1324
2.74k
        if (ret) {
1325
0
            LOGINT(ctx);
1326
0
        }
1327
2.74k
    }
1328
13.6k
}
1329
1330
void
1331
lys_unres_glob_erase(struct lys_glob_unres *unres)
1332
119k
{
1333
119k
    uint32_t i;
1334
1335
534k
    for (i = 0; i < unres->dep_sets.count; ++i) {
1336
414k
        ly_set_free(unres->dep_sets.objs[i], NULL);
1337
414k
    }
1338
119k
    ly_set_erase(&unres->dep_sets, NULL);
1339
119k
    ly_set_erase(&unres->implementing, NULL);
1340
119k
    ly_set_erase(&unres->creating, NULL);
1341
1342
119k
    assert(!unres->ds_unres.whens.count);
1343
119k
    assert(!unres->ds_unres.musts.count);
1344
119k
    assert(!unres->ds_unres.leafrefs.count);
1345
119k
    assert(!unres->ds_unres.disabled_leafrefs.count);
1346
119k
    assert(!unres->ds_unres.dflts.count);
1347
119k
    assert(!unres->ds_unres.disabled.count);
1348
119k
}
1349
1350
LIBYANG_API_DEF LY_ERR
1351
lys_set_implemented(struct lys_module *mod, const char **features)
1352
0
{
1353
0
    LY_ERR ret = LY_SUCCESS;
1354
0
    struct lys_glob_unres *unres = &mod->ctx->unres;
1355
1356
0
    LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !(mod->ctx->opts & LY_CTX_INT_IMMUTABLE), LY_EINVAL);
1357
1358
    /* implement */
1359
0
    ret = _lys_set_implemented(mod, features, unres);
1360
0
    LY_CHECK_GOTO(ret, cleanup);
1361
1362
0
    if (!(mod->ctx->opts & LY_CTX_EXPLICIT_COMPILE)) {
1363
        /* create dep set for the module and mark all the modules that will be (re)compiled */
1364
0
        LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(mod->ctx, &unres->dep_sets, mod), cleanup);
1365
1366
        /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
1367
0
        LY_CHECK_GOTO(ret = lys_compile_depset_all(mod->ctx, unres), cleanup);
1368
1369
        /* unres resolved */
1370
0
        lys_unres_glob_erase(unres);
1371
1372
        /* new context state */
1373
0
        ly_ctx_new_change(mod->ctx);
1374
0
    }
1375
1376
0
cleanup:
1377
0
    if (ret) {
1378
0
        lys_unres_glob_revert(mod->ctx, unres);
1379
0
        lys_unres_glob_erase(unres);
1380
0
    }
1381
0
    return ret;
1382
0
}
1383
1384
/**
1385
 * @brief Resolve (find) all imported and included modules.
1386
 *
1387
 * @param[in] pctx Parser context.
1388
 * @param[in] pmod Parsed module to resolve.
1389
 * @param[out] new_mods Set with all the newly loaded modules.
1390
 * @return LY_ERR value.
1391
 */
1392
static LY_ERR
1393
lysp_resolve_import_include(struct lysp_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
1394
272k
{
1395
272k
    struct lysp_import *imp;
1396
272k
    LY_ARRAY_COUNT_TYPE u, v;
1397
1398
272k
    pmod->parsing = 1;
1399
272k
    LY_ARRAY_FOR(pmod->imports, u) {
1400
230k
        imp = &pmod->imports[u];
1401
230k
        if (!imp->module) {
1402
230k
            LY_CHECK_RET(lys_parse_load(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, new_mods, &imp->module));
1403
1404
230k
            if (!imp->rev[0]) {
1405
                /* This module must be selected for the next similar
1406
                 * import without revision-date to avoid incorrect
1407
                 * derived identities in the ::lys_module.identities.
1408
                 */
1409
176k
                imp->module->latest_revision |= LYS_MOD_IMPORTED_REV;
1410
176k
            }
1411
230k
        }
1412
        /* check for importing the same module twice */
1413
368k
        for (v = 0; v < u; ++v) {
1414
137k
            if (imp->module == pmod->imports[v].module) {
1415
0
                LOGWRN(PARSER_CTX(pctx), "Single revision of the module \"%s\" imported twice.", imp->name);
1416
0
            }
1417
137k
        }
1418
230k
    }
1419
272k
    LY_CHECK_RET(lysp_load_submodules(pctx, pmod, new_mods));
1420
1421
272k
    pmod->parsing = 0;
1422
1423
272k
    return LY_SUCCESS;
1424
272k
}
1425
1426
/**
1427
 * @brief Generate path of the given parsed node.
1428
 *
1429
 * @param[in] node Schema path of this node will be generated.
1430
 * @param[in] parent Build relative path only until this parent is found. If NULL, the full absolute path is printed.
1431
 * @param[in] pmod Parsed module of a top-level parent of @p node.
1432
 * @return NULL in case of memory allocation error, path of the node otherwise.
1433
 * In case the @p buffer is NULL, the returned string is dynamically allocated and caller is responsible to free it.
1434
 */
1435
static char *
1436
lysp_path_until(const struct lysp_node *node, const struct lysp_node *parent, const struct lysp_module *pmod)
1437
26
{
1438
26
    const struct lysp_node *iter;
1439
26
    char *path = NULL, *s;
1440
26
    const char *slash, *mod_colon, *mod_prefix, *node_start, *node_end;
1441
26
    int len = 0;
1442
1443
392
    for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
1444
366
        if (parent && (iter->parent == parent)) {
1445
0
            slash = "";
1446
366
        } else {
1447
366
            slash = "/";
1448
366
        }
1449
1450
366
        if (iter->parent) {
1451
            /* prefix is the same as in parent */
1452
340
            mod_colon = "";
1453
340
            mod_prefix = "";
1454
340
        } else {
1455
            /* print prefix */
1456
26
            mod_colon = ":";
1457
26
            mod_prefix = pmod->mod->name;
1458
26
        }
1459
1460
        /* non-compiled schema nodes */
1461
366
        switch (iter->nodetype) {
1462
243
        case LYS_CONTAINER:
1463
321
        case LYS_CHOICE:
1464
322
        case LYS_LEAF:
1465
324
        case LYS_LEAFLIST:
1466
350
        case LYS_LIST:
1467
351
        case LYS_ANYXML:
1468
351
        case LYS_ANYDATA:
1469
351
        case LYS_CASE:
1470
353
        case LYS_RPC:
1471
353
        case LYS_ACTION:
1472
358
        case LYS_NOTIF:
1473
358
        case LYS_INPUT:
1474
358
        case LYS_OUTPUT:
1475
358
            node_start = "";
1476
358
            node_end = "";
1477
358
            break;
1478
1
        case LYS_USES:
1479
1
            node_start = "{uses='";
1480
1
            node_end = "'}";
1481
1
            break;
1482
6
        case LYS_GROUPING:
1483
6
            node_start = "{grouping='";
1484
6
            node_end = "'}";
1485
6
            break;
1486
1
        case LYS_AUGMENT:
1487
1
            node_start = "{augment='";
1488
1
            node_end = "'}";
1489
1
            break;
1490
0
        default:
1491
0
            len = -1;
1492
0
            goto cleanup;
1493
366
        }
1494
1495
366
        s = path;
1496
366
        len = asprintf(&path, "%s%s%s%s%s%s%s", slash, mod_prefix, mod_colon, node_start, iter->name, node_end, s ? s : "");
1497
366
        free(s);
1498
366
    }
1499
1500
26
    if (len == 0) {
1501
0
        path = strdup("/");
1502
0
    }
1503
1504
26
cleanup:
1505
26
    if (len < 0) {
1506
0
        free(path);
1507
0
        path = NULL;
1508
0
    }
1509
26
    return path;
1510
26
}
1511
1512
/**
1513
 * @brief Append a formatted message to a buffer.
1514
 *
1515
 * @param[in,out] buf Buffer to use.
1516
 * @param[in,out] size Size of @p buf.
1517
 * @param[in] format Message format.
1518
 * @param[in] ... Message format arguments.
1519
 * @return LY_ERR value.
1520
 */
1521
static LY_ERR
1522
lysp_ext_instance_path_append(char **buf, uint32_t *size, const char *format, ...)
1523
1.23M
{
1524
1.23M
    va_list ap;
1525
1.23M
    uint32_t len;
1526
1527
    /* learn the required length */
1528
1.23M
    va_start(ap, format);
1529
1.23M
    len = vsnprintf(*buf ? *buf + *size : NULL, 0, format, ap);
1530
1.23M
    va_end(ap);
1531
1532
    /* realloc */
1533
1.23M
    *buf = ly_realloc(*buf, (*size) + len + 1);
1534
1.23M
    LY_CHECK_ERR_RET(!*buf, LOGMEM(NULL), LY_EMEM);
1535
1536
    /* print */
1537
1.23M
    va_start(ap, format);
1538
1.23M
    *size += vsnprintf(*buf + *size, len + 1, format, ap);
1539
1.23M
    va_end(ap);
1540
1541
1.23M
    return LY_SUCCESS;
1542
1.23M
}
1543
1544
/**
1545
 * @brief Append the log path of a statement to a string, recursively.
1546
 *
1547
 * @param[in] ctx Context for logging.
1548
 * @param[in] stmt Statement to append.
1549
 * @param[in] stmt_idx Index of @p stmt.
1550
 * @param[in] stmt_p Pointer to the statement structure.
1551
 * @param[in] pmod Parsed module to use.
1552
 * @param[in,out] buf Buffer to use.
1553
 * @param[in,out] size Size of @p buf.
1554
 * @return LY_ERR value.
1555
 */
1556
static LY_ERR
1557
lysp_ext_instance_path_stmt_append_r(const struct ly_ctx *ctx, enum ly_stmt stmt, LY_ARRAY_COUNT_TYPE stmt_idx,
1558
        const void *stmt_p, const struct lysp_module *pmod, char **buf, uint32_t *size)
1559
413k
{
1560
413k
    if (*size && ((*buf)[*size - 1] != ':')) {
1561
        /* slash after the previous path, if not module name */
1562
38
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/"));
1563
38
    }
1564
1565
413k
    switch (stmt) {
1566
1
    case LY_STMT_NOTIFICATION:
1567
1
    case LY_STMT_INPUT:
1568
1
    case LY_STMT_OUTPUT:
1569
1
    case LY_STMT_ACTION:
1570
2
    case LY_STMT_RPC:
1571
2
    case LY_STMT_ANYDATA:
1572
3
    case LY_STMT_ANYXML:
1573
4
    case LY_STMT_AUGMENT:
1574
4
    case LY_STMT_CASE:
1575
9
    case LY_STMT_CHOICE:
1576
14
    case LY_STMT_CONTAINER:
1577
17
    case LY_STMT_GROUPING:
1578
18
    case LY_STMT_LEAF:
1579
20
    case LY_STMT_LEAF_LIST:
1580
25
    case LY_STMT_LIST:
1581
26
    case LY_STMT_USES:
1582
26
        *buf = lysp_path_until(stmt_p, NULL, pmod);
1583
26
        LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
1584
26
        *size = strlen(*buf);
1585
26
        break;
1586
0
    case LY_STMT_ARGUMENT:
1587
0
    case LY_STMT_YIN_ELEMENT:
1588
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION, 0, stmt_p, pmod, buf, size));
1589
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1590
0
        break;
1591
0
    case LY_STMT_BASE: {
1592
0
        const char * const *bases = stmt_p;
1593
1594
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), bases[stmt_idx]));
1595
0
        break;
1596
0
    }
1597
0
    case LY_STMT_BELONGS_TO: {
1598
0
        const struct lysp_submodule *submod = stmt_p;
1599
1600
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), submod->name));
1601
0
        break;
1602
0
    }
1603
0
    case LY_STMT_BIT:
1604
0
    case LY_STMT_ENUM: {
1605
0
        const struct lysp_type_enum *be = stmt_p;
1606
1607
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), be->name));
1608
0
        break;
1609
0
    }
1610
0
    case LY_STMT_CONFIG:
1611
0
    case LY_STMT_CONTACT:
1612
0
    case LY_STMT_DESCRIPTION:
1613
0
    case LY_STMT_MANDATORY:
1614
0
    case LY_STMT_MAX_ELEMENTS:
1615
0
    case LY_STMT_MIN_ELEMENTS:
1616
0
    case LY_STMT_NAMESPACE:
1617
0
    case LY_STMT_ORGANIZATION:
1618
2
    case LY_STMT_PREFIX:
1619
2
    case LY_STMT_YANG_VERSION:
1620
2
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s}", lyplg_ext_stmt2str(stmt)));
1621
2
        break;
1622
0
    case LY_STMT_DEFAULT: {
1623
0
        const struct lysp_qname *qn = stmt_p;
1624
1625
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qn->str));
1626
0
        break;
1627
0
    }
1628
0
    case LY_STMT_DEVIATE: {
1629
0
        const struct lysp_deviate *d = stmt_p;
1630
1631
0
        switch (d->mod) {
1632
0
        case LYS_DEV_NOT_SUPPORTED:
1633
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='not-supported'}", lyplg_ext_stmt2str(stmt)));
1634
0
            break;
1635
0
        case LYS_DEV_ADD:
1636
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='add'}", lyplg_ext_stmt2str(stmt)));
1637
0
            break;
1638
0
        case LYS_DEV_DELETE:
1639
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='delete'}", lyplg_ext_stmt2str(stmt)));
1640
0
            break;
1641
0
        case LYS_DEV_REPLACE:
1642
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='replace'}", lyplg_ext_stmt2str(stmt)));
1643
0
            break;
1644
0
        }
1645
0
        break;
1646
0
    }
1647
0
    case LY_STMT_DEVIATION: {
1648
0
        const struct lysp_deviation *dev = stmt_p;
1649
1650
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), dev->nodeid));
1651
0
        break;
1652
0
    }
1653
0
    case LY_STMT_ERROR_APP_TAG:
1654
0
    case LY_STMT_ERROR_MESSAGE:
1655
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{restriction}/{%s}", lyplg_ext_stmt2str(stmt)));
1656
0
        break;
1657
1
    case LY_STMT_EXTENSION: {
1658
1
        const struct lysp_ext *ext = stmt_p;
1659
1660
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), ext->name));
1661
1
        break;
1662
1
    }
1663
413k
    case LY_STMT_EXTENSION_INSTANCE: {
1664
413k
        const struct lysp_ext_instance *ext = stmt_p;
1665
1666
413k
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{ext-inst='%s'}", ext->name));
1667
413k
        if (ext->argument) {
1668
413k
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/%s", ext->argument));
1669
413k
        }
1670
413k
        break;
1671
413k
    }
1672
413k
    case LY_STMT_FEATURE: {
1673
1
        const struct lysp_feature *f = stmt_p;
1674
1675
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), f->name));
1676
1
        break;
1677
1
    }
1678
0
    case LY_STMT_FRACTION_DIGITS:
1679
0
    case LY_STMT_PATH:
1680
0
    case LY_STMT_REQUIRE_INSTANCE:
1681
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_TYPE, 0, stmt_p, pmod, buf, size));
1682
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1683
0
        break;
1684
1
    case LY_STMT_IDENTITY: {
1685
1
        const struct lysp_ident *id = stmt_p;
1686
1687
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), id->name));
1688
1
        break;
1689
1
    }
1690
0
    case LY_STMT_IF_FEATURE:
1691
0
    case LY_STMT_UNIQUE: {
1692
0
        const struct lysp_qname *qns = stmt_p;
1693
1694
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), qns[stmt_idx].str));
1695
0
        break;
1696
0
    }
1697
0
    case LY_STMT_IMPORT: {
1698
0
        const struct lysp_import *imp = stmt_p;
1699
1700
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), imp->name));
1701
0
        break;
1702
0
    }
1703
0
    case LY_STMT_INCLUDE:  {
1704
0
        const struct lysp_include *inc = stmt_p;
1705
1706
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), inc->name));
1707
0
        break;
1708
0
    }
1709
0
    case LY_STMT_KEY:
1710
0
    case LY_STMT_ORDERED_BY:
1711
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_LIST, 0, stmt_p, pmod, buf, size));
1712
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1713
0
        break;
1714
0
    case LY_STMT_LENGTH:
1715
1
    case LY_STMT_MUST:
1716
1
    case LY_STMT_RANGE: {
1717
1
        const struct lysp_restr *res = stmt_p;
1718
1719
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str));
1720
1
        break;
1721
1
    }
1722
0
    case LY_STMT_MODIFIER:
1723
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_PATTERN, 0, stmt_p, pmod, buf, size));
1724
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1725
0
        break;
1726
1
    case LY_STMT_PATTERN: {
1727
1
        const struct lysp_restr *res = stmt_p;
1728
1729
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), res->arg.str + 1));
1730
1
        break;
1731
1
    }
1732
0
    case LY_STMT_POSITION:
1733
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_BIT, 0, stmt_p, pmod, buf, size));
1734
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1735
0
        break;
1736
0
    case LY_STMT_PRESENCE:
1737
0
    case LY_STMT_REFERENCE:
1738
0
    case LY_STMT_REVISION_DATE:
1739
0
    case LY_STMT_UNITS: {
1740
0
        const char *str = stmt_p;
1741
1742
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), str));
1743
0
        break;
1744
0
    }
1745
0
    case LY_STMT_REFINE: {
1746
0
        const struct lysp_refine *rf = stmt_p;
1747
1748
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rf->nodeid));
1749
0
        break;
1750
0
    }
1751
0
    case LY_STMT_REVISION: {
1752
0
        const struct lysp_revision *rev = stmt_p;
1753
1754
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), rev->date));
1755
0
        break;
1756
0
    }
1757
0
    case LY_STMT_STATUS: {
1758
0
        const uint16_t *flags = stmt_p;
1759
1760
0
        if (*flags & LYS_STATUS_OBSLT) {
1761
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='obsolete'}", lyplg_ext_stmt2str(stmt)));
1762
0
        } else if (*flags & LYS_STATUS_DEPRC) {
1763
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='deprecated'}", lyplg_ext_stmt2str(stmt)));
1764
0
        } else {
1765
0
            LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='current'}", lyplg_ext_stmt2str(stmt)));
1766
0
        }
1767
0
        break;
1768
0
    }
1769
0
    case LY_STMT_TYPE: {
1770
0
        const struct lysp_type *typ = stmt_p;
1771
1772
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), typ->name));
1773
0
        break;
1774
0
    }
1775
0
    case LY_STMT_TYPEDEF: {
1776
0
        const struct lysp_tpdf *tpdf = stmt_p;
1777
1778
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), tpdf->name));
1779
0
        break;
1780
0
    }
1781
0
    case LY_STMT_VALUE:
1782
0
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_ENUM, 0, stmt_p, pmod, buf, size));
1783
0
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "/{%s}", lyplg_ext_stmt2str(stmt)));
1784
0
        break;
1785
1
    case LY_STMT_WHEN: {
1786
1
        const struct lysp_when *wh = stmt_p;
1787
1788
1
        LY_CHECK_RET(lysp_ext_instance_path_append(buf, size, "{%s='%s'}", lyplg_ext_stmt2str(stmt), wh->cond));
1789
1
        break;
1790
1
    }
1791
0
    case LY_STMT_NONE:
1792
0
    case LY_STMT_MODULE:
1793
0
    case LY_STMT_SUBMODULE:
1794
0
    case LY_STMT_SYNTAX_SEMICOLON:
1795
0
    case LY_STMT_SYNTAX_LEFT_BRACE:
1796
0
    case LY_STMT_SYNTAX_RIGHT_BRACE:
1797
0
    case LY_STMT_ARG_TEXT:
1798
0
    case LY_STMT_ARG_VALUE:
1799
        /* invalid */
1800
0
        LOGINT_RET(ctx);
1801
413k
    }
1802
1803
413k
    return LY_SUCCESS;
1804
413k
}
1805
1806
LY_ERR
1807
lysp_ext_instance_path(const struct ly_ctx *ctx, const struct lysp_module *pmod, const struct lysp_ext_instance *ext,
1808
        char **path)
1809
413k
{
1810
413k
    char *buf = NULL;
1811
413k
    uint32_t size = 0;
1812
1813
413k
    if (ext->parent_stmt == LY_STMT_MODULE) {
1814
        /* module name */
1815
413k
        LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", ((struct lysp_module *)ext->parent)->mod->name));
1816
413k
    } else if (ext->parent_stmt == LY_STMT_SUBMODULE) {
1817
        /* submodule name */
1818
0
        LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", ((struct lysp_submodule *)ext->parent)->name));
1819
38
    } else {
1820
        /* start with the module name unless a node is parent, which will include its module name */
1821
38
        if (!(ext->parent_stmt & LY_STMT_NODE_MASK)) {
1822
12
            LY_CHECK_RET(lysp_ext_instance_path_append(&buf, &size, "/%s:", pmod->mod->name));
1823
12
        }
1824
1825
        /* generate path of the parent statement */
1826
38
        LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, ext->parent_stmt, ext->parent_stmt_index, ext->parent, pmod,
1827
38
                &buf, &size));
1828
38
    }
1829
1830
    /* append the extension instance path */
1831
413k
    LY_CHECK_RET(lysp_ext_instance_path_stmt_append_r(ctx, LY_STMT_EXTENSION_INSTANCE, 0, ext, pmod, &buf, &size));
1832
1833
413k
    *path = buf;
1834
413k
    return LY_SUCCESS;
1835
413k
}
1836
1837
/**
1838
 * @brief Find ext instance plugins for all the parsed extensions.
1839
 *
1840
 * @param[in] mod Module to use.
1841
 */
1842
static void
1843
lysp_resolve_ext_instance_plugins(struct lys_module *mod)
1844
272k
{
1845
272k
    LY_ARRAY_COUNT_TYPE u, v;
1846
272k
    const struct lysp_include *inc;
1847
1848
    /* module */
1849
272k
    LY_ARRAY_FOR(mod->parsed->extensions, u) {
1850
112k
        mod->parsed->extensions[u].plugin_ref = lyplg_ext_plugin_find(mod->ctx, mod->name,
1851
112k
                mod->revision, mod->parsed->extensions[u].name);
1852
112k
    }
1853
1854
    /* submodules */
1855
272k
    LY_ARRAY_FOR(mod->parsed->includes, v) {
1856
0
        inc = &mod->parsed->includes[v];
1857
1858
0
        LY_ARRAY_FOR(inc->submodule->extensions, u) {
1859
0
            inc->submodule->extensions[u].plugin_ref = lyplg_ext_plugin_find(mod->ctx, mod->name,
1860
0
                    mod->revision, inc->submodule->extensions[u].name);
1861
0
        }
1862
0
    }
1863
272k
}
1864
1865
/**
1866
 * @brief Resolve (find) all extension instance records and finish their parsing.
1867
 *
1868
 * @param[in] pctx Parse context with all the parsed extension instances.
1869
 * @return LY_ERR value.
1870
 */
1871
static LY_ERR
1872
lysp_resolve_ext_instance_records(struct lysp_ctx *pctx)
1873
272k
{
1874
272k
    LY_ERR r;
1875
272k
    struct lysp_ext_instance *ext, *exts;
1876
272k
    struct lysp_ext *ext_def;
1877
272k
    const struct lys_module *mod;
1878
272k
    uint32_t i;
1879
272k
    LY_ARRAY_COUNT_TYPE u;
1880
272k
    char *path = NULL;
1881
272k
    struct lyplg_ext *ext_plg;
1882
1883
    /* first finish parsing all extension instances ... */
1884
328k
    for (i = 0; i < pctx->ext_inst.count; ++i) {
1885
55.9k
        exts = pctx->ext_inst.objs[i];
1886
413k
        LY_ARRAY_FOR(exts, u) {
1887
413k
            ext = &exts[u];
1888
1889
            /* find the extension definition, use its plugin */
1890
413k
            LY_CHECK_RET(lysp_ext_find_definition(PARSER_CTX(pctx), PARSER_CUR_PMOD(pctx), ext, &mod, &ext_def));
1891
413k
            ext->plugin_ref = ext_def->plugin_ref;
1892
1893
            /* resolve the argument, if needed */
1894
413k
            LY_CHECK_RET(lysp_ext_instance_resolve_argument(PARSER_CTX(pctx), ext_def, ext));
1895
413k
        }
1896
55.9k
    }
1897
1898
    /* ... then call the parse callback */
1899
328k
    for (i = 0; i < pctx->ext_inst.count; ++i) {
1900
55.7k
        exts = pctx->ext_inst.objs[i];
1901
55.7k
        u = 0;
1902
468k
        while (u < LY_ARRAY_COUNT(exts)) {
1903
413k
            ext = &exts[u];
1904
413k
            if (!ext->plugin_ref || !(ext_plg = LYSC_GET_EXT_PLG(ext->plugin_ref))->parse) {
1905
0
                goto next_iter;
1906
0
            }
1907
1908
            /* set up log path */
1909
413k
            LY_CHECK_RET(lysp_ext_instance_path(PARSER_CTX(pctx), PARSER_CUR_PMOD(pctx), ext, &path));
1910
413k
            ly_log_location(NULL, path, NULL);
1911
1912
            /* parse */
1913
413k
            r = ext_plg->parse(pctx, ext);
1914
1915
413k
            ly_log_location_revert(0, 1, 0);
1916
413k
            free(path);
1917
1918
413k
            if (r == LY_ENOT) {
1919
                /* instance should be ignored, remove it */
1920
0
                lysp_ext_instance_free(PARSER_CTX(pctx), ext);
1921
0
                LY_ARRAY_DECREMENT(exts);
1922
0
                if (u < LY_ARRAY_COUNT(exts)) {
1923
                    /* replace by the last item */
1924
0
                    *ext = exts[LY_ARRAY_COUNT(exts)];
1925
0
                } /* else if there are no more items, leave the empty array, we are not able to free it */
1926
0
                continue;
1927
413k
            } else if (r) {
1928
                /* error */
1929
0
                return r;
1930
0
            }
1931
1932
413k
next_iter:
1933
413k
            ++u;
1934
413k
        }
1935
55.7k
    }
1936
1937
272k
    return LY_SUCCESS;
1938
272k
}
1939
1940
/**
1941
 * @brief Generate a warning if the filename does not match the expected module name and version.
1942
 *
1943
 * @param[in] ctx Context for logging
1944
 * @param[in] name Expected module name
1945
 * @param[in] revision Expected module revision, or NULL if not to be checked
1946
 * @param[in] filename File path to be checked
1947
 */
1948
static void
1949
ly_check_module_filename(const struct ly_ctx *ctx, const char *name, const char *revision, const char *filename)
1950
0
{
1951
0
    const char *basename, *rev, *dot;
1952
0
    size_t len;
1953
1954
    /* check that name and revision match filename */
1955
0
    basename = strrchr(filename, '/');
1956
#ifdef _WIN32
1957
    const char *backslash = strrchr(filename, '\\');
1958
1959
    if (!basename || (basename && backslash && (backslash > basename))) {
1960
        basename = backslash;
1961
    }
1962
#endif
1963
0
    if (!basename) {
1964
0
        basename = filename;
1965
0
    } else {
1966
0
        basename++; /* leading slash */
1967
0
    }
1968
0
    rev = strchr(basename, '@');
1969
0
    dot = strrchr(basename, '.');
1970
1971
    /* name */
1972
0
    len = strlen(name);
1973
0
    if (strncmp(basename, name, len) ||
1974
0
            ((rev && (rev != &basename[len])) || (!rev && (dot != &basename[len])))) {
1975
0
        LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", basename, name);
1976
0
    }
1977
0
    if (rev) {
1978
0
        len = dot - ++rev;
1979
0
        if (!revision || (len != LY_REV_SIZE - 1) || strncmp(revision, rev, len)) {
1980
0
            LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", basename,
1981
0
                    revision ? revision : "none");
1982
0
        }
1983
0
    }
1984
0
}
1985
1986
/**
1987
 * @brief Check created (sub)module that it matches the expected module.
1988
 *
1989
 * @param[in] ctx Context to use.
1990
 * @param[in] mod Parsed module.
1991
 * @param[in] submod Parsed submodule.
1992
 * @param[in] mod_data Expected module data.
1993
 * @return LY_SUCCESS on success;
1994
 * @return LY_EEXIST if the same module already exists;
1995
 * @return LY_ERR on error.
1996
 */
1997
static LY_ERR
1998
lysp_load_module_data_check(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod,
1999
        const struct lysp_load_module_data *mod_data)
2000
0
{
2001
0
    const char *name;
2002
0
    uint8_t latest_revision;
2003
0
    struct lysp_revision *revs;
2004
2005
0
    name = mod ? mod->mod->name : submod->name;
2006
0
    revs = mod ? mod->revs : submod->revs;
2007
0
    latest_revision = mod ? mod->mod->latest_revision : submod->latest_revision;
2008
2009
0
    if (mod_data->name) {
2010
        /* check name of the parsed module */
2011
0
        if (strcmp(mod_data->name, name)) {
2012
0
            LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\".", name, mod_data->name);
2013
0
            return LY_EINVAL;
2014
0
        }
2015
0
    }
2016
2017
0
    if (mod_data->revision) {
2018
        /* check revision of the parsed module */
2019
0
        if (!revs || strcmp(mod_data->revision, revs[0].date)) {
2020
0
            LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
2021
0
                    revs ? revs[0].date : "none", mod_data->revision);
2022
0
            return LY_EINVAL;
2023
0
        }
2024
0
    } else if (!latest_revision) {
2025
        /* do not log, we just need to drop the schema and use the latest revision from the context */
2026
0
        return LY_EEXIST;
2027
0
    }
2028
2029
0
    if (submod) {
2030
0
        assert(mod_data->submoduleof);
2031
2032
        /* check that the submodule belongs-to our module */
2033
0
        if (strcmp(mod_data->submoduleof, submod->mod->name)) {
2034
0
            LOGVAL(ctx, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
2035
0
                    submod->name, mod_data->submoduleof, submod->mod->name);
2036
0
            return LY_EVALID;
2037
0
        }
2038
        /* check circular dependency */
2039
0
        if (submod->parsing) {
2040
0
            LOGVAL(ctx, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
2041
0
            return LY_EVALID;
2042
0
        }
2043
0
    }
2044
2045
0
    if (mod_data->path) {
2046
0
        ly_check_module_filename(ctx, name, revs ? revs[0].date : NULL, mod_data->path);
2047
0
    }
2048
2049
0
    return LY_SUCCESS;
2050
0
}
2051
2052
LY_ERR
2053
lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lysp_ctx *main_ctx,
2054
        const struct lysp_load_module_data *mod_data, ly_bool in_searchdirs, struct ly_set *new_mods,
2055
        struct lysp_submodule **submodule)
2056
0
{
2057
0
    LY_ERR rc = LY_SUCCESS, r;
2058
0
    struct lysp_submodule *submod = NULL, *latest_sp;
2059
0
    struct lysp_yang_ctx *yangctx = NULL;
2060
0
    struct lysp_yin_ctx *yinctx = NULL;
2061
0
    struct lysp_ctx *pctx = NULL;
2062
2063
0
    LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
2064
2065
0
    *submodule = NULL;
2066
2067
0
    switch (format) {
2068
0
    case LYS_IN_YIN:
2069
0
        rc = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
2070
0
        pctx = (struct lysp_ctx *)yinctx;
2071
0
        break;
2072
0
    case LYS_IN_YANG:
2073
0
        rc = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
2074
0
        pctx = (struct lysp_ctx *)yangctx;
2075
0
        break;
2076
0
    default:
2077
0
        LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
2078
0
        rc = LY_EINVAL;
2079
0
        break;
2080
0
    }
2081
0
    LY_CHECK_GOTO(rc, cleanup);
2082
0
    assert(submod);
2083
2084
    /* make sure that the newest revision is at position 0 */
2085
0
    lysp_sort_revisions(submod->revs);
2086
2087
    /* decide the latest revision */
2088
0
    latest_sp = (struct lysp_submodule *)ly_ctx_get_submodule2_latest(submod->mod, submod->name);
2089
0
    if (latest_sp) {
2090
0
        if (submod->revs) {
2091
0
            if (!latest_sp->revs) {
2092
                /* latest has no revision, so mod is anyway newer */
2093
0
                submod->latest_revision = latest_sp->latest_revision;
2094
                /* the latest_sp is zeroed later when the new module is being inserted into the context */
2095
0
            } else if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
2096
0
                submod->latest_revision = latest_sp->latest_revision;
2097
                /* the latest_sp is zeroed later when the new module is being inserted into the context */
2098
0
            } else {
2099
0
                latest_sp = NULL;
2100
0
            }
2101
0
        } else {
2102
0
            latest_sp = NULL;
2103
0
        }
2104
0
    } else {
2105
        /* if found in searchdirs and looking for the latest revision, it is the latest revision available,
2106
         * otherwise the only such submodule in the context */
2107
0
        submod->latest_revision = (in_searchdirs && !mod_data->revision) ? 2 : 1;
2108
0
    }
2109
2110
    /* check the parsed submodule is as expected */
2111
0
    r = lysp_load_module_data_check(ctx, NULL, submod, mod_data);
2112
0
    if (r == LY_EEXIST) {
2113
        /* not an error, the submodule already exists so free this one */
2114
0
        ly_set_erase(&pctx->tpdfs_nodes, NULL);
2115
0
        ly_set_erase(&pctx->grps_nodes, NULL);
2116
0
        ly_set_erase(&pctx->ext_inst, NULL);
2117
0
        lysp_module_free(ctx, (struct lysp_module *)submod);
2118
0
        submod = NULL;
2119
0
        goto cleanup;
2120
0
    } else if (r) {
2121
0
        rc = r;
2122
0
        goto cleanup;
2123
0
    }
2124
2125
0
    if (latest_sp) {
2126
0
        latest_sp->latest_revision = 0;
2127
0
    }
2128
2129
0
    LY_CHECK_GOTO(rc = lys_parser_fill_filepath(ctx, in, &submod->filepath), cleanup);
2130
2131
    /* resolve imports and includes */
2132
0
    LY_CHECK_GOTO(rc = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), cleanup);
2133
2134
0
cleanup:
2135
0
    if (rc) {
2136
0
        LOGERR(ctx, rc, "Parsing submodule \"%s\" failed.", mod_data->name);
2137
0
        if (pctx) {
2138
0
            ly_set_erase(&pctx->tpdfs_nodes, NULL);
2139
0
            ly_set_erase(&pctx->grps_nodes, NULL);
2140
0
            ly_set_erase(&pctx->ext_inst, NULL);
2141
0
        }
2142
0
        lysp_module_free(ctx, (struct lysp_module *)submod);
2143
0
    } else if (submod) {
2144
0
        *submodule = submod;
2145
2146
        /* merge submod unres into main_ctx unres */
2147
0
        ly_set_merge(&pctx->main_ctx->tpdfs_nodes, &pctx->tpdfs_nodes, 1, NULL);
2148
0
        ly_set_erase(&pctx->tpdfs_nodes, NULL);
2149
0
        ly_set_merge(&pctx->main_ctx->grps_nodes, &pctx->grps_nodes, 1, NULL);
2150
0
        ly_set_erase(&pctx->grps_nodes, NULL);
2151
0
        ly_set_merge(&pctx->main_ctx->ext_inst, &pctx->ext_inst, 1, NULL);
2152
0
        ly_set_erase(&pctx->ext_inst, NULL);
2153
0
    }
2154
2155
0
    if (format == LYS_IN_YANG) {
2156
0
        lysp_yang_ctx_free(yangctx);
2157
0
    } else {
2158
0
        lysp_yin_ctx_free(yinctx);
2159
0
    }
2160
0
    return rc;
2161
0
}
2162
2163
/**
2164
 * @brief Add ietf-netconf metadata to the parsed module. Operation, filter, and select are added.
2165
 *
2166
 * @param[in] pctx Parse context.
2167
 * @param[in] mod Parsed module to add to.
2168
 * @return LY_SUCCESS on success.
2169
 * @return LY_ERR on error.
2170
 */
2171
static LY_ERR
2172
lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
2173
1.16k
{
2174
1.16k
    struct lysp_ext_instance *extp, *prev_exts = mod->exts;
2175
1.16k
    struct lysp_stmt *stmt;
2176
1.16k
    struct lysp_node_leaf *leaf;
2177
1.16k
    struct lysp_node_container *cont;
2178
1.16k
    struct lysp_type_enum *enm;
2179
1.16k
    struct lysp_import *imp;
2180
1.16k
    uint32_t idx;
2181
2182
    /*
2183
     * 1) edit-config's operation
2184
     */
2185
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
2186
1.16k
    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
2187
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
2188
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "operation", 0, &extp->argument));
2189
1.16k
    extp->format = LY_VALUE_SCHEMA;
2190
1.16k
    extp->prefix_data = mod;
2191
1.16k
    extp->parent = mod;
2192
1.16k
    extp->parent_stmt = LY_STMT_MODULE;
2193
1.16k
    extp->flags = LYS_INTERNAL;
2194
2195
1.16k
    extp->child = stmt = calloc(1, sizeof *extp->child);
2196
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2197
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
2198
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
2199
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2200
1.16k
    stmt->prefix_data = mod;
2201
1.16k
    stmt->kw = LY_STMT_TYPE;
2202
2203
1.16k
    stmt->child = calloc(1, sizeof *stmt->child);
2204
1.16k
    stmt = stmt->child;
2205
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2206
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2207
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "merge", 0, &stmt->arg));
2208
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2209
1.16k
    stmt->prefix_data = mod;
2210
1.16k
    stmt->kw = LY_STMT_ENUM;
2211
2212
1.16k
    stmt->next = calloc(1, sizeof *stmt->child);
2213
1.16k
    stmt = stmt->next;
2214
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2215
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2216
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "replace", 0, &stmt->arg));
2217
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2218
1.16k
    stmt->prefix_data = mod;
2219
1.16k
    stmt->kw = LY_STMT_ENUM;
2220
2221
1.16k
    stmt->next = calloc(1, sizeof *stmt->child);
2222
1.16k
    stmt = stmt->next;
2223
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2224
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2225
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "create", 0, &stmt->arg));
2226
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2227
1.16k
    stmt->prefix_data = mod;
2228
1.16k
    stmt->kw = LY_STMT_ENUM;
2229
2230
1.16k
    stmt->next = calloc(1, sizeof *stmt->child);
2231
1.16k
    stmt = stmt->next;
2232
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2233
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2234
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "delete", 0, &stmt->arg));
2235
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2236
1.16k
    stmt->prefix_data = mod;
2237
1.16k
    stmt->kw = LY_STMT_ENUM;
2238
2239
1.16k
    stmt->next = calloc(1, sizeof *stmt->child);
2240
1.16k
    stmt = stmt->next;
2241
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2242
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2243
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "remove", 0, &stmt->arg));
2244
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2245
1.16k
    stmt->prefix_data = mod;
2246
1.16k
    stmt->kw = LY_STMT_ENUM;
2247
2248
    /*
2249
     * 2) filter's type
2250
     */
2251
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
2252
1.16k
    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
2253
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
2254
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &extp->argument));
2255
1.16k
    extp->format = LY_VALUE_SCHEMA;
2256
1.16k
    extp->prefix_data = mod;
2257
1.16k
    extp->parent = mod;
2258
1.16k
    extp->parent_stmt = LY_STMT_MODULE;
2259
1.16k
    extp->flags = LYS_INTERNAL;
2260
2261
1.16k
    extp->child = stmt = calloc(1, sizeof *extp->child);
2262
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2263
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
2264
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enumeration", 0, &stmt->arg));
2265
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2266
1.16k
    stmt->prefix_data = mod;
2267
1.16k
    stmt->kw = LY_STMT_TYPE;
2268
2269
1.16k
    stmt->child = calloc(1, sizeof *stmt->child);
2270
1.16k
    stmt = stmt->child;
2271
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2272
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2273
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "subtree", 0, &stmt->arg));
2274
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2275
1.16k
    stmt->prefix_data = mod;
2276
1.16k
    stmt->kw = LY_STMT_ENUM;
2277
2278
1.16k
    stmt->next = calloc(1, sizeof *stmt->child);
2279
1.16k
    stmt = stmt->next;
2280
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2281
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enum", 0, &stmt->stmt));
2282
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
2283
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2284
1.16k
    stmt->prefix_data = mod;
2285
1.16k
    stmt->kw = LY_STMT_ENUM;
2286
2287
    /* if-feature for enum allowed only for YANG 1.1 modules */
2288
1.16k
    if (mod->version >= LYS_VERSION_1_1) {
2289
0
        stmt->child = calloc(1, sizeof *stmt->child);
2290
0
        stmt = stmt->child;
2291
0
        LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2292
0
        LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "if-feature", 0, &stmt->stmt));
2293
0
        LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "xpath", 0, &stmt->arg));
2294
0
        stmt->format = LY_VALUE_SCHEMA;
2295
0
        stmt->prefix_data = mod;
2296
0
        stmt->kw = LY_STMT_IF_FEATURE;
2297
0
    }
2298
2299
    /*
2300
     * 3) filter's select
2301
     */
2302
2.33k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
2303
2.33k
    LY_CHECK_ERR_RET(!extp, LOGMEM(mod->mod->ctx), LY_EMEM);
2304
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
2305
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "select", 0, &extp->argument));
2306
1.16k
    extp->format = LY_VALUE_SCHEMA;
2307
1.16k
    extp->prefix_data = mod;
2308
1.16k
    extp->parent = mod;
2309
1.16k
    extp->parent_stmt = LY_STMT_MODULE;
2310
1.16k
    extp->flags = LYS_INTERNAL;
2311
2312
1.16k
    extp->child = stmt = calloc(1, sizeof *extp->child);
2313
1.16k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2314
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
2315
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &stmt->arg));
2316
1.16k
    stmt->format = LY_VALUE_SCHEMA;
2317
1.16k
    stmt->prefix_data = mod;
2318
1.16k
    stmt->kw = LY_STMT_TYPE;
2319
2320
1.16k
    if (!prev_exts) {
2321
        /* first extension instances */
2322
1.15k
        assert(pctx->main_ctx == pctx);
2323
1.15k
        LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
2324
1.15k
    } else {
2325
        /* replace previously stored extension instances */
2326
7
        if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
2327
0
            LOGINT_RET(mod->mod->ctx);
2328
0
        }
2329
7
        pctx->ext_inst.objs[idx] = mod->exts;
2330
7
    }
2331
2332
    /*
2333
     * 4) rpc-error
2334
     */
2335
2.33k
    LY_LIST_NEW_RET(mod->mod->ctx, &mod->data, cont, next, LY_EMEM);
2336
2.33k
    cont->nodetype = LYS_CONTAINER;
2337
2.33k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "rpc-error", 0, &cont->name));
2338
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "presence", 0, &cont->presence));
2339
1.16k
    cont->flags = LYS_INTERNAL;
2340
2341
1.16k
    LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
2342
1.16k
    leaf->nodetype = LYS_LEAF;
2343
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error-type", 0, &leaf->name));
2344
1.16k
    leaf->flags = LYS_INTERNAL;
2345
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
2346
1.16k
    leaf->type.pmod = mod;
2347
1.16k
    leaf->type.flags = LYS_SET_ENUM;
2348
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2349
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "transport", 0, &enm->name));
2350
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2351
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "rpc", 0, &enm->name));
2352
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2353
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "protocol", 0, &enm->name));
2354
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2355
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "application", 0, &enm->name));
2356
2357
1.16k
    LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
2358
1.16k
    leaf->nodetype = LYS_LEAF;
2359
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error-tag", 0, &leaf->name));
2360
1.16k
    leaf->flags = LYS_INTERNAL;
2361
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
2362
1.16k
    leaf->type.pmod = mod;
2363
1.16k
    leaf->type.flags = LYS_SET_ENUM;
2364
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2365
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "in-use", 0, &enm->name));
2366
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2367
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "invalid-value", 0, &enm->name));
2368
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2369
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "too-big", 0, &enm->name));
2370
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2371
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "missing-attribute", 0, &enm->name));
2372
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2373
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "bad-attribute", 0, &enm->name));
2374
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2375
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "unknown-attribute", 0, &enm->name));
2376
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2377
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "missing-element", 0, &enm->name));
2378
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2379
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "bad-element", 0, &enm->name));
2380
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2381
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "unknown-element", 0, &enm->name));
2382
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2383
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "unknown-namespace", 0, &enm->name));
2384
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2385
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "access-denied", 0, &enm->name));
2386
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2387
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "lock-denied", 0, &enm->name));
2388
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2389
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "resource-denied", 0, &enm->name));
2390
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2391
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "rollback-failed", 0, &enm->name));
2392
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2393
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "data-exists", 0, &enm->name));
2394
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2395
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "data-missing", 0, &enm->name));
2396
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2397
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "operation-not-supported", 0, &enm->name));
2398
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2399
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "operation-failed", 0, &enm->name));
2400
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2401
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "partial-operation", 0, &enm->name));
2402
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2403
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "malformed-message", 0, &enm->name));
2404
2405
1.16k
    LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
2406
1.16k
    leaf->nodetype = LYS_LEAF;
2407
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error-severity", 0, &leaf->name));
2408
1.16k
    leaf->flags = LYS_INTERNAL;
2409
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
2410
1.16k
    leaf->type.pmod = mod;
2411
1.16k
    leaf->type.flags = LYS_SET_ENUM;
2412
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2413
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error", 0, &enm->name));
2414
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
2415
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "warning", 0, &enm->name));
2416
2417
1.16k
    LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
2418
1.16k
    leaf->nodetype = LYS_LEAF;
2419
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error-app-tag", 0, &leaf->name));
2420
1.16k
    leaf->flags = LYS_INTERNAL;
2421
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "string", 0, &leaf->type.name));
2422
1.16k
    leaf->type.pmod = mod;
2423
2424
1.16k
    LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
2425
1.16k
    leaf->nodetype = LYS_LEAF;
2426
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "error-path", 0, &leaf->name));
2427
1.16k
    leaf->flags = LYS_INTERNAL;
2428
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &leaf->type.name));
2429
1.16k
    leaf->type.pmod = mod;
2430
2431
    /* the rest are opaque nodes, error-message (because of 'xml:lang' attribute) and error-info (because can be any nodes) */
2432
2433
    /* create new imports for the used prefixes */
2434
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
2435
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
2436
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
2437
1.16k
    imp->flags = LYS_INTERNAL;
2438
2439
1.16k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
2440
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
2441
1.16k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
2442
1.16k
    imp->flags = LYS_INTERNAL;
2443
2444
1.16k
    return LY_SUCCESS;
2445
1.16k
}
2446
2447
/**
2448
 * @brief Add ietf-netconf-with-defaults "default" metadata to the parsed module.
2449
 *
2450
 * @param[in] pctx Parse context.
2451
 * @param[in] mod Parsed module to add to.
2452
 * @return LY_SUCCESS on success.
2453
 * @return LY_ERR on error.
2454
 */
2455
static LY_ERR
2456
lysp_add_internal_ietf_netconf_with_defaults(struct lysp_ctx *pctx, struct lysp_module *mod)
2457
0
{
2458
0
    struct lysp_ext_instance *extp, *prev_exts = mod->exts;
2459
0
    struct lysp_stmt *stmt;
2460
0
    struct lysp_import *imp;
2461
0
    uint32_t idx;
2462
2463
    /* add new extension instance */
2464
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->exts, extp, LY_EMEM);
2465
2466
    /* fill in the extension instance fields */
2467
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_:annotation", 0, &extp->name));
2468
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "default", 0, &extp->argument));
2469
0
    extp->format = LY_VALUE_SCHEMA;
2470
0
    extp->prefix_data = mod;
2471
0
    extp->parent = mod;
2472
0
    extp->parent_stmt = LY_STMT_MODULE;
2473
0
    extp->flags = LYS_INTERNAL;
2474
2475
0
    extp->child = stmt = calloc(1, sizeof *extp->child);
2476
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2477
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
2478
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "boolean", 0, &stmt->arg));
2479
0
    stmt->format = LY_VALUE_SCHEMA;
2480
0
    stmt->prefix_data = mod;
2481
0
    stmt->kw = LY_STMT_TYPE;
2482
2483
0
    if (!prev_exts) {
2484
        /* first extension instances */
2485
0
        assert(pctx->main_ctx == pctx);
2486
0
        LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
2487
0
    } else {
2488
        /* replace previously stored extension instances */
2489
0
        if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
2490
0
            LOGINT_RET(mod->mod->ctx);
2491
0
        }
2492
0
        pctx->ext_inst.objs[idx] = mod->exts;
2493
0
    }
2494
2495
    /* create new import for the used prefix */
2496
0
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
2497
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
2498
0
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md_", 0, &imp->prefix));
2499
0
    imp->flags = LYS_INTERNAL;
2500
2501
0
    return LY_SUCCESS;
2502
0
}
2503
2504
/**
2505
 * @brief Define a new internal 'lyds_tree' value for metadata.
2506
 *
2507
 * The 'lyds_tree' is a data type containing a reference to a binary search tree
2508
 * by which the data nodes are ordered.
2509
 *
2510
 * @param[in] pctx Parse context.
2511
 * @param[in] mod Parsed module to add to.
2512
 * @return LY_SUCCESS on success.
2513
 * @return LY_ERR on error.
2514
 */
2515
static LY_ERR
2516
lysp_add_internal_yang(struct lysp_ctx *pctx, struct lysp_module *mod)
2517
27.3k
{
2518
27.3k
    struct lysp_ext_instance *extp, *prev_exts = mod->exts;
2519
27.3k
    struct lysp_stmt *stmt;
2520
27.3k
    struct lysp_tpdf *tpdf;
2521
27.3k
    struct lysp_node_leaf *leaf;
2522
27.3k
    struct lysp_import *imp;
2523
27.3k
    uint32_t idx;
2524
2525
    /* add new typedef */
2526
27.3k
    LY_ARRAY_NEW_RET(PARSER_CTX(pctx), mod->typedefs, tpdf, LY_EMEM);
2527
27.3k
    LY_CHECK_RET(lysdict_insert(PARSER_CTX(pctx), "lyds_tree", 0, &tpdf->name));
2528
27.3k
    LY_CHECK_RET(lysdict_insert(PARSER_CTX(pctx), "uint64", 0, &tpdf->type.name));
2529
27.3k
    tpdf->type.pmod = mod;
2530
2531
    /* add new extension instance */
2532
27.3k
    LY_ARRAY_NEW_RET(PARSER_CTX(pctx), mod->exts, extp, LY_EMEM);
2533
2534
    /* fill in the extension instance fields */
2535
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "md:annotation", 0, &extp->name));
2536
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "lyds_tree", 0, &extp->argument));
2537
27.3k
    extp->format = LY_VALUE_SCHEMA;
2538
27.3k
    extp->prefix_data = mod;
2539
27.3k
    extp->parent = mod;
2540
27.3k
    extp->parent_stmt = LY_STMT_MODULE;
2541
27.3k
    extp->flags = LYS_INTERNAL;
2542
2543
    /* prepare for metadata plugin */
2544
27.3k
    extp->child = stmt = calloc(1, sizeof *extp->child);
2545
27.3k
    LY_CHECK_ERR_RET(!stmt, LOGMEM(mod->mod->ctx), LY_EMEM);
2546
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "type", 0, &stmt->stmt));
2547
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "lyds_tree", 0, &stmt->arg));
2548
27.3k
    stmt->format = LY_VALUE_SCHEMA;
2549
27.3k
    stmt->prefix_data = mod;
2550
27.3k
    stmt->kw = LY_STMT_TYPE;
2551
2552
27.3k
    if (!prev_exts) {
2553
        /* first extension instances */
2554
12
        assert(pctx->main_ctx == pctx);
2555
12
        LY_CHECK_RET(ly_set_add(&pctx->ext_inst, mod->exts, 1, NULL));
2556
27.3k
    } else {
2557
        /* replace previously stored extension instances */
2558
27.3k
        if (!ly_set_contains(&pctx->ext_inst, prev_exts, &idx)) {
2559
0
            LOGINT_RET(mod->mod->ctx);
2560
0
        }
2561
27.3k
        pctx->ext_inst.objs[idx] = mod->exts;
2562
27.3k
    }
2563
2564
    /* add a date-and-time leaf so that such values can be validated (there is a compiled type) */
2565
54.6k
    LY_LIST_NEW_RET(mod->mod->ctx, &mod->data, leaf, next, LY_EMEM);
2566
54.6k
    leaf->nodetype = LYS_LEAF;
2567
54.6k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "date-and-time", 0, &leaf->name));
2568
27.3k
    leaf->flags = LYS_INTERNAL;
2569
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "yang_:date-and-time", 0, &leaf->type.name));
2570
27.3k
    leaf->type.pmod = mod;
2571
2572
    /* create new imports for the used prefixes */
2573
27.3k
    LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
2574
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "ietf-yang-types", 0, &imp->name));
2575
27.3k
    LY_CHECK_RET(lysdict_insert(mod->mod->ctx, "yang_", 0, &imp->prefix));
2576
27.3k
    imp->flags = LYS_INTERNAL;
2577
2578
27.3k
    return LY_SUCCESS;
2579
27.3k
}
2580
2581
/**
2582
 * @brief Compile (copy) all submodules of a parsed module.
2583
 *
2584
 * @param[in] mod Module with the parsed and compiled module.
2585
 * @return LY_ERR value.
2586
 */
2587
static LY_ERR
2588
lys_compile_submodules(struct lys_module *mod)
2589
272k
{
2590
272k
    LY_ERR rc = LY_SUCCESS;
2591
272k
    LY_ARRAY_COUNT_TYPE u;
2592
272k
    const struct lysp_submodule *submodp;
2593
272k
    struct lysc_submodule *submod;
2594
2595
272k
    LY_ARRAY_FOR(mod->parsed->includes, u) {
2596
0
        submodp = mod->parsed->includes[u].submodule;
2597
2598
0
        LY_ARRAY_NEW_GOTO(mod->ctx, mod->submodules, submod, rc, cleanup);
2599
0
        DUP_STRING_GOTO(mod->ctx, submodp->name, submod->name, rc, cleanup);
2600
0
        if (submodp->revs) {
2601
0
            LY_CHECK_GOTO(rc = lysdict_insert(mod->ctx, submodp->revs[0].date, 0, &submod->revision), cleanup);
2602
0
        }
2603
0
        DUP_STRING_GOTO(mod->ctx, submodp->filepath, submod->filepath, rc, cleanup);
2604
0
    }
2605
2606
272k
cleanup:
2607
272k
    return rc;
2608
272k
}
2609
2610
LY_ERR
2611
lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const struct lysp_load_module_data *mod_data,
2612
        struct ly_set *new_mods, struct lys_module **module)
2613
283k
{
2614
283k
    LY_ERR rc = LY_SUCCESS, r;
2615
283k
    struct lys_module *mod = NULL, *latest, *mod_dup = NULL;
2616
283k
    struct lysp_yang_ctx *yangctx = NULL;
2617
283k
    struct lysp_yin_ctx *yinctx = NULL;
2618
283k
    struct lysp_ctx *pctx = NULL;
2619
283k
    ly_bool mod_created = 0, mod_exists = 0;
2620
2621
283k
    assert(ctx && in && new_mods);
2622
2623
283k
    if (module) {
2624
283k
        *module = NULL;
2625
283k
    }
2626
2627
283k
    mod = calloc(1, sizeof *mod);
2628
283k
    LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
2629
283k
    mod->ctx = ctx;
2630
2631
    /* parse */
2632
283k
    switch (format) {
2633
0
    case LYS_IN_YIN:
2634
0
        rc = yin_parse_module(&yinctx, in, mod);
2635
0
        pctx = (struct lysp_ctx *)yinctx;
2636
0
        break;
2637
283k
    case LYS_IN_YANG:
2638
283k
        rc = yang_parse_module(&yangctx, in, mod);
2639
283k
        pctx = (struct lysp_ctx *)yangctx;
2640
283k
        break;
2641
0
    default:
2642
0
        LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
2643
0
        rc = LY_EINVAL;
2644
0
        break;
2645
283k
    }
2646
283k
    LY_CHECK_GOTO(rc, cleanup);
2647
2648
    /* make sure that the newest revision is at position 0 */
2649
272k
    lysp_sort_revisions(mod->parsed->revs);
2650
272k
    if (mod->parsed->revs) {
2651
245k
        LY_CHECK_GOTO(rc = lysdict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), cleanup);
2652
245k
    }
2653
2654
    /* set YANG version */
2655
272k
    switch (mod->parsed->version) {
2656
88.4k
    case LYS_VERSION_UNDEF:
2657
88.4k
    case LYS_VERSION_1_0:
2658
88.4k
        mod->version = LYS_VERSION_1_0;
2659
88.4k
        break;
2660
184k
    case LYS_VERSION_1_1:
2661
184k
        mod->version = LYS_VERSION_1_1;
2662
184k
        break;
2663
272k
    }
2664
2665
    /* decide the latest revision */
2666
272k
    latest = ly_ctx_get_module_latest(ctx, mod->name);
2667
272k
    if (latest) {
2668
26
        if (mod->revision) {
2669
7
            if (!latest->revision) {
2670
                /* latest has no revision, so mod is anyway newer */
2671
0
                mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
2672
                /* the latest is zeroed later when the new module is being inserted into the context */
2673
7
            } else if (strcmp(mod->revision, latest->revision) > 0) {
2674
4
                mod->latest_revision = latest->latest_revision & (LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
2675
                /* the latest is zeroed later when the new module is being inserted into the context */
2676
4
            } else {
2677
3
                latest = NULL;
2678
3
            }
2679
19
        } else {
2680
19
            latest = NULL;
2681
19
        }
2682
272k
    } else {
2683
272k
        mod->latest_revision = LYS_MOD_LATEST_REV;
2684
272k
    }
2685
2686
272k
    if (mod_data) {
2687
        /* check the parsed module it is as expected */
2688
0
        r = lysp_load_module_data_check(ctx, mod->parsed, NULL, mod_data);
2689
0
        if (r == LY_EEXIST) {
2690
0
            mod_exists = 1;
2691
0
            goto cleanup;
2692
0
        } else if (r) {
2693
0
            rc = r;
2694
0
            goto cleanup;
2695
0
        }
2696
0
    }
2697
2698
    /* check whether it is not already in the context in the same revision */
2699
272k
    mod_dup = ly_ctx_get_module(ctx, mod->name, mod->revision);
2700
272k
    if (mod_dup) {
2701
        /* nothing to do */
2702
1
        LOGVRB("Module \"%s@%s\" is already present in the context.", mod_dup->name,
2703
1
                mod_dup->revision ? mod_dup->revision : "<none>");
2704
1
        goto cleanup;
2705
1
    }
2706
2707
    /* check whether there is not a namespace collision */
2708
272k
    mod_dup = ly_ctx_get_module_latest_ns(ctx, mod->ns);
2709
272k
    if (mod_dup && (mod_dup->revision == mod->revision)) {
2710
0
        LOGERR(ctx, LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\".",
2711
0
                mod_dup->name, mod->name, mod->ns);
2712
0
        rc = LY_EINVAL;
2713
0
        goto cleanup;
2714
0
    }
2715
2716
272k
    switch (in->type) {
2717
0
    case LY_IN_FILEPATH:
2718
0
        ly_check_module_filename(ctx, mod->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL, in->method.fpath.filepath);
2719
0
        break;
2720
0
    case LY_IN_FD:
2721
0
    case LY_IN_FILE:
2722
272k
    case LY_IN_MEMORY:
2723
        /* nothing special to do */
2724
272k
        break;
2725
0
    case LY_IN_ERROR:
2726
0
        LOGINT(ctx);
2727
0
        rc = LY_EINT;
2728
0
        goto cleanup;
2729
272k
    }
2730
272k
    LY_CHECK_GOTO(rc = lys_parser_fill_filepath(ctx, in, &mod->filepath), cleanup);
2731
2732
272k
    if (latest) {
2733
4
        latest->latest_revision &= ~(LYS_MOD_LATEST_REV | LYS_MOD_LATEST_SEARCHDIRS);
2734
4
    }
2735
2736
    /* add internal data in case specific modules were parsed */
2737
272k
    if (!strcmp(mod->name, "ietf-netconf")) {
2738
1.16k
        LY_CHECK_GOTO(rc = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
2739
271k
    } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
2740
0
        LY_CHECK_GOTO(rc = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
2741
271k
    } else if (!strcmp(mod->name, "yang")) {
2742
27.3k
        LY_CHECK_GOTO(rc = lysp_add_internal_yang(pctx, mod->parsed), cleanup);
2743
27.3k
    }
2744
2745
    /* add the module into newly created module set, will also be freed from there on any error */
2746
272k
    LY_CHECK_GOTO(rc = ly_set_add(new_mods, mod, 1, NULL), cleanup);
2747
272k
    mod_created = 1;
2748
2749
    /* add into context */
2750
272k
    rc = ly_set_add(&ctx->modules, mod, 1, NULL);
2751
272k
    LY_CHECK_GOTO(rc, cleanup);
2752
2753
    /* resolve includes and all imports */
2754
272k
    LY_CHECK_GOTO(rc = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
2755
2756
    /* resolve extension plugins and parse extension instances */
2757
272k
    lysp_resolve_ext_instance_plugins(mod);
2758
272k
    LY_CHECK_GOTO(rc = lysp_resolve_ext_instance_records(pctx), cleanup);
2759
2760
    /* check name collisions */
2761
272k
    LY_CHECK_GOTO(rc = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
2762
272k
    LY_CHECK_GOTO(rc = lysp_check_dup_groupings(pctx, mod->parsed), cleanup);
2763
272k
    LY_CHECK_GOTO(rc = lysp_check_dup_features(pctx, mod->parsed), cleanup);
2764
272k
    LY_CHECK_GOTO(rc = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
2765
2766
    /* compile features, extensions, identities, and submodules */
2767
272k
    LY_CHECK_GOTO(rc = lys_compile_feature_iffeatures(mod->parsed), cleanup);
2768
272k
    LY_CHECK_GOTO(rc = lys_compile_extensions(mod), cleanup);
2769
272k
    LY_CHECK_GOTO(rc = lys_compile_identities(mod), cleanup);
2770
272k
    LY_CHECK_GOTO(rc = lys_compile_submodules(mod), cleanup);
2771
2772
283k
cleanup:
2773
283k
    if (rc && mod && mod->name) {
2774
        /* there are cases when path is not available for parsing error, so this additional
2775
         * message tries to add information about the module where the error occurred */
2776
8.97k
        const struct ly_err_item *e = ly_err_last(ctx);
2777
2778
8.97k
        if (e && (!e->schema_path || e->line)) {
2779
0
            LOGERR(ctx, LY_EOTHER, "Parsing module \"%s\" failed.", mod->name);
2780
0
        }
2781
8.97k
    }
2782
283k
    if (!mod_created) {
2783
10.6k
        lys_module_free(ctx, mod, 0);
2784
10.6k
        mod = mod_dup;
2785
10.6k
    }
2786
2787
283k
    if (format == LYS_IN_YANG) {
2788
283k
        lysp_yang_ctx_free(yangctx);
2789
283k
    } else {
2790
0
        lysp_yin_ctx_free(yinctx);
2791
0
    }
2792
2793
283k
    if (!rc && !mod_exists && module) {
2794
272k
        *module = mod;
2795
272k
    }
2796
283k
    return rc;
2797
272k
}
2798
2799
static LYS_INFORMAT
2800
lys_parse_get_format(const struct ly_in *in, LYS_INFORMAT format)
2801
37.4k
{
2802
37.4k
    if (!format && (in->type == LY_IN_FILEPATH)) {
2803
        /* unknown format - try to detect it from filename's suffix */
2804
0
        const char *path = in->method.fpath.filepath;
2805
0
        size_t len = strlen(path);
2806
2807
        /* ignore trailing whitespaces */
2808
0
        for ( ; len > 0 && isspace(path[len - 1]); len--) {}
2809
2810
0
        if ((len >= LY_YANG_SUFFIX_LEN + 1) &&
2811
0
                !strncmp(&path[len - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX, LY_YANG_SUFFIX_LEN)) {
2812
0
            format = LYS_IN_YANG;
2813
0
        } else if ((len >= LY_YIN_SUFFIX_LEN + 1) &&
2814
0
                !strncmp(&path[len - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX, LY_YIN_SUFFIX_LEN)) {
2815
0
            format = LYS_IN_YIN;
2816
0
        } /* else still unknown */
2817
0
    }
2818
2819
37.4k
    return format;
2820
37.4k
}
2821
2822
LIBYANG_API_DEF LY_ERR
2823
lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char **features, struct lys_module **module)
2824
37.4k
{
2825
37.4k
    LY_ERR ret = LY_SUCCESS;
2826
37.4k
    struct lys_module *mod;
2827
2828
37.4k
    if (module) {
2829
0
        *module = NULL;
2830
0
    }
2831
74.9k
    LY_CHECK_ARG_RET(NULL, ctx, !(ctx->opts & LY_CTX_INT_IMMUTABLE), in, LY_EINVAL);
2832
2833
37.4k
    format = lys_parse_get_format(in, format);
2834
37.4k
    LY_CHECK_ARG_RET(ctx, format, LY_EINVAL);
2835
2836
    /* remember input position */
2837
37.4k
    in->func_start = in->current;
2838
2839
    /* parse */
2840
37.4k
    ret = lys_parse_in(ctx, in, format, NULL, &ctx->unres.creating, &mod);
2841
37.4k
    LY_CHECK_GOTO(ret, cleanup);
2842
2843
    /* implement */
2844
26.5k
    ret = _lys_set_implemented(mod, features, &ctx->unres);
2845
26.5k
    LY_CHECK_GOTO(ret, cleanup);
2846
2847
26.4k
    if (!(ctx->opts & LY_CTX_EXPLICIT_COMPILE)) {
2848
        /* create dep set for the module and mark all the modules that will be (re)compiled */
2849
26.4k
        LY_CHECK_GOTO(ret = lys_unres_dep_sets_create(ctx, &ctx->unres.dep_sets, mod), cleanup);
2850
2851
        /* (re)compile the whole dep set (other dep sets will have no modules marked for compilation) */
2852
26.4k
        LY_CHECK_GOTO(ret = lys_compile_depset_all(ctx, &ctx->unres), cleanup);
2853
2854
        /* unres resolved */
2855
23.7k
        lys_unres_glob_erase(&ctx->unres);
2856
2857
        /* new context state */
2858
23.7k
        ly_ctx_new_change(ctx);
2859
23.7k
    }
2860
2861
37.4k
cleanup:
2862
37.4k
    if (ret) {
2863
13.6k
        lys_unres_glob_revert(ctx, &ctx->unres);
2864
13.6k
        lys_unres_glob_erase(&ctx->unres);
2865
23.7k
    } else if (module) {
2866
0
        *module = mod;
2867
0
    }
2868
37.4k
    return ret;
2869
26.4k
}
2870
2871
LIBYANG_API_DEF LY_ERR
2872
lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_module **module)
2873
37.4k
{
2874
37.4k
    LY_ERR ret;
2875
37.4k
    struct ly_in *in = NULL;
2876
2877
112k
    LY_CHECK_ARG_RET(ctx, ctx, !(ctx->opts & LY_CTX_INT_IMMUTABLE), data, format != LYS_IN_UNKNOWN, LY_EINVAL);
2878
2879
37.4k
    LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
2880
2881
37.4k
    ret = lys_parse(ctx, in, format, NULL, module);
2882
37.4k
    ly_in_free(in, 0);
2883
2884
37.4k
    return ret;
2885
37.4k
}
2886
2887
LIBYANG_API_DEF LY_ERR
2888
lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_module **module)
2889
0
{
2890
0
    LY_ERR ret;
2891
0
    struct ly_in *in = NULL;
2892
2893
0
    LY_CHECK_ARG_RET(ctx, ctx, !(ctx->opts & LY_CTX_INT_IMMUTABLE), fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
2894
2895
0
    LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
2896
2897
0
    ret = lys_parse(ctx, in, format, NULL, module);
2898
0
    ly_in_free(in, 0);
2899
2900
0
    return ret;
2901
0
}
2902
2903
LIBYANG_API_DEF LY_ERR
2904
lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, struct lys_module **module)
2905
0
{
2906
0
    LY_ERR ret;
2907
0
    struct ly_in *in = NULL;
2908
2909
0
    LY_CHECK_ARG_RET(ctx, ctx, !(ctx->opts & LY_CTX_INT_IMMUTABLE), path, format != LYS_IN_UNKNOWN, LY_EINVAL);
2910
2911
0
    LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
2912
0
            LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
2913
2914
0
    ret = lys_parse(ctx, in, format, NULL, module);
2915
0
    ly_in_free(in, 0);
2916
2917
0
    return ret;
2918
0
}
2919
2920
/**
2921
 * @brief Check file type of a file.
2922
 *
2923
 * @param[in] file Dirent file to check.
2924
 * @param[in] wd Working directory.
2925
 * @param[in,out] dirs Set with searched directories to add to.
2926
 * @param[in] implicit_cwd Whether implicit CWD is used.
2927
 * @param[out] skip Whether to skip this file.
2928
 * @return LY_ERR value.
2929
 */
2930
static LY_ERR
2931
lys_search_localfile_file_type(const struct dirent *file, const char *wd, struct ly_set *dirs, ly_bool implicit_cwd,
2932
        ly_bool *skip)
2933
1.00M
{
2934
1.00M
    LY_ERR rc = LY_SUCCESS;
2935
1.00M
    char *str = NULL;
2936
1.00M
    ly_bool is_dir = 0, is_reg = 0, need_stat = 1;
2937
1.00M
    struct stat st;
2938
2939
1.00M
    *skip = 0;
2940
2941
1.00M
#ifdef HAVE_DIRENT_D_TYPE
2942
1.00M
    if (file->d_type == DT_DIR) {
2943
        /* dirent - dir */
2944
686k
        is_dir = 1;
2945
686k
        need_stat = 0;
2946
686k
    } else if (file->d_type == DT_REG) {
2947
        /* dirent - file */
2948
318k
        is_reg = 1;
2949
318k
        need_stat = 0;
2950
318k
    } else if ((file->d_type != DT_UNKNOWN) && (file->d_type != DT_LNK)) {
2951
        /* it is a known type, but not dir or regular file, so trust d_type and just skip it */
2952
0
        need_stat = 0;
2953
0
    }
2954
1.00M
#endif // HAVE_DIRENT_D_TYPE
2955
2956
1.00M
    if (need_stat) {
2957
        /* need to use stat to determine the file type */
2958
0
        if (asprintf(&str, "%s/%s", wd, file->d_name) == -1) {
2959
0
            LOGMEM(NULL);
2960
0
            rc = LY_EMEM;
2961
0
            goto cleanup;
2962
0
        }
2963
0
        if (stat(str, &st)) {
2964
0
            LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
2965
0
                    file->d_name, wd, strerror(errno));
2966
0
        } else if (S_ISDIR(st.st_mode)) {
2967
            /* stat - dir */
2968
0
            is_dir = 1;
2969
0
        } else if (S_ISREG(st.st_mode)) {
2970
            /* stat - file */
2971
0
            is_reg = 1;
2972
0
        }
2973
0
    }
2974
2975
1.00M
    if (is_dir && (dirs->count || !implicit_cwd)) {
2976
        /* we have another subdirectory in searchpath to explore,
2977
         * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
2978
0
        if (!str && (asprintf(&str, "%s/%s", wd, file->d_name) == -1)) {
2979
0
            LOGMEM(NULL);
2980
0
            rc = LY_EMEM;
2981
0
            goto cleanup;
2982
0
        }
2983
0
        if ((rc = ly_set_add(dirs, str, 0, NULL))) {
2984
0
            goto cleanup;
2985
0
        }
2986
0
        str = NULL;
2987
2988
        /* continue with the next item in current directory */
2989
0
        *skip = 1;
2990
1.00M
    } else if (!is_reg) {
2991
        /* not a regular file (note that we see the target of symlinks instead of symlinks */
2992
686k
        *skip = 1;
2993
686k
    }
2994
2995
1.00M
cleanup:
2996
1.00M
    free(str);
2997
1.00M
    return rc;
2998
1.00M
}
2999
3000
LIBYANG_API_DEF LY_ERR
3001
lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *name, const char *revision,
3002
        char **localfile, LYS_INFORMAT *format)
3003
54.6k
{
3004
54.6k
    LY_ERR ret = LY_EMEM;
3005
54.6k
    size_t len, flen, match_len = 0, dir_len;
3006
54.6k
    ly_bool implicit_cwd = 0, skip;
3007
54.6k
    char *wd;
3008
54.6k
    DIR *dir = NULL;
3009
54.6k
    struct dirent *file;
3010
54.6k
    char *match_name = NULL;
3011
54.6k
    LYS_INFORMAT format_aux, match_format = 0;
3012
54.6k
    struct ly_set *dirs;
3013
3014
54.6k
    LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
3015
3016
    /* start to fill the dir fifo with the context's search path (if set)
3017
     * and the current working directory */
3018
54.6k
    LY_CHECK_RET(ly_set_new(&dirs));
3019
3020
54.6k
    len = strlen(name);
3021
54.6k
    if (cwd) {
3022
54.6k
        wd = get_current_dir_name();
3023
54.6k
        if (!wd) {
3024
0
            LOGMEM(NULL);
3025
0
            goto cleanup;
3026
54.6k
        } else {
3027
            /* add implicit current working directory (./) to be searched,
3028
             * this directory is not searched recursively */
3029
54.6k
            ret = ly_set_add(dirs, wd, 0, NULL);
3030
54.6k
            LY_CHECK_GOTO(ret, cleanup);
3031
54.6k
            implicit_cwd = 1;
3032
54.6k
        }
3033
54.6k
    }
3034
54.6k
    if (searchpaths) {
3035
54.6k
        for (uint64_t i = 0; searchpaths[i]; i++) {
3036
            /* check for duplicities with the implicit current working directory */
3037
0
            if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
3038
0
                implicit_cwd = 0;
3039
0
                continue;
3040
0
            }
3041
0
            wd = strdup(searchpaths[i]);
3042
0
            if (!wd) {
3043
0
                LOGMEM(NULL);
3044
0
                goto cleanup;
3045
0
            } else {
3046
0
                ret = ly_set_add(dirs, wd, 0, NULL);
3047
0
                LY_CHECK_GOTO(ret, cleanup);
3048
0
            }
3049
0
        }
3050
54.6k
    }
3051
54.6k
    wd = NULL;
3052
3053
    /* start searching */
3054
109k
    while (dirs->count) {
3055
54.6k
        free(wd);
3056
3057
54.6k
        dirs->count--;
3058
54.6k
        wd = (char *)dirs->objs[dirs->count];
3059
54.6k
        dirs->objs[dirs->count] = NULL;
3060
54.6k
        LOGVRB("Searching for \"%s\" in \"%s\".", name, wd);
3061
3062
54.6k
        if (dir) {
3063
0
            closedir(dir);
3064
0
        }
3065
54.6k
        dir = opendir(wd);
3066
54.6k
        dir_len = strlen(wd);
3067
54.6k
        if (!dir) {
3068
0
            LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
3069
0
            continue;
3070
0
        }
3071
3072
        /* search the directory */
3073
1.16M
        while ((file = readdir(dir))) {
3074
1.11M
            if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
3075
                /* skip . and .. */
3076
109k
                continue;
3077
109k
            }
3078
3079
            /* check whether file type is */
3080
1.00M
            if ((ret = lys_search_localfile_file_type(file, wd, dirs, implicit_cwd, &skip))) {
3081
0
                goto cleanup;
3082
0
            }
3083
3084
            /* here we know that the item is a file which can contain a module */
3085
1.00M
            if (strncmp(name, file->d_name, len) || ((file->d_name[len] != '.') && (file->d_name[len] != '@'))) {
3086
                /* different filename than the module we search for */
3087
1.00M
                continue;
3088
1.00M
            }
3089
3090
            /* get type according to filename suffix */
3091
0
            flen = strlen(file->d_name);
3092
0
            if ((flen >= LY_YANG_SUFFIX_LEN + 1) && !strcmp(&file->d_name[flen - LY_YANG_SUFFIX_LEN], LY_YANG_SUFFIX)) {
3093
0
                format_aux = LYS_IN_YANG;
3094
0
            } else if ((flen >= LY_YIN_SUFFIX_LEN + 1) && !strcmp(&file->d_name[flen - LY_YIN_SUFFIX_LEN], LY_YIN_SUFFIX)) {
3095
0
                format_aux = LYS_IN_YIN;
3096
0
            } else {
3097
                /* not supported suffix/file format */
3098
0
                continue;
3099
0
            }
3100
3101
0
            if (revision) {
3102
                /* we look for the specific revision, try to get it from the filename */
3103
0
                if (file->d_name[len] == '@') {
3104
                    /* check revision from the filename */
3105
0
                    if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
3106
                        /* another revision */
3107
0
                        continue;
3108
0
                    } else {
3109
                        /* exact revision */
3110
0
                        free(match_name);
3111
0
                        if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
3112
0
                            LOGMEM(NULL);
3113
0
                            goto cleanup;
3114
0
                        }
3115
0
                        match_len = dir_len + 1 + len;
3116
0
                        match_format = format_aux;
3117
0
                        goto success;
3118
0
                    }
3119
0
                } else {
3120
                    /* continue trying to find exact revision match, use this only if not found */
3121
0
                    free(match_name);
3122
0
                    if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
3123
0
                        LOGMEM(NULL);
3124
0
                        goto cleanup;
3125
0
                    }
3126
0
                    match_len = dir_len + 1 + len;
3127
0
                    match_format = format_aux;
3128
0
                    continue;
3129
0
                }
3130
0
            } else {
3131
                /* remember the revision and try to find the newest one */
3132
0
                if (match_name) {
3133
0
                    if ((file->d_name[len] != '@') ||
3134
0
                            lys_check_date(NULL, &file->d_name[len + 1],
3135
0
                            flen - ((format_aux == LYS_IN_YANG) ? LY_YANG_SUFFIX_LEN : LY_YIN_SUFFIX_LEN) - len - 1, "revision")) {
3136
0
                        continue;
3137
0
                    } else if ((match_name[match_len] == '@') &&
3138
0
                            (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
3139
0
                        continue;
3140
0
                    }
3141
0
                    free(match_name);
3142
0
                }
3143
3144
0
                if (asprintf(&match_name, "%s/%s", wd, file->d_name) == -1) {
3145
0
                    LOGMEM(NULL);
3146
0
                    goto cleanup;
3147
0
                }
3148
0
                match_len = dir_len + 1 + len;
3149
0
                match_format = format_aux;
3150
0
                continue;
3151
0
            }
3152
0
        }
3153
54.6k
    }
3154
3155
54.6k
success:
3156
54.6k
    (*localfile) = match_name;
3157
54.6k
    match_name = NULL;
3158
54.6k
    if (format) {
3159
54.6k
        (*format) = match_format;
3160
54.6k
    }
3161
54.6k
    ret = LY_SUCCESS;
3162
3163
54.6k
cleanup:
3164
54.6k
    free(wd);
3165
54.6k
    if (dir) {
3166
54.6k
        closedir(dir);
3167
54.6k
    }
3168
54.6k
    free(match_name);
3169
54.6k
    ly_set_free(dirs, free);
3170
3171
54.6k
    return ret;
3172
54.6k
}