Coverage Report

Created: 2025-08-03 06:36

/src/libyang/src/parser_yang.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file parser_yang.c
3
 * @author Michal Vasko <mvasko@cesnet.cz>
4
 * @brief YANG parser
5
 *
6
 * Copyright (c) 2018 CESNET, z.s.p.o.
7
 *
8
 * This source code is licensed under BSD 3-Clause License (the "License").
9
 * You may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     https://opensource.org/licenses/BSD-3-Clause
13
 */
14
#include "parser_internal.h"
15
16
#include <assert.h>
17
#include <ctype.h>
18
#include <errno.h>
19
#include <stdint.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "common.h"
25
#include "context.h"
26
#include "dict.h"
27
#include "in_internal.h"
28
#include "log.h"
29
#include "parser_schema.h"
30
#include "path.h"
31
#include "set.h"
32
#include "tree.h"
33
#include "tree_edit.h"
34
#include "tree_schema.h"
35
#include "tree_schema_internal.h"
36
37
struct lys_glob_unres;
38
39
/**
40
 * @brief Insert WORD into the libyang context's dictionary and store as TARGET.
41
 * @param[in] CTX yang parser context to access libyang context.
42
 * @param[in] BUF buffer in case the word is not a constant and can be inserted directly (zero-copy)
43
 * @param[out] TARGET variable where to store the pointer to the inserted value.
44
 * @param[in] WORD string to store.
45
 * @param[in] LEN length of the string in WORD to store.
46
 */
47
#define INSERT_WORD_RET(CTX, BUF, TARGET, WORD, LEN) \
48
0
    if (BUF) {LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(CTX), WORD, &(TARGET)));}\
49
0
    else {LY_CHECK_RET(lydict_insert(PARSER_CTX(CTX), LEN ? WORD : "", LEN, &(TARGET)));}
50
51
/**
52
 * @brief Read from the IN structure COUNT items. Also updates the indent value in yang parser context
53
 * @param[in] CTX yang parser context to update its indent value.
54
 * @param[in] COUNT number of items for which the DATA pointer is supposed to move on.
55
 */
56
0
#define MOVE_INPUT(CTX, COUNT) ly_in_skip((CTX)->in, COUNT);(CTX)->indent+=COUNT
57
58
/**
59
 * @brief Loop through all substatements.
60
 *
61
 * @param[in] CTX yang parser context for logging.
62
 * @param[out] KW YANG keyword read.
63
 * @param[out] WORD Pointer to the keyword itself.
64
 * @param[out] WORD_LEN Length of the keyword.
65
 * @param[out] ERR Variable for error storing.
66
 * @param[in] SUC_CMD Command is applied if a semicolon is found, so no
67
 * substatements are available. It is expected to contain a return or goto command.
68
 * @param[in] ERR_CMD Command is applied if an error occurs before loop through
69
 * substatements. It is expected to contain return or goto command.
70
 *
71
 * @return In case there are no substatements or a fatal error encountered.
72
 */
73
#define YANG_READ_SUBSTMT_FOR(CTX, KW, WORD, WORD_LEN, ERR, SUC_CMD, ERR_CMD) \
74
0
    if ((ERR = get_keyword(CTX, &KW, &WORD, &WORD_LEN))) { \
75
0
        ERR_CMD; \
76
0
    } \
77
0
    if (KW == LY_STMT_SYNTAX_SEMICOLON) { \
78
0
        SUC_CMD; \
79
0
    } \
80
0
    if (KW != LY_STMT_SYNTAX_LEFT_BRACE) { \
81
0
        LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
82
0
        ERR = LY_EVALID; \
83
0
        ERR_CMD; \
84
0
    } \
85
0
    for (ERR = get_keyword(CTX, &KW, &WORD, &WORD_LEN); \
86
0
            !ERR && (KW != LY_STMT_SYNTAX_RIGHT_BRACE); \
87
0
            ERR = get_keyword(CTX, &KW, &WORD, &WORD_LEN))
88
89
LY_ERR parse_container(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent,
90
        struct lysp_node **siblings);
91
LY_ERR parse_uses(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
92
LY_ERR parse_choice(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
93
LY_ERR parse_case(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
94
LY_ERR parse_list(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
95
LY_ERR parse_grouping(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node_grp **groupings);
96
97
/**
98
 * @brief Add another character to dynamic buffer, a low-level function.
99
 *
100
 * Enlarge if needed. Updates \p input as well as \p buf_used.
101
 *
102
 * @param[in] ctx libyang context for logging.
103
 * @param[in,out] in Input structure.
104
 * @param[in] len Number of bytes to get from the input string and copy into the buffer.
105
 * @param[in,out] buf Buffer to use, can be moved by realloc().
106
 * @param[in,out] buf_len Current size of the buffer.
107
 * @param[in,out] buf_used Currently used characters of the buffer.
108
 *
109
 * @return LY_ERR values.
110
 */
111
LY_ERR
112
buf_add_char(struct ly_ctx *ctx, struct ly_in *in, size_t len, char **buf, size_t *buf_len, size_t *buf_used)
113
0
{
114
0
#define BUF_STEP 16;
115
0
    if (*buf_len <= (*buf_used) + len) {
116
0
        *buf_len += BUF_STEP;
117
0
        *buf = ly_realloc(*buf, *buf_len);
118
0
        LY_CHECK_ERR_RET(!*buf, LOGMEM(ctx), LY_EMEM);
119
0
    }
120
0
    if (*buf_used) {
121
0
        ly_in_read(in, &(*buf)[*buf_used], len);
122
0
    } else {
123
0
        ly_in_read(in, *buf, len);
124
0
    }
125
126
0
    (*buf_used) += len;
127
0
    return LY_SUCCESS;
128
0
#undef BUF_STEP
129
0
}
130
131
/**
132
 * @brief Store a single UTF8 character. It depends whether in a dynamically-allocated buffer or just as a pointer to the data.
133
 *
134
 * @param[in] ctx yang parser context for logging.
135
 * @param[in] arg Type of the input string to select method of checking character validity.
136
 * @param[in,out] word_p Word pointer. If buffer (\p word_b) was not yet needed, it is just a pointer to the first
137
 * stored character. If buffer was needed (\p word_b is non-NULL or \p need_buf is set), it is pointing to the buffer.
138
 * @param[in,out] word_len Current length of the word pointed to by \p word_p.
139
 * @param[in,out] word_b Word buffer. Is kept NULL as long as it is not requested (word is a substring of the data).
140
 * @param[in,out] buf_len Current length of \p word_b.
141
 * @param[in] need_buf Flag if the dynamically allocated buffer is required.
142
 * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
143
 * 0 - colon not yet found (no prefix)
144
 * 1 - \p c is the colon character
145
 * 2 - prefix already processed, now processing the identifier
146
 *
147
 * @return LY_ERR values.
148
 */
149
LY_ERR
150
buf_store_char(struct lys_yang_parser_ctx *ctx, enum yang_arg arg, char **word_p, size_t *word_len,
151
        char **word_b, size_t *buf_len, ly_bool need_buf, uint8_t *prefix)
152
0
{
153
0
    uint32_t c;
154
0
    size_t len;
155
156
    /* check  valid combination of input paremeters - if need_buf specified, word_b must be provided */
157
0
    assert(!need_buf || (need_buf && word_b));
158
159
    /* get UTF8 code point (and number of bytes coding the character) */
160
0
    LY_CHECK_ERR_RET(ly_getutf8(&ctx->in->current, &c, &len),
161
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[-len]), LY_EVALID);
162
0
    ctx->in->current -= len;
163
0
    if (c == '\n') {
164
0
        ctx->indent = 0;
165
0
        LY_IN_NEW_LINE(ctx->in);
166
0
    } else {
167
        /* note - even the multibyte character is count as 1 */
168
0
        ++ctx->indent;
169
0
    }
170
171
    /* check character validity */
172
0
    switch (arg) {
173
0
    case Y_IDENTIF_ARG:
174
0
        LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !(*word_len), NULL));
175
0
        break;
176
0
    case Y_PREF_IDENTIF_ARG:
177
0
        LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !(*word_len), prefix));
178
0
        break;
179
0
    case Y_STR_ARG:
180
0
    case Y_MAYBE_STR_ARG:
181
0
        LY_CHECK_RET(lysp_check_stringchar((struct lys_parser_ctx *)ctx, c));
182
0
        break;
183
0
    }
184
185
0
    if (word_b && *word_b) {
186
        /* add another character into buffer */
187
0
        if (buf_add_char(PARSER_CTX(ctx), ctx->in, len, word_b, buf_len, word_len)) {
188
0
            return LY_EMEM;
189
0
        }
190
191
        /* in case of realloc */
192
0
        *word_p = *word_b;
193
0
    } else if (word_b && need_buf) {
194
        /* first time we need a buffer, copy everything read up to now */
195
0
        if (*word_len) {
196
0
            *word_b = malloc(*word_len);
197
0
            LY_CHECK_ERR_RET(!*word_b, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
198
0
            *buf_len = *word_len;
199
0
            memcpy(*word_b, *word_p, *word_len);
200
0
        }
201
202
        /* add this new character into buffer */
203
0
        if (buf_add_char(PARSER_CTX(ctx), ctx->in, len, word_b, buf_len, word_len)) {
204
0
            return LY_EMEM;
205
0
        }
206
207
        /* in case of realloc */
208
0
        *word_p = *word_b;
209
0
    } else {
210
        /* just remember the first character pointer */
211
0
        if (!*word_p) {
212
0
            *word_p = (char *)ctx->in->current;
213
0
        }
214
        /* ... and update the word's length */
215
0
        (*word_len) += len;
216
0
        ly_in_skip(ctx->in, len);
217
0
    }
218
219
0
    return LY_SUCCESS;
220
0
}
221
222
/**
223
 * @brief Skip YANG comment in data.
224
 *
225
 * @param[in] ctx yang parser context for logging.
226
 * @param[in] comment Type of the comment to process:
227
 *                    1 for a one-line comment,
228
 *                    2 for a block comment.
229
 * @return LY_ERR values.
230
 */
231
LY_ERR
232
skip_comment(struct lys_yang_parser_ctx *ctx, uint8_t comment)
233
0
{
234
    /* internal statuses: */
235
0
#define COMMENT_NO        0 /* comment ended */
236
0
#define COMMENT_LINE      1 /* in line comment */
237
0
#define COMMENT_BLOCK     2 /* in block comment */
238
0
#define COMMENT_BLOCK_END 3 /* in block comment with last read character '*' */
239
240
0
    while (ctx->in->current[0] && comment) {
241
0
        switch (comment) {
242
0
        case COMMENT_LINE:
243
0
            if (ctx->in->current[0] == '\n') {
244
0
                comment = COMMENT_NO;
245
0
                LY_IN_NEW_LINE(ctx->in);
246
0
            }
247
0
            break;
248
0
        case COMMENT_BLOCK:
249
0
            if (ctx->in->current[0] == '*') {
250
0
                comment = COMMENT_BLOCK_END;
251
0
            } else if (ctx->in->current[0] == '\n') {
252
0
                LY_IN_NEW_LINE(ctx->in);
253
0
            }
254
0
            break;
255
0
        case COMMENT_BLOCK_END:
256
0
            if (ctx->in->current[0] == '/') {
257
0
                comment = COMMENT_NO;
258
0
            } else if (ctx->in->current[0] != '*') {
259
0
                if (ctx->in->current[0] == '\n') {
260
0
                    LY_IN_NEW_LINE(ctx->in);
261
0
                }
262
0
                comment = COMMENT_BLOCK;
263
0
            }
264
0
            break;
265
0
        default:
266
0
            LOGINT_RET(PARSER_CTX(ctx));
267
0
        }
268
269
0
        if (ctx->in->current[0] == '\n') {
270
0
            ctx->indent = 0;
271
0
        } else {
272
0
            ++ctx->indent;
273
0
        }
274
0
        ++ctx->in->current;
275
0
    }
276
277
0
    if (!ctx->in->current[0] && (comment >= COMMENT_BLOCK)) {
278
0
        LOGVAL_PARSER(ctx, LYVE_SYNTAX, "Unexpected end-of-input, non-terminated comment.");
279
0
        return LY_EVALID;
280
0
    }
281
282
0
    return LY_SUCCESS;
283
284
0
#undef COMMENT_NO
285
0
#undef COMMENT_LINE
286
0
#undef COMMENT_BLOCK
287
0
#undef COMMENT_BLOCK_END
288
0
}
289
290
/**
291
 * @brief Read a quoted string from data.
292
 *
293
 * @param[in] ctx yang parser context for logging.
294
 * @param[in] arg Type of YANG keyword argument expected.
295
 * @param[out] word_p Pointer to the read quoted string.
296
 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read quoted string. If not needed,
297
 * set to NULL. Otherwise equal to \p word_p.
298
 * @param[out] word_len Length of the read quoted string.
299
 * @param[out] buf_len Length of the dynamically-allocated buffer \p word_b.
300
 * @param[in] indent Current indent (number of YANG spaces). Needed for correct multi-line string
301
 * indenation in the final quoted string.
302
 *
303
 * @return LY_ERR values.
304
 */
305
static LY_ERR
306
read_qstring(struct lys_yang_parser_ctx *ctx, enum yang_arg arg, char **word_p, char **word_b,
307
        size_t *word_len, size_t *buf_len)
308
0
{
309
    /* string parsing status: */
310
0
#define STRING_ENDED 0 /* string ended */
311
0
#define STRING_SINGLE_QUOTED 1 /* string with ' */
312
0
#define STRING_DOUBLE_QUOTED 2 /* string with " */
313
0
#define STRING_DOUBLE_QUOTED_ESCAPED 3 /* string with " with last character \ */
314
0
#define STRING_PAUSED_NEXTSTRING     4 /* string finished, now skipping whitespaces looking for + */
315
0
#define STRING_PAUSED_CONTINUE       5 /* string continues after +, skipping whitespaces */
316
317
0
    uint8_t string;
318
0
    uint64_t block_indent = 0, current_indent = 0;
319
0
    ly_bool need_buf = 0;
320
0
    uint8_t prefix = 0;
321
0
    const char *c;
322
0
    uint64_t trailing_ws = 0; /* current number of stored trailing whitespace characters */
323
324
0
    if (ctx->in->current[0] == '\"') {
325
0
        string = STRING_DOUBLE_QUOTED;
326
0
        current_indent = block_indent = ctx->indent + 1;
327
0
    } else {
328
0
        assert(ctx->in->current[0] == '\'');
329
0
        string = STRING_SINGLE_QUOTED;
330
0
    }
331
0
    MOVE_INPUT(ctx, 1);
332
333
0
    while (ctx->in->current[0] && string) {
334
0
        switch (string) {
335
0
        case STRING_SINGLE_QUOTED:
336
0
            switch (ctx->in->current[0]) {
337
0
            case '\'':
338
                /* string may be finished, but check for + */
339
0
                string = STRING_PAUSED_NEXTSTRING;
340
0
                MOVE_INPUT(ctx, 1);
341
0
                break;
342
0
            default:
343
                /* check and store character */
344
0
                LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
345
0
                break;
346
0
            }
347
0
            break;
348
0
        case STRING_DOUBLE_QUOTED:
349
0
            switch (ctx->in->current[0]) {
350
0
            case '\"':
351
                /* string may be finished, but check for + */
352
0
                string = STRING_PAUSED_NEXTSTRING;
353
0
                MOVE_INPUT(ctx, 1);
354
0
                trailing_ws = 0;
355
0
                break;
356
0
            case '\\':
357
                /* special character following */
358
0
                string = STRING_DOUBLE_QUOTED_ESCAPED;
359
360
                /* the backslash sequence is substituted, so we will need a buffer to store the result */
361
0
                need_buf = 1;
362
363
                /* move forward to the escaped character */
364
0
                ++ctx->in->current;
365
366
                /* note that the trailing whitespaces are supposed to be trimmed before substitution of
367
                 * backslash-escaped characters (RFC 7950, 6.1.3), so we have to zero the trailing whitespaces counter */
368
0
                trailing_ws = 0;
369
370
                /* since the backslash-escaped character is handled as first non-whitespace character, stop eating indentation */
371
0
                current_indent = block_indent;
372
0
                break;
373
0
            case ' ':
374
0
                if (current_indent < block_indent) {
375
0
                    ++current_indent;
376
0
                    MOVE_INPUT(ctx, 1);
377
0
                } else {
378
                    /* check and store whitespace character */
379
0
                    LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
380
0
                    trailing_ws++;
381
0
                }
382
0
                break;
383
0
            case '\t':
384
0
                if (current_indent < block_indent) {
385
0
                    assert(need_buf);
386
0
                    current_indent += Y_TAB_SPACES;
387
0
                    ctx->indent += Y_TAB_SPACES;
388
0
                    for ( ; current_indent > block_indent; --current_indent, --ctx->indent) {
389
                        /* store leftover spaces from the tab */
390
0
                        c = ctx->in->current;
391
0
                        ctx->in->current = " ";
392
0
                        LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
393
0
                        ctx->in->current = c;
394
0
                        trailing_ws++;
395
0
                    }
396
0
                    ++ctx->in->current;
397
0
                } else {
398
                    /* check and store whitespace character */
399
0
                    LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
400
0
                    trailing_ws++;
401
                    /* additional characters for indentation - only 1 was count in buf_store_char */
402
0
                    ctx->indent += Y_TAB_SPACES - 1;
403
0
                }
404
0
                break;
405
0
            case '\r':
406
0
                if (ctx->in->current[1] != '\n') {
407
0
                    LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
408
0
                    return LY_EVALID;
409
0
                }
410
            /* fallthrough */
411
0
            case '\n':
412
0
                if (block_indent) {
413
                    /* we will be removing the indents so we need our own buffer */
414
0
                    need_buf = 1;
415
416
                    /* remove trailing tabs and spaces */
417
0
                    (*word_len) = *word_len - trailing_ws;
418
419
                    /* restart indentation */
420
0
                    current_indent = 0;
421
0
                }
422
423
                /* check and store character */
424
0
                LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
425
426
                /* reset context indentation counter for possible string after this one */
427
0
                ctx->indent = 0;
428
0
                trailing_ws = 0;
429
0
                break;
430
0
            default:
431
                /* first non-whitespace character, stop eating indentation */
432
0
                current_indent = block_indent;
433
434
                /* check and store character */
435
0
                LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
436
0
                trailing_ws = 0;
437
0
                break;
438
0
            }
439
0
            break;
440
0
        case STRING_DOUBLE_QUOTED_ESCAPED:
441
            /* string encoded characters */
442
0
            c = ctx->in->current;
443
0
            switch (ctx->in->current[0]) {
444
0
            case 'n':
445
0
                ctx->in->current = "\n";
446
                /* fix false newline count in buf_store_char() */
447
0
                ctx->in->line--;
448
0
                break;
449
0
            case 't':
450
0
                ctx->in->current = "\t";
451
0
                break;
452
0
            case '\"':
453
0
            case '\\':
454
                /* ok as is */
455
0
                break;
456
0
            default:
457
0
                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.",
458
0
                        ctx->in->current[0]);
459
0
                return LY_EVALID;
460
0
            }
461
462
            /* check and store character */
463
0
            LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
464
465
0
            string = STRING_DOUBLE_QUOTED;
466
0
            ctx->in->current = c + 1;
467
0
            break;
468
0
        case STRING_PAUSED_NEXTSTRING:
469
0
            switch (ctx->in->current[0]) {
470
0
            case '+':
471
                /* string continues */
472
0
                string = STRING_PAUSED_CONTINUE;
473
0
                need_buf = 1;
474
0
                break;
475
0
            case '\r':
476
0
                if (ctx->in->current[1] != '\n') {
477
0
                    LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
478
0
                    return LY_EVALID;
479
0
                }
480
0
                MOVE_INPUT(ctx, 1);
481
            /* fallthrough */
482
0
            case '\n':
483
0
                LY_IN_NEW_LINE(ctx->in);
484
            /* fall through */
485
0
            case ' ':
486
0
            case '\t':
487
                /* just skip */
488
0
                break;
489
0
            default:
490
                /* string is finished */
491
0
                goto string_end;
492
0
            }
493
0
            MOVE_INPUT(ctx, 1);
494
0
            break;
495
0
        case STRING_PAUSED_CONTINUE:
496
0
            switch (ctx->in->current[0]) {
497
0
            case '\r':
498
0
                if (ctx->in->current[1] != '\n') {
499
0
                    LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
500
0
                    return LY_EVALID;
501
0
                }
502
0
                MOVE_INPUT(ctx, 1);
503
            /* fallthrough */
504
0
            case '\n':
505
0
                LY_IN_NEW_LINE(ctx->in);
506
            /* fall through */
507
0
            case ' ':
508
0
            case '\t':
509
                /* skip */
510
0
                break;
511
0
            case '\'':
512
0
                string = STRING_SINGLE_QUOTED;
513
0
                break;
514
0
            case '\"':
515
0
                string = STRING_DOUBLE_QUOTED;
516
0
                break;
517
0
            default:
518
                /* it must be quoted again */
519
0
                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Both string parts divided by '+' must be quoted.");
520
0
                return LY_EVALID;
521
0
            }
522
0
            MOVE_INPUT(ctx, 1);
523
0
            break;
524
0
        default:
525
0
            return LY_EINT;
526
0
        }
527
0
    }
528
529
0
string_end:
530
0
    if ((arg <= Y_PREF_IDENTIF_ARG) && !(*word_len)) {
531
        /* empty identifier */
532
0
        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Statement argument is required.");
533
0
        return LY_EVALID;
534
0
    }
535
0
    return LY_SUCCESS;
536
537
0
#undef STRING_ENDED
538
0
#undef STRING_SINGLE_QUOTED
539
0
#undef STRING_DOUBLE_QUOTED
540
0
#undef STRING_DOUBLE_QUOTED_ESCAPED
541
0
#undef STRING_PAUSED_NEXTSTRING
542
0
#undef STRING_PAUSED_CONTINUE
543
0
}
544
545
/**
546
 * @brief Get another YANG string from the raw data.
547
 *
548
 * @param[in] ctx yang parser context for logging.
549
 * @param[in] arg Type of YANG keyword argument expected.
550
 * @param[out] flags optional output argument to get flag of the argument's quoting (LYS_*QUOTED - see
551
 * [schema node flags](@ref snodeflags))
552
 * @param[out] word_p Pointer to the read string. Can return NULL if \p arg is #Y_MAYBE_STR_ARG.
553
 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read string. If not needed,
554
 * set to NULL. Otherwise equal to \p word_p.
555
 * @param[out] word_len Length of the read string.
556
 * @return LY_ERR values.
557
 */
558
LY_ERR
559
get_argument(struct lys_yang_parser_ctx *ctx, enum yang_arg arg, uint16_t *flags, char **word_p,
560
        char **word_b, size_t *word_len)
561
0
{
562
0
    LY_ERR ret;
563
0
    size_t buf_len = 0;
564
0
    uint8_t prefix = 0;
565
566
    /* word buffer - dynamically allocated */
567
0
    *word_b = NULL;
568
569
    /* word pointer - just a pointer to data */
570
0
    *word_p = NULL;
571
572
0
    *word_len = 0;
573
0
    while (ctx->in->current[0]) {
574
0
        switch (ctx->in->current[0]) {
575
0
        case '\'':
576
0
        case '\"':
577
0
            if (*word_len) {
578
                /* invalid - quotes cannot be in unquoted string and only optsep, ; or { can follow it */
579
0
                LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, ctx->in->current,
580
0
                        "unquoted string character, optsep, semicolon or opening brace");
581
0
                ret = LY_EVALID;
582
0
                goto error;
583
0
            }
584
0
            if (flags) {
585
0
                (*flags) |= ctx->in->current[0] == '\'' ? LYS_SINGLEQUOTED : LYS_DOUBLEQUOTED;
586
0
            }
587
0
            LY_CHECK_GOTO(ret = read_qstring(ctx, arg, word_p, word_b, word_len, &buf_len), error);
588
0
            goto str_end;
589
0
        case '/':
590
0
            if (ctx->in->current[1] == '/') {
591
                /* one-line comment */
592
0
                MOVE_INPUT(ctx, 2);
593
0
                LY_CHECK_GOTO(ret = skip_comment(ctx, 1), error);
594
0
            } else if (ctx->in->current[1] == '*') {
595
                /* block comment */
596
0
                MOVE_INPUT(ctx, 2);
597
0
                LY_CHECK_GOTO(ret = skip_comment(ctx, 2), error);
598
0
            } else {
599
                /* not a comment after all */
600
0
                LY_CHECK_GOTO(ret = buf_store_char(ctx, arg, word_p, word_len, word_b, &buf_len, 0, &prefix), error);
601
0
            }
602
0
            break;
603
0
        case ' ':
604
0
            if (*word_len) {
605
                /* word is finished */
606
0
                goto str_end;
607
0
            }
608
0
            MOVE_INPUT(ctx, 1);
609
0
            break;
610
0
        case '\t':
611
0
            if (*word_len) {
612
                /* word is finished */
613
0
                goto str_end;
614
0
            }
615
            /* tabs count for 8 spaces */
616
0
            ctx->indent += Y_TAB_SPACES;
617
618
0
            ++ctx->in->current;
619
0
            break;
620
0
        case '\r':
621
0
            if (ctx->in->current[1] != '\n') {
622
0
                LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
623
0
                ret = LY_EVALID;
624
0
                goto error;
625
0
            }
626
0
            MOVE_INPUT(ctx, 1);
627
        /* fallthrough */
628
0
        case '\n':
629
0
            if (*word_len) {
630
                /* word is finished */
631
0
                goto str_end;
632
0
            }
633
0
            LY_IN_NEW_LINE(ctx->in);
634
0
            MOVE_INPUT(ctx, 1);
635
636
            /* reset indent */
637
0
            ctx->indent = 0;
638
0
            break;
639
0
        case ';':
640
0
        case '{':
641
0
            if (*word_len || (arg == Y_MAYBE_STR_ARG)) {
642
                /* word is finished */
643
0
                goto str_end;
644
0
            }
645
646
0
            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, ctx->in->current, "an argument");
647
0
            ret = LY_EVALID;
648
0
            goto error;
649
0
        case '}':
650
            /* invalid - braces cannot be in unquoted string (opening braces terminates the string and can follow it) */
651
0
            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, ctx->in->current,
652
0
                    "unquoted string character, optsep, semicolon or opening brace");
653
0
            ret = LY_EVALID;
654
0
            goto error;
655
0
        default:
656
0
            LY_CHECK_GOTO(ret = buf_store_char(ctx, arg, word_p, word_len, word_b, &buf_len, 0, &prefix), error);
657
0
            break;
658
0
        }
659
0
    }
660
661
    /* unexpected end of loop */
662
0
    LOGVAL_PARSER(ctx, LY_VCODE_EOF);
663
0
    ret = LY_EVALID;
664
0
    goto error;
665
666
0
str_end:
667
    /* terminating NULL byte for buf */
668
0
    if (*word_b) {
669
0
        (*word_b) = ly_realloc(*word_b, (*word_len) + 1);
670
0
        LY_CHECK_ERR_RET(!(*word_b), LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
671
0
        (*word_b)[*word_len] = '\0';
672
0
        *word_p = *word_b;
673
0
    }
674
675
0
    return LY_SUCCESS;
676
677
0
error:
678
0
    free(*word_b);
679
0
    *word_b = NULL;
680
0
    return ret;
681
0
}
682
683
/**
684
 * @brief Get another YANG keyword from the raw data.
685
 *
686
 * @param[in] ctx yang parser context for logging.
687
 * @param[out] kw YANG keyword read.
688
 * @param[out] word_p Pointer to the keyword in the data. Useful for extension instances.
689
 * @param[out] word_len Length of the keyword in the data. Useful for extension instances.
690
 *
691
 * @return LY_ERR values.
692
 */
693
LY_ERR
694
get_keyword(struct lys_yang_parser_ctx *ctx, enum ly_stmt *kw, char **word_p, size_t *word_len)
695
0
{
696
0
    uint8_t prefix;
697
0
    const char *word_start;
698
0
    size_t len;
699
700
0
    if (word_p) {
701
0
        *word_p = NULL;
702
0
        *word_len = 0;
703
0
    }
704
705
    /* first skip "optsep", comments */
706
0
    while (ctx->in->current[0]) {
707
0
        switch (ctx->in->current[0]) {
708
0
        case '/':
709
0
            if (ctx->in->current[1] == '/') {
710
                /* one-line comment */
711
0
                MOVE_INPUT(ctx, 2);
712
0
                LY_CHECK_RET(skip_comment(ctx, 1));
713
0
            } else if (ctx->in->current[1] == '*') {
714
                /* block comment */
715
0
                MOVE_INPUT(ctx, 2);
716
0
                LY_CHECK_RET(skip_comment(ctx, 2));
717
0
            } else {
718
                /* error - not a comment after all, keyword cannot start with slash */
719
0
                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '/'.");
720
0
                return LY_EVALID;
721
0
            }
722
0
            continue;
723
0
        case '\n':
724
            /* skip whitespaces (optsep) */
725
0
            LY_IN_NEW_LINE(ctx->in);
726
0
            ctx->indent = 0;
727
0
            break;
728
0
        case ' ':
729
            /* skip whitespaces (optsep) */
730
0
            ++ctx->indent;
731
0
            break;
732
0
        case '\t':
733
            /* skip whitespaces (optsep) */
734
0
            ctx->indent += Y_TAB_SPACES;
735
0
            break;
736
0
        case '\r':
737
            /* possible CRLF endline */
738
0
            if (ctx->in->current[1] == '\n') {
739
0
                break;
740
0
            }
741
        /* fallthrough */
742
0
        default:
743
            /* either a keyword start or an invalid character */
744
0
            goto keyword_start;
745
0
        }
746
747
0
        ly_in_skip(ctx->in, 1);
748
0
    }
749
750
0
keyword_start:
751
0
    word_start = ctx->in->current;
752
0
    *kw = lysp_match_kw(ctx->in, &ctx->indent);
753
754
0
    if ((*kw == LY_STMT_SYNTAX_SEMICOLON) || (*kw == LY_STMT_SYNTAX_LEFT_BRACE) || (*kw == LY_STMT_SYNTAX_RIGHT_BRACE)) {
755
0
        goto success;
756
0
    }
757
758
0
    if (*kw != LY_STMT_NONE) {
759
        /* make sure we have the whole keyword */
760
0
        switch (ctx->in->current[0]) {
761
0
        case '\r':
762
0
            if (ctx->in->current[1] != '\n') {
763
0
                LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
764
0
                return LY_EVALID;
765
0
            }
766
0
            MOVE_INPUT(ctx, 1);
767
        /* fallthrough */
768
0
        case '\n':
769
0
        case '\t':
770
0
        case ' ':
771
            /* mandatory "sep" is just checked, not eaten so nothing in the context is updated */
772
0
            break;
773
0
        case ':':
774
            /* keyword is not actually a keyword, but prefix of an extension.
775
             * To avoid repeated check of the prefix syntax, move to the point where the colon was read
776
             * and we will be checking the keyword (extension instance) itself */
777
0
            prefix = 1;
778
0
            MOVE_INPUT(ctx, 1);
779
0
            goto extension;
780
0
        case '{':
781
            /* allowed only for input and output statements which can be without arguments */
782
0
            if ((*kw == LY_STMT_INPUT) || (*kw == LY_STMT_OUTPUT)) {
783
0
                break;
784
0
            }
785
        /* fall through */
786
0
        default:
787
0
            MOVE_INPUT(ctx, 1);
788
0
            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(ctx->in->current - word_start), word_start,
789
0
                    "a keyword followed by a separator");
790
0
            return LY_EVALID;
791
0
        }
792
0
    } else {
793
        /* still can be an extension */
794
0
        prefix = 0;
795
796
0
extension:
797
0
        while (ctx->in->current[0] && (ctx->in->current[0] != ' ') && (ctx->in->current[0] != '\t') &&
798
0
                (ctx->in->current[0] != '\n') && (ctx->in->current[0] != '\r') && (ctx->in->current[0] != '{') &&
799
0
                (ctx->in->current[0] != ';')) {
800
0
            uint32_t c = 0;
801
802
0
            LY_CHECK_ERR_RET(ly_getutf8(&ctx->in->current, &c, &len),
803
0
                    LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[-len]), LY_EVALID);
804
0
            ++ctx->indent;
805
            /* check character validity */
806
0
            LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c,
807
0
                    ctx->in->current - len == word_start ? 1 : 0, &prefix));
808
0
        }
809
0
        if (!ctx->in->current[0]) {
810
0
            LOGVAL_PARSER(ctx, LY_VCODE_EOF);
811
0
            return LY_EVALID;
812
0
        }
813
814
        /* prefix is mandatory for extension instances */
815
0
        if (prefix != 2) {
816
0
            LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(ctx->in->current - word_start), word_start, "a keyword");
817
0
            return LY_EVALID;
818
0
        }
819
820
0
        *kw = LY_STMT_EXTENSION_INSTANCE;
821
0
    }
822
823
0
success:
824
0
    if (word_p) {
825
0
        *word_p = (char *)word_start;
826
0
        *word_len = ctx->in->current - word_start;
827
0
    }
828
829
0
    return LY_SUCCESS;
830
0
}
831
832
/**
833
 * @brief Parse extension instance substatements.
834
 *
835
 * @param[in] ctx yang parser context for logging.
836
 * @param[in] kw Statement keyword value matching @p word value.
837
 * @param[in] word Extension instance substatement name (keyword).
838
 * @param[in] word_len Extension instance substatement name length.
839
 * @param[in,out] child Children of this extension instance to add to.
840
 *
841
 * @return LY_ERR values.
842
 */
843
static LY_ERR
844
parse_ext_substmt(struct lys_yang_parser_ctx *ctx, enum ly_stmt kw, char *word, size_t word_len,
845
        struct lysp_stmt **child)
846
0
{
847
0
    char *buf;
848
0
    LY_ERR ret = LY_SUCCESS;
849
0
    enum ly_stmt child_kw;
850
0
    struct lysp_stmt *stmt, *par_child;
851
852
0
    stmt = calloc(1, sizeof *stmt);
853
0
    LY_CHECK_ERR_RET(!stmt, LOGMEM(NULL), LY_EMEM);
854
855
    /* insert into parent statements */
856
0
    if (!*child) {
857
0
        *child = stmt;
858
0
    } else {
859
0
        for (par_child = *child; par_child->next; par_child = par_child->next) {}
860
0
        par_child->next = stmt;
861
0
    }
862
863
    /* statement */
864
0
    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), word, word_len, &stmt->stmt));
865
866
    /* get optional argument */
867
0
    LY_CHECK_RET(get_argument(ctx, Y_MAYBE_STR_ARG, &stmt->flags, &word, &buf, &word_len));
868
0
    if (word) {
869
0
        INSERT_WORD_RET(ctx, buf, stmt->arg, word, word_len);
870
0
    }
871
872
0
    stmt->format = LY_VALUE_SCHEMA;
873
0
    stmt->prefix_data = ctx->parsed_mod;
874
0
    stmt->kw = kw;
875
876
0
    YANG_READ_SUBSTMT_FOR(ctx, child_kw, word, word_len, ret, return LY_SUCCESS, return ret) {
877
0
        LY_CHECK_RET(parse_ext_substmt(ctx, child_kw, word, word_len, &stmt->child));
878
0
    }
879
0
    return ret;
880
0
}
881
882
/**
883
 * @brief Parse extension instance.
884
 *
885
 * @param[in] ctx yang parser context for logging.
886
 * @param[in] ext_name Extension instance substatement name (keyword).
887
 * @param[in] ext_name_len Extension instance substatement name length.
888
 * @param[in] insubstmt The statement this extension instance is a substatement of.
889
 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
890
 * @param[in,out] exts Extension instances to add to.
891
 *
892
 * @return LY_ERR values.
893
 */
894
static LY_ERR
895
parse_ext(struct lys_yang_parser_ctx *ctx, const char *ext_name, size_t ext_name_len, enum ly_stmt insubstmt,
896
        LY_ARRAY_COUNT_TYPE insubstmt_index, struct lysp_ext_instance **exts)
897
0
{
898
0
    LY_ERR ret = LY_SUCCESS;
899
0
    char *buf, *word;
900
0
    size_t word_len;
901
0
    struct lysp_ext_instance *e;
902
0
    enum ly_stmt kw;
903
904
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *exts, e, LY_EMEM);
905
906
0
    if (!ly_strnchr(ext_name, ':', ext_name_len)) {
907
0
        LOGVAL_PARSER(ctx, LYVE_SYNTAX, "Extension instance \"%*.s\" without the mandatory prefix.", ext_name_len, ext_name);
908
0
        return LY_EVALID;
909
0
    }
910
911
    /* store name */
912
0
    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), ext_name, ext_name_len, &e->name));
913
914
    /* get optional argument */
915
0
    LY_CHECK_RET(get_argument(ctx, Y_MAYBE_STR_ARG, NULL, &word, &buf, &word_len));
916
0
    if (word) {
917
0
        INSERT_WORD_RET(ctx, buf, e->argument, word, word_len);
918
0
    }
919
920
    /* store the rest of information */
921
0
    e->format = LY_VALUE_SCHEMA;
922
0
    e->parsed = NULL;
923
0
    e->prefix_data = ctx->parsed_mod;
924
0
    e->parent_stmt = insubstmt;
925
0
    e->parent_stmt_index = insubstmt_index;
926
927
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
928
0
        LY_CHECK_RET(parse_ext_substmt(ctx, kw, word, word_len, &e->child));
929
0
    }
930
0
    return ret;
931
0
}
932
933
/**
934
 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
935
 * description, etc...
936
 *
937
 * @param[in] ctx yang parser context for logging.
938
 * @param[in] substmt Type of this substatement.
939
 * @param[in] substmt_index Index of this substatement.
940
 * @param[in,out] value Place to store the parsed value.
941
 * @param[in] arg Type of the YANG keyword argument (of the value).
942
 * @param[in,out] exts Extension instances to add to.
943
 *
944
 * @return LY_ERR values.
945
 */
946
static LY_ERR
947
parse_text_field(struct lys_yang_parser_ctx *ctx, enum ly_stmt substmt, uint32_t substmt_index,
948
        const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
949
0
{
950
0
    LY_ERR ret = LY_SUCCESS;
951
0
    char *buf, *word;
952
0
    size_t word_len;
953
0
    enum ly_stmt kw;
954
955
0
    if (*value) {
956
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(substmt));
957
0
        return LY_EVALID;
958
0
    }
959
960
    /* get value */
961
0
    LY_CHECK_RET(get_argument(ctx, arg, NULL, &word, &buf, &word_len));
962
963
    /* store value and spend buf if allocated */
964
0
    INSERT_WORD_RET(ctx, buf, *value, word, word_len);
965
966
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
967
0
        switch (kw) {
968
0
        case LY_STMT_EXTENSION_INSTANCE:
969
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, substmt_index, exts));
970
0
            break;
971
0
        default:
972
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
973
0
            return LY_EVALID;
974
0
        }
975
0
    }
976
0
    return ret;
977
0
}
978
979
/**
980
 * @brief Parse the yang-version statement.
981
 *
982
 * @param[in] ctx yang parser context for logging.
983
 * @param[out] version Storage for the parsed information.
984
 * @param[in,out] exts Extension instances to add to.
985
 *
986
 * @return LY_ERR values.
987
 */
988
static LY_ERR
989
parse_yangversion(struct lys_yang_parser_ctx *ctx, uint8_t *version, struct lysp_ext_instance **exts)
990
0
{
991
0
    LY_ERR ret = LY_SUCCESS;
992
0
    char *buf, *word;
993
0
    size_t word_len;
994
0
    enum ly_stmt kw;
995
996
0
    if (*version) {
997
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yang-version");
998
0
        return LY_EVALID;
999
0
    }
1000
1001
    /* get value */
1002
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1003
1004
0
    if ((word_len == 1) && !strncmp(word, "1", word_len)) {
1005
0
        *version = LYS_VERSION_1_0;
1006
0
    } else if ((word_len == ly_strlen_const("1.1")) && !strncmp(word, "1.1", word_len)) {
1007
0
        *version = LYS_VERSION_1_1;
1008
0
    } else {
1009
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
1010
0
        free(buf);
1011
0
        return LY_EVALID;
1012
0
    }
1013
0
    free(buf);
1014
1015
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1016
0
        switch (kw) {
1017
0
        case LY_STMT_EXTENSION_INSTANCE:
1018
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YANG_VERSION, 0, exts));
1019
0
            break;
1020
0
        default:
1021
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
1022
0
            return LY_EVALID;
1023
0
        }
1024
0
    }
1025
0
    return ret;
1026
0
}
1027
1028
/**
1029
 * @brief Parse the belongs-to statement.
1030
 *
1031
 * @param[in] ctx yang parser context for logging.
1032
 * @param[in,out] prefix Place to store the parsed belongs-to prefix value.
1033
 * @param[in,out] exts Extension instances to add to.
1034
 *
1035
 * @return LY_ERR values.
1036
 */
1037
static LY_ERR
1038
parse_belongsto(struct lys_yang_parser_ctx *ctx, const char **prefix, struct lysp_ext_instance **exts)
1039
0
{
1040
0
    LY_ERR ret = LY_SUCCESS;
1041
0
    char *buf, *word;
1042
0
    size_t word_len;
1043
0
    enum ly_stmt kw;
1044
1045
0
    if (*prefix) {
1046
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "belongs-to");
1047
0
        return LY_EVALID;
1048
0
    }
1049
1050
    /* get value, it must match the main module */
1051
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
1052
0
    if (ly_strncmp(ctx->parsed_mod->mod->name, word, word_len)) {
1053
0
        LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Submodule \"belongs-to\" value \"%.*s\" does not match its module name \"%s\".",
1054
0
                (int)word_len, word, ctx->parsed_mod->mod->name);
1055
0
        free(buf);
1056
0
        return LY_EVALID;
1057
0
    }
1058
0
    free(buf);
1059
1060
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
1061
0
        switch (kw) {
1062
0
        case LY_STMT_PREFIX:
1063
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts));
1064
0
            break;
1065
0
        case LY_STMT_EXTENSION_INSTANCE:
1066
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_BELONGS_TO, 0, exts));
1067
0
            break;
1068
0
        default:
1069
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
1070
0
            return LY_EVALID;
1071
0
        }
1072
0
    }
1073
0
    LY_CHECK_RET(ret);
1074
0
checks:
1075
    /* mandatory substatements */
1076
0
    if (!*prefix) {
1077
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
1078
0
        return LY_EVALID;
1079
0
    }
1080
0
    return ret;
1081
0
}
1082
1083
/**
1084
 * @brief Parse the revision-date statement.
1085
 *
1086
 * @param[in] ctx yang parser context for logging.
1087
 * @param[in,out] rev Array to store the parsed value in.
1088
 * @param[in,out] exts Extension instances to add to.
1089
 *
1090
 * @return LY_ERR values.
1091
 */
1092
static LY_ERR
1093
parse_revisiondate(struct lys_yang_parser_ctx *ctx, char *rev, struct lysp_ext_instance **exts)
1094
0
{
1095
0
    LY_ERR ret = LY_SUCCESS;
1096
0
    char *buf, *word;
1097
0
    size_t word_len;
1098
0
    enum ly_stmt kw;
1099
1100
0
    if (rev[0]) {
1101
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "revision-date");
1102
0
        return LY_EVALID;
1103
0
    }
1104
1105
    /* get value */
1106
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1107
1108
    /* check value */
1109
0
    if (lysp_check_date((struct lys_parser_ctx *)ctx, word, word_len, "revision-date")) {
1110
0
        free(buf);
1111
0
        return LY_EVALID;
1112
0
    }
1113
1114
    /* store value and spend buf if allocated */
1115
0
    strncpy(rev, word, word_len);
1116
0
    free(buf);
1117
1118
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1119
0
        switch (kw) {
1120
0
        case LY_STMT_EXTENSION_INSTANCE:
1121
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REVISION_DATE, 0, exts));
1122
0
            break;
1123
0
        default:
1124
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
1125
0
            return LY_EVALID;
1126
0
        }
1127
0
    }
1128
0
    return ret;
1129
0
}
1130
1131
/**
1132
 * @brief Parse the include statement.
1133
 *
1134
 * @param[in] ctx yang parser context for logging.
1135
 * @param[in] module_name Name of the module to check name collisions.
1136
 * @param[in,out] includes Parsed includes to add to.
1137
 *
1138
 * @return LY_ERR values.
1139
 */
1140
static LY_ERR
1141
parse_include(struct lys_yang_parser_ctx *ctx, const char *module_name, struct lysp_include **includes)
1142
0
{
1143
0
    LY_ERR ret = LY_SUCCESS;
1144
0
    char *buf, *word;
1145
0
    size_t word_len;
1146
0
    enum ly_stmt kw;
1147
0
    struct lysp_include *inc;
1148
1149
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *includes, inc, LY_EMEM);
1150
1151
    /* get value */
1152
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
1153
1154
0
    INSERT_WORD_RET(ctx, buf, inc->name, word, word_len);
1155
1156
    /* submodules share the namespace with the module names, so there must not be
1157
     * a module of the same name in the context, no need for revision matching */
1158
0
    if (!strcmp(module_name, inc->name) || ly_ctx_get_module_latest(PARSER_CTX(ctx), inc->name)) {
1159
0
        LOGVAL_PARSER(ctx, LY_VCODE_NAME2_COL, "module", "submodule", inc->name);
1160
0
        return LY_EVALID;
1161
0
    }
1162
1163
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1164
0
        switch (kw) {
1165
0
        case LY_STMT_DESCRIPTION:
1166
0
            PARSER_CHECK_STMTVER2_RET(ctx, "description", "include");
1167
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts));
1168
0
            break;
1169
0
        case LY_STMT_REFERENCE:
1170
0
            PARSER_CHECK_STMTVER2_RET(ctx, "reference", "include");
1171
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts));
1172
0
            break;
1173
0
        case LY_STMT_REVISION_DATE:
1174
0
            LY_CHECK_RET(parse_revisiondate(ctx, inc->rev, &inc->exts));
1175
0
            break;
1176
0
        case LY_STMT_EXTENSION_INSTANCE:
1177
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_INCLUDE, 0, &inc->exts));
1178
0
            break;
1179
0
        default:
1180
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
1181
0
            return LY_EVALID;
1182
0
        }
1183
0
    }
1184
0
    return ret;
1185
0
}
1186
1187
/**
1188
 * @brief Parse the import statement.
1189
 *
1190
 * @param[in] ctx yang parser context for logging.
1191
 * @param[in] module_prefix Prefix of the module to check prefix collisions.
1192
 * @param[in,out] imports Parsed imports to add to.
1193
 *
1194
 * @return LY_ERR values.
1195
 */
1196
static LY_ERR
1197
parse_import(struct lys_yang_parser_ctx *ctx, const char *module_prefix, struct lysp_import **imports)
1198
0
{
1199
0
    LY_ERR ret = LY_SUCCESS;
1200
0
    char *buf, *word;
1201
0
    size_t word_len;
1202
0
    enum ly_stmt kw;
1203
0
    struct lysp_import *imp;
1204
1205
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *imports, imp, LY_EVALID);
1206
1207
    /* get value */
1208
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
1209
0
    INSERT_WORD_RET(ctx, buf, imp->name, word, word_len);
1210
1211
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
1212
0
        switch (kw) {
1213
0
        case LY_STMT_PREFIX:
1214
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
1215
0
            LY_CHECK_RET(lysp_check_prefix((struct lys_parser_ctx *)ctx, *imports, module_prefix, &imp->prefix), LY_EVALID);
1216
0
            break;
1217
0
        case LY_STMT_DESCRIPTION:
1218
0
            PARSER_CHECK_STMTVER2_RET(ctx, "description", "import");
1219
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts));
1220
0
            break;
1221
0
        case LY_STMT_REFERENCE:
1222
0
            PARSER_CHECK_STMTVER2_RET(ctx, "reference", "import");
1223
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts));
1224
0
            break;
1225
0
        case LY_STMT_REVISION_DATE:
1226
0
            LY_CHECK_RET(parse_revisiondate(ctx, imp->rev, &imp->exts));
1227
0
            break;
1228
0
        case LY_STMT_EXTENSION_INSTANCE:
1229
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_IMPORT, 0, &imp->exts));
1230
0
            break;
1231
0
        default:
1232
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
1233
0
            return LY_EVALID;
1234
0
        }
1235
0
    }
1236
0
    LY_CHECK_RET(ret);
1237
0
checks:
1238
    /* mandatory substatements */
1239
0
    LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
1240
1241
0
    return ret;
1242
0
}
1243
1244
/**
1245
 * @brief Parse the revision statement.
1246
 *
1247
 * @param[in] ctx yang parser context for logging.
1248
 * @param[in,out] revs Parsed revisions to add to.
1249
 *
1250
 * @return LY_ERR values.
1251
 */
1252
static LY_ERR
1253
parse_revision(struct lys_yang_parser_ctx *ctx, struct lysp_revision **revs)
1254
0
{
1255
0
    LY_ERR ret = LY_SUCCESS;
1256
0
    char *buf, *word;
1257
0
    size_t word_len;
1258
0
    enum ly_stmt kw;
1259
0
    struct lysp_revision *rev;
1260
1261
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *revs, rev, LY_EMEM);
1262
1263
    /* get value */
1264
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1265
1266
    /* check value */
1267
0
    if (lysp_check_date((struct lys_parser_ctx *)ctx, word, word_len, "revision")) {
1268
0
        free(buf);
1269
0
        return LY_EVALID;
1270
0
    }
1271
1272
0
    strncpy(rev->date, word, word_len);
1273
0
    free(buf);
1274
1275
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1276
0
        switch (kw) {
1277
0
        case LY_STMT_DESCRIPTION:
1278
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts));
1279
0
            break;
1280
0
        case LY_STMT_REFERENCE:
1281
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts));
1282
0
            break;
1283
0
        case LY_STMT_EXTENSION_INSTANCE:
1284
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REVISION, 0, &rev->exts));
1285
0
            break;
1286
0
        default:
1287
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
1288
0
            return LY_EVALID;
1289
0
        }
1290
0
    }
1291
0
    return ret;
1292
0
}
1293
1294
/**
1295
 * @brief Parse a generic text field that can have more instances such as base.
1296
 *
1297
 * @param[in] ctx yang parser context for logging.
1298
 * @param[in] substmt Type of this substatement.
1299
 * @param[in,out] texts Parsed values to add to.
1300
 * @param[in] arg Type of the expected argument.
1301
 * @param[in,out] exts Extension instances to add to.
1302
 *
1303
 * @return LY_ERR values.
1304
 */
1305
static LY_ERR
1306
parse_text_fields(struct lys_yang_parser_ctx *ctx, enum ly_stmt substmt, const char ***texts, enum yang_arg arg,
1307
        struct lysp_ext_instance **exts)
1308
0
{
1309
0
    LY_ERR ret = LY_SUCCESS;
1310
0
    char *buf, *word;
1311
0
    const char **item;
1312
0
    size_t word_len;
1313
0
    enum ly_stmt kw;
1314
1315
    /* allocate new pointer */
1316
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
1317
1318
    /* get value */
1319
0
    LY_CHECK_RET(get_argument(ctx, arg, NULL, &word, &buf, &word_len));
1320
1321
0
    INSERT_WORD_RET(ctx, buf, *item, word, word_len);
1322
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1323
0
        switch (kw) {
1324
0
        case LY_STMT_EXTENSION_INSTANCE:
1325
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
1326
0
            break;
1327
0
        default:
1328
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
1329
0
            return LY_EVALID;
1330
0
        }
1331
0
    }
1332
0
    return ret;
1333
0
}
1334
1335
/**
1336
 * @brief Parse a generic text field that can have more instances such as base.
1337
 *
1338
 * @param[in] ctx yang parser context for logging.
1339
 * @param[in] substmt Type of this substatement.
1340
 * @param[in,out] qnames Parsed qnames to add to.
1341
 * @param[in] arg Type of the expected argument.
1342
 * @param[in,out] exts Extension instances to add to.
1343
 *
1344
 * @return LY_ERR values.
1345
 */
1346
static LY_ERR
1347
parse_qnames(struct lys_yang_parser_ctx *ctx, enum ly_stmt substmt, struct lysp_qname **qnames,
1348
        enum yang_arg arg, struct lysp_ext_instance **exts)
1349
0
{
1350
0
    LY_ERR ret = LY_SUCCESS;
1351
0
    char *buf, *word;
1352
0
    struct lysp_qname *item;
1353
0
    size_t word_len;
1354
0
    enum ly_stmt kw;
1355
1356
    /* allocate new pointer */
1357
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *qnames, item, LY_EMEM);
1358
1359
    /* get value */
1360
0
    LY_CHECK_RET(get_argument(ctx, arg, NULL, &word, &buf, &word_len));
1361
1362
0
    INSERT_WORD_RET(ctx, buf, item->str, word, word_len);
1363
0
    item->mod = ctx->parsed_mod;
1364
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1365
0
        switch (kw) {
1366
0
        case LY_STMT_EXTENSION_INSTANCE:
1367
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*qnames) - 1, exts));
1368
0
            break;
1369
0
        default:
1370
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
1371
0
            return LY_EVALID;
1372
0
        }
1373
0
    }
1374
0
    return ret;
1375
0
}
1376
1377
/**
1378
 * @brief Parse the config statement.
1379
 *
1380
 * @param[in] ctx yang parser context for logging.
1381
 * @param[in,out] flags Flags to add to.
1382
 * @param[in,out] exts Extension instances to add to.
1383
 *
1384
 * @return LY_ERR values.
1385
 */
1386
static LY_ERR
1387
parse_config(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
1388
0
{
1389
0
    LY_ERR ret = LY_SUCCESS;
1390
0
    char *buf, *word;
1391
0
    size_t word_len;
1392
0
    enum ly_stmt kw;
1393
1394
0
    if (*flags & LYS_CONFIG_MASK) {
1395
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "config");
1396
0
        return LY_EVALID;
1397
0
    }
1398
1399
    /* get value */
1400
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1401
1402
0
    if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
1403
0
        *flags |= LYS_CONFIG_W;
1404
0
    } else if ((word_len == ly_strlen_const("false")) && !strncmp(word, "false", word_len)) {
1405
0
        *flags |= LYS_CONFIG_R;
1406
0
    } else {
1407
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "config");
1408
0
        free(buf);
1409
0
        return LY_EVALID;
1410
0
    }
1411
0
    free(buf);
1412
1413
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1414
0
        switch (kw) {
1415
0
        case LY_STMT_EXTENSION_INSTANCE:
1416
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CONFIG, 0, exts));
1417
0
            break;
1418
0
        default:
1419
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
1420
0
            return LY_EVALID;
1421
0
        }
1422
0
    }
1423
0
    return ret;
1424
0
}
1425
1426
/**
1427
 * @brief Parse the mandatory statement.
1428
 *
1429
 * @param[in] ctx yang parser context for logging.
1430
 * @param[in,out] flags Flags to add to.
1431
 * @param[in,out] exts Extension instances to add to.
1432
 *
1433
 * @return LY_ERR values.
1434
 */
1435
static LY_ERR
1436
parse_mandatory(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
1437
0
{
1438
0
    LY_ERR ret = LY_SUCCESS;
1439
0
    char *buf, *word;
1440
0
    size_t word_len;
1441
0
    enum ly_stmt kw;
1442
1443
0
    if (*flags & LYS_MAND_MASK) {
1444
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "mandatory");
1445
0
        return LY_EVALID;
1446
0
    }
1447
1448
    /* get value */
1449
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1450
1451
0
    if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
1452
0
        *flags |= LYS_MAND_TRUE;
1453
0
    } else if ((word_len == ly_strlen_const("false")) && !strncmp(word, "false", word_len)) {
1454
0
        *flags |= LYS_MAND_FALSE;
1455
0
    } else {
1456
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "mandatory");
1457
0
        free(buf);
1458
0
        return LY_EVALID;
1459
0
    }
1460
0
    free(buf);
1461
1462
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1463
0
        switch (kw) {
1464
0
        case LY_STMT_EXTENSION_INSTANCE:
1465
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MANDATORY, 0, exts));
1466
0
            break;
1467
0
        default:
1468
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
1469
0
            return LY_EVALID;
1470
0
        }
1471
0
    }
1472
0
    return ret;
1473
0
}
1474
1475
/**
1476
 * @brief Parse a restriction such as range or length.
1477
 *
1478
 * @param[in] ctx yang parser context for logging.
1479
 * @param[in] restr_kw Type of this particular restriction.
1480
 * @param[in,out] exts Extension instances to add to.
1481
 *
1482
 * @return LY_ERR values.
1483
 */
1484
static LY_ERR
1485
parse_restr(struct lys_yang_parser_ctx *ctx, enum ly_stmt restr_kw, struct lysp_restr *restr)
1486
0
{
1487
0
    LY_ERR ret = LY_SUCCESS;
1488
0
    char *buf, *word;
1489
0
    size_t word_len;
1490
0
    enum ly_stmt kw;
1491
1492
    /* get value */
1493
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1494
1495
0
    CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
1496
0
    INSERT_WORD_RET(ctx, buf, restr->arg.str, word, word_len);
1497
0
    restr->arg.mod = ctx->parsed_mod;
1498
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1499
0
        switch (kw) {
1500
0
        case LY_STMT_DESCRIPTION:
1501
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
1502
0
            break;
1503
0
        case LY_STMT_REFERENCE:
1504
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
1505
0
            break;
1506
0
        case LY_STMT_ERROR_APP_TAG:
1507
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
1508
0
            break;
1509
0
        case LY_STMT_ERROR_MESSAGE:
1510
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
1511
0
            break;
1512
0
        case LY_STMT_EXTENSION_INSTANCE:
1513
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, restr_kw, 0, &restr->exts));
1514
0
            break;
1515
0
        default:
1516
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
1517
0
            return LY_EVALID;
1518
0
        }
1519
0
    }
1520
0
    return ret;
1521
0
}
1522
1523
/**
1524
 * @brief Parse a restriction that can have more instances such as must.
1525
 *
1526
 * @param[in] ctx yang parser context for logging.
1527
 * @param[in] restr_kw Type of this particular restriction.
1528
 * @param[in,out] restrs Restrictions to add to.
1529
 *
1530
 * @return LY_ERR values.
1531
 */
1532
static LY_ERR
1533
parse_restrs(struct lys_yang_parser_ctx *ctx, enum ly_stmt restr_kw, struct lysp_restr **restrs)
1534
0
{
1535
0
    struct lysp_restr *restr;
1536
1537
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
1538
0
    return parse_restr(ctx, restr_kw, restr);
1539
0
}
1540
1541
/**
1542
 * @brief Parse the status statement.
1543
 *
1544
 * @param[in] ctx yang parser context for logging.
1545
 * @param[in,out] flags Flags to add to.
1546
 * @param[in,out] exts Extension instances to add to.
1547
 *
1548
 * @return LY_ERR values.
1549
 */
1550
static LY_ERR
1551
parse_status(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
1552
0
{
1553
0
    LY_ERR ret = LY_SUCCESS;
1554
0
    char *buf, *word;
1555
0
    size_t word_len;
1556
0
    enum ly_stmt kw;
1557
1558
0
    if (*flags & LYS_STATUS_MASK) {
1559
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
1560
0
        return LY_EVALID;
1561
0
    }
1562
1563
    /* get value */
1564
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1565
1566
0
    if ((word_len == ly_strlen_const("current")) && !strncmp(word, "current", word_len)) {
1567
0
        *flags |= LYS_STATUS_CURR;
1568
0
    } else if ((word_len == ly_strlen_const("deprecated")) && !strncmp(word, "deprecated", word_len)) {
1569
0
        *flags |= LYS_STATUS_DEPRC;
1570
0
    } else if ((word_len == ly_strlen_const("obsolete")) && !strncmp(word, "obsolete", word_len)) {
1571
0
        *flags |= LYS_STATUS_OBSLT;
1572
0
    } else {
1573
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "status");
1574
0
        free(buf);
1575
0
        return LY_EVALID;
1576
0
    }
1577
0
    free(buf);
1578
1579
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1580
0
        switch (kw) {
1581
0
        case LY_STMT_EXTENSION_INSTANCE:
1582
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_STATUS, 0, exts));
1583
0
            break;
1584
0
        default:
1585
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
1586
0
            return LY_EVALID;
1587
0
        }
1588
0
    }
1589
0
    return ret;
1590
0
}
1591
1592
/**
1593
 * @brief Parse the when statement.
1594
 *
1595
 * @param[in] ctx yang parser context for logging.
1596
 * @param[in,out] when_p When pointer to parse to.
1597
 *
1598
 * @return LY_ERR values.
1599
 */
1600
LY_ERR
1601
parse_when(struct lys_yang_parser_ctx *ctx, struct lysp_when **when_p)
1602
0
{
1603
0
    LY_ERR ret = LY_SUCCESS;
1604
0
    char *buf, *word;
1605
0
    size_t word_len;
1606
0
    enum ly_stmt kw;
1607
0
    struct lysp_when *when;
1608
1609
0
    if (*when_p) {
1610
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "when");
1611
0
        return LY_EVALID;
1612
0
    }
1613
1614
0
    when = calloc(1, sizeof *when);
1615
0
    LY_CHECK_ERR_RET(!when, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
1616
0
    *when_p = when;
1617
1618
    /* get value */
1619
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1620
0
    CHECK_NONEMPTY(ctx, word_len, "when");
1621
0
    INSERT_WORD_RET(ctx, buf, when->cond, word, word_len);
1622
1623
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1624
0
        switch (kw) {
1625
0
        case LY_STMT_DESCRIPTION:
1626
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts));
1627
0
            break;
1628
0
        case LY_STMT_REFERENCE:
1629
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts));
1630
0
            break;
1631
0
        case LY_STMT_EXTENSION_INSTANCE:
1632
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_WHEN, 0, &when->exts));
1633
0
            break;
1634
0
        default:
1635
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
1636
0
            return LY_EVALID;
1637
0
        }
1638
0
    }
1639
0
    return ret;
1640
0
}
1641
1642
/**
1643
 * @brief Parse the anydata or anyxml statement.
1644
 *
1645
 * @param[in] ctx yang parser context for logging.
1646
 * @param[in] any_kw Type of this particular keyword.
1647
 * @param[in,out] siblings Siblings to add to.
1648
 *
1649
 * @return LY_ERR values.
1650
 */
1651
LY_ERR
1652
parse_any(struct lys_yang_parser_ctx *ctx, enum ly_stmt any_kw, struct lysp_node *parent, struct lysp_node **siblings)
1653
0
{
1654
0
    LY_ERR ret = LY_SUCCESS;
1655
0
    char *buf, *word;
1656
0
    size_t word_len;
1657
0
    struct lysp_node_anydata *any;
1658
0
    enum ly_stmt kw;
1659
1660
    /* create new structure and insert into siblings */
1661
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, any, next, LY_EMEM);
1662
1663
0
    any->nodetype = any_kw == LY_STMT_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
1664
0
    any->parent = parent;
1665
1666
    /* get name */
1667
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
1668
0
    INSERT_WORD_RET(ctx, buf, any->name, word, word_len);
1669
1670
    /* parse substatements */
1671
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1672
0
        switch (kw) {
1673
0
        case LY_STMT_CONFIG:
1674
0
            LY_CHECK_RET(parse_config(ctx, &any->flags, &any->exts));
1675
0
            break;
1676
0
        case LY_STMT_DESCRIPTION:
1677
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts));
1678
0
            break;
1679
0
        case LY_STMT_IF_FEATURE:
1680
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &any->iffeatures, Y_STR_ARG, &any->exts));
1681
0
            break;
1682
0
        case LY_STMT_MANDATORY:
1683
0
            LY_CHECK_RET(parse_mandatory(ctx, &any->flags, &any->exts));
1684
0
            break;
1685
0
        case LY_STMT_MUST:
1686
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &any->musts));
1687
0
            break;
1688
0
        case LY_STMT_REFERENCE:
1689
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts));
1690
0
            break;
1691
0
        case LY_STMT_STATUS:
1692
0
            LY_CHECK_RET(parse_status(ctx, &any->flags, &any->exts));
1693
0
            break;
1694
0
        case LY_STMT_WHEN:
1695
0
            LY_CHECK_RET(parse_when(ctx, &any->when));
1696
0
            break;
1697
0
        case LY_STMT_EXTENSION_INSTANCE:
1698
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, any_kw, 0, &any->exts));
1699
0
            break;
1700
0
        default:
1701
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(any_kw));
1702
0
            return LY_EVALID;
1703
0
        }
1704
0
    }
1705
0
    return ret;
1706
0
}
1707
1708
/**
1709
 * @brief Parse the value or position statement. Substatement of type enum statement.
1710
 *
1711
 * @param[in] ctx yang parser context for logging.
1712
 * @param[in] val_kw Type of this particular keyword.
1713
 * @param[in,out] value Value to write to.
1714
 * @param[in,out] flags Flags to write to.
1715
 * @param[in,out] exts Extension instances to add to.
1716
 *
1717
 * @return LY_ERR values.
1718
 */
1719
LY_ERR
1720
parse_type_enum_value_pos(struct lys_yang_parser_ctx *ctx, enum ly_stmt val_kw, int64_t *value, uint16_t *flags,
1721
        struct lysp_ext_instance **exts)
1722
0
{
1723
0
    LY_ERR ret = LY_SUCCESS;
1724
0
    char *buf, *word, *ptr;
1725
0
    size_t word_len;
1726
0
    long int num = 0;
1727
0
    unsigned long int unum = 0;
1728
0
    enum ly_stmt kw;
1729
1730
0
    if (*flags & LYS_SET_VALUE) {
1731
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
1732
0
        return LY_EVALID;
1733
0
    }
1734
0
    *flags |= LYS_SET_VALUE;
1735
1736
    /* get value */
1737
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1738
1739
0
    if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(word, "-0", 2))) {
1740
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
1741
0
        goto error;
1742
0
    }
1743
1744
0
    errno = 0;
1745
0
    if (val_kw == LY_STMT_VALUE) {
1746
0
        num = strtol(word, &ptr, LY_BASE_DEC);
1747
0
        if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
1748
0
            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
1749
0
            goto error;
1750
0
        }
1751
0
    } else {
1752
0
        unum = strtoul(word, &ptr, LY_BASE_DEC);
1753
0
        if (unum > UINT64_C(4294967295)) {
1754
0
            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
1755
0
            goto error;
1756
0
        }
1757
0
    }
1758
    /* we have not parsed the whole argument */
1759
0
    if ((size_t)(ptr - word) != word_len) {
1760
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
1761
0
        goto error;
1762
0
    }
1763
0
    if (errno == ERANGE) {
1764
0
        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
1765
0
        goto error;
1766
0
    }
1767
0
    if (val_kw == LY_STMT_VALUE) {
1768
0
        *value = num;
1769
0
    } else {
1770
0
        *value = unum;
1771
0
    }
1772
0
    free(buf);
1773
1774
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1775
0
        switch (kw) {
1776
0
        case LY_STMT_EXTENSION_INSTANCE:
1777
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, val_kw == LY_STMT_VALUE ? LY_STMT_VALUE : LY_STMT_POSITION, 0, exts));
1778
0
            break;
1779
0
        default:
1780
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
1781
0
            return LY_EVALID;
1782
0
        }
1783
0
    }
1784
0
    return ret;
1785
1786
0
error:
1787
0
    free(buf);
1788
0
    return LY_EVALID;
1789
0
}
1790
1791
/**
1792
 * @brief Parse the enum or bit statement. Substatement of type statement.
1793
 *
1794
 * @param[in] ctx yang parser context for logging.
1795
 * @param[in] enum_kw Type of this particular keyword.
1796
 * @param[in,out] enums Enums or bits to add to.
1797
 *
1798
 * @return LY_ERR values.
1799
 */
1800
static LY_ERR
1801
parse_type_enum(struct lys_yang_parser_ctx *ctx, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
1802
0
{
1803
0
    LY_ERR ret = LY_SUCCESS;
1804
0
    char *buf, *word;
1805
0
    size_t word_len;
1806
0
    enum ly_stmt kw;
1807
0
    struct lysp_type_enum *enm;
1808
1809
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
1810
1811
    /* get value */
1812
0
    LY_CHECK_RET(get_argument(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
1813
0
    if (enum_kw == LY_STMT_ENUM) {
1814
0
        ret = lysp_check_enum_name((struct lys_parser_ctx *)ctx, (const char *)word, word_len);
1815
0
        LY_CHECK_ERR_RET(ret, free(buf), ret);
1816
0
    } /* else nothing specific for YANG_BIT */
1817
1818
0
    INSERT_WORD_RET(ctx, buf, enm->name, word, word_len);
1819
0
    CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
1820
1821
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1822
0
        switch (kw) {
1823
0
        case LY_STMT_DESCRIPTION:
1824
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
1825
0
            break;
1826
0
        case LY_STMT_IF_FEATURE:
1827
0
            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
1828
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
1829
0
            break;
1830
0
        case LY_STMT_REFERENCE:
1831
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
1832
0
            break;
1833
0
        case LY_STMT_STATUS:
1834
0
            LY_CHECK_RET(parse_status(ctx, &enm->flags, &enm->exts));
1835
0
            break;
1836
0
        case LY_STMT_VALUE:
1837
0
            LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
1838
0
                    ly_stmt2str(enum_kw)), LY_EVALID);
1839
0
            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, &enm->value, &enm->flags, &enm->exts));
1840
0
            break;
1841
0
        case LY_STMT_POSITION:
1842
0
            LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
1843
0
                    ly_stmt2str(enum_kw)), LY_EVALID);
1844
0
            LY_CHECK_RET(parse_type_enum_value_pos(ctx, kw, &enm->value, &enm->flags, &enm->exts));
1845
0
            break;
1846
0
        case LY_STMT_EXTENSION_INSTANCE:
1847
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, enum_kw, 0, &enm->exts));
1848
0
            break;
1849
0
        default:
1850
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
1851
0
            return LY_EVALID;
1852
0
        }
1853
0
    }
1854
0
    return ret;
1855
0
}
1856
1857
/**
1858
 * @brief Parse the fraction-digits statement. Substatement of type statement.
1859
 *
1860
 * @param[in] ctx yang parser context for logging.
1861
 * @param[in,out] fracdig Value to write to.
1862
 * @param[in,out] exts Extension instances to add to.
1863
 *
1864
 * @return LY_ERR values.
1865
 */
1866
static LY_ERR
1867
parse_type_fracdigits(struct lys_yang_parser_ctx *ctx, uint8_t *fracdig, struct lysp_ext_instance **exts)
1868
0
{
1869
0
    LY_ERR ret = LY_SUCCESS;
1870
0
    char *buf, *word, *ptr;
1871
0
    size_t word_len;
1872
0
    unsigned long int num;
1873
0
    enum ly_stmt kw;
1874
1875
0
    if (*fracdig) {
1876
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
1877
0
        return LY_EVALID;
1878
0
    }
1879
1880
    /* get value */
1881
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1882
1883
0
    if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
1884
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
1885
0
        free(buf);
1886
0
        return LY_EVALID;
1887
0
    }
1888
1889
0
    errno = 0;
1890
0
    num = strtoul(word, &ptr, LY_BASE_DEC);
1891
    /* we have not parsed the whole argument */
1892
0
    if ((size_t)(ptr - word) != word_len) {
1893
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
1894
0
        free(buf);
1895
0
        return LY_EVALID;
1896
0
    }
1897
0
    if ((errno == ERANGE) || (num > LY_TYPE_DEC64_FD_MAX)) {
1898
0
        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
1899
0
        free(buf);
1900
0
        return LY_EVALID;
1901
0
    }
1902
0
    *fracdig = num;
1903
0
    free(buf);
1904
1905
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1906
0
        switch (kw) {
1907
0
        case LY_STMT_EXTENSION_INSTANCE:
1908
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_FRACTION_DIGITS, 0, exts));
1909
0
            break;
1910
0
        default:
1911
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
1912
0
            return LY_EVALID;
1913
0
        }
1914
0
    }
1915
0
    return ret;
1916
0
}
1917
1918
/**
1919
 * @brief Parse the require-instance statement. Substatement of type statement.
1920
 *
1921
 * @param[in] ctx yang parser context for logging.
1922
 * @param[in,out] reqinst Value to write to.
1923
 * @param[in,out] flags Flags to write to.
1924
 * @param[in,out] exts Extension instances to add to.
1925
 *
1926
 * @return LY_ERR values.
1927
 */
1928
static LY_ERR
1929
parse_type_reqinstance(struct lys_yang_parser_ctx *ctx, uint8_t *reqinst, uint16_t *flags,
1930
        struct lysp_ext_instance **exts)
1931
0
{
1932
0
    LY_ERR ret = LY_SUCCESS;
1933
0
    char *buf, *word;
1934
0
    size_t word_len;
1935
0
    enum ly_stmt kw;
1936
1937
0
    if (*flags & LYS_SET_REQINST) {
1938
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
1939
0
        return LY_EVALID;
1940
0
    }
1941
0
    *flags |= LYS_SET_REQINST;
1942
1943
    /* get value */
1944
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1945
1946
0
    if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
1947
0
        *reqinst = 1;
1948
0
    } else if ((word_len != ly_strlen_const("false")) || strncmp(word, "false", word_len)) {
1949
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
1950
0
        free(buf);
1951
0
        return LY_EVALID;
1952
0
    }
1953
0
    free(buf);
1954
1955
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
1956
0
        switch (kw) {
1957
0
        case LY_STMT_EXTENSION_INSTANCE:
1958
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REQUIRE_INSTANCE, 0, exts));
1959
0
            break;
1960
0
        default:
1961
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
1962
0
            return LY_EVALID;
1963
0
        }
1964
0
    }
1965
0
    return ret;
1966
0
}
1967
1968
/**
1969
 * @brief Parse the modifier statement. Substatement of type pattern statement.
1970
 *
1971
 * @param[in] ctx yang parser context for logging.
1972
 * @param[in,out] pat Value to write to.
1973
 * @param[in,out] exts Extension instances to add to.
1974
 *
1975
 * @return LY_ERR values.
1976
 */
1977
static LY_ERR
1978
parse_type_pattern_modifier(struct lys_yang_parser_ctx *ctx, const char **pat, struct lysp_ext_instance **exts)
1979
0
{
1980
0
    LY_ERR ret = LY_SUCCESS;
1981
0
    char *buf, *word;
1982
0
    size_t word_len;
1983
0
    enum ly_stmt kw;
1984
1985
0
    if ((*pat)[0] == LYSP_RESTR_PATTERN_NACK) {
1986
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
1987
0
        return LY_EVALID;
1988
0
    }
1989
1990
    /* get value */
1991
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
1992
1993
0
    if ((word_len != ly_strlen_const("invert-match")) || strncmp(word, "invert-match", word_len)) {
1994
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
1995
0
        free(buf);
1996
0
        return LY_EVALID;
1997
0
    }
1998
0
    free(buf);
1999
2000
    /* replace the value in the dictionary */
2001
0
    buf = malloc(strlen(*pat) + 1);
2002
0
    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
2003
0
    strcpy(buf, *pat);
2004
0
    lydict_remove(PARSER_CTX(ctx), *pat);
2005
2006
0
    assert(buf[0] == LYSP_RESTR_PATTERN_ACK);
2007
0
    buf[0] = LYSP_RESTR_PATTERN_NACK;
2008
0
    LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, pat));
2009
2010
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2011
0
        switch (kw) {
2012
0
        case LY_STMT_EXTENSION_INSTANCE:
2013
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MODIFIER, 0, exts));
2014
0
            break;
2015
0
        default:
2016
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
2017
0
            return LY_EVALID;
2018
0
        }
2019
0
    }
2020
0
    return ret;
2021
0
}
2022
2023
/**
2024
 * @brief Parse the pattern statement. Substatement of type statement.
2025
 *
2026
 * @param[in] ctx yang parser context for logging.
2027
 * @param[in,out] patterns Restrictions to add to.
2028
 *
2029
 * @return LY_ERR values.
2030
 */
2031
static LY_ERR
2032
parse_type_pattern(struct lys_yang_parser_ctx *ctx, struct lysp_restr **patterns)
2033
0
{
2034
0
    LY_ERR ret = LY_SUCCESS;
2035
0
    char *buf, *word;
2036
0
    size_t word_len;
2037
0
    enum ly_stmt kw;
2038
0
    struct lysp_restr *restr;
2039
2040
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
2041
2042
    /* get value */
2043
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
2044
2045
    /* add special meaning first byte */
2046
0
    if (buf) {
2047
0
        buf = ly_realloc(buf, word_len + 2);
2048
0
        word = buf;
2049
0
    } else {
2050
0
        buf = malloc(word_len + 2);
2051
0
    }
2052
0
    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
2053
0
    memmove(buf + 1, word, word_len);
2054
0
    buf[0] = LYSP_RESTR_PATTERN_ACK; /* pattern's default regular-match flag */
2055
0
    buf[word_len + 1] = '\0'; /* terminating NULL byte */
2056
0
    LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str));
2057
0
    restr->arg.mod = ctx->parsed_mod;
2058
2059
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2060
0
        switch (kw) {
2061
0
        case LY_STMT_DESCRIPTION:
2062
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
2063
0
            break;
2064
0
        case LY_STMT_REFERENCE:
2065
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
2066
0
            break;
2067
0
        case LY_STMT_ERROR_APP_TAG:
2068
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_APP_TAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
2069
0
            break;
2070
0
        case LY_STMT_ERROR_MESSAGE:
2071
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ERROR_MESSAGE, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
2072
0
            break;
2073
0
        case LY_STMT_MODIFIER:
2074
0
            PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
2075
0
            LY_CHECK_RET(parse_type_pattern_modifier(ctx, &restr->arg.str, &restr->exts));
2076
0
            break;
2077
0
        case LY_STMT_EXTENSION_INSTANCE:
2078
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_PATTERN, 0, &restr->exts));
2079
0
            break;
2080
0
        default:
2081
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
2082
0
            return LY_EVALID;
2083
0
        }
2084
0
    }
2085
0
    return ret;
2086
0
}
2087
2088
/**
2089
 * @brief Parse the type statement.
2090
 *
2091
 * @param[in] ctx yang parser context for logging.
2092
 * @param[in,out] type Type to wrote to.
2093
 *
2094
 * @return LY_ERR values.
2095
 */
2096
static LY_ERR
2097
parse_type(struct lys_yang_parser_ctx *ctx, struct lysp_type *type)
2098
0
{
2099
0
    LY_ERR ret = LY_SUCCESS;
2100
0
    char *buf, *word;
2101
0
    const char *str_path = NULL;
2102
0
    size_t word_len;
2103
0
    enum ly_stmt kw;
2104
0
    struct lysp_type *nest_type;
2105
2106
0
    if (type->name) {
2107
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
2108
0
        return LY_EVALID;
2109
0
    }
2110
2111
    /* get value */
2112
0
    LY_CHECK_RET(get_argument(ctx, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2113
0
    INSERT_WORD_RET(ctx, buf, type->name, word, word_len);
2114
2115
    /* set module */
2116
0
    type->pmod = ctx->parsed_mod;
2117
2118
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2119
0
        switch (kw) {
2120
0
        case LY_STMT_BASE:
2121
0
            LY_CHECK_RET(parse_text_fields(ctx, LY_STMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
2122
0
            type->flags |= LYS_SET_BASE;
2123
0
            break;
2124
0
        case LY_STMT_BIT:
2125
0
            LY_CHECK_RET(parse_type_enum(ctx, kw, &type->bits));
2126
0
            type->flags |= LYS_SET_BIT;
2127
0
            break;
2128
0
        case LY_STMT_ENUM:
2129
0
            LY_CHECK_RET(parse_type_enum(ctx, kw, &type->enums));
2130
0
            type->flags |= LYS_SET_ENUM;
2131
0
            break;
2132
0
        case LY_STMT_FRACTION_DIGITS:
2133
0
            LY_CHECK_RET(parse_type_fracdigits(ctx, &type->fraction_digits, &type->exts));
2134
0
            type->flags |= LYS_SET_FRDIGITS;
2135
0
            break;
2136
0
        case LY_STMT_LENGTH:
2137
0
            if (type->length) {
2138
0
                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
2139
0
                return LY_EVALID;
2140
0
            }
2141
0
            type->length = calloc(1, sizeof *type->length);
2142
0
            LY_CHECK_ERR_RET(!type->length, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
2143
2144
0
            LY_CHECK_RET(parse_restr(ctx, kw, type->length));
2145
0
            type->flags |= LYS_SET_LENGTH;
2146
0
            break;
2147
0
        case LY_STMT_PATH:
2148
0
            if (type->path) {
2149
0
                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(LY_STMT_PATH));
2150
0
                return LY_EVALID;
2151
0
            }
2152
2153
            /* Usually, in the parser_yang.c, the result of the parsing is stored directly in the
2154
             * corresponding structure, so in case of failure, the lysp_module_free function will take
2155
             * care of removing the parsed value from the dictionary. But in this case, it is not possible
2156
             * to rely on lysp_module_free because the result of the parsing is stored in a local variable.
2157
             */
2158
0
            LY_CHECK_ERR_RET(ret = parse_text_field(ctx, LY_STMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts),
2159
0
                    lydict_remove(PARSER_CTX(ctx), str_path), ret);
2160
0
            ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
2161
0
                    LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
2162
            /* Moreover, even if successful, the string is removed from the dictionary. */
2163
0
            lydict_remove(PARSER_CTX(ctx), str_path);
2164
0
            LY_CHECK_RET(ret);
2165
0
            type->flags |= LYS_SET_PATH;
2166
0
            break;
2167
0
        case LY_STMT_PATTERN:
2168
0
            LY_CHECK_RET(parse_type_pattern(ctx, &type->patterns));
2169
0
            type->flags |= LYS_SET_PATTERN;
2170
0
            break;
2171
0
        case LY_STMT_RANGE:
2172
0
            if (type->range) {
2173
0
                LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
2174
0
                return LY_EVALID;
2175
0
            }
2176
0
            type->range = calloc(1, sizeof *type->range);
2177
0
            LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
2178
2179
0
            LY_CHECK_RET(parse_restr(ctx, kw, type->range));
2180
0
            type->flags |= LYS_SET_RANGE;
2181
0
            break;
2182
0
        case LY_STMT_REQUIRE_INSTANCE:
2183
0
            LY_CHECK_RET(parse_type_reqinstance(ctx, &type->require_instance, &type->flags, &type->exts));
2184
            /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
2185
0
            break;
2186
0
        case LY_STMT_TYPE:
2187
0
            LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
2188
0
            LY_CHECK_RET(parse_type(ctx, nest_type));
2189
0
            type->flags |= LYS_SET_TYPE;
2190
0
            break;
2191
0
        case LY_STMT_EXTENSION_INSTANCE:
2192
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_TYPE, 0, &type->exts));
2193
0
            break;
2194
0
        default:
2195
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
2196
0
            return LY_EVALID;
2197
0
        }
2198
0
    }
2199
0
    return ret;
2200
0
}
2201
2202
/**
2203
 * @brief Parse the leaf statement.
2204
 *
2205
 * @param[in] ctx yang parser context for logging.
2206
 * @param[in,out] siblings Siblings to add to.
2207
 *
2208
 * @return LY_ERR values.
2209
 */
2210
LY_ERR
2211
parse_leaf(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
2212
0
{
2213
0
    LY_ERR ret = LY_SUCCESS;
2214
0
    char *buf, *word;
2215
0
    size_t word_len;
2216
0
    enum ly_stmt kw;
2217
0
    struct lysp_node_leaf *leaf;
2218
2219
    /* create new leaf structure */
2220
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, leaf, next, LY_EMEM);
2221
0
    leaf->nodetype = LYS_LEAF;
2222
0
    leaf->parent = parent;
2223
2224
    /* get name */
2225
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2226
0
    INSERT_WORD_RET(ctx, buf, leaf->name, word, word_len);
2227
2228
    /* parse substatements */
2229
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
2230
0
        switch (kw) {
2231
0
        case LY_STMT_CONFIG:
2232
0
            LY_CHECK_RET(parse_config(ctx, &leaf->flags, &leaf->exts));
2233
0
            break;
2234
0
        case LY_STMT_DEFAULT:
2235
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &leaf->dflt.str, Y_STR_ARG, &leaf->exts));
2236
0
            leaf->dflt.mod = ctx->parsed_mod;
2237
0
            break;
2238
0
        case LY_STMT_DESCRIPTION:
2239
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts));
2240
0
            break;
2241
0
        case LY_STMT_IF_FEATURE:
2242
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &leaf->iffeatures, Y_STR_ARG, &leaf->exts));
2243
0
            break;
2244
0
        case LY_STMT_MANDATORY:
2245
0
            LY_CHECK_RET(parse_mandatory(ctx, &leaf->flags, &leaf->exts));
2246
0
            break;
2247
0
        case LY_STMT_MUST:
2248
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &leaf->musts));
2249
0
            break;
2250
0
        case LY_STMT_REFERENCE:
2251
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts));
2252
0
            break;
2253
0
        case LY_STMT_STATUS:
2254
0
            LY_CHECK_RET(parse_status(ctx, &leaf->flags, &leaf->exts));
2255
0
            break;
2256
0
        case LY_STMT_TYPE:
2257
0
            LY_CHECK_RET(parse_type(ctx, &leaf->type));
2258
0
            break;
2259
0
        case LY_STMT_UNITS:
2260
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts));
2261
0
            break;
2262
0
        case LY_STMT_WHEN:
2263
0
            LY_CHECK_RET(parse_when(ctx, &leaf->when));
2264
0
            break;
2265
0
        case LY_STMT_EXTENSION_INSTANCE:
2266
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LEAF, 0, &leaf->exts));
2267
0
            break;
2268
0
        default:
2269
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
2270
0
            return LY_EVALID;
2271
0
        }
2272
0
    }
2273
0
    LY_CHECK_RET(ret);
2274
0
checks:
2275
    /* mandatory substatements */
2276
0
    if (!leaf->type.name) {
2277
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf");
2278
0
        return LY_EVALID;
2279
0
    }
2280
2281
0
    return ret;
2282
0
}
2283
2284
/**
2285
 * @brief Parse the max-elements statement.
2286
 *
2287
 * @param[in] ctx yang parser context for logging.
2288
 * @param[in,out] max Value to write to.
2289
 * @param[in,out] flags Flags to write to.
2290
 * @param[in,out] exts Extension instances to add to.
2291
 *
2292
 * @return LY_ERR values.
2293
 */
2294
LY_ERR
2295
parse_maxelements(struct lys_yang_parser_ctx *ctx, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
2296
0
{
2297
0
    LY_ERR ret = LY_SUCCESS;
2298
0
    char *buf, *word, *ptr;
2299
0
    size_t word_len;
2300
0
    unsigned long int num;
2301
0
    enum ly_stmt kw;
2302
2303
0
    if (*flags & LYS_SET_MAX) {
2304
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "max-elements");
2305
0
        return LY_EVALID;
2306
0
    }
2307
0
    *flags |= LYS_SET_MAX;
2308
2309
    /* get value */
2310
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
2311
2312
0
    if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
2313
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
2314
0
        free(buf);
2315
0
        return LY_EVALID;
2316
0
    }
2317
2318
0
    if (ly_strncmp("unbounded", word, word_len)) {
2319
0
        errno = 0;
2320
0
        num = strtoul(word, &ptr, LY_BASE_DEC);
2321
        /* we have not parsed the whole argument */
2322
0
        if ((size_t)(ptr - word) != word_len) {
2323
0
            LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
2324
0
            free(buf);
2325
0
            return LY_EVALID;
2326
0
        }
2327
0
        if ((errno == ERANGE) || (num > UINT32_MAX)) {
2328
0
            LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
2329
0
            free(buf);
2330
0
            return LY_EVALID;
2331
0
        }
2332
2333
0
        *max = num;
2334
0
    } else {
2335
        /* unbounded */
2336
0
        *max = 0;
2337
0
    }
2338
0
    free(buf);
2339
2340
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2341
0
        switch (kw) {
2342
0
        case LY_STMT_EXTENSION_INSTANCE:
2343
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MAX_ELEMENTS, 0, exts));
2344
0
            break;
2345
0
        default:
2346
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
2347
0
            return LY_EVALID;
2348
0
        }
2349
0
    }
2350
0
    return ret;
2351
0
}
2352
2353
/**
2354
 * @brief Parse the min-elements statement.
2355
 *
2356
 * @param[in] ctx yang parser context for logging.
2357
 * @param[in,out] min Value to write to.
2358
 * @param[in,out] flags Flags to write to.
2359
 * @param[in,out] exts Extension instances to add to.
2360
 *
2361
 * @return LY_ERR values.
2362
 */
2363
LY_ERR
2364
parse_minelements(struct lys_yang_parser_ctx *ctx, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
2365
0
{
2366
0
    LY_ERR ret = LY_SUCCESS;
2367
0
    char *buf, *word, *ptr;
2368
0
    size_t word_len;
2369
0
    unsigned long int num;
2370
0
    enum ly_stmt kw;
2371
2372
0
    if (*flags & LYS_SET_MIN) {
2373
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "min-elements");
2374
0
        return LY_EVALID;
2375
0
    }
2376
0
    *flags |= LYS_SET_MIN;
2377
2378
    /* get value */
2379
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
2380
2381
0
    if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
2382
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
2383
0
        free(buf);
2384
0
        return LY_EVALID;
2385
0
    }
2386
2387
0
    errno = 0;
2388
0
    num = strtoul(word, &ptr, LY_BASE_DEC);
2389
    /* we have not parsed the whole argument */
2390
0
    if ((size_t)(ptr - word) != word_len) {
2391
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
2392
0
        free(buf);
2393
0
        return LY_EVALID;
2394
0
    }
2395
0
    if ((errno == ERANGE) || (num > UINT32_MAX)) {
2396
0
        LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
2397
0
        free(buf);
2398
0
        return LY_EVALID;
2399
0
    }
2400
0
    *min = num;
2401
0
    free(buf);
2402
2403
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2404
0
        switch (kw) {
2405
0
        case LY_STMT_EXTENSION_INSTANCE:
2406
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MIN_ELEMENTS, 0, exts));
2407
0
            break;
2408
0
        default:
2409
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
2410
0
            return LY_EVALID;
2411
0
        }
2412
0
    }
2413
0
    return ret;
2414
0
}
2415
2416
/**
2417
 * @brief Parse the ordered-by statement.
2418
 *
2419
 * @param[in] ctx yang parser context for logging.
2420
 * @param[in,out] flags Flags to write to.
2421
 * @param[in,out] exts Extension instances to add to.
2422
 *
2423
 * @return LY_ERR values.
2424
 */
2425
static LY_ERR
2426
parse_orderedby(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
2427
0
{
2428
0
    LY_ERR ret = LY_SUCCESS;
2429
0
    char *buf, *word;
2430
0
    size_t word_len;
2431
0
    enum ly_stmt kw;
2432
2433
0
    if (*flags & LYS_ORDBY_MASK) {
2434
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "ordered-by");
2435
0
        return LY_EVALID;
2436
0
    }
2437
2438
    /* get value */
2439
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
2440
2441
0
    if ((word_len == ly_strlen_const("system")) && !strncmp(word, "system", word_len)) {
2442
0
        *flags |= LYS_ORDBY_SYSTEM;
2443
0
    } else if ((word_len == ly_strlen_const("user")) && !strncmp(word, "user", word_len)) {
2444
0
        *flags |= LYS_ORDBY_USER;
2445
0
    } else {
2446
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
2447
0
        free(buf);
2448
0
        return LY_EVALID;
2449
0
    }
2450
0
    free(buf);
2451
2452
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2453
0
        switch (kw) {
2454
0
        case LY_STMT_EXTENSION_INSTANCE:
2455
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_ORDERED_BY, 0, exts));
2456
0
            break;
2457
0
        default:
2458
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
2459
0
            return LY_EVALID;
2460
0
        }
2461
0
    }
2462
0
    return ret;
2463
0
}
2464
2465
/**
2466
 * @brief Parse the leaf-list statement.
2467
 *
2468
 * @param[in] ctx yang parser context for logging.
2469
 * @param[in,out] siblings Siblings to add to.
2470
 *
2471
 * @return LY_ERR values.
2472
 */
2473
LY_ERR
2474
parse_leaflist(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
2475
0
{
2476
0
    LY_ERR ret = LY_SUCCESS;
2477
0
    char *buf, *word;
2478
0
    size_t word_len;
2479
0
    enum ly_stmt kw;
2480
0
    struct lysp_node_leaflist *llist;
2481
2482
    /* create new leaf-list structure */
2483
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, llist, next, LY_EMEM);
2484
0
    llist->nodetype = LYS_LEAFLIST;
2485
0
    llist->parent = parent;
2486
2487
    /* get name */
2488
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2489
0
    INSERT_WORD_RET(ctx, buf, llist->name, word, word_len);
2490
2491
    /* parse substatements */
2492
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
2493
0
        switch (kw) {
2494
0
        case LY_STMT_CONFIG:
2495
0
            LY_CHECK_RET(parse_config(ctx, &llist->flags, &llist->exts));
2496
0
            break;
2497
0
        case LY_STMT_DEFAULT:
2498
0
            PARSER_CHECK_STMTVER2_RET(ctx, "default", "leaf-list");
2499
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts));
2500
0
            break;
2501
0
        case LY_STMT_DESCRIPTION:
2502
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts));
2503
0
            break;
2504
0
        case LY_STMT_IF_FEATURE:
2505
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &llist->iffeatures, Y_STR_ARG, &llist->exts));
2506
0
            break;
2507
0
        case LY_STMT_MAX_ELEMENTS:
2508
0
            LY_CHECK_RET(parse_maxelements(ctx, &llist->max, &llist->flags, &llist->exts));
2509
0
            break;
2510
0
        case LY_STMT_MIN_ELEMENTS:
2511
0
            LY_CHECK_RET(parse_minelements(ctx, &llist->min, &llist->flags, &llist->exts));
2512
0
            break;
2513
0
        case LY_STMT_MUST:
2514
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &llist->musts));
2515
0
            break;
2516
0
        case LY_STMT_ORDERED_BY:
2517
0
            LY_CHECK_RET(parse_orderedby(ctx, &llist->flags, &llist->exts));
2518
0
            break;
2519
0
        case LY_STMT_REFERENCE:
2520
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts));
2521
0
            break;
2522
0
        case LY_STMT_STATUS:
2523
0
            LY_CHECK_RET(parse_status(ctx, &llist->flags, &llist->exts));
2524
0
            break;
2525
0
        case LY_STMT_TYPE:
2526
0
            LY_CHECK_RET(parse_type(ctx, &llist->type));
2527
0
            break;
2528
0
        case LY_STMT_UNITS:
2529
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts));
2530
0
            break;
2531
0
        case LY_STMT_WHEN:
2532
0
            LY_CHECK_RET(parse_when(ctx, &llist->when));
2533
0
            break;
2534
0
        case LY_STMT_EXTENSION_INSTANCE:
2535
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LEAF_LIST, 0, &llist->exts));
2536
0
            break;
2537
0
        default:
2538
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
2539
0
            return LY_EVALID;
2540
0
        }
2541
0
    }
2542
0
    LY_CHECK_RET(ret);
2543
0
checks:
2544
    /* mandatory substatements */
2545
0
    if (!llist->type.name) {
2546
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
2547
0
        return LY_EVALID;
2548
0
    }
2549
2550
0
    return ret;
2551
0
}
2552
2553
/**
2554
 * @brief Parse the refine statement.
2555
 *
2556
 * @param[in] ctx yang parser context for logging.
2557
 * @param[in,out] refines Refines to add to.
2558
 *
2559
 * @return LY_ERR values.
2560
 */
2561
static LY_ERR
2562
parse_refine(struct lys_yang_parser_ctx *ctx, struct lysp_refine **refines)
2563
0
{
2564
0
    LY_ERR ret = LY_SUCCESS;
2565
0
    char *buf, *word;
2566
0
    size_t word_len;
2567
0
    enum ly_stmt kw;
2568
0
    struct lysp_refine *rf;
2569
2570
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *refines, rf, LY_EMEM);
2571
2572
    /* get value */
2573
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
2574
0
    CHECK_NONEMPTY(ctx, word_len, "refine");
2575
0
    INSERT_WORD_RET(ctx, buf, rf->nodeid, word, word_len);
2576
2577
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2578
0
        switch (kw) {
2579
0
        case LY_STMT_CONFIG:
2580
0
            LY_CHECK_RET(parse_config(ctx, &rf->flags, &rf->exts));
2581
0
            break;
2582
0
        case LY_STMT_DEFAULT:
2583
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, &rf->dflts, Y_STR_ARG, &rf->exts));
2584
0
            break;
2585
0
        case LY_STMT_DESCRIPTION:
2586
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts));
2587
0
            break;
2588
0
        case LY_STMT_IF_FEATURE:
2589
0
            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", "refine");
2590
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &rf->iffeatures, Y_STR_ARG, &rf->exts));
2591
0
            break;
2592
0
        case LY_STMT_MAX_ELEMENTS:
2593
0
            LY_CHECK_RET(parse_maxelements(ctx, &rf->max, &rf->flags, &rf->exts));
2594
0
            break;
2595
0
        case LY_STMT_MIN_ELEMENTS:
2596
0
            LY_CHECK_RET(parse_minelements(ctx, &rf->min, &rf->flags, &rf->exts));
2597
0
            break;
2598
0
        case LY_STMT_MUST:
2599
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &rf->musts));
2600
0
            break;
2601
0
        case LY_STMT_MANDATORY:
2602
0
            LY_CHECK_RET(parse_mandatory(ctx, &rf->flags, &rf->exts));
2603
0
            break;
2604
0
        case LY_STMT_REFERENCE:
2605
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts));
2606
0
            break;
2607
0
        case LY_STMT_PRESENCE:
2608
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts));
2609
0
            break;
2610
0
        case LY_STMT_EXTENSION_INSTANCE:
2611
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REFINE, 0, &rf->exts));
2612
0
            break;
2613
0
        default:
2614
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
2615
0
            return LY_EVALID;
2616
0
        }
2617
0
    }
2618
0
    return ret;
2619
0
}
2620
2621
/**
2622
 * @brief Parse the typedef statement.
2623
 *
2624
 * @param[in] ctx yang parser context for logging.
2625
 * @param[in,out] typedefs Typedefs to add to.
2626
 *
2627
 * @return LY_ERR values.
2628
 */
2629
static LY_ERR
2630
parse_typedef(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_tpdf **typedefs)
2631
0
{
2632
0
    LY_ERR ret = LY_SUCCESS;
2633
0
    char *buf, *word;
2634
0
    size_t word_len;
2635
0
    enum ly_stmt kw;
2636
0
    struct lysp_tpdf *tpdf;
2637
2638
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *typedefs, tpdf, LY_EMEM);
2639
2640
    /* get value */
2641
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2642
0
    INSERT_WORD_RET(ctx, buf, tpdf->name, word, word_len);
2643
2644
    /* parse substatements */
2645
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
2646
0
        switch (kw) {
2647
0
        case LY_STMT_DEFAULT:
2648
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &tpdf->dflt.str, Y_STR_ARG, &tpdf->exts));
2649
0
            tpdf->dflt.mod = ctx->parsed_mod;
2650
0
            break;
2651
0
        case LY_STMT_DESCRIPTION:
2652
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts));
2653
0
            break;
2654
0
        case LY_STMT_REFERENCE:
2655
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts));
2656
0
            break;
2657
0
        case LY_STMT_STATUS:
2658
0
            LY_CHECK_RET(parse_status(ctx, &tpdf->flags, &tpdf->exts));
2659
0
            break;
2660
0
        case LY_STMT_TYPE:
2661
0
            LY_CHECK_RET(parse_type(ctx, &tpdf->type));
2662
0
            break;
2663
0
        case LY_STMT_UNITS:
2664
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts));
2665
0
            break;
2666
0
        case LY_STMT_EXTENSION_INSTANCE:
2667
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_TYPEDEF, 0, &tpdf->exts));
2668
0
            break;
2669
0
        default:
2670
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
2671
0
            return LY_EVALID;
2672
0
        }
2673
0
    }
2674
0
    LY_CHECK_RET(ret);
2675
0
checks:
2676
    /* mandatory substatements */
2677
0
    if (!tpdf->type.name) {
2678
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "typedef");
2679
0
        return LY_EVALID;
2680
0
    }
2681
2682
    /* store data for collision check */
2683
0
    if (parent && !(parent->nodetype & (LYS_GROUPING | LYS_RPC | LYS_ACTION | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
2684
0
        LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, parent, 0, NULL));
2685
0
    }
2686
2687
0
    return ret;
2688
0
}
2689
2690
/**
2691
 * @brief Parse the input or output statement.
2692
 *
2693
 * @param[in] ctx yang parser context for logging.
2694
 * @param[in] kw Type of this particular keyword
2695
 * @param[in,out] inout_p Input/output pointer to write to.
2696
 *
2697
 * @return LY_ERR values.
2698
 */
2699
static LY_ERR
2700
parse_inout(struct lys_yang_parser_ctx *ctx, enum ly_stmt inout_kw, struct lysp_node *parent,
2701
        struct lysp_node_action_inout *inout_p)
2702
0
{
2703
0
    LY_ERR ret = LY_SUCCESS;
2704
0
    char *word;
2705
0
    size_t word_len;
2706
0
    enum ly_stmt kw;
2707
0
    ly_bool input = &((struct lysp_node_action *)parent)->input == inout_p ? 1 : 0;
2708
2709
0
    if (inout_p->nodetype) {
2710
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
2711
0
        return LY_EVALID;
2712
0
    }
2713
2714
    /* initiate structure */
2715
0
    LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), input ? "input" : "output", 0, &inout_p->name));
2716
0
    inout_p->nodetype = input ? LYS_INPUT : LYS_OUTPUT;
2717
0
    inout_p->parent = parent;
2718
2719
    /* parse substatements */
2720
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
2721
0
        switch (kw) {
2722
0
        case LY_STMT_ANYDATA:
2723
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
2724
        /* fall through */
2725
0
        case LY_STMT_ANYXML:
2726
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)inout_p, &inout_p->child));
2727
0
            break;
2728
0
        case LY_STMT_CHOICE:
2729
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2730
0
            break;
2731
0
        case LY_STMT_CONTAINER:
2732
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2733
0
            break;
2734
0
        case LY_STMT_LEAF:
2735
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2736
0
            break;
2737
0
        case LY_STMT_LEAF_LIST:
2738
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2739
0
            break;
2740
0
        case LY_STMT_LIST:
2741
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2742
0
            break;
2743
0
        case LY_STMT_USES:
2744
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)inout_p, &inout_p->child));
2745
0
            break;
2746
0
        case LY_STMT_TYPEDEF:
2747
0
            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)inout_p, &inout_p->typedefs));
2748
0
            break;
2749
0
        case LY_STMT_MUST:
2750
0
            PARSER_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(inout_kw));
2751
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &inout_p->musts));
2752
0
            break;
2753
0
        case LY_STMT_GROUPING:
2754
0
            LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)inout_p, &inout_p->groupings));
2755
0
            break;
2756
0
        case LY_STMT_EXTENSION_INSTANCE:
2757
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, inout_kw, 0, &inout_p->exts));
2758
0
            break;
2759
0
        default:
2760
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
2761
0
            return LY_EVALID;
2762
0
        }
2763
0
    }
2764
0
    LY_CHECK_RET(ret);
2765
2766
0
checks:
2767
0
    if (!inout_p->child) {
2768
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
2769
0
        return LY_EVALID;
2770
0
    }
2771
2772
0
    return ret;
2773
0
}
2774
2775
/**
2776
 * @brief Parse the action statement.
2777
 *
2778
 * @param[in] ctx yang parser context for logging.
2779
 * @param[in,out] actions Actions to add to.
2780
 *
2781
 * @return LY_ERR values.
2782
 */
2783
LY_ERR
2784
parse_action(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node_action **actions)
2785
0
{
2786
0
    LY_ERR ret = LY_SUCCESS;
2787
0
    char *buf, *word;
2788
0
    size_t word_len;
2789
0
    enum ly_stmt kw;
2790
0
    struct lysp_node_action *act;
2791
2792
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), actions, act, next, LY_EMEM);
2793
2794
    /* get value */
2795
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2796
0
    INSERT_WORD_RET(ctx, buf, act->name, word, word_len);
2797
0
    act->nodetype = parent ? LYS_ACTION : LYS_RPC;
2798
0
    act->parent = parent;
2799
2800
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
2801
0
        switch (kw) {
2802
0
        case LY_STMT_DESCRIPTION:
2803
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts));
2804
0
            break;
2805
0
        case LY_STMT_IF_FEATURE:
2806
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &act->iffeatures, Y_STR_ARG, &act->exts));
2807
0
            break;
2808
0
        case LY_STMT_REFERENCE:
2809
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts));
2810
0
            break;
2811
0
        case LY_STMT_STATUS:
2812
0
            LY_CHECK_RET(parse_status(ctx, &act->flags, &act->exts));
2813
0
            break;
2814
2815
0
        case LY_STMT_INPUT:
2816
0
            LY_CHECK_RET(parse_inout(ctx, kw, (struct lysp_node *)act, &act->input));
2817
0
            break;
2818
0
        case LY_STMT_OUTPUT:
2819
0
            LY_CHECK_RET(parse_inout(ctx, kw, (struct lysp_node *)act, &act->output));
2820
0
            break;
2821
2822
0
        case LY_STMT_TYPEDEF:
2823
0
            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)act, &act->typedefs));
2824
0
            break;
2825
0
        case LY_STMT_GROUPING:
2826
0
            LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)act, &act->groupings));
2827
0
            break;
2828
0
        case LY_STMT_EXTENSION_INSTANCE:
2829
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, parent ? LY_STMT_ACTION : LY_STMT_RPC, 0, &act->exts));
2830
0
            break;
2831
0
        default:
2832
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
2833
0
            return LY_EVALID;
2834
0
        }
2835
0
    }
2836
0
    LY_CHECK_RET(ret);
2837
2838
0
checks:
2839
    /* always initialize inout, they are technically present (needed for later deviations/refines) */
2840
0
    if (!act->input.nodetype) {
2841
0
        act->input.nodetype = LYS_INPUT;
2842
0
        act->input.parent = (struct lysp_node *)act;
2843
0
        LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), "input", 0, &act->input.name));
2844
0
    }
2845
0
    if (!act->output.nodetype) {
2846
0
        act->output.nodetype = LYS_OUTPUT;
2847
0
        act->output.parent = (struct lysp_node *)act;
2848
0
        LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), "output", 0, &act->output.name));
2849
0
    }
2850
2851
0
    return ret;
2852
0
}
2853
2854
/**
2855
 * @brief Parse the notification statement.
2856
 *
2857
 * @param[in] ctx yang parser context for logging.
2858
 * @param[in,out] notifs Notifications to add to.
2859
 *
2860
 * @return LY_ERR values.
2861
 */
2862
LY_ERR
2863
parse_notif(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node_notif **notifs)
2864
0
{
2865
0
    LY_ERR ret = LY_SUCCESS;
2866
0
    char *buf, *word;
2867
0
    size_t word_len;
2868
0
    enum ly_stmt kw;
2869
0
    struct lysp_node_notif *notif;
2870
2871
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), notifs, notif, next, LY_EMEM);
2872
2873
    /* get value */
2874
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2875
0
    INSERT_WORD_RET(ctx, buf, notif->name, word, word_len);
2876
0
    notif->nodetype = LYS_NOTIF;
2877
0
    notif->parent = parent;
2878
2879
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2880
0
        switch (kw) {
2881
0
        case LY_STMT_DESCRIPTION:
2882
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts));
2883
0
            break;
2884
0
        case LY_STMT_IF_FEATURE:
2885
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &notif->iffeatures, Y_STR_ARG, &notif->exts));
2886
0
            break;
2887
0
        case LY_STMT_REFERENCE:
2888
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts));
2889
0
            break;
2890
0
        case LY_STMT_STATUS:
2891
0
            LY_CHECK_RET(parse_status(ctx, &notif->flags, &notif->exts));
2892
0
            break;
2893
2894
0
        case LY_STMT_ANYDATA:
2895
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "notification");
2896
        /* fall through */
2897
0
        case LY_STMT_ANYXML:
2898
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)notif, &notif->child));
2899
0
            break;
2900
0
        case LY_STMT_CHOICE:
2901
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)notif, &notif->child));
2902
0
            break;
2903
0
        case LY_STMT_CONTAINER:
2904
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)notif, &notif->child));
2905
0
            break;
2906
0
        case LY_STMT_LEAF:
2907
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)notif, &notif->child));
2908
0
            break;
2909
0
        case LY_STMT_LEAF_LIST:
2910
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)notif, &notif->child));
2911
0
            break;
2912
0
        case LY_STMT_LIST:
2913
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)notif, &notif->child));
2914
0
            break;
2915
0
        case LY_STMT_USES:
2916
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)notif, &notif->child));
2917
0
            break;
2918
2919
0
        case LY_STMT_MUST:
2920
0
            PARSER_CHECK_STMTVER2_RET(ctx, "must", "notification");
2921
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &notif->musts));
2922
0
            break;
2923
0
        case LY_STMT_TYPEDEF:
2924
0
            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)notif, &notif->typedefs));
2925
0
            break;
2926
0
        case LY_STMT_GROUPING:
2927
0
            LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)notif, &notif->groupings));
2928
0
            break;
2929
0
        case LY_STMT_EXTENSION_INSTANCE:
2930
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_NOTIFICATION, 0, &notif->exts));
2931
0
            break;
2932
0
        default:
2933
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
2934
0
            return LY_EVALID;
2935
0
        }
2936
0
    }
2937
2938
0
    return ret;
2939
0
}
2940
2941
/**
2942
 * @brief Parse the grouping statement.
2943
 *
2944
 * @param[in] ctx yang parser context for logging.
2945
 * @param[in,out] groupings Groupings to add to.
2946
 *
2947
 * @return LY_ERR values.
2948
 */
2949
LY_ERR
2950
parse_grouping(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node_grp **groupings)
2951
0
{
2952
0
    LY_ERR ret = LY_SUCCESS;
2953
0
    char *buf, *word;
2954
0
    size_t word_len;
2955
0
    enum ly_stmt kw;
2956
0
    struct lysp_node_grp *grp;
2957
2958
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), groupings, grp, next, LY_EMEM);
2959
2960
    /* get value */
2961
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
2962
0
    INSERT_WORD_RET(ctx, buf, grp->name, word, word_len);
2963
0
    grp->nodetype = LYS_GROUPING;
2964
0
    grp->parent = parent;
2965
2966
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
2967
0
        switch (kw) {
2968
0
        case LY_STMT_DESCRIPTION:
2969
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts));
2970
0
            break;
2971
0
        case LY_STMT_REFERENCE:
2972
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts));
2973
0
            break;
2974
0
        case LY_STMT_STATUS:
2975
0
            LY_CHECK_RET(parse_status(ctx, &grp->flags, &grp->exts));
2976
0
            break;
2977
2978
0
        case LY_STMT_ANYDATA:
2979
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "grouping");
2980
        /* fall through */
2981
0
        case LY_STMT_ANYXML:
2982
0
            LY_CHECK_RET(parse_any(ctx, kw, &grp->node, &grp->child));
2983
0
            break;
2984
0
        case LY_STMT_CHOICE:
2985
0
            LY_CHECK_RET(parse_choice(ctx, &grp->node, &grp->child));
2986
0
            break;
2987
0
        case LY_STMT_CONTAINER:
2988
0
            LY_CHECK_RET(parse_container(ctx, &grp->node, &grp->child));
2989
0
            break;
2990
0
        case LY_STMT_LEAF:
2991
0
            LY_CHECK_RET(parse_leaf(ctx, &grp->node, &grp->child));
2992
0
            break;
2993
0
        case LY_STMT_LEAF_LIST:
2994
0
            LY_CHECK_RET(parse_leaflist(ctx, &grp->node, &grp->child));
2995
0
            break;
2996
0
        case LY_STMT_LIST:
2997
0
            LY_CHECK_RET(parse_list(ctx, &grp->node, &grp->child));
2998
0
            break;
2999
0
        case LY_STMT_USES:
3000
0
            LY_CHECK_RET(parse_uses(ctx, &grp->node, &grp->child));
3001
0
            break;
3002
3003
0
        case LY_STMT_TYPEDEF:
3004
0
            LY_CHECK_RET(parse_typedef(ctx, &grp->node, &grp->typedefs));
3005
0
            break;
3006
0
        case LY_STMT_ACTION:
3007
0
            PARSER_CHECK_STMTVER2_RET(ctx, "action", "grouping");
3008
0
            LY_CHECK_RET(parse_action(ctx, &grp->node, &grp->actions));
3009
0
            break;
3010
0
        case LY_STMT_GROUPING:
3011
0
            LY_CHECK_RET(parse_grouping(ctx, &grp->node, &grp->groupings));
3012
0
            break;
3013
0
        case LY_STMT_NOTIFICATION:
3014
0
            PARSER_CHECK_STMTVER2_RET(ctx, "notification", "grouping");
3015
0
            LY_CHECK_RET(parse_notif(ctx, &grp->node, &grp->notifs));
3016
0
            break;
3017
0
        case LY_STMT_EXTENSION_INSTANCE:
3018
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_GROUPING, 0, &grp->exts));
3019
0
            break;
3020
0
        default:
3021
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
3022
0
            return LY_EVALID;
3023
0
        }
3024
0
    }
3025
3026
0
    return ret;
3027
0
}
3028
3029
/**
3030
 * @brief Parse the augment statement.
3031
 *
3032
 * @param[in] ctx yang parser context for logging.
3033
 * @param[in,out] augments Augments to add to.
3034
 *
3035
 * @return LY_ERR values.
3036
 */
3037
LY_ERR
3038
parse_augment(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node_augment **augments)
3039
0
{
3040
0
    LY_ERR ret = LY_SUCCESS;
3041
0
    char *buf, *word;
3042
0
    size_t word_len;
3043
0
    enum ly_stmt kw;
3044
0
    struct lysp_node_augment *aug;
3045
3046
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), augments, aug, next, LY_EMEM);
3047
3048
    /* get value */
3049
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
3050
0
    CHECK_NONEMPTY(ctx, word_len, "augment");
3051
0
    INSERT_WORD_RET(ctx, buf, aug->nodeid, word, word_len);
3052
0
    aug->nodetype = LYS_AUGMENT;
3053
0
    aug->parent = parent;
3054
3055
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3056
0
        switch (kw) {
3057
0
        case LY_STMT_DESCRIPTION:
3058
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts));
3059
0
            break;
3060
0
        case LY_STMT_IF_FEATURE:
3061
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &aug->iffeatures, Y_STR_ARG, &aug->exts));
3062
0
            break;
3063
0
        case LY_STMT_REFERENCE:
3064
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts));
3065
0
            break;
3066
0
        case LY_STMT_STATUS:
3067
0
            LY_CHECK_RET(parse_status(ctx, &aug->flags, &aug->exts));
3068
0
            break;
3069
0
        case LY_STMT_WHEN:
3070
0
            LY_CHECK_RET(parse_when(ctx, &aug->when));
3071
0
            break;
3072
3073
0
        case LY_STMT_ANYDATA:
3074
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "augment");
3075
        /* fall through */
3076
0
        case LY_STMT_ANYXML:
3077
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)aug, &aug->child));
3078
0
            break;
3079
0
        case LY_STMT_CASE:
3080
0
            LY_CHECK_RET(parse_case(ctx, (struct lysp_node *)aug, &aug->child));
3081
0
            break;
3082
0
        case LY_STMT_CHOICE:
3083
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)aug, &aug->child));
3084
0
            break;
3085
0
        case LY_STMT_CONTAINER:
3086
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)aug, &aug->child));
3087
0
            break;
3088
0
        case LY_STMT_LEAF:
3089
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)aug, &aug->child));
3090
0
            break;
3091
0
        case LY_STMT_LEAF_LIST:
3092
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)aug, &aug->child));
3093
0
            break;
3094
0
        case LY_STMT_LIST:
3095
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)aug, &aug->child));
3096
0
            break;
3097
0
        case LY_STMT_USES:
3098
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)aug, &aug->child));
3099
0
            break;
3100
3101
0
        case LY_STMT_ACTION:
3102
0
            PARSER_CHECK_STMTVER2_RET(ctx, "action", "augment");
3103
0
            LY_CHECK_RET(parse_action(ctx, (struct lysp_node *)aug, &aug->actions));
3104
0
            break;
3105
0
        case LY_STMT_NOTIFICATION:
3106
0
            PARSER_CHECK_STMTVER2_RET(ctx, "notification", "augment");
3107
0
            LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)aug, &aug->notifs));
3108
0
            break;
3109
0
        case LY_STMT_EXTENSION_INSTANCE:
3110
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_AUGMENT, 0, &aug->exts));
3111
0
            break;
3112
0
        default:
3113
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
3114
0
            return LY_EVALID;
3115
0
        }
3116
0
    }
3117
3118
0
    return ret;
3119
0
}
3120
3121
/**
3122
 * @brief Parse the uses statement.
3123
 *
3124
 * @param[in] ctx yang parser context for logging.
3125
 * @param[in,out] siblings Siblings to add to.
3126
 *
3127
 * @return LY_ERR values.
3128
 */
3129
LY_ERR
3130
parse_uses(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
3131
0
{
3132
0
    LY_ERR ret = LY_SUCCESS;
3133
0
    char *buf, *word;
3134
0
    size_t word_len;
3135
0
    enum ly_stmt kw;
3136
0
    struct lysp_node_uses *uses;
3137
3138
    /* create uses structure */
3139
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, uses, next, LY_EMEM);
3140
0
    uses->nodetype = LYS_USES;
3141
0
    uses->parent = parent;
3142
3143
    /* get name */
3144
0
    LY_CHECK_RET(get_argument(ctx, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3145
0
    INSERT_WORD_RET(ctx, buf, uses->name, word, word_len);
3146
3147
    /* parse substatements */
3148
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3149
0
        switch (kw) {
3150
0
        case LY_STMT_DESCRIPTION:
3151
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts));
3152
0
            break;
3153
0
        case LY_STMT_IF_FEATURE:
3154
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &uses->iffeatures, Y_STR_ARG, &uses->exts));
3155
0
            break;
3156
0
        case LY_STMT_REFERENCE:
3157
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts));
3158
0
            break;
3159
0
        case LY_STMT_STATUS:
3160
0
            LY_CHECK_RET(parse_status(ctx, &uses->flags, &uses->exts));
3161
0
            break;
3162
0
        case LY_STMT_WHEN:
3163
0
            LY_CHECK_RET(parse_when(ctx, &uses->when));
3164
0
            break;
3165
3166
0
        case LY_STMT_REFINE:
3167
0
            LY_CHECK_RET(parse_refine(ctx, &uses->refines));
3168
0
            break;
3169
0
        case LY_STMT_AUGMENT:
3170
0
            LY_CHECK_RET(parse_augment(ctx, (struct lysp_node *)uses, &uses->augments));
3171
0
            break;
3172
0
        case LY_STMT_EXTENSION_INSTANCE:
3173
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_USES, 0, &uses->exts));
3174
0
            break;
3175
0
        default:
3176
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
3177
0
            return LY_EVALID;
3178
0
        }
3179
0
    }
3180
3181
0
    return ret;
3182
0
}
3183
3184
/**
3185
 * @brief Parse the case statement.
3186
 *
3187
 * @param[in] ctx yang parser context for logging.
3188
 * @param[in,out] siblings Siblings to add to.
3189
 *
3190
 * @return LY_ERR values.
3191
 */
3192
LY_ERR
3193
parse_case(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
3194
0
{
3195
0
    LY_ERR ret = LY_SUCCESS;
3196
0
    char *buf, *word;
3197
0
    size_t word_len;
3198
0
    enum ly_stmt kw;
3199
0
    struct lysp_node_case *cas;
3200
3201
    /* create new case structure */
3202
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, cas, next, LY_EMEM);
3203
0
    cas->nodetype = LYS_CASE;
3204
0
    cas->parent = parent;
3205
3206
    /* get name */
3207
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3208
0
    INSERT_WORD_RET(ctx, buf, cas->name, word, word_len);
3209
3210
    /* parse substatements */
3211
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3212
0
        switch (kw) {
3213
0
        case LY_STMT_DESCRIPTION:
3214
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts));
3215
0
            break;
3216
0
        case LY_STMT_IF_FEATURE:
3217
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &cas->iffeatures, Y_STR_ARG, &cas->exts));
3218
0
            break;
3219
0
        case LY_STMT_REFERENCE:
3220
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts));
3221
0
            break;
3222
0
        case LY_STMT_STATUS:
3223
0
            LY_CHECK_RET(parse_status(ctx, &cas->flags, &cas->exts));
3224
0
            break;
3225
0
        case LY_STMT_WHEN:
3226
0
            LY_CHECK_RET(parse_when(ctx, &cas->when));
3227
0
            break;
3228
3229
0
        case LY_STMT_ANYDATA:
3230
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "case");
3231
        /* fall through */
3232
0
        case LY_STMT_ANYXML:
3233
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)cas, &cas->child));
3234
0
            break;
3235
0
        case LY_STMT_CHOICE:
3236
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)cas, &cas->child));
3237
0
            break;
3238
0
        case LY_STMT_CONTAINER:
3239
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)cas, &cas->child));
3240
0
            break;
3241
0
        case LY_STMT_LEAF:
3242
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)cas, &cas->child));
3243
0
            break;
3244
0
        case LY_STMT_LEAF_LIST:
3245
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)cas, &cas->child));
3246
0
            break;
3247
0
        case LY_STMT_LIST:
3248
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)cas, &cas->child));
3249
0
            break;
3250
0
        case LY_STMT_USES:
3251
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)cas, &cas->child));
3252
0
            break;
3253
0
        case LY_STMT_EXTENSION_INSTANCE:
3254
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CASE, 0, &cas->exts));
3255
0
            break;
3256
0
        default:
3257
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
3258
0
            return LY_EVALID;
3259
0
        }
3260
0
    }
3261
0
    return ret;
3262
0
}
3263
3264
/**
3265
 * @brief Parse the choice statement.
3266
 *
3267
 * @param[in] ctx yang parser context for logging.
3268
 * @param[in,out] siblings Siblings to add to.
3269
 *
3270
 * @return LY_ERR values.
3271
 */
3272
LY_ERR
3273
parse_choice(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
3274
0
{
3275
0
    LY_ERR ret = LY_SUCCESS;
3276
0
    char *buf, *word;
3277
0
    size_t word_len;
3278
0
    enum ly_stmt kw;
3279
0
    struct lysp_node_choice *choice;
3280
3281
    /* create new choice structure */
3282
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, choice, next, LY_EMEM);
3283
0
    choice->nodetype = LYS_CHOICE;
3284
0
    choice->parent = parent;
3285
3286
    /* get name */
3287
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3288
0
    INSERT_WORD_RET(ctx, buf, choice->name, word, word_len);
3289
3290
    /* parse substatements */
3291
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3292
0
        switch (kw) {
3293
0
        case LY_STMT_CONFIG:
3294
0
            LY_CHECK_RET(parse_config(ctx, &choice->flags, &choice->exts));
3295
0
            break;
3296
0
        case LY_STMT_DESCRIPTION:
3297
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &choice->dsc, Y_STR_ARG, &choice->exts));
3298
0
            break;
3299
0
        case LY_STMT_IF_FEATURE:
3300
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &choice->iffeatures, Y_STR_ARG, &choice->exts));
3301
0
            break;
3302
0
        case LY_STMT_MANDATORY:
3303
0
            LY_CHECK_RET(parse_mandatory(ctx, &choice->flags, &choice->exts));
3304
0
            break;
3305
0
        case LY_STMT_REFERENCE:
3306
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &choice->ref, Y_STR_ARG, &choice->exts));
3307
0
            break;
3308
0
        case LY_STMT_STATUS:
3309
0
            LY_CHECK_RET(parse_status(ctx, &choice->flags, &choice->exts));
3310
0
            break;
3311
0
        case LY_STMT_WHEN:
3312
0
            LY_CHECK_RET(parse_when(ctx, &choice->when));
3313
0
            break;
3314
0
        case LY_STMT_DEFAULT:
3315
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &choice->dflt.str, Y_PREF_IDENTIF_ARG,
3316
0
                    &choice->exts));
3317
0
            choice->dflt.mod = ctx->parsed_mod;
3318
0
            break;
3319
3320
0
        case LY_STMT_ANYDATA:
3321
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "choice");
3322
        /* fall through */
3323
0
        case LY_STMT_ANYXML:
3324
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)choice, &choice->child));
3325
0
            break;
3326
0
        case LY_STMT_CASE:
3327
0
            LY_CHECK_RET(parse_case(ctx, (struct lysp_node *)choice, &choice->child));
3328
0
            break;
3329
0
        case LY_STMT_CHOICE:
3330
0
            PARSER_CHECK_STMTVER2_RET(ctx, "choice", "choice");
3331
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)choice, &choice->child));
3332
0
            break;
3333
0
        case LY_STMT_CONTAINER:
3334
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)choice, &choice->child));
3335
0
            break;
3336
0
        case LY_STMT_LEAF:
3337
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)choice, &choice->child));
3338
0
            break;
3339
0
        case LY_STMT_LEAF_LIST:
3340
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)choice, &choice->child));
3341
0
            break;
3342
0
        case LY_STMT_LIST:
3343
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)choice, &choice->child));
3344
0
            break;
3345
0
        case LY_STMT_EXTENSION_INSTANCE:
3346
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CHOICE, 0, &choice->exts));
3347
0
            break;
3348
0
        default:
3349
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
3350
0
            return LY_EVALID;
3351
0
        }
3352
0
    }
3353
0
    return ret;
3354
0
}
3355
3356
/**
3357
 * @brief Parse the container statement.
3358
 *
3359
 * @param[in] ctx yang parser context for logging.
3360
 * @param[in,out] siblings Siblings to add to.
3361
 *
3362
 * @return LY_ERR values.
3363
 */
3364
LY_ERR
3365
parse_container(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
3366
0
{
3367
0
    LY_ERR ret = 0;
3368
0
    char *buf, *word;
3369
0
    size_t word_len;
3370
0
    enum ly_stmt kw;
3371
0
    struct lysp_node_container *cont;
3372
3373
    /* create new container structure */
3374
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, cont, next, LY_EMEM);
3375
0
    cont->nodetype = LYS_CONTAINER;
3376
0
    cont->parent = parent;
3377
3378
    /* get name */
3379
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3380
0
    INSERT_WORD_RET(ctx, buf, cont->name, word, word_len);
3381
3382
    /* parse substatements */
3383
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3384
0
        switch (kw) {
3385
0
        case LY_STMT_CONFIG:
3386
0
            LY_CHECK_RET(parse_config(ctx, &cont->flags, &cont->exts));
3387
0
            break;
3388
0
        case LY_STMT_DESCRIPTION:
3389
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts));
3390
0
            break;
3391
0
        case LY_STMT_IF_FEATURE:
3392
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &cont->iffeatures, Y_STR_ARG, &cont->exts));
3393
0
            break;
3394
0
        case LY_STMT_REFERENCE:
3395
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts));
3396
0
            break;
3397
0
        case LY_STMT_STATUS:
3398
0
            LY_CHECK_RET(parse_status(ctx, &cont->flags, &cont->exts));
3399
0
            break;
3400
0
        case LY_STMT_WHEN:
3401
0
            LY_CHECK_RET(parse_when(ctx, &cont->when));
3402
0
            break;
3403
0
        case LY_STMT_PRESENCE:
3404
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts));
3405
0
            break;
3406
3407
0
        case LY_STMT_ANYDATA:
3408
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "container");
3409
        /* fall through */
3410
0
        case LY_STMT_ANYXML:
3411
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)cont, &cont->child));
3412
0
            break;
3413
0
        case LY_STMT_CHOICE:
3414
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)cont, &cont->child));
3415
0
            break;
3416
0
        case LY_STMT_CONTAINER:
3417
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)cont, &cont->child));
3418
0
            break;
3419
0
        case LY_STMT_LEAF:
3420
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)cont, &cont->child));
3421
0
            break;
3422
0
        case LY_STMT_LEAF_LIST:
3423
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)cont, &cont->child));
3424
0
            break;
3425
0
        case LY_STMT_LIST:
3426
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)cont, &cont->child));
3427
0
            break;
3428
0
        case LY_STMT_USES:
3429
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)cont, &cont->child));
3430
0
            break;
3431
3432
0
        case LY_STMT_TYPEDEF:
3433
0
            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)cont, &cont->typedefs));
3434
0
            break;
3435
0
        case LY_STMT_MUST:
3436
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &cont->musts));
3437
0
            break;
3438
0
        case LY_STMT_ACTION:
3439
0
            PARSER_CHECK_STMTVER2_RET(ctx, "action", "container");
3440
0
            LY_CHECK_RET(parse_action(ctx, (struct lysp_node *)cont, &cont->actions));
3441
0
            break;
3442
0
        case LY_STMT_GROUPING:
3443
0
            LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)cont, &cont->groupings));
3444
0
            break;
3445
0
        case LY_STMT_NOTIFICATION:
3446
0
            PARSER_CHECK_STMTVER2_RET(ctx, "notification", "container");
3447
0
            LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)cont, &cont->notifs));
3448
0
            break;
3449
0
        case LY_STMT_EXTENSION_INSTANCE:
3450
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CONTAINER, 0, &cont->exts));
3451
0
            break;
3452
0
        default:
3453
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
3454
0
            return LY_EVALID;
3455
0
        }
3456
0
    }
3457
3458
0
    return ret;
3459
0
}
3460
3461
/**
3462
 * @brief Parse the list statement.
3463
 *
3464
 * @param[in] ctx yang parser context for logging.
3465
 * @param[in,out] siblings Siblings to add to.
3466
 *
3467
 * @return LY_ERR values.
3468
 */
3469
LY_ERR
3470
parse_list(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings)
3471
0
{
3472
0
    LY_ERR ret = LY_SUCCESS;
3473
0
    char *buf, *word;
3474
0
    size_t word_len;
3475
0
    enum ly_stmt kw;
3476
0
    struct lysp_node_list *list;
3477
3478
    /* create new list structure */
3479
0
    LY_LIST_NEW_RET(PARSER_CTX(ctx), siblings, list, next, LY_EMEM);
3480
0
    list->nodetype = LYS_LIST;
3481
0
    list->parent = parent;
3482
3483
    /* get name */
3484
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3485
0
    INSERT_WORD_RET(ctx, buf, list->name, word, word_len);
3486
3487
    /* parse substatements */
3488
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3489
0
        switch (kw) {
3490
0
        case LY_STMT_CONFIG:
3491
0
            LY_CHECK_RET(parse_config(ctx, &list->flags, &list->exts));
3492
0
            break;
3493
0
        case LY_STMT_DESCRIPTION:
3494
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts));
3495
0
            break;
3496
0
        case LY_STMT_IF_FEATURE:
3497
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &list->iffeatures, Y_STR_ARG, &list->exts));
3498
0
            break;
3499
0
        case LY_STMT_REFERENCE:
3500
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts));
3501
0
            break;
3502
0
        case LY_STMT_STATUS:
3503
0
            LY_CHECK_RET(parse_status(ctx, &list->flags, &list->exts));
3504
0
            break;
3505
0
        case LY_STMT_WHEN:
3506
0
            LY_CHECK_RET(parse_when(ctx, &list->when));
3507
0
            break;
3508
0
        case LY_STMT_KEY:
3509
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts));
3510
0
            break;
3511
0
        case LY_STMT_MAX_ELEMENTS:
3512
0
            LY_CHECK_RET(parse_maxelements(ctx, &list->max, &list->flags, &list->exts));
3513
0
            break;
3514
0
        case LY_STMT_MIN_ELEMENTS:
3515
0
            LY_CHECK_RET(parse_minelements(ctx, &list->min, &list->flags, &list->exts));
3516
0
            break;
3517
0
        case LY_STMT_ORDERED_BY:
3518
0
            LY_CHECK_RET(parse_orderedby(ctx, &list->flags, &list->exts));
3519
0
            break;
3520
0
        case LY_STMT_UNIQUE:
3521
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_UNIQUE, &list->uniques, Y_STR_ARG, &list->exts));
3522
0
            break;
3523
3524
0
        case LY_STMT_ANYDATA:
3525
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "list");
3526
        /* fall through */
3527
0
        case LY_STMT_ANYXML:
3528
0
            LY_CHECK_RET(parse_any(ctx, kw, (struct lysp_node *)list, &list->child));
3529
0
            break;
3530
0
        case LY_STMT_CHOICE:
3531
0
            LY_CHECK_RET(parse_choice(ctx, (struct lysp_node *)list, &list->child));
3532
0
            break;
3533
0
        case LY_STMT_CONTAINER:
3534
0
            LY_CHECK_RET(parse_container(ctx, (struct lysp_node *)list, &list->child));
3535
0
            break;
3536
0
        case LY_STMT_LEAF:
3537
0
            LY_CHECK_RET(parse_leaf(ctx, (struct lysp_node *)list, &list->child));
3538
0
            break;
3539
0
        case LY_STMT_LEAF_LIST:
3540
0
            LY_CHECK_RET(parse_leaflist(ctx, (struct lysp_node *)list, &list->child));
3541
0
            break;
3542
0
        case LY_STMT_LIST:
3543
0
            LY_CHECK_RET(parse_list(ctx, (struct lysp_node *)list, &list->child));
3544
0
            break;
3545
0
        case LY_STMT_USES:
3546
0
            LY_CHECK_RET(parse_uses(ctx, (struct lysp_node *)list, &list->child));
3547
0
            break;
3548
3549
0
        case LY_STMT_TYPEDEF:
3550
0
            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node *)list, &list->typedefs));
3551
0
            break;
3552
0
        case LY_STMT_MUST:
3553
0
            LY_CHECK_RET(parse_restrs(ctx, kw, &list->musts));
3554
0
            break;
3555
0
        case LY_STMT_ACTION:
3556
0
            PARSER_CHECK_STMTVER2_RET(ctx, "action", "list");
3557
0
            LY_CHECK_RET(parse_action(ctx, (struct lysp_node *)list, &list->actions));
3558
0
            break;
3559
0
        case LY_STMT_GROUPING:
3560
0
            LY_CHECK_RET(parse_grouping(ctx, (struct lysp_node *)list, &list->groupings));
3561
0
            break;
3562
0
        case LY_STMT_NOTIFICATION:
3563
0
            PARSER_CHECK_STMTVER2_RET(ctx, "notification", "list");
3564
0
            LY_CHECK_RET(parse_notif(ctx, (struct lysp_node *)list, &list->notifs));
3565
0
            break;
3566
0
        case LY_STMT_EXTENSION_INSTANCE:
3567
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_LIST, 0, &list->exts));
3568
0
            break;
3569
0
        default:
3570
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
3571
0
            return LY_EVALID;
3572
0
        }
3573
0
    }
3574
3575
0
    return ret;
3576
0
}
3577
3578
/**
3579
 * @brief Parse the yin-element statement.
3580
 *
3581
 * @param[in] ctx yang parser context for logging.
3582
 * @param[in,out] flags Flags to write to.
3583
 * @param[in,out] exts Extension instances to add to.
3584
 *
3585
 * @return LY_ERR values.
3586
 */
3587
static LY_ERR
3588
parse_yinelement(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
3589
0
{
3590
0
    LY_ERR ret = LY_SUCCESS;
3591
0
    char *buf, *word;
3592
0
    size_t word_len;
3593
0
    enum ly_stmt kw;
3594
3595
0
    if (*flags & LYS_YINELEM_MASK) {
3596
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
3597
0
        return LY_EVALID;
3598
0
    }
3599
3600
    /* get value */
3601
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
3602
3603
0
    if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
3604
0
        *flags |= LYS_YINELEM_TRUE;
3605
0
    } else if ((word_len == ly_strlen_const("false")) && !strncmp(word, "false", word_len)) {
3606
0
        *flags |= LYS_YINELEM_FALSE;
3607
0
    } else {
3608
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
3609
0
        free(buf);
3610
0
        return LY_EVALID;
3611
0
    }
3612
0
    free(buf);
3613
3614
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3615
0
        switch (kw) {
3616
0
        case LY_STMT_EXTENSION_INSTANCE:
3617
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YIN_ELEMENT, 0, exts));
3618
0
            LY_CHECK_RET(ret);
3619
0
            break;
3620
0
        default:
3621
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
3622
0
            return LY_EVALID;
3623
0
        }
3624
0
    }
3625
0
    return ret;
3626
0
}
3627
3628
/**
3629
 * @brief Parse the argument statement.
3630
 *
3631
 * @param[in] ctx yang parser context for logging.
3632
 * @param[in,out] argument Value to write to.
3633
 * @param[in,out] flags Flags to write to.
3634
 * @param[in,out] exts Extension instances to add to.
3635
 *
3636
 * @return LY_ERR values.
3637
 */
3638
static LY_ERR
3639
parse_argument(struct lys_yang_parser_ctx *ctx, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
3640
0
{
3641
0
    LY_ERR ret = LY_SUCCESS;
3642
0
    char *buf, *word;
3643
0
    size_t word_len;
3644
0
    enum ly_stmt kw;
3645
3646
0
    if (*argument) {
3647
0
        LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "argument");
3648
0
        return LY_EVALID;
3649
0
    }
3650
3651
    /* get value */
3652
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3653
0
    INSERT_WORD_RET(ctx, buf, *argument, word, word_len);
3654
3655
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3656
0
        switch (kw) {
3657
0
        case LY_STMT_YIN_ELEMENT:
3658
0
            LY_CHECK_RET(parse_yinelement(ctx, flags, exts));
3659
0
            break;
3660
0
        case LY_STMT_EXTENSION_INSTANCE:
3661
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_ARGUMENT, 0, exts));
3662
0
            break;
3663
0
        default:
3664
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
3665
0
            return LY_EVALID;
3666
0
        }
3667
0
    }
3668
0
    return ret;
3669
0
}
3670
3671
/**
3672
 * @brief Parse the extension statement.
3673
 *
3674
 * @param[in] ctx yang parser context for logging.
3675
 * @param[in,out] extensions Extensions to add to.
3676
 *
3677
 * @return LY_ERR values.
3678
 */
3679
static LY_ERR
3680
parse_extension(struct lys_yang_parser_ctx *ctx, struct lysp_ext **extensions)
3681
0
{
3682
0
    LY_ERR ret = LY_SUCCESS;
3683
0
    char *buf, *word;
3684
0
    size_t word_len;
3685
0
    enum ly_stmt kw;
3686
0
    struct lysp_ext *ex;
3687
3688
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *extensions, ex, LY_EMEM);
3689
3690
    /* get value */
3691
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
3692
0
    INSERT_WORD_RET(ctx, buf, ex->name, word, word_len);
3693
3694
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3695
0
        switch (kw) {
3696
0
        case LY_STMT_DESCRIPTION:
3697
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts));
3698
0
            break;
3699
0
        case LY_STMT_REFERENCE:
3700
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts));
3701
0
            break;
3702
0
        case LY_STMT_STATUS:
3703
0
            LY_CHECK_RET(parse_status(ctx, &ex->flags, &ex->exts));
3704
0
            break;
3705
0
        case LY_STMT_ARGUMENT:
3706
0
            LY_CHECK_RET(parse_argument(ctx, &ex->argname, &ex->flags, &ex->exts));
3707
0
            break;
3708
0
        case LY_STMT_EXTENSION_INSTANCE:
3709
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_EXTENSION, 0, &ex->exts));
3710
0
            break;
3711
0
        default:
3712
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
3713
0
            return LY_EVALID;
3714
0
        }
3715
0
    }
3716
0
    return ret;
3717
0
}
3718
3719
/**
3720
 * @brief Parse the deviate statement.
3721
 *
3722
 * @param[in] ctx yang parser context for logging.
3723
 * @param[in,out] deviates Deviates to add to.
3724
 *
3725
 * @return LY_ERR values.
3726
 */
3727
LY_ERR
3728
parse_deviate(struct lys_yang_parser_ctx *ctx, struct lysp_deviate **deviates)
3729
0
{
3730
0
    LY_ERR ret = LY_SUCCESS;
3731
0
    char *buf, *word;
3732
0
    size_t word_len, dev_mod;
3733
0
    enum ly_stmt kw;
3734
0
    struct lysp_deviate *d;
3735
0
    struct lysp_deviate_add *d_add = NULL;
3736
0
    struct lysp_deviate_rpl *d_rpl = NULL;
3737
0
    struct lysp_deviate_del *d_del = NULL;
3738
0
    const char **d_units = NULL;
3739
0
    struct lysp_qname **d_uniques = NULL, **d_dflts = NULL;
3740
0
    struct lysp_restr **d_musts = NULL;
3741
0
    uint16_t *d_flags = 0;
3742
0
    uint32_t *d_min = 0, *d_max = 0;
3743
3744
    /* get value */
3745
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
3746
3747
0
    if ((word_len == ly_strlen_const("not-supported")) && !strncmp(word, "not-supported", word_len)) {
3748
0
        dev_mod = LYS_DEV_NOT_SUPPORTED;
3749
0
    } else if ((word_len == ly_strlen_const("add")) && !strncmp(word, "add", word_len)) {
3750
0
        dev_mod = LYS_DEV_ADD;
3751
0
    } else if ((word_len == ly_strlen_const("replace")) && !strncmp(word, "replace", word_len)) {
3752
0
        dev_mod = LYS_DEV_REPLACE;
3753
0
    } else if ((word_len == ly_strlen_const("delete")) && !strncmp(word, "delete", word_len)) {
3754
0
        dev_mod = LYS_DEV_DELETE;
3755
0
    } else {
3756
0
        LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "deviate");
3757
0
        free(buf);
3758
0
        return LY_EVALID;
3759
0
    }
3760
0
    free(buf);
3761
3762
    /* create structure */
3763
0
    switch (dev_mod) {
3764
0
    case LYS_DEV_NOT_SUPPORTED:
3765
0
        d = calloc(1, sizeof *d);
3766
0
        LY_CHECK_ERR_RET(!d, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
3767
0
        break;
3768
0
    case LYS_DEV_ADD:
3769
0
        d_add = calloc(1, sizeof *d_add);
3770
0
        LY_CHECK_ERR_RET(!d_add, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
3771
0
        d = (struct lysp_deviate *)d_add;
3772
0
        d_units = &d_add->units;
3773
0
        d_uniques = &d_add->uniques;
3774
0
        d_dflts = &d_add->dflts;
3775
0
        d_musts = &d_add->musts;
3776
0
        d_flags = &d_add->flags;
3777
0
        d_min = &d_add->min;
3778
0
        d_max = &d_add->max;
3779
0
        break;
3780
0
    case LYS_DEV_REPLACE:
3781
0
        d_rpl = calloc(1, sizeof *d_rpl);
3782
0
        LY_CHECK_ERR_RET(!d_rpl, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
3783
0
        d = (struct lysp_deviate *)d_rpl;
3784
0
        d_units = &d_rpl->units;
3785
0
        d_flags = &d_rpl->flags;
3786
0
        d_min = &d_rpl->min;
3787
0
        d_max = &d_rpl->max;
3788
0
        break;
3789
0
    case LYS_DEV_DELETE:
3790
0
        d_del = calloc(1, sizeof *d_del);
3791
0
        LY_CHECK_ERR_RET(!d_del, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
3792
0
        d = (struct lysp_deviate *)d_del;
3793
0
        d_units = &d_del->units;
3794
0
        d_uniques = &d_del->uniques;
3795
0
        d_dflts = &d_del->dflts;
3796
0
        d_musts = &d_del->musts;
3797
0
        break;
3798
0
    default:
3799
0
        assert(0);
3800
0
        LOGINT_RET(PARSER_CTX(ctx));
3801
0
    }
3802
0
    d->mod = dev_mod;
3803
3804
    /* insert into siblings */
3805
0
    LY_LIST_INSERT(deviates, d, next);
3806
3807
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
3808
0
        switch (kw) {
3809
0
        case LY_STMT_CONFIG:
3810
0
            switch (dev_mod) {
3811
0
            case LYS_DEV_NOT_SUPPORTED:
3812
0
            case LYS_DEV_DELETE:
3813
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3814
0
                return LY_EVALID;
3815
0
            default:
3816
0
                LY_CHECK_RET(parse_config(ctx, d_flags, &d->exts));
3817
0
                break;
3818
0
            }
3819
0
            break;
3820
0
        case LY_STMT_DEFAULT:
3821
0
            switch (dev_mod) {
3822
0
            case LYS_DEV_NOT_SUPPORTED:
3823
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3824
0
                return LY_EVALID;
3825
0
            case LYS_DEV_REPLACE:
3826
0
                LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &d_rpl->dflt.str, Y_STR_ARG, &d->exts));
3827
0
                d_rpl->dflt.mod = ctx->parsed_mod;
3828
0
                break;
3829
0
            default:
3830
0
                LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, d_dflts, Y_STR_ARG, &d->exts));
3831
0
                break;
3832
0
            }
3833
0
            break;
3834
0
        case LY_STMT_MANDATORY:
3835
0
            switch (dev_mod) {
3836
0
            case LYS_DEV_NOT_SUPPORTED:
3837
0
            case LYS_DEV_DELETE:
3838
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3839
0
                return LY_EVALID;
3840
0
            default:
3841
0
                LY_CHECK_RET(parse_mandatory(ctx, d_flags, &d->exts));
3842
0
                break;
3843
0
            }
3844
0
            break;
3845
0
        case LY_STMT_MAX_ELEMENTS:
3846
0
            switch (dev_mod) {
3847
0
            case LYS_DEV_NOT_SUPPORTED:
3848
0
            case LYS_DEV_DELETE:
3849
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3850
0
                return LY_EVALID;
3851
0
            default:
3852
0
                LY_CHECK_RET(parse_maxelements(ctx, d_max, d_flags, &d->exts));
3853
0
                break;
3854
0
            }
3855
0
            break;
3856
0
        case LY_STMT_MIN_ELEMENTS:
3857
0
            switch (dev_mod) {
3858
0
            case LYS_DEV_NOT_SUPPORTED:
3859
0
            case LYS_DEV_DELETE:
3860
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3861
0
                return LY_EVALID;
3862
0
            default:
3863
0
                LY_CHECK_RET(parse_minelements(ctx, d_min, d_flags, &d->exts));
3864
0
                break;
3865
0
            }
3866
0
            break;
3867
0
        case LY_STMT_MUST:
3868
0
            switch (dev_mod) {
3869
0
            case LYS_DEV_NOT_SUPPORTED:
3870
0
            case LYS_DEV_REPLACE:
3871
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3872
0
                return LY_EVALID;
3873
0
            default:
3874
0
                LY_CHECK_RET(parse_restrs(ctx, kw, d_musts));
3875
0
                break;
3876
0
            }
3877
0
            break;
3878
0
        case LY_STMT_TYPE:
3879
0
            switch (dev_mod) {
3880
0
            case LYS_DEV_NOT_SUPPORTED:
3881
0
            case LYS_DEV_ADD:
3882
0
            case LYS_DEV_DELETE:
3883
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3884
0
                return LY_EVALID;
3885
0
            default:
3886
0
                if (d_rpl->type) {
3887
0
                    LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
3888
0
                    return LY_EVALID;
3889
0
                }
3890
0
                d_rpl->type = calloc(1, sizeof *d_rpl->type);
3891
0
                LY_CHECK_ERR_RET(!d_rpl->type, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
3892
0
                LY_CHECK_RET(parse_type(ctx, d_rpl->type));
3893
0
                break;
3894
0
            }
3895
0
            break;
3896
0
        case LY_STMT_UNIQUE:
3897
0
            switch (dev_mod) {
3898
0
            case LYS_DEV_NOT_SUPPORTED:
3899
0
            case LYS_DEV_REPLACE:
3900
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3901
0
                return LY_EVALID;
3902
0
            default:
3903
0
                LY_CHECK_RET(parse_qnames(ctx, LY_STMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts));
3904
0
                break;
3905
0
            }
3906
0
            break;
3907
0
        case LY_STMT_UNITS:
3908
0
            switch (dev_mod) {
3909
0
            case LYS_DEV_NOT_SUPPORTED:
3910
0
                LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
3911
0
                return LY_EVALID;
3912
0
            default:
3913
0
                LY_CHECK_RET(parse_text_field(ctx, LY_STMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts));
3914
0
                break;
3915
0
            }
3916
0
            break;
3917
0
        case LY_STMT_EXTENSION_INSTANCE:
3918
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_DEVIATE, 0, &d->exts));
3919
0
            break;
3920
0
        default:
3921
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
3922
0
            return LY_EVALID;
3923
0
        }
3924
0
    }
3925
0
    return ret;
3926
0
}
3927
3928
/**
3929
 * @brief Parse the deviation statement.
3930
 *
3931
 * @param[in] ctx yang parser context for logging.
3932
 * @param[in,out] deviations Deviations to add to.
3933
 *
3934
 * @return LY_ERR values.
3935
 */
3936
LY_ERR
3937
parse_deviation(struct lys_yang_parser_ctx *ctx, struct lysp_deviation **deviations)
3938
0
{
3939
0
    LY_ERR ret = LY_SUCCESS;
3940
0
    char *buf, *word;
3941
0
    size_t word_len;
3942
0
    enum ly_stmt kw;
3943
0
    struct lysp_deviation *dev;
3944
3945
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *deviations, dev, LY_EMEM);
3946
3947
    /* get value */
3948
0
    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
3949
0
    CHECK_NONEMPTY(ctx, word_len, "deviation");
3950
0
    INSERT_WORD_RET(ctx, buf, dev->nodeid, word, word_len);
3951
3952
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
3953
0
        switch (kw) {
3954
0
        case LY_STMT_DESCRIPTION:
3955
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts));
3956
0
            break;
3957
0
        case LY_STMT_DEVIATE:
3958
0
            LY_CHECK_RET(parse_deviate(ctx, &dev->deviates));
3959
0
            break;
3960
0
        case LY_STMT_REFERENCE:
3961
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts));
3962
0
            break;
3963
0
        case LY_STMT_EXTENSION_INSTANCE:
3964
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_DEVIATION, 0, &dev->exts));
3965
0
            break;
3966
0
        default:
3967
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
3968
0
            return LY_EVALID;
3969
0
        }
3970
0
    }
3971
0
    LY_CHECK_RET(ret);
3972
0
checks:
3973
    /* mandatory substatements */
3974
0
    if (!dev->deviates) {
3975
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
3976
0
        return LY_EVALID;
3977
0
    }
3978
3979
0
    return ret;
3980
0
}
3981
3982
/**
3983
 * @brief Parse the feature statement.
3984
 *
3985
 * @param[in] ctx yang parser context for logging.
3986
 * @param[in,out] features Features to add to.
3987
 *
3988
 * @return LY_ERR values.
3989
 */
3990
LY_ERR
3991
parse_feature(struct lys_yang_parser_ctx *ctx, struct lysp_feature **features)
3992
0
{
3993
0
    LY_ERR ret = LY_SUCCESS;
3994
0
    char *buf, *word;
3995
0
    size_t word_len;
3996
0
    enum ly_stmt kw;
3997
0
    struct lysp_feature *feat;
3998
3999
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *features, feat, LY_EMEM);
4000
4001
    /* get value */
4002
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
4003
0
    INSERT_WORD_RET(ctx, buf, feat->name, word, word_len);
4004
4005
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
4006
0
        switch (kw) {
4007
0
        case LY_STMT_DESCRIPTION:
4008
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts));
4009
0
            break;
4010
0
        case LY_STMT_IF_FEATURE:
4011
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &feat->iffeatures, Y_STR_ARG, &feat->exts));
4012
0
            break;
4013
0
        case LY_STMT_REFERENCE:
4014
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts));
4015
0
            break;
4016
0
        case LY_STMT_STATUS:
4017
0
            LY_CHECK_RET(parse_status(ctx, &feat->flags, &feat->exts));
4018
0
            break;
4019
0
        case LY_STMT_EXTENSION_INSTANCE:
4020
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_FEATURE, 0, &feat->exts));
4021
0
            break;
4022
0
        default:
4023
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
4024
0
            return LY_EVALID;
4025
0
        }
4026
0
    }
4027
0
    return ret;
4028
0
}
4029
4030
/**
4031
 * @brief Parse the identity statement.
4032
 *
4033
 * @param[in] ctx yang parser context for logging.
4034
 * @param[in,out] identities Identities to add to.
4035
 *
4036
 * @return LY_ERR values.
4037
 */
4038
LY_ERR
4039
parse_identity(struct lys_yang_parser_ctx *ctx, struct lysp_ident **identities)
4040
0
{
4041
0
    LY_ERR ret = LY_SUCCESS;
4042
0
    char *buf, *word;
4043
0
    size_t word_len;
4044
0
    enum ly_stmt kw;
4045
0
    struct lysp_ident *ident;
4046
4047
0
    LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *identities, ident, LY_EMEM);
4048
4049
    /* get value */
4050
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
4051
0
    INSERT_WORD_RET(ctx, buf, ident->name, word, word_len);
4052
4053
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
4054
0
        switch (kw) {
4055
0
        case LY_STMT_DESCRIPTION:
4056
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
4057
0
            break;
4058
0
        case LY_STMT_IF_FEATURE:
4059
0
            PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", "identity");
4060
0
            LY_CHECK_RET(parse_qnames(ctx, LY_STMT_IF_FEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts));
4061
0
            break;
4062
0
        case LY_STMT_REFERENCE:
4063
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts));
4064
0
            break;
4065
0
        case LY_STMT_STATUS:
4066
0
            LY_CHECK_RET(parse_status(ctx, &ident->flags, &ident->exts));
4067
0
            break;
4068
0
        case LY_STMT_BASE:
4069
0
            if (ident->bases && (ctx->parsed_mod->version < LYS_VERSION_1_1)) {
4070
0
                LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
4071
0
                return LY_EVALID;
4072
0
            }
4073
0
            LY_CHECK_RET(parse_text_fields(ctx, LY_STMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts));
4074
0
            break;
4075
0
        case LY_STMT_EXTENSION_INSTANCE:
4076
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_IDENTITY, 0, &ident->exts));
4077
0
            break;
4078
0
        default:
4079
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
4080
0
            return LY_EVALID;
4081
0
        }
4082
0
    }
4083
0
    return ret;
4084
0
}
4085
4086
/**
4087
 * @brief Parse module substatements.
4088
 *
4089
 * @param[in] ctx yang parser context for logging.
4090
 * @param[in,out] mod Module to write to.
4091
 *
4092
 * @return LY_ERR values.
4093
 */
4094
LY_ERR
4095
parse_module(struct lys_yang_parser_ctx *ctx, struct lysp_module *mod)
4096
0
{
4097
0
    LY_ERR ret = 0;
4098
0
    char *buf, *word;
4099
0
    size_t word_len;
4100
0
    enum ly_stmt kw, prev_kw = 0;
4101
0
    enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
4102
0
    const struct lysp_submodule *dup;
4103
4104
0
    mod->is_submod = 0;
4105
4106
    /* module name */
4107
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
4108
0
    INSERT_WORD_RET(ctx, buf, mod->mod->name, word, word_len);
4109
4110
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
4111
4112
0
#define CHECK_ORDER(SECTION) \
4113
0
        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
4114
4115
0
        switch (kw) {
4116
        /* module header */
4117
0
        case LY_STMT_NAMESPACE:
4118
0
        case LY_STMT_PREFIX:
4119
0
            CHECK_ORDER(Y_MOD_MODULE_HEADER);
4120
0
            break;
4121
0
        case LY_STMT_YANG_VERSION:
4122
0
            CHECK_ORDER(Y_MOD_MODULE_HEADER);
4123
0
            break;
4124
        /* linkage */
4125
0
        case LY_STMT_INCLUDE:
4126
0
        case LY_STMT_IMPORT:
4127
0
            CHECK_ORDER(Y_MOD_LINKAGE);
4128
0
            break;
4129
        /* meta */
4130
0
        case LY_STMT_ORGANIZATION:
4131
0
        case LY_STMT_CONTACT:
4132
0
        case LY_STMT_DESCRIPTION:
4133
0
        case LY_STMT_REFERENCE:
4134
0
            CHECK_ORDER(Y_MOD_META);
4135
0
            break;
4136
4137
        /* revision */
4138
0
        case LY_STMT_REVISION:
4139
0
            CHECK_ORDER(Y_MOD_REVISION);
4140
0
            break;
4141
        /* body */
4142
0
        case LY_STMT_ANYDATA:
4143
0
        case LY_STMT_ANYXML:
4144
0
        case LY_STMT_AUGMENT:
4145
0
        case LY_STMT_CHOICE:
4146
0
        case LY_STMT_CONTAINER:
4147
0
        case LY_STMT_DEVIATION:
4148
0
        case LY_STMT_EXTENSION:
4149
0
        case LY_STMT_FEATURE:
4150
0
        case LY_STMT_GROUPING:
4151
0
        case LY_STMT_IDENTITY:
4152
0
        case LY_STMT_LEAF:
4153
0
        case LY_STMT_LEAF_LIST:
4154
0
        case LY_STMT_LIST:
4155
0
        case LY_STMT_NOTIFICATION:
4156
0
        case LY_STMT_RPC:
4157
0
        case LY_STMT_TYPEDEF:
4158
0
        case LY_STMT_USES:
4159
0
        case LY_STMT_EXTENSION_INSTANCE:
4160
0
            mod_stmt = Y_MOD_BODY;
4161
0
            break;
4162
0
        default:
4163
            /* error handled in the next switch */
4164
0
            break;
4165
0
        }
4166
0
#undef CHECK_ORDER
4167
4168
0
        prev_kw = kw;
4169
0
        switch (kw) {
4170
        /* module header */
4171
0
        case LY_STMT_YANG_VERSION:
4172
0
            LY_CHECK_RET(parse_yangversion(ctx, &mod->version, &mod->exts));
4173
0
            break;
4174
0
        case LY_STMT_NAMESPACE:
4175
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_NAMESPACE, 0, &mod->mod->ns, Y_STR_ARG, &mod->exts));
4176
0
            break;
4177
0
        case LY_STMT_PREFIX:
4178
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, &mod->mod->prefix, Y_IDENTIF_ARG, &mod->exts));
4179
0
            break;
4180
4181
        /* linkage */
4182
0
        case LY_STMT_INCLUDE:
4183
0
            LY_CHECK_RET(parse_include(ctx, mod->mod->name, &mod->includes));
4184
0
            break;
4185
0
        case LY_STMT_IMPORT:
4186
0
            LY_CHECK_RET(parse_import(ctx, mod->mod->prefix, &mod->imports));
4187
0
            break;
4188
4189
        /* meta */
4190
0
        case LY_STMT_ORGANIZATION:
4191
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ORGANIZATION, 0, &mod->mod->org, Y_STR_ARG, &mod->exts));
4192
0
            break;
4193
0
        case LY_STMT_CONTACT:
4194
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_CONTACT, 0, &mod->mod->contact, Y_STR_ARG, &mod->exts));
4195
0
            break;
4196
0
        case LY_STMT_DESCRIPTION:
4197
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &mod->mod->dsc, Y_STR_ARG, &mod->exts));
4198
0
            break;
4199
0
        case LY_STMT_REFERENCE:
4200
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &mod->mod->ref, Y_STR_ARG, &mod->exts));
4201
0
            break;
4202
4203
        /* revision */
4204
0
        case LY_STMT_REVISION:
4205
0
            LY_CHECK_RET(parse_revision(ctx, &mod->revs));
4206
0
            break;
4207
4208
        /* body */
4209
0
        case LY_STMT_ANYDATA:
4210
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "module");
4211
        /* fall through */
4212
0
        case LY_STMT_ANYXML:
4213
0
            LY_CHECK_RET(parse_any(ctx, kw, NULL, &mod->data));
4214
0
            break;
4215
0
        case LY_STMT_CHOICE:
4216
0
            LY_CHECK_RET(parse_choice(ctx, NULL, &mod->data));
4217
0
            break;
4218
0
        case LY_STMT_CONTAINER:
4219
0
            LY_CHECK_RET(parse_container(ctx, NULL, &mod->data));
4220
0
            break;
4221
0
        case LY_STMT_LEAF:
4222
0
            LY_CHECK_RET(parse_leaf(ctx, NULL, &mod->data));
4223
0
            break;
4224
0
        case LY_STMT_LEAF_LIST:
4225
0
            LY_CHECK_RET(parse_leaflist(ctx, NULL, &mod->data));
4226
0
            break;
4227
0
        case LY_STMT_LIST:
4228
0
            LY_CHECK_RET(parse_list(ctx, NULL, &mod->data));
4229
0
            break;
4230
0
        case LY_STMT_USES:
4231
0
            LY_CHECK_RET(parse_uses(ctx, NULL, &mod->data));
4232
0
            break;
4233
4234
0
        case LY_STMT_AUGMENT:
4235
0
            LY_CHECK_RET(parse_augment(ctx, NULL, &mod->augments));
4236
0
            break;
4237
0
        case LY_STMT_DEVIATION:
4238
0
            LY_CHECK_RET(parse_deviation(ctx, &mod->deviations));
4239
0
            break;
4240
0
        case LY_STMT_EXTENSION:
4241
0
            LY_CHECK_RET(parse_extension(ctx, &mod->extensions));
4242
0
            break;
4243
0
        case LY_STMT_FEATURE:
4244
0
            LY_CHECK_RET(parse_feature(ctx, &mod->features));
4245
0
            break;
4246
0
        case LY_STMT_GROUPING:
4247
0
            LY_CHECK_RET(parse_grouping(ctx, NULL, &mod->groupings));
4248
0
            break;
4249
0
        case LY_STMT_IDENTITY:
4250
0
            LY_CHECK_RET(parse_identity(ctx, &mod->identities));
4251
0
            break;
4252
0
        case LY_STMT_NOTIFICATION:
4253
0
            LY_CHECK_RET(parse_notif(ctx, NULL, &mod->notifs));
4254
0
            break;
4255
0
        case LY_STMT_RPC:
4256
0
            LY_CHECK_RET(parse_action(ctx, NULL, &mod->rpcs));
4257
0
            break;
4258
0
        case LY_STMT_TYPEDEF:
4259
0
            LY_CHECK_RET(parse_typedef(ctx, NULL, &mod->typedefs));
4260
0
            break;
4261
0
        case LY_STMT_EXTENSION_INSTANCE:
4262
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MODULE, 0, &mod->exts));
4263
0
            break;
4264
4265
0
        default:
4266
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
4267
0
            return LY_EVALID;
4268
0
        }
4269
0
    }
4270
0
    LY_CHECK_RET(ret);
4271
4272
0
checks:
4273
    /* mandatory substatements */
4274
0
    if (!mod->mod->ns) {
4275
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "namespace", "module");
4276
0
        return LY_EVALID;
4277
0
    } else if (!mod->mod->prefix) {
4278
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "module");
4279
0
        return LY_EVALID;
4280
0
    }
4281
4282
    /* submodules share the namespace with the module names, so there must not be
4283
     * a submodule of the same name in the context, no need for revision matching */
4284
0
    dup = ly_ctx_get_submodule_latest(PARSER_CTX(ctx), mod->mod->name);
4285
0
    if (dup) {
4286
0
        LOGVAL_PARSER(ctx, LY_VCODE_NAME2_COL, "module", "submodule", mod->mod->name);
4287
0
        return LY_EVALID;
4288
0
    }
4289
4290
0
    return ret;
4291
0
}
4292
4293
/**
4294
 * @brief Parse submodule substatements.
4295
 *
4296
 * @param[in] ctx yang parser context for logging.
4297
 * @param[out] submod Parsed submodule structure.
4298
 *
4299
 * @return LY_ERR values.
4300
 */
4301
LY_ERR
4302
parse_submodule(struct lys_yang_parser_ctx *ctx, struct lysp_submodule *submod)
4303
0
{
4304
0
    LY_ERR ret = 0;
4305
0
    char *buf, *word;
4306
0
    size_t word_len;
4307
0
    enum ly_stmt kw, prev_kw = 0;
4308
0
    enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
4309
0
    const struct lysp_submodule *dup;
4310
4311
0
    submod->is_submod = 1;
4312
4313
    /* submodule name */
4314
0
    LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
4315
0
    INSERT_WORD_RET(ctx, buf, submod->name, word, word_len);
4316
4317
0
    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
4318
4319
0
#define CHECK_ORDER(SECTION) \
4320
0
        if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
4321
4322
0
        switch (kw) {
4323
        /* module header */
4324
0
        case LY_STMT_BELONGS_TO:
4325
0
            CHECK_ORDER(Y_MOD_MODULE_HEADER);
4326
0
            break;
4327
0
        case LY_STMT_YANG_VERSION:
4328
0
            CHECK_ORDER(Y_MOD_MODULE_HEADER);
4329
0
            break;
4330
        /* linkage */
4331
0
        case LY_STMT_INCLUDE:
4332
0
        case LY_STMT_IMPORT:
4333
0
            CHECK_ORDER(Y_MOD_LINKAGE);
4334
0
            break;
4335
        /* meta */
4336
0
        case LY_STMT_ORGANIZATION:
4337
0
        case LY_STMT_CONTACT:
4338
0
        case LY_STMT_DESCRIPTION:
4339
0
        case LY_STMT_REFERENCE:
4340
0
            CHECK_ORDER(Y_MOD_META);
4341
0
            break;
4342
4343
        /* revision */
4344
0
        case LY_STMT_REVISION:
4345
0
            CHECK_ORDER(Y_MOD_REVISION);
4346
0
            break;
4347
        /* body */
4348
0
        case LY_STMT_ANYDATA:
4349
0
        case LY_STMT_ANYXML:
4350
0
        case LY_STMT_AUGMENT:
4351
0
        case LY_STMT_CHOICE:
4352
0
        case LY_STMT_CONTAINER:
4353
0
        case LY_STMT_DEVIATION:
4354
0
        case LY_STMT_EXTENSION:
4355
0
        case LY_STMT_FEATURE:
4356
0
        case LY_STMT_GROUPING:
4357
0
        case LY_STMT_IDENTITY:
4358
0
        case LY_STMT_LEAF:
4359
0
        case LY_STMT_LEAF_LIST:
4360
0
        case LY_STMT_LIST:
4361
0
        case LY_STMT_NOTIFICATION:
4362
0
        case LY_STMT_RPC:
4363
0
        case LY_STMT_TYPEDEF:
4364
0
        case LY_STMT_USES:
4365
0
        case LY_STMT_EXTENSION_INSTANCE:
4366
0
            mod_stmt = Y_MOD_BODY;
4367
0
            break;
4368
0
        default:
4369
            /* error handled in the next switch */
4370
0
            break;
4371
0
        }
4372
0
#undef CHECK_ORDER
4373
4374
0
        prev_kw = kw;
4375
0
        switch (kw) {
4376
        /* module header */
4377
0
        case LY_STMT_YANG_VERSION:
4378
0
            LY_CHECK_RET(parse_yangversion(ctx, &submod->version, &submod->exts));
4379
0
            break;
4380
0
        case LY_STMT_BELONGS_TO:
4381
0
            LY_CHECK_RET(parse_belongsto(ctx, &submod->prefix, &submod->exts));
4382
0
            break;
4383
4384
        /* linkage */
4385
0
        case LY_STMT_INCLUDE:
4386
0
            if (submod->version == LYS_VERSION_1_1) {
4387
0
                LOGWRN(PARSER_CTX(ctx), "YANG version 1.1 expects all includes in main module, includes in submodules (%s) are not necessary.",
4388
0
                        submod->name);
4389
0
            }
4390
0
            LY_CHECK_RET(parse_include(ctx, submod->name, &submod->includes));
4391
0
            break;
4392
0
        case LY_STMT_IMPORT:
4393
0
            LY_CHECK_RET(parse_import(ctx, submod->prefix, &submod->imports));
4394
0
            break;
4395
4396
        /* meta */
4397
0
        case LY_STMT_ORGANIZATION:
4398
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_ORGANIZATION, 0, &submod->org, Y_STR_ARG, &submod->exts));
4399
0
            break;
4400
0
        case LY_STMT_CONTACT:
4401
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_CONTACT, 0, &submod->contact, Y_STR_ARG, &submod->exts));
4402
0
            break;
4403
0
        case LY_STMT_DESCRIPTION:
4404
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &submod->dsc, Y_STR_ARG, &submod->exts));
4405
0
            break;
4406
0
        case LY_STMT_REFERENCE:
4407
0
            LY_CHECK_RET(parse_text_field(ctx, LY_STMT_REFERENCE, 0, &submod->ref, Y_STR_ARG, &submod->exts));
4408
0
            break;
4409
4410
        /* revision */
4411
0
        case LY_STMT_REVISION:
4412
0
            LY_CHECK_RET(parse_revision(ctx, &submod->revs));
4413
0
            break;
4414
4415
        /* body */
4416
0
        case LY_STMT_ANYDATA:
4417
0
            PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "submodule");
4418
        /* fall through */
4419
0
        case LY_STMT_ANYXML:
4420
0
            LY_CHECK_RET(parse_any(ctx, kw, NULL, &submod->data));
4421
0
            break;
4422
0
        case LY_STMT_CHOICE:
4423
0
            LY_CHECK_RET(parse_choice(ctx, NULL, &submod->data));
4424
0
            break;
4425
0
        case LY_STMT_CONTAINER:
4426
0
            LY_CHECK_RET(parse_container(ctx, NULL, &submod->data));
4427
0
            break;
4428
0
        case LY_STMT_LEAF:
4429
0
            LY_CHECK_RET(parse_leaf(ctx, NULL, &submod->data));
4430
0
            break;
4431
0
        case LY_STMT_LEAF_LIST:
4432
0
            LY_CHECK_RET(parse_leaflist(ctx, NULL, &submod->data));
4433
0
            break;
4434
0
        case LY_STMT_LIST:
4435
0
            LY_CHECK_RET(parse_list(ctx, NULL, &submod->data));
4436
0
            break;
4437
0
        case LY_STMT_USES:
4438
0
            LY_CHECK_RET(parse_uses(ctx, NULL, &submod->data));
4439
0
            break;
4440
4441
0
        case LY_STMT_AUGMENT:
4442
0
            LY_CHECK_RET(parse_augment(ctx, NULL, &submod->augments));
4443
0
            break;
4444
0
        case LY_STMT_DEVIATION:
4445
0
            LY_CHECK_RET(parse_deviation(ctx, &submod->deviations));
4446
0
            break;
4447
0
        case LY_STMT_EXTENSION:
4448
0
            LY_CHECK_RET(parse_extension(ctx, &submod->extensions));
4449
0
            break;
4450
0
        case LY_STMT_FEATURE:
4451
0
            LY_CHECK_RET(parse_feature(ctx, &submod->features));
4452
0
            break;
4453
0
        case LY_STMT_GROUPING:
4454
0
            LY_CHECK_RET(parse_grouping(ctx, NULL, &submod->groupings));
4455
0
            break;
4456
0
        case LY_STMT_IDENTITY:
4457
0
            LY_CHECK_RET(parse_identity(ctx, &submod->identities));
4458
0
            break;
4459
0
        case LY_STMT_NOTIFICATION:
4460
0
            LY_CHECK_RET(parse_notif(ctx, NULL, &submod->notifs));
4461
0
            break;
4462
0
        case LY_STMT_RPC:
4463
0
            LY_CHECK_RET(parse_action(ctx, NULL, &submod->rpcs));
4464
0
            break;
4465
0
        case LY_STMT_TYPEDEF:
4466
0
            LY_CHECK_RET(parse_typedef(ctx, NULL, &submod->typedefs));
4467
0
            break;
4468
0
        case LY_STMT_EXTENSION_INSTANCE:
4469
0
            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_SUBMODULE, 0, &submod->exts));
4470
0
            break;
4471
4472
0
        default:
4473
0
            LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
4474
0
            return LY_EVALID;
4475
0
        }
4476
0
    }
4477
0
    LY_CHECK_RET(ret);
4478
4479
0
checks:
4480
    /* mandatory substatements */
4481
0
    if (!submod->prefix) {
4482
0
        LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
4483
0
        return LY_EVALID;
4484
0
    }
4485
4486
    /* submodules share the namespace with the module names, so there must not be
4487
     * a submodule of the same name in the context, no need for revision matching */
4488
0
    dup = ly_ctx_get_submodule_latest(PARSER_CTX(ctx), submod->name);
4489
    /* main modules may have different revisions */
4490
0
    if (dup && strcmp(dup->mod->name, submod->mod->name)) {
4491
0
        LOGVAL_PARSER(ctx, LY_VCODE_NAME_COL, "submodules", dup->name);
4492
0
        return LY_EVALID;
4493
0
    }
4494
4495
0
    return ret;
4496
0
}
4497
4498
/**
4499
 * @brief Skip any redundant characters, namely whitespaces and comments.
4500
 *
4501
 * @param[in] ctx Yang parser context.
4502
 * @return LY_SUCCESS on success.
4503
 * @return LY_EVALID on invalid comment.
4504
 */
4505
static LY_ERR
4506
skip_redundant_chars(struct lys_yang_parser_ctx *ctx)
4507
0
{
4508
    /* read some trailing spaces, new lines, or comments */
4509
0
    while (ctx->in->current[0]) {
4510
0
        if (!strncmp(ctx->in->current, "//", 2)) {
4511
            /* one-line comment */
4512
0
            ly_in_skip(ctx->in, 2);
4513
0
            LY_CHECK_RET(skip_comment(ctx, 1));
4514
0
        } else if (!strncmp(ctx->in->current, "/*", 2)) {
4515
            /* block comment */
4516
0
            ly_in_skip(ctx->in, 2);
4517
0
            LY_CHECK_RET(skip_comment(ctx, 2));
4518
0
        } else if (isspace(ctx->in->current[0])) {
4519
            /* whitespace */
4520
0
            if (ctx->in->current[0] == '\n') {
4521
0
                LY_IN_NEW_LINE(ctx->in);
4522
0
            }
4523
0
            ly_in_skip(ctx->in, 1);
4524
0
        } else {
4525
0
            break;
4526
0
        }
4527
0
    }
4528
4529
0
    return LY_SUCCESS;
4530
0
}
4531
4532
LY_ERR
4533
yang_parse_submodule(struct lys_yang_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx,
4534
        struct ly_in *in, struct lysp_submodule **submod)
4535
0
{
4536
0
    LY_ERR ret = LY_SUCCESS;
4537
0
    char *word;
4538
0
    size_t word_len;
4539
0
    enum ly_stmt kw;
4540
0
    struct lysp_submodule *mod_p = NULL;
4541
4542
    /* create context */
4543
0
    *context = calloc(1, sizeof **context);
4544
0
    LY_CHECK_ERR_RET(!(*context), LOGMEM(ly_ctx), LY_EMEM);
4545
0
    (*context)->format = LYS_IN_YANG;
4546
0
    (*context)->unres = main_ctx->unres;
4547
0
    (*context)->in = in;
4548
4549
0
    mod_p = calloc(1, sizeof *mod_p);
4550
0
    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ly_ctx); ret = LY_EMEM, cleanup);
4551
0
    mod_p->mod = main_ctx->parsed_mod->mod;
4552
0
    mod_p->parsing = 1;
4553
0
    (*context)->parsed_mod = (struct lysp_module *)mod_p;
4554
4555
0
    LOG_LOCINIT(NULL, NULL, NULL, in);
4556
4557
    /* map the typedefs and groupings list from main context to the submodule's context */
4558
0
    memcpy(&(*context)->tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
4559
0
    memcpy(&(*context)->grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
4560
4561
    /* skip redundant but valid characters at the beginning */
4562
0
    ret = skip_redundant_chars(*context);
4563
0
    LY_CHECK_GOTO(ret, cleanup);
4564
4565
    /* "module"/"submodule" */
4566
0
    ret = get_keyword(*context, &kw, &word, &word_len);
4567
0
    LY_CHECK_GOTO(ret, cleanup);
4568
4569
0
    if (kw == LY_STMT_MODULE) {
4570
0
        LOGERR(ly_ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
4571
0
        ret = LY_EINVAL;
4572
0
        goto cleanup;
4573
0
    } else if (kw != LY_STMT_SUBMODULE) {
4574
0
        LOGVAL_PARSER(*context, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
4575
0
        ret = LY_EVALID;
4576
0
        goto cleanup;
4577
0
    }
4578
4579
    /* substatements */
4580
0
    ret = parse_submodule(*context, mod_p);
4581
0
    LY_CHECK_GOTO(ret, cleanup);
4582
4583
    /* skip redundant but valid characters at the end */
4584
0
    ret = skip_redundant_chars(*context);
4585
0
    LY_CHECK_GOTO(ret, cleanup);
4586
0
    if (in->current[0]) {
4587
0
        LOGVAL_PARSER(*context, LY_VCODE_TRAILING_SUBMOD, 15, in->current, strlen(in->current) > 15 ? "..." : "");
4588
0
        ret = LY_EVALID;
4589
0
        goto cleanup;
4590
0
    }
4591
4592
0
    mod_p->parsing = 0;
4593
0
    *submod = mod_p;
4594
4595
0
cleanup:
4596
0
    LOG_LOCBACK(0, 0, 0, 1);
4597
0
    if (ret) {
4598
0
        lysp_module_free((struct lysp_module *)mod_p);
4599
0
        yang_parser_ctx_free(*context);
4600
0
        *context = NULL;
4601
0
    }
4602
4603
0
    return ret;
4604
0
}
4605
4606
LY_ERR
4607
yang_parse_module(struct lys_yang_parser_ctx **context, struct ly_in *in, struct lys_module *mod, struct lys_glob_unres *unres)
4608
0
{
4609
0
    LY_ERR ret = LY_SUCCESS;
4610
0
    char *word;
4611
0
    size_t word_len;
4612
0
    enum ly_stmt kw;
4613
0
    struct lysp_module *mod_p = NULL;
4614
4615
    /* create context */
4616
0
    *context = calloc(1, sizeof **context);
4617
0
    LY_CHECK_ERR_RET(!(*context), LOGMEM(mod->ctx), LY_EMEM);
4618
0
    (*context)->format = LYS_IN_YANG;
4619
0
    (*context)->unres = unres;
4620
0
    (*context)->in = in;
4621
4622
0
    mod_p = calloc(1, sizeof *mod_p);
4623
0
    LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(mod->ctx), cleanup);
4624
0
    mod_p->mod = mod;
4625
0
    mod_p->parsing = 1;
4626
0
    (*context)->parsed_mod = mod_p;
4627
4628
0
    LOG_LOCINIT(NULL, NULL, NULL, in);
4629
4630
    /* skip redundant but valid characters at the beginning */
4631
0
    ret = skip_redundant_chars(*context);
4632
0
    LY_CHECK_GOTO(ret, cleanup);
4633
4634
    /* "module"/"submodule" */
4635
0
    ret = get_keyword(*context, &kw, &word, &word_len);
4636
0
    LY_CHECK_GOTO(ret, cleanup);
4637
4638
0
    if (kw == LY_STMT_SUBMODULE) {
4639
0
        LOGERR(mod->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
4640
0
        ret = LY_EINVAL;
4641
0
        goto cleanup;
4642
0
    } else if (kw != LY_STMT_MODULE) {
4643
0
        LOGVAL_PARSER((*context), LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
4644
0
        ret = LY_EVALID;
4645
0
        goto cleanup;
4646
0
    }
4647
4648
    /* substatements */
4649
0
    ret = parse_module(*context, mod_p);
4650
0
    LY_CHECK_GOTO(ret, cleanup);
4651
4652
    /* skip redundant but valid characters at the end */
4653
0
    ret = skip_redundant_chars(*context);
4654
0
    LY_CHECK_GOTO(ret, cleanup);
4655
0
    if (in->current[0]) {
4656
0
        LOGVAL_PARSER(*context, LY_VCODE_TRAILING_MOD, 15, in->current, strlen(in->current) > 15 ? "..." : "");
4657
0
        ret = LY_EVALID;
4658
0
        goto cleanup;
4659
0
    }
4660
4661
0
    mod_p->parsing = 0;
4662
0
    mod->parsed = mod_p;
4663
4664
0
cleanup:
4665
0
    LOG_LOCBACK(0, 0, 0, 1);
4666
0
    if (ret) {
4667
0
        lysp_module_free(mod_p);
4668
0
        yang_parser_ctx_free(*context);
4669
0
        *context = NULL;
4670
0
    }
4671
4672
0
    return ret;
4673
0
}