blob: 31b73657b6b99586a9f9318cde90fa6ad23afa73 [file] [log] [blame]
Michal Vasko7fbc8162018-09-17 10:35:16 +02001/**
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 <sys/types.h>
15#include <sys/stat.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <stdint.h>
21#include <errno.h>
22#include <ctype.h>
23#include <string.h>
24#include <dirent.h>
25#include <assert.h>
26
27#include "common.h"
28#include "context.h"
29#include "libyang.h"
30
Michal Vaskoea5abea2018-09-18 13:10:54 +020031/**
32 * @brief Loop through all substatements providing, return if there are none.
33 *
34 * @param[in] CTX libyang context for logging.
35 * @param[in] DATA Raw data to read from.
36 * @param[out] KW YANG keyword read.
37 * @param[out] WORD Pointer to the keyword itself.
38 * @param[out] WORD_LEN Length of the keyword.
39 * @param[out] ERR Variable for error storing.
40 *
41 * @return In case there are no substatements or a fatal error encountered.
42 */
Michal Vasko7fbc8162018-09-17 10:35:16 +020043#define YANG_READ_SUBSTMT_FOR(CTX, DATA, KW, WORD, WORD_LEN, ERR) \
44 ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN); \
Radek Krejcic59bc972018-09-17 16:13:06 +020045 LY_CHECK_RET(ERR); \
Michal Vasko7fbc8162018-09-17 10:35:16 +020046 \
47 if (KW == YANG_SEMICOLON) { \
48 return ERR; \
49 } \
50 if (KW != YANG_LEFT_BRACE) { \
Radek Krejcic59bc972018-09-17 16:13:06 +020051 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
Michal Vasko7fbc8162018-09-17 10:35:16 +020052 return LY_EVALID; \
53 } \
54 for (ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN); \
55 !ERR && (KW != YANG_RIGHT_BRACE); \
56 ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN))
57
Michal Vasko7fbc8162018-09-17 10:35:16 +020058static LY_ERR parse_container(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings);
59static LY_ERR parse_uses(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings);
60static LY_ERR parse_choice(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings);
61static LY_ERR parse_case(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings);
62static LY_ERR parse_list(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings);
63static LY_ERR parse_grouping(struct ly_ctx *ctx, const char **data, struct lysp_grp **groupings);
64
Michal Vaskoea5abea2018-09-18 13:10:54 +020065/**
66 * @brief Add another character to dynamic buffer, a low-level function.
67 *
68 * Enlarge if needed. Does not update \p buf_used !
69 *
70 * @param[in] ctx libyang context for logging.
71 * @param[in] c Character to store.
72 * @param[in,out] buf Buffer to use, can be moved by realloc().
73 * @param[in,out] buf_len Current size of the buffer.
74 * @param[in] buf_used Currently used characters of the buffer.
75 *
76 * @return LY_ERR values.
77 */
Michal Vasko7fbc8162018-09-17 10:35:16 +020078static LY_ERR
79buf_add_char(struct ly_ctx *ctx, char c, char **buf, int *buf_len, int buf_used)
80{
81 if (*buf_len == buf_used) {
82 *buf_len += 16;
83 *buf = ly_realloc(*buf, *buf_len);
84 LY_CHECK_ERR_RET(!*buf, LOGMEM(ctx), LY_EMEM);
85 }
86
87 (*buf)[buf_used] = c;
88 return LY_SUCCESS;
89}
90
Michal Vaskoea5abea2018-09-18 13:10:54 +020091/**
92 * @brief Store a character. It depends whether in a dynamically-allocated buffer or just as a pointer to the data.
93 *
94 * @param[in] ctx libyang context for logging.
95 * @param[in] c Pointer to the character to store.
96 * @param[out] word_p Word pointer. If buffer (\p word_b) was not yet needed, it is just a pointer to the first
97 * stored character. If buffer was needed (\p word_b is non-NULL or \p need_buf is set), it is pointing to the buffer.
98 * @param[out] word_len Current length of the word pointed to by \p word_p.
99 * @param[in,out] word_b Word buffer. Is kept NULL as long as it is not needed (word is a substring of the data).
100 * @param[in,out] buf_len Current length of \p word_b.
101 * @param[in] need_buf Whether we need a buffer or not.
102 *
103 * @return LY_ERR values.
104 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200105static LY_ERR
106buf_store_char(struct ly_ctx *ctx, const char *c, char **word_p, int *word_len, char **word_b, int *buf_len, int need_buf)
107{
108 if (word_b && *word_b) {
109 /* add another character into buffer */
110 if (buf_add_char(ctx, *c, word_b, buf_len, *word_len)) {
111 return LY_EMEM;
112 }
113
114 /* in case of realloc */
115 *word_p = *word_b;
116 } else if (need_buf) {
117 /* first time we need a buffer, copy everything read up to now */
118 if (*word_len) {
119 *word_b = malloc(*word_len);
120 LY_CHECK_ERR_RET(!*word_b, LOGMEM(ctx), LY_EMEM);
121 *buf_len = *word_len;
122 memcpy(*word_b, *word_p, *word_len);
123 }
124
125 /* add this new character into buffer */
126 if (buf_add_char(ctx, *c, word_b, buf_len, *word_len)) {
127 return LY_EMEM;
128 }
129
130 /* in case of realloc */
131 *word_p = *word_b;
132 } else {
133 /* just remember the first character pointer */
134 if (!*word_p) {
135 *word_p = (char *)c;
136 }
137 }
138
139 ++(*word_len);
140 return LY_SUCCESS;
141}
142
Michal Vaskoea5abea2018-09-18 13:10:54 +0200143/**
144 * @brief Check that a character is correct and valid.
145 *
146 * @param[in] ctx libyang context for logging.
147 * @param[in] c Character to check.
148 * @param[in] arg Type of YANG keyword argument expected. Affects character validity.
149 * @param[in] first Whether the character is the first of the word. May affect validity.
150 * @param[in,out] prefix Set to 0 on first call. Used for internal tracking of a prefix presence.
151 *
152 * @return LY_ERR values.
153 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200154static LY_ERR
155check_char(struct ly_ctx *ctx, char c, enum yang_arg arg, int first, int *prefix)
156{
157 if ((arg == Y_STR_ARG) || (arg == Y_MAYBE_STR_ARG)) {
158 if ((c < ' ') && (c != '\t') && (c != '\n')) {
159 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHAR, c);
160 return LY_EVALID;
161 }
162 } else if ((arg == Y_IDENTIF_ARG) || (arg == Y_PREF_IDENTIF_ARG)) {
163 if (c < ' ') {
164 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHAR, c);
165 return LY_EVALID;
166 }
167
168 if (first || (*prefix == 2)) {
169 /* either first character of the whole identifier or of the name after prefix */
170 if (!isalpha(c) && (c != '_')) {
171 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG, "Invalid identifier first character '%c'.", c);
172 return LY_EVALID;
173 }
174 if (*prefix == 2) {
175 *prefix = 1;
176 }
177 } else {
178 /* other characters */
179 if (!isalnum(c) && (c != '_') && (c != '-') && (c != '.')) {
180 if ((arg == Y_PREF_IDENTIF_ARG) && !*prefix && (c == ':')) {
181 /* this is fine */
182 *prefix = 2;
183 } else {
184 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG, "Invalid identifier character '%c'.", c);
185 return LY_EVALID;
186 }
187 }
188 }
189 }
190
191 return LY_SUCCESS;
192}
193
Michal Vaskoea5abea2018-09-18 13:10:54 +0200194/**
195 * @brief Skip YANG comment in data.
196 *
197 * @param[in] ctx libyang context for logging.
198 * @param[in,out] data Data to read from, always moved to currently handled character.
199 * @param[in] comment 1 for a one-line comment, 2 for a block comment.
200 *
201 * @return LY_ERR values.
202 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200203static LY_ERR
204skip_comment(struct ly_ctx *ctx, const char **data, int comment)
205{
206 /* comment: 0 - comment ended, 1 - in line comment, 2 - in block comment, 3 - in block comment with last read character '*' */
207
208 while (**data && comment) {
209 switch (comment) {
210 case 1:
211 if (**data == '\n') {
212 comment = 0;
213 }
214 break;
215 case 2:
216 if (**data == '*') {
217 comment = 3;
218 }
219 break;
220 case 3:
221 if (**data == '/') {
222 comment = 0;
223 } else {
224 comment = 2;
225 }
226 break;
227 default:
228 LOGINT_RET(ctx);
229 }
230
231 ++(*data);
232 }
233
234 if (!**data && (comment > 1)) {
235 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Unexpected end-of-file, non-terminated comment.");
236 return LY_EVALID;
237 }
238
239 return LY_SUCCESS;
240}
241
Michal Vaskoea5abea2018-09-18 13:10:54 +0200242/**
243 * @brief Read a quoted string from data.
244 *
245 * @param[in] ctx libyang context for logging.
246 * @param[in,out] data Data to read from, always moved to currently handled character.
247 * @param[in] arg Type of YANG keyword argument expected.
248 * @param[out] word_p Pointer to the read quoted string.
249 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read quoted string. If not needed,
250 * set to NULL. Otherwise equal to \p word_p.
251 * @param[out] word_len Length of the read quoted string.
252 * @param[out] buf_len Length of the dynamically-allocated buffer \p word_b.
253 * @param[in] indent Current indent (number of YANG spaces). Needed for correct multi-line string
254 * indenation in the final quoted string.
255 *
256 * @return LY_ERR values.
257 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200258static LY_ERR
259read_qstring(struct ly_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, int *word_len,
260 int *buf_len, int indent)
261{
262 /* string: 0 - string ended, 1 - string with ', 2 - string with ", 3 - string with " with last character \,
263 * 4 - string finished, now skipping whitespaces looking for +,
264 * 5 - string continues after +, skipping whitespaces */
265 int string, str_nl_indent = 0, need_buf = 0, prefix = 0;
266 const char *c;
267
268 if (**data == '\"') {
269 /* indent of the " itself */
270 ++indent;
271 string = 2;
272 } else {
273 assert(**data == '\'');
274 string = 1;
275 }
276 ++(*data);
277
278 while (**data && string) {
279 switch (string) {
280 case 1:
281 switch (**data) {
282 case '\'':
283 /* string may be finished, but check for + */
284 string = 4;
285 break;
286 default:
287 /* check and store character */
288 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
289 return LY_EVALID;
290 }
291 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
292 return LY_EMEM;
293 }
294 break;
295 }
296 break;
297 case 2:
298 switch (**data) {
299 case '\"':
300 /* string may be finished, but check for + */
301 string = 4;
302 break;
303 case '\\':
304 /* special character following */
305 string = 3;
306 break;
307 case ' ':
308 if (str_nl_indent) {
309 --str_nl_indent;
310 } else {
311 /* check and store character */
312 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
313 return LY_EVALID;
314 }
315 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
316 return LY_EMEM;
317 }
318 }
319 break;
320 case '\t':
321 if (str_nl_indent) {
322 if (str_nl_indent < 9) {
323 str_nl_indent = 0;
324 } else {
325 str_nl_indent -= 8;
326 }
327 } else {
328 /* check and store character */
329 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
330 return LY_EVALID;
331 }
332 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
333 return LY_EMEM;
334 }
335 }
336 break;
337 case '\n':
338 str_nl_indent = indent;
339 if (indent) {
340 /* we will be removing the indents so we need our own buffer */
341 need_buf = 1;
342 }
343
344 /* check and store character */
345 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
346 return LY_EVALID;
347 }
348 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
349 return LY_EMEM;
350 }
351 break;
352 default:
353 /* first non-whitespace character, clear current indent */
354 str_nl_indent = 0;
355
356 /* check and store character */
357 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
358 return LY_EVALID;
359 }
360 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
361 return LY_EMEM;
362 }
363 break;
364 }
365 break;
366 case 3:
367 /* string encoded characters */
368 switch (**data) {
369 case 'n':
370 c = "\n";
371 break;
372 case 't':
373 c = "\t";
374 break;
375 case '\"':
376 c = *data;
377 break;
378 case '\\':
379 c = *data;
380 break;
381 default:
382 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG,
383 "Double-quoted string unknown special character '\\%c'.\n", **data);
384 return LY_EVALID;
385 }
386
387 /* check and store character */
388 if (check_char(ctx, *c, arg, !*word_len, &prefix)) {
389 return LY_EVALID;
390 }
391 if (buf_store_char(ctx, c, word_p, word_len, word_b, buf_len, need_buf)) {
392 return LY_EMEM;
393 }
394
395 string = 2;
396 break;
397 case 4:
398 switch (**data) {
399 case '+':
400 /* string continues */
401 string = 5;
402 break;
403 case ' ':
404 case '\t':
405 case '\n':
406 /* just skip */
407 break;
408 default:
409 /* string is finished */
410 goto string_end;
411 }
412 break;
413 case 5:
414 switch (**data) {
415 case ' ':
416 case '\t':
417 case '\n':
418 /* skip */
419 break;
420 case '\'':
421 string = 1;
422 break;
423 case '\"':
424 string = 2;
425 break;
426 default:
427 /* it must be quoted again */
428 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG,
429 "Both string parts divided by '+' must be quoted.\n");
430 return LY_EVALID;
431 }
432 break;
433 default:
434 return LY_EINT;
435 }
436
437 ++(*data);
438 }
439
440string_end:
441 return LY_SUCCESS;
442}
443
Michal Vaskoea5abea2018-09-18 13:10:54 +0200444/**
445 * @brief Get another YANG string from the raw data.
446 *
447 * @param[in] ctx libyang context for logging.
448 * @param[in,out] data Data to read from, always moved to currently handled character.
449 * @param[in] arg Type of YANG keyword argument expected.
450 * @param[out] word_p Pointer to the read string.
451 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read string. If not needed,
452 * set to NULL. Otherwise equal to \p word_p.
453 * @param[out] word_len Length of the read string.
454 *
455 * @return LY_ERR values.
Michal Vasko7fbc8162018-09-17 10:35:16 +0200456 */
457static LY_ERR
458get_string(struct ly_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, int *word_len)
459{
460 int buf_len = 0, slash = 0, indent = 0, prefix = 0;
461 LY_ERR ret;
462
463 /* word buffer - dynamically allocated */
464 *word_b = NULL;
465
466 /* word pointer - just a pointer to data */
467 *word_p = NULL;
468
469 *word_len = 0;
470 while (**data) {
471 if (slash) {
472 if (**data == '/') {
473 /* one-line comment */
474 ret = skip_comment(ctx, data, 1);
475 if (ret) {
476 return ret;
477 }
478 } else if (**data == '*') {
479 /* block comment */
480 ret = skip_comment(ctx, data, 2);
481 if (ret) {
482 return ret;
483 }
484 } else {
485 /* not a comment after all */
486 ret = buf_store_char(ctx, (*data) - 1, word_p, word_len, word_b, &buf_len, 0);
487 if (ret) {
488 return ret;
489 }
490 }
491 slash = 0;
492 }
493
494 switch (**data) {
495 case '\'':
496 case '\"':
497 if (*word_len) {
498 /* we want strings always in a separate word, leave it */
499 goto str_end;
500 }
501 ret = read_qstring(ctx, data, arg, word_p, word_b, word_len, &buf_len, indent);
502 if (ret) {
503 return ret;
504 }
505 goto str_end;
506 case '/':
507 slash = 1;
508 break;
509 case ' ':
510 if (*word_len) {
511 /* word is finished */
512 goto str_end;
513 }
514 /* increase indent */
515 ++indent;
516 break;
517 case '\t':
518 if (*word_len) {
519 /* word is finished */
520 goto str_end;
521 }
522 /* tabs count for 8 spaces */
523 indent += 8;
524 break;
525 case '\n':
526 if (*word_len) {
527 /* word is finished */
528 goto str_end;
529 }
530 /* reset indent */
531 indent = 0;
532 break;
533 case ';':
534 case '{':
535 if (*word_len || (arg == Y_MAYBE_STR_ARG)) {
536 /* word is finished */
537 goto str_end;
538 }
539
540 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, 1, *data, "an argument");
541 return LY_EVALID;
542 default:
543 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
544 return LY_EVALID;
545 }
546
547 if (buf_store_char(ctx, *data, word_p, word_len, word_b, &buf_len, 0)) {
548 return LY_EMEM;
549 }
550 break;
551 }
552
553 ++(*data);
554 }
555
556str_end:
557 /* ending '\0' for buf */
558 if (*word_b) {
559 if (buf_add_char(ctx, '\0', word_b, &buf_len, *word_len)) {
560 return LY_EMEM;
561 }
562 *word_p = *word_b;
563 }
564
565 return LY_SUCCESS;
566}
567
Michal Vaskoea5abea2018-09-18 13:10:54 +0200568/**
569 * @brief Get another YANG keyword from the raw data.
570 *
571 * @param[in] ctx libyang context for logging.
572 * @param[in,out] data Data to read from, always moved to currently handled character.
573 * @param[out] kw YANG keyword read.
574 * @param[out] word_p Pointer to the keyword in the data. Useful for extension instances.
575 * @param[out] word_len Length of the keyword in the data. Useful for extension instances.
576 *
577 * @return LY_ERR values.
578 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200579static LY_ERR
580get_keyword(struct ly_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, int *word_len)
581{
582 LY_ERR ret;
583 int prefix;
584 const char *word_start;
585 /* slash: 0 - nothing, 1 - last character was '/' */
586 int slash = 0;
587
588 if (word_p) {
589 *word_p = NULL;
590 *word_len = 0;
591 }
592
593 /* first skip "optsep", comments */
594 while (**data) {
595 if (slash) {
596 if (**data == '/') {
597 /* one-line comment */
598 ret = skip_comment(ctx, data, 1);
599 if (ret) {
600 return ret;
601 }
602 } else if (**data == '*') {
603 /* block comment */
604 ret = skip_comment(ctx, data, 2);
605 if (ret) {
606 return ret;
607 }
608 } else {
609 /* not a comment after all */
610 goto keyword_start;
611 }
612 slash = 0;
613 }
614
615 switch (**data) {
616 case '/':
617 slash = 1;
618 break;
619 case ' ':
620 case '\t':
621 case '\n':
622 /* skip whitespaces (optsep) */
623 break;
624 default:
625 /* either a keyword start or an invalid character */
626 goto keyword_start;
627 }
628
629 ++(*data);
630 }
631
632keyword_start:
633 word_start = *data;
634 *kw = YANG_NONE;
635
636 /* read the keyword itself */
637 switch (**data) {
638 case 'a':
639 ++(*data);
640 if (!strncmp(*data, "rgument", 7)) {
641 *data += 7;
642 *kw = YANG_ARGUMENT;
643 } else if (!strncmp(*data, "ugment", 6)) {
644 *data += 6;
645 *kw = YANG_AUGMENT;
646 } else if (!strncmp(*data, "ction", 5)) {
647 *data += 5;
648 *kw = YANG_ACTION;
649 } else if (!strncmp(*data, "ny", 2)) {
650 *data += 2;
651 if (!strncmp(*data, "data", 4)) {
652 *data += 4;
653 *kw = YANG_ANYDATA;
654 } else if (!strncmp(*data, "xml", 3)) {
655 *data += 3;
656 *kw = YANG_ANYXML;
657 }
658 }
659 break;
660 case 'b':
661 ++(*data);
662 if (!strncmp(*data, "ase", 3)) {
663 *data += 3;
664 *kw = YANG_BASE;
665 } else if (!strncmp(*data, "elongs-to", 9)) {
666 *data += 9;
667 *kw = YANG_BELONGS_TO;
668 } else if (!strncmp(*data, "it", 2)) {
669 *data += 2;
670 *kw = YANG_BIT;
671 }
672 break;
673 case 'c':
674 ++(*data);
675 if (!strncmp(*data, "ase", 3)) {
676 *data += 3;
677 *kw = YANG_CASE;
678 } else if (!strncmp(*data, "hoice", 5)) {
679 *data += 5;
680 *kw = YANG_CHOICE;
681 } else if (!strncmp(*data, "on", 2)) {
682 *data += 2;
683 if (!strncmp(*data, "fig", 3)) {
684 *data += 3;
685 *kw = YANG_CONFIG;
686 } else if (!strncmp(*data, "ta", 2)) {
687 *data += 2;
688 if (!strncmp(*data, "ct", 2)) {
689 *data += 2;
690 *kw = YANG_CONTACT;
691 } else if (!strncmp(*data, "iner", 4)) {
692 *data += 4;
693 *kw = YANG_CONTAINER;
694 }
695 }
696 }
697 break;
698 case 'd':
699 ++(*data);
700 if (**data == 'e') {
701 ++(*data);
702 if (!strncmp(*data, "fault", 5)) {
703 *data += 5;
704 *kw = YANG_DEFAULT;
705 } else if (!strncmp(*data, "scription", 9)) {
706 *data += 9;
707 *kw = YANG_DESCRIPTION;
708 } else if (!strncmp(*data, "viat", 4)) {
709 *data += 4;
710 if (**data == 'e') {
711 ++(*data);
712 *kw = YANG_DEVIATE;
713 } else if (!strncmp(*data, "ion", 3)) {
714 *data += 3;
715 *kw = YANG_DEVIATION;
716 }
717 }
718 }
719 break;
720 case 'e':
721 ++(*data);
722 if (!strncmp(*data, "num", 3)) {
723 *data += 3;
724 *kw = YANG_ENUM;
725 } else if (!strncmp(*data, "rror-", 5)) {
726 *data += 5;
727 if (!strncmp(*data, "app-tag", 7)) {
728 *data += 7;
729 *kw = YANG_ERROR_APP_TAG;
730 } else if (!strncmp(*data, "message", 7)) {
731 *data += 7;
732 *kw = YANG_ERROR_MESSAGE;
733 }
734 } else if (!strncmp(*data, "xtension", 8)) {
735 *data += 8;
736 *kw = YANG_EXTENSION;
737 }
738 break;
739 case 'f':
740 ++(*data);
741 if (!strncmp(*data, "eature", 6)) {
742 *data += 6;
743 *kw = YANG_FEATURE;
744 } else if (!strncmp(*data, "raction-digits", 14)) {
745 *data += 14;
746 *kw = YANG_FRACTION_DIGITS;
747 }
748 break;
749 case 'g':
750 ++(*data);
751 if (!strncmp(*data, "rouping", 7)) {
752 *data += 7;
753 *kw = YANG_GROUPING;
754 }
755 break;
756 case 'i':
757 ++(*data);
758 if (!strncmp(*data, "dentity", 7)) {
759 *data += 7;
760 *kw = YANG_IDENTITY;
761 } else if (!strncmp(*data, "f-feature", 9)) {
762 *data += 9;
763 *kw = YANG_IF_FEATURE;
764 } else if (!strncmp(*data, "mport", 5)) {
765 *data += 5;
766 *kw = YANG_IMPORT;
767 } else if (**data == 'n') {
768 ++(*data);
769 if (!strncmp(*data, "clude", 5)) {
770 *data += 5;
771 *kw = YANG_INCLUDE;
772 } else if (!strncmp(*data, "put", 3)) {
773 *data += 3;
774 *kw = YANG_INPUT;
775 }
776 }
777 break;
778 case 'k':
779 ++(*data);
780 if (!strncmp(*data, "ey", 2)) {
781 *data += 2;
782 *kw = YANG_KEY;
783 }
784 break;
785 case 'l':
786 ++(*data);
787 if (**data == 'e') {
788 ++(*data);
789 if (!strncmp(*data, "af", 2)) {
790 *data += 2;
791 if (**data != '-') {
792 *kw = YANG_LEAF;
793 } else if (!strncmp(*data, "-list", 5)) {
794 *data += 5;
795 *kw = YANG_LEAF_LIST;
796 }
797 } else if (!strncmp(*data, "ngth", 4)) {
798 *data += 4;
799 *kw = YANG_LENGTH;
800 }
801 } else if (!strncmp(*data, "ist", 3)) {
802 *data += 3;
803 *kw = YANG_LIST;
804 }
805 break;
806 case 'm':
807 ++(*data);
808 if (**data == 'a') {
809 ++(*data);
810 if (!strncmp(*data, "ndatory", 7)) {
811 *data += 7;
812 *kw = YANG_MANDATORY;
813 } else if (!strncmp(*data, "x-elements", 10)) {
814 *data += 10;
815 *kw = YANG_MAX_ELEMENTS;
816 }
817 } else if (!strncmp(*data, "in-elements", 11)) {
818 *data += 11;
819 *kw = YANG_MIN_ELEMENTS;
820 } else if (!strncmp(*data, "ust", 3)) {
821 *data += 3;
822 *kw = YANG_MUST;
823 } else if (!strncmp(*data, "od", 2)) {
824 *data += 2;
825 if (!strncmp(*data, "ule", 3)) {
826 *data += 3;
827 *kw = YANG_MODULE;
828 } else if (!strncmp(*data, "ifier", 5)) {
829 *data += 3;
830 *kw = YANG_MODIFIER;
831 }
832 }
833 break;
834 case 'n':
835 ++(*data);
836 if (!strncmp(*data, "amespace", 8)) {
837 *data += 8;
838 *kw = YANG_NAMESPACE;
839 } else if (!strncmp(*data, "otification", 11)) {
840 *data += 11;
841 *kw = YANG_NOTIFICATION;
842 }
843 break;
844 case 'o':
845 ++(*data);
846 if (**data == 'r') {
847 ++(*data);
848 if (!strncmp(*data, "dered-by", 8)) {
849 *data += 8;
850 *kw = YANG_ORDERED_BY;
851 } else if (!strncmp(*data, "ganization", 10)) {
852 *data += 10;
853 *kw = YANG_ORGANIZATION;
854 }
855 } else if (!strncmp(*data, "utput", 5)) {
856 *data += 5;
857 *kw = YANG_OUTPUT;
858 }
859 break;
860 case 'p':
861 ++(*data);
862 if (!strncmp(*data, "at", 2)) {
863 *data += 2;
864 if (**data == 'h') {
865 ++(*data);
866 *kw = YANG_PATH;
867 } else if (!strncmp(*data, "tern", 4)) {
868 *data += 4;
869 *kw = YANG_PATTERN;
870 }
871 } else if (!strncmp(*data, "osition", 7)) {
872 *data += 7;
873 *kw = YANG_POSITION;
874 } else if (!strncmp(*data, "re", 2)) {
875 *data += 2;
876 if (!strncmp(*data, "fix", 3)) {
877 *data += 3;
878 *kw = YANG_PREFIX;
879 } else if (!strncmp(*data, "sence", 5)) {
880 *data += 5;
881 *kw = YANG_PRESENCE;
882 }
883 }
884 break;
885 case 'r':
886 ++(*data);
887 if (!strncmp(*data, "ange", 4)) {
888 *data += 4;
889 *kw = YANG_RANGE;
890 } else if (**data == 'e') {
891 ++(*data);
892 if (**data == 'f') {
893 ++(*data);
894 if (!strncmp(*data, "erence", 6)) {
895 *data += 6;
896 *kw = YANG_REFERENCE;
897 } else if (!strncmp(*data, "ine", 3)) {
898 *data += 3;
899 *kw = YANG_REFINE;
900 }
901 } else if (!strncmp(*data, "quire-instance", 14)) {
902 *data += 14;
903 *kw = YANG_REQUIRE_INSTANCE;
904 } else if (!strncmp(*data, "vision", 6)) {
905 *data += 6;
906 if (**data != '-') {
907 *kw = YANG_REVISION;
908 } else if (!strncmp(*data, "-date", 5)) {
909 *data += 5;
910 *kw = YANG_REVISION_DATE;
911 }
912 }
913 } else if (!strncmp(*data, "pc", 2)) {
914 *data += 2;
915 *kw = YANG_RPC;
916 }
917 break;
918 case 's':
919 ++(*data);
920 if (!strncmp(*data, "tatus", 5)) {
921 *data += 5;
922 *kw = YANG_STATUS;
923 } else if (!strncmp(*data, "ubmodule", 8)) {
924 *data += 8;
925 *kw = YANG_SUBMODULE;
926 }
927 break;
928 case 't':
929 ++(*data);
930 if (!strncmp(*data, "ype", 3)) {
931 *data += 3;
932 if (**data != 'd') {
933 *kw = YANG_TYPE;
934 } else if (!strncmp(*data, "def", 3)) {
935 *data += 3;
936 *kw = YANG_TYPEDEF;
937 }
938 }
939 break;
940 case 'u':
941 ++(*data);
942 if (!strncmp(*data, "ni", 2)) {
943 *data += 2;
944 if (!strncmp(*data, "que", 3)) {
945 *data += 3;
946 *kw = YANG_UNIQUE;
947 } else if (!strncmp(*data, "ts", 2)) {
948 *data += 2;
949 *kw = YANG_UNITS;
950 }
951 } else if (!strncmp(*data, "ses", 3)) {
952 *data += 3;
953 *kw = YANG_USES;
954 }
955 break;
956 case 'v':
957 ++(*data);
958 if (!strncmp(*data, "alue", 4)) {
959 *data += 4;
960 *kw = YANG_VALUE;
961 }
962 break;
963 case 'w':
964 ++(*data);
965 if (!strncmp(*data, "hen", 3)) {
966 *data += 3;
967 *kw = YANG_WHEN;
968 }
969 break;
970 case 'y':
971 ++(*data);
972 if (!strncmp(*data, "ang-version", 11)) {
973 *data += 11;
974 *kw = YANG_YANG_VERSION;
975 } else if (!strncmp(*data, "in-element", 10)) {
976 *data += 10;
977 *kw = YANG_YIN_ELEMENT;
978 }
979 break;
980 case ';':
981 ++(*data);
982 *kw = YANG_SEMICOLON;
983 break;
984 case '{':
985 ++(*data);
986 *kw = YANG_LEFT_BRACE;
987 break;
988 case '}':
989 ++(*data);
990 *kw = YANG_RIGHT_BRACE;
991 break;
992 default:
993 break;
994 }
995
996 if (*kw != YANG_NONE) {
997 /* make sure we have the whole keyword */
998 switch (**data) {
999 case ' ':
1000 case '\t':
1001 case '\n':
1002 /* mandatory "sep" */
1003 break;
1004 default:
1005 ++(*data);
1006 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
1007 "a keyword followed by a separator");
1008 return LY_EVALID;
1009 }
1010 } else {
1011 /* still can be an extension */
1012 prefix = 0;
1013 while (**data && (**data != ' ') && (**data != '\t') && (**data != '\n') && (**data != '{') && (**data != ';')) {
1014 if (check_char(ctx, **data, Y_PREF_IDENTIF_ARG, *data == word_start ? 1 : 0, &prefix)) {
1015 return LY_EVALID;
1016 }
1017 ++(*data);
1018 }
1019 if (!**data) {
Radek Krejcic07921a2018-09-17 11:40:15 +02001020 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_EOF);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001021 return LY_EVALID;
1022 }
1023
1024 /* prefix is mandatory for extension instances */
1025 if (prefix != 1) {
1026 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
1027 return LY_EVALID;
1028 }
1029
1030 *kw = YANG_CUSTOM;
1031 }
1032
1033 if (word_p) {
1034 *word_p = (char *)word_start;
1035 *word_len = *data - word_start;
1036 }
1037
1038 return LY_SUCCESS;
1039}
1040
Michal Vaskoea5abea2018-09-18 13:10:54 +02001041/**
1042 * @brief Parse extension instance substatements.
1043 *
1044 * @param[in] ctx libyang context for logging.
1045 * @param[in,out] data Data to read from, always moved to currently handled character.
1046 * @param[in] word Extension instance substatement name (keyword).
1047 * @param[in] word_len Extension instance substatement name length.
1048 * @param[in,out] child Children of this extension instance to add to.
1049 *
1050 * @return LY_ERR values.
1051 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001052static LY_ERR
1053parse_ext_substmt(struct ly_ctx *ctx, const char **data, char *word, int word_len,
1054 struct lysp_stmt **child)
1055{
1056 char *buf;
1057 LY_ERR ret = 0;
1058 enum yang_keyword kw;
1059 struct lysp_stmt *stmt, *par_child;
1060
1061 stmt = calloc(1, sizeof *stmt);
1062 LY_CHECK_ERR_RET(!stmt, LOGMEM(NULL), LY_EMEM);
1063
1064 stmt->stmt = lydict_insert(ctx, word, word_len);
1065
1066 /* get optional argument */
1067 ret = get_string(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001068 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001069
1070 if (buf) {
1071 stmt->arg = lydict_insert_zc(ctx, word);
1072 } else {
1073 stmt->arg = lydict_insert(ctx, word, word_len);
1074 }
1075
1076 /* insert into parent statements */
1077 if (!*child) {
1078 *child = stmt;
1079 } else {
1080 for (par_child = *child; par_child->next; par_child = par_child->next);
1081 par_child->next = stmt;
1082 }
1083
1084 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001085 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001086
1087 ret = parse_ext_substmt(ctx, data, word, word_len, &stmt->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001088 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001089 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001090 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001091
1092 return ret;
1093}
1094
Michal Vaskoea5abea2018-09-18 13:10:54 +02001095/**
1096 * @brief Parse extension instance.
1097 *
1098 * @param[in] ctx libyang context for logging.
1099 * @param[in,out] data Data to read from, always moved to currently handled character.
1100 * @param[in] ext_name Extension instance substatement name (keyword).
1101 * @param[in] ext_name_len Extension instance substatement name length.
1102 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
1103 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
1104 * @param[in,out] exts Extension instances to add to.
1105 *
1106 * @return LY_ERR values.
1107 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001108static LY_ERR
1109parse_ext(struct ly_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
1110 uint32_t insubstmt_index, struct lysp_ext_instance **exts)
1111{
1112 LY_ERR ret = 0;
1113 char *buf, *word;
1114 int word_len;
1115 struct lysp_ext_instance *e;
1116 enum yang_keyword kw;
1117
1118 LYSP_ARRAY_NEW_RET(ctx, exts, e, LY_EMEM);
1119
1120 /* store name and insubstmt info */
1121 e->name = lydict_insert(ctx, ext_name, ext_name_len);
1122 e->insubstmt = insubstmt;
1123 e->insubstmt_index = insubstmt_index;
1124
1125 /* get optional argument */
1126 ret = get_string(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001127 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001128
1129 if (buf) {
1130 e->argument = lydict_insert_zc(ctx, word);
1131 } else {
1132 e->argument = lydict_insert(ctx, word, word_len);
1133 }
1134
1135 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001136 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001137
1138 ret = parse_ext_substmt(ctx, data, word, word_len, &e->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001139 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001140 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001141 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001142
1143 return ret;
1144}
1145
Michal Vaskoea5abea2018-09-18 13:10:54 +02001146/**
1147 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
1148 * description, etc...
1149 *
1150 * @param[in] ctx libyang context for logging.
1151 * @param[in,out] data Data to read from, always moved to currently handled character.
1152 * @param[in] substmt Type of this substatement.
1153 * @param[in] substmt_index Index of this substatement.
1154 * @param[in,out] value Place to store the parsed value.
1155 * @param[in] arg Type of the YANG keyword argument (of the value).
1156 * @param[in,out] exts Extension instances to add to.
1157 *
1158 * @return LY_ERR values.
1159 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001160static LY_ERR
1161parse_text_field(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
1162 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
1163{
1164 LY_ERR ret = 0;
1165 char *buf, *word;
1166 int word_len;
1167 enum yang_keyword kw;
1168
1169 if (*value) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001170 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001171 return LY_EVALID;
1172 }
1173
1174 /* get value */
1175 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001176 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001177
1178 /* store value and spend buf if allocated */
1179 if (buf) {
1180 *value = lydict_insert_zc(ctx, word);
1181 } else {
1182 *value = lydict_insert(ctx, word, word_len);
1183 }
1184
1185 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001186 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001187
1188 switch (kw) {
1189 case YANG_CUSTOM:
1190 ret = parse_ext(ctx, data, word, word_len, substmt, substmt_index, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001191 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001192 break;
1193 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001194 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001195 return LY_EVALID;
1196 }
1197 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001198 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001199
1200 return ret;
1201}
1202
Michal Vaskoea5abea2018-09-18 13:10:54 +02001203/**
1204 * @brief Parse the yang-version statement.
1205 *
1206 * @param[in] ctx libyang context for logging.
1207 * @param[in,out] data Data to read from, always moved to currently handled character.
1208 * @param[in] mod Module to store the parsed information in.
1209 *
1210 * @return LY_ERR values.
1211 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001212static LY_ERR
1213parse_yangversion(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
1214{
1215 LY_ERR ret = 0;
1216 char *buf, *word;
1217 int word_len;
1218 enum yang_keyword kw;
1219
1220 if (mod->version) {
1221 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yang-version");
1222 return LY_EVALID;
1223 }
1224
1225 /* get value */
1226 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001227 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001228
1229 if ((word_len == 3) && !strncmp(word, "1.0", word_len)) {
1230 mod->version = LYS_VERSION_1_0;
1231 } else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
1232 mod->version = LYS_VERSION_1_1;
1233 } else {
1234 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yang-version");
1235 free(buf);
1236 return LY_EVALID;
1237 }
1238 free(buf);
1239
1240 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001241 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001242
1243 switch (kw) {
1244 case YANG_CUSTOM:
1245 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, &mod->exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001246 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001247 break;
1248 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001249 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001250 return LY_EVALID;
1251 }
1252 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001253 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001254
1255 return ret;
1256}
1257
Michal Vaskoea5abea2018-09-18 13:10:54 +02001258/**
1259 * @brief Parse the belongs-to statement.
1260 *
1261 * @param[in] ctx libyang context for logging.
1262 * @param[in,out] data Data to read from, always moved to currently handled character.
1263 * @param[in,out] belongsto Place to store the parsed value.
1264 * @param[in,out] prefix Place to store the parsed belongs-to prefix value.
1265 * @param[in,out] exts Extension instances to add to.
1266 *
1267 * @return LY_ERR values.
1268 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001269static LY_ERR
1270parse_belongsto(struct ly_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
1271{
1272 LY_ERR ret = 0;
1273 char *buf, *word;
1274 int word_len;
1275 enum yang_keyword kw;
1276
1277 if (*belongsto) {
1278 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "belongs-to");
1279 return LY_EVALID;
1280 }
1281
1282 /* get value */
1283 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001284 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001285
1286 if (buf) {
1287 *belongsto = lydict_insert_zc(ctx, word);
1288 } else {
1289 *belongsto = lydict_insert(ctx, word, word_len);
1290 }
1291
1292 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001293 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001294
1295 switch (kw) {
1296 case YANG_PREFIX:
1297 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts);
1298 break;
1299 case YANG_CUSTOM:
1300 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_BELONGSTO, 0, exts);
1301 break;
1302 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001303 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001304 return LY_EVALID;
1305 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001306 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001307 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001308 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001309
1310 /* mandatory substatements */
1311 if (!*prefix) {
1312 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "belongs-to");
1313 return LY_EVALID;
1314 }
1315
1316 return ret;
1317}
1318
Michal Vaskoea5abea2018-09-18 13:10:54 +02001319/**
1320 * @brief Parse the revision-date statement.
1321 *
1322 * @param[in] ctx libyang context for logging.
1323 * @param[in,out] data Data to read from, always moved to currently handled character.
1324 * @param[in,out] rev Array to store the parsed value in.
1325 * @param[in,out] exts Extension instances to add to.
1326 *
1327 * @return LY_ERR values.
1328 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001329static LY_ERR
1330parse_revisiondate(struct ly_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
1331{
1332 LY_ERR ret = 0;
1333 char *buf, *word;
1334 int word_len;
1335 enum yang_keyword kw;
1336
1337 if (rev[0]) {
1338 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "revision-date");
1339 return LY_EVALID;
1340 }
1341
1342 /* get value */
1343 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001344 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001345
1346 /* check value */
1347 if (lysp_check_date(ctx, word, word_len, "revision-date")) {
1348 free(buf);
1349 return LY_EVALID;
1350 }
1351
1352 /* store value and spend buf if allocated */
1353 strncpy(rev, word, word_len);
1354 free(buf);
1355
1356 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001357 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001358
1359 switch (kw) {
1360 case YANG_CUSTOM:
1361 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REVISIONDATE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001362 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001363 break;
1364 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001365 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001366 return LY_EVALID;
1367 }
1368 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001369 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001370
1371 return ret;
1372}
1373
Michal Vaskoea5abea2018-09-18 13:10:54 +02001374/**
1375 * @brief Parse the include statement.
1376 *
1377 * @param[in] ctx libyang context for logging.
1378 * @param[in,out] data Data to read from, always moved to currently handled character.
1379 * @param[in,out] includes Parsed includes to add to.
1380 *
1381 * @return LY_ERR values.
1382 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001383static LY_ERR
1384parse_include(struct ly_ctx *ctx, const char **data, struct lysp_include **includes)
1385{
1386 LY_ERR ret = 0;
1387 char *buf, *word;
1388 int word_len;
1389 enum yang_keyword kw;
1390 struct lysp_include *inc;
1391
1392 LYSP_ARRAY_NEW_RET(ctx, includes, inc, LY_EMEM);
1393
1394 /* get value */
1395 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001396 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001397
1398 if (buf) {
1399 inc->name = lydict_insert_zc(ctx, word);
1400 } else {
1401 inc->name = lydict_insert(ctx, word, word_len);
1402 }
1403
1404 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001405 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001406
1407 switch (kw) {
1408 case YANG_DESCRIPTION:
1409 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts);
1410 break;
1411 case YANG_REFERENCE:
1412 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts);
1413 break;
1414 case YANG_REVISION_DATE:
1415 ret = parse_revisiondate(ctx, data, inc->rev, &inc->exts);
1416 break;
1417 case YANG_CUSTOM:
1418 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inc->exts);
1419 break;
1420 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001421 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001422 return LY_EVALID;
1423 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001424 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001425 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001426 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001427
1428 return ret;
1429}
1430
Michal Vaskoea5abea2018-09-18 13:10:54 +02001431/**
1432 * @brief Parse the import statement.
1433 *
1434 * @param[in] ctx libyang context for logging.
1435 * @param[in,out] data Data to read from, always moved to currently handled character.
1436 * @param[in,out] imports Parsed imports to add to.
1437 *
1438 * @return LY_ERR values.
1439 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001440static LY_ERR
1441parse_import(struct ly_ctx *ctx, const char **data, struct lysp_import **imports)
1442{
1443 LY_ERR ret = 0;
1444 char *buf, *word;
1445 int word_len;
1446 enum yang_keyword kw;
1447 struct lysp_import *imp;
1448
1449 LYSP_ARRAY_NEW_RET(ctx, imports, imp, LY_EVALID);
1450
1451 /* get value */
1452 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001453 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001454
1455 if (buf) {
1456 imp->name = lydict_insert_zc(ctx, word);
1457 } else {
1458 imp->name = lydict_insert(ctx, word, word_len);
1459 }
1460
1461 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001462 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001463
1464 switch (kw) {
1465 case YANG_PREFIX:
1466 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts);
1467 break;
1468 case YANG_DESCRIPTION:
1469 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts);
1470 break;
1471 case YANG_REFERENCE:
1472 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts);
1473 break;
1474 case YANG_REVISION_DATE:
1475 ret = parse_revisiondate(ctx, data, imp->rev, &imp->exts);
1476 break;
1477 case YANG_CUSTOM:
1478 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &imp->exts);
1479 break;
1480 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001481 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001482 return LY_EVALID;
1483 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001484 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001485 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001486 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001487
1488 /* mandatory substatements */
1489 if (!imp->prefix) {
1490 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "import");
1491 return LY_EVALID;
1492 }
1493
1494 return ret;
1495}
1496
Michal Vaskoea5abea2018-09-18 13:10:54 +02001497/**
1498 * @brief Parse the revision statement.
1499 *
1500 * @param[in] ctx libyang context for logging.
1501 * @param[in,out] data Data to read from, always moved to currently handled character.
1502 * @param[in,out] revs Parsed revisions to add to.
1503 *
1504 * @return LY_ERR values.
1505 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001506static LY_ERR
1507parse_revision(struct ly_ctx *ctx, const char **data, struct lysp_revision **revs)
1508{
1509 LY_ERR ret = 0;
1510 char *buf, *word;
1511 int word_len;
1512 enum yang_keyword kw;
1513 struct lysp_revision *rev;
1514
1515 LYSP_ARRAY_NEW_RET(ctx, revs, rev, LY_EMEM);
1516
1517 /* get value */
1518 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001519 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001520
1521 /* check value */
1522 if (lysp_check_date(ctx, word, word_len, "revision")) {
1523 return LY_EVALID;
1524 }
1525
1526 strncpy(rev->rev, word, word_len);
1527 free(buf);
1528
1529 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001530 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001531
1532 switch (kw) {
1533 case YANG_DESCRIPTION:
1534 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts);
1535 break;
1536 case YANG_REFERENCE:
1537 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts);
1538 break;
1539 case YANG_CUSTOM:
1540 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rev->exts);
1541 break;
1542 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001543 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001544 return LY_EVALID;
1545 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001546 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001547 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001548 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001549
1550 return ret;
1551}
1552
Michal Vaskoea5abea2018-09-18 13:10:54 +02001553/**
1554 * @brief Parse a generic text field that can have more instances such as base.
1555 *
1556 * @param[in] ctx libyang context for logging.
1557 * @param[in,out] data Data to read from, always moved to currently handled character.
1558 * @param[in] substmt Type of this substatement.
1559 * @param[in,out] texts Parsed values to add to.
1560 * @param[in] arg Type of the expected argument.
1561 * @param[in,out] exts Extension instances to add to.
1562 *
1563 * @return LY_ERR values.
1564 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001565static LY_ERR
1566parse_text_fields(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
1567 struct lysp_ext_instance **exts)
1568{
1569 LY_ERR ret = 0;
1570 char *buf, *word;
1571 int count, word_len;
1572 enum yang_keyword kw;
1573
1574 /* allocate new pointer */
1575 for (count = 1; (*texts) && (*texts)[count - 1]; ++count);
1576 *texts = realloc(*texts, count * sizeof **texts);
1577 LY_CHECK_ERR_RET(!*texts, LOGMEM(ctx), LY_EMEM);
1578
1579 /* get value */
1580 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001581 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001582
1583 if (buf) {
1584 (*texts)[count - 1] = lydict_insert_zc(ctx, word);
1585 } else {
1586 (*texts)[count - 1] = lydict_insert(ctx, word, word_len);
1587 }
1588
1589 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001590 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001591
1592 switch (kw) {
1593 case YANG_CUSTOM:
1594 ret = parse_ext(ctx, data, word, word_len, substmt, count - 1, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001595 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001596 break;
1597 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001598 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001599 return LY_EVALID;
1600 }
1601 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001602 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001603
1604 return ret;
1605}
1606
Michal Vaskoea5abea2018-09-18 13:10:54 +02001607/**
1608 * @brief Parse the config statement.
1609 *
1610 * @param[in] ctx libyang context for logging.
1611 * @param[in,out] data Data to read from, always moved to currently handled character.
1612 * @param[in,out] flags Flags to add to.
1613 * @param[in,out] exts Extension instances to add to.
1614 *
1615 * @return LY_ERR values.
1616 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001617static LY_ERR
1618parse_config(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1619{
1620 LY_ERR ret = 0;
1621 char *buf, *word;
1622 int word_len;
1623 enum yang_keyword kw;
1624
1625 if (*flags & LYS_CONFIG_MASK) {
1626 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "config");
1627 return LY_EVALID;
1628 }
1629
1630 /* get value */
1631 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001632 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001633
1634 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1635 *flags |= LYS_CONFIG_W;
1636 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1637 *flags |= LYS_CONFIG_R;
1638 } else {
1639 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "config");
1640 free(buf);
1641 return LY_EVALID;
1642 }
1643 free(buf);
1644
1645 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001646 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001647
1648 switch (kw) {
1649 case YANG_CUSTOM:
1650 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_CONFIG, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001651 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001652 break;
1653 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001654 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001655 return LY_EVALID;
1656 }
1657 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001658 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001659
1660 return ret;
1661}
1662
Michal Vaskoea5abea2018-09-18 13:10:54 +02001663/**
1664 * @brief Parse the mandatory statement.
1665 *
1666 * @param[in] ctx libyang context for logging.
1667 * @param[in,out] data Data to read from, always moved to currently handled character.
1668 * @param[in,out] flags Flags to add to.
1669 * @param[in,out] exts Extension instances to add to.
1670 *
1671 * @return LY_ERR values.
1672 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001673static LY_ERR
1674parse_mandatory(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1675{
1676 LY_ERR ret = 0;
1677 char *buf, *word;
1678 int word_len;
1679 enum yang_keyword kw;
1680
1681 if (*flags & LYS_MAND_MASK) {
1682 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "mandatory");
1683 return LY_EVALID;
1684 }
1685
1686 /* get value */
1687 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001688 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001689
1690 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1691 *flags |= LYS_MAND_TRUE;
1692 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1693 *flags |= LYS_MAND_FALSE;
1694 } else {
1695 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "mandatory");
1696 free(buf);
1697 return LY_EVALID;
1698 }
1699 free(buf);
1700
1701 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001702 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001703
1704 switch (kw) {
1705 case YANG_CUSTOM:
1706 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MANDATORY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001707 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001708 break;
1709 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001710 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001711 return LY_EVALID;
1712 }
1713 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001714 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001715
1716 return ret;
1717}
1718
Michal Vaskoea5abea2018-09-18 13:10:54 +02001719/**
1720 * @brief Parse a restriction such as range or length.
1721 *
1722 * @param[in] ctx libyang context for logging.
1723 * @param[in,out] data Data to read from, always moved to currently handled character.
1724 * @param[in] restr_kw Type of this particular restriction.
1725 * @param[in,out] exts Extension instances to add to.
1726 *
1727 * @return LY_ERR values.
1728 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001729static LY_ERR
1730parse_restr(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
1731{
1732 LY_ERR ret = 0;
1733 char *buf, *word;
1734 int word_len;
1735 enum yang_keyword kw;
1736
1737 /* get value */
1738 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001739 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001740
1741 if (buf) {
1742 restr->arg = lydict_insert_zc(ctx, word);
1743 } else {
1744 restr->arg = lydict_insert(ctx, word, word_len);
1745 }
1746
1747 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001748 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001749
1750 switch (kw) {
1751 case YANG_DESCRIPTION:
1752 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
1753 break;
1754 case YANG_REFERENCE:
1755 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
1756 break;
1757 case YANG_ERROR_APP_TAG:
1758 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
1759 break;
1760 case YANG_ERROR_MESSAGE:
1761 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
1762 break;
1763 case YANG_CUSTOM:
1764 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
1765 break;
1766 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001767 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001768 return LY_EVALID;
1769 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001770 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001771 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001772 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001773
1774 return ret;
1775}
1776
Michal Vaskoea5abea2018-09-18 13:10:54 +02001777/**
1778 * @brief Parse a restriction that can have more instances such as must.
1779 *
1780 * @param[in] ctx libyang context for logging.
1781 * @param[in,out] data Data to read from, always moved to currently handled character.
1782 * @param[in] restr_kw Type of this particular restriction.
1783 * @param[in,out] restrs Restrictions to add to.
1784 *
1785 * @return LY_ERR values.
1786 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001787static LY_ERR
1788parse_restrs(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
1789{
1790 struct lysp_restr *restr;
1791
1792 LYSP_ARRAY_NEW_RET(ctx, restrs, restr, LY_EMEM);
1793
1794 return parse_restr(ctx, data, restr_kw, restr);
1795}
1796
Michal Vaskoea5abea2018-09-18 13:10:54 +02001797/**
1798 * @brief Parse the status statement.
1799 *
1800 * @param[in] ctx libyang context for logging.
1801 * @param[in,out] data Data to read from, always moved to currently handled character.
1802 * @param[in,out] flags Flags to add to.
1803 * @param[in,out] exts Extension instances to add to.
1804 *
1805 * @return LY_ERR values.
1806 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001807static LY_ERR
1808parse_status(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1809{
1810 LY_ERR ret = 0;
1811 char *buf, *word;
1812 int word_len;
1813 enum yang_keyword kw;
1814
1815 if (*flags & LYS_STATUS_MASK) {
1816 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "status");
1817 return LY_EVALID;
1818 }
1819
1820 /* get value */
1821 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001822 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001823
1824 if ((word_len == 7) && !strncmp(word, "current", word_len)) {
1825 *flags |= LYS_STATUS_CURR;
1826 } else if ((word_len == 10) && !strncmp(word, "deprecated", word_len)) {
1827 *flags |= LYS_STATUS_DEPRC;
1828 } else if ((word_len == 8) && !strncmp(word, "obsolete", word_len)) {
1829 *flags |= LYS_STATUS_OBSLT;
1830 } else {
1831 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "status");
1832 free(buf);
1833 return LY_EVALID;
1834 }
1835 free(buf);
1836
1837 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001838 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001839
1840 switch (kw) {
1841 case YANG_CUSTOM:
1842 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_STATUS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001843 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001844 break;
1845 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001846 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001847 return LY_EVALID;
1848 }
1849 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001850 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001851
1852 return ret;
1853}
1854
Michal Vaskoea5abea2018-09-18 13:10:54 +02001855/**
1856 * @brief Parse the when statement.
1857 *
1858 * @param[in] ctx libyang context for logging.
1859 * @param[in,out] data Data to read from, always moved to currently handled character.
1860 * @param[in,out] when_p When pointer to parse to.
1861 *
1862 * @return LY_ERR values.
1863 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001864static LY_ERR
1865parse_when(struct ly_ctx *ctx, const char **data, struct lysp_when **when_p)
1866{
1867 LY_ERR ret = 0;
1868 char *buf, *word;
1869 int word_len;
1870 enum yang_keyword kw;
1871 struct lysp_when *when;
1872
1873 if (*when_p) {
1874 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "when");
1875 return LY_EVALID;
1876 }
1877
1878 when = calloc(1, sizeof *when);
1879 LY_CHECK_ERR_RET(!when, LOGMEM(ctx), LY_EMEM);
1880 *when_p = when;
1881
1882 /* get value */
1883 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001884 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001885
1886 if (buf) {
1887 when->cond = lydict_insert_zc(ctx, word);
1888 } else {
1889 when->cond = lydict_insert(ctx, word, word_len);
1890 }
1891
1892 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001893 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001894
1895 switch (kw) {
1896 case YANG_DESCRIPTION:
1897 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts);
1898 break;
1899 case YANG_REFERENCE:
1900 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts);
1901 break;
1902 case YANG_CUSTOM:
1903 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &when->exts);
1904 break;
1905 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001906 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001907 return LY_EVALID;
1908 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001909 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001910 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001911 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001912
1913 return ret;
1914}
1915
Michal Vaskoea5abea2018-09-18 13:10:54 +02001916/**
1917 * @brief Parse the anydata or anyxml statement.
1918 *
1919 * @param[in] ctx libyang context for logging.
1920 * @param[in,out] data Data to read from, always moved to currently handled character.
1921 * @param[in] kw Type of this particular keyword.
1922 * @param[in,out] siblings Siblings to add to.
1923 *
1924 * @return LY_ERR values.
1925 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001926static LY_ERR
1927parse_any(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node **siblings)
1928{
1929 LY_ERR ret = 0;
1930 char *buf, *word;
1931 int word_len;
1932 struct lysp_node *iter;
1933 struct lysp_node_anydata *any;
1934
1935 /* create structure */
1936 any = calloc(1, sizeof *any);
1937 LY_CHECK_ERR_RET(!any, LOGMEM(ctx), LY_EMEM);
1938 any->nodetype = kw == YANG_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
1939
1940 /* insert into siblings */
1941 if (!*siblings) {
1942 *siblings = (struct lysp_node *)any;
1943 } else {
1944 for (iter = *siblings; iter->next; iter = iter->next);
1945 iter->next = (struct lysp_node *)any;
1946 }
1947
1948 /* get name */
1949 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001950 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001951
1952 if (buf) {
1953 any->name = lydict_insert_zc(ctx, word);
1954 } else {
1955 any->name = lydict_insert(ctx, word, word_len);
1956 }
1957
1958 /* parse substatements */
1959 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001960 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001961
1962 switch (kw) {
1963 case YANG_CONFIG:
1964 ret = parse_config(ctx, data, &any->flags, &any->exts);
1965 break;
1966 case YANG_DESCRIPTION:
1967 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts);
1968 break;
1969 case YANG_IF_FEATURE:
1970 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &any->iffeatures, Y_STR_ARG, &any->exts);
1971 break;
1972 case YANG_MANDATORY:
1973 ret = parse_mandatory(ctx, data, &any->flags, &any->exts);
1974 break;
1975 case YANG_MUST:
1976 ret = parse_restrs(ctx, data, kw, &any->musts);
1977 break;
1978 case YANG_REFERENCE:
1979 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts);
1980 break;
1981 case YANG_STATUS:
1982 ret = parse_status(ctx, data, &any->flags, &any->exts);
1983 break;
1984 case YANG_WHEN:
1985 ret = parse_when(ctx, data, &any->when);
1986 break;
1987 case YANG_CUSTOM:
1988 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &any->exts);
1989 break;
1990 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001991 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
1992 (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(YANG_ANYDATA) : ly_stmt2str(YANG_ANYXML));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001993 return LY_EVALID;
1994 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001995 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001996 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001997 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001998
1999 return ret;
2000}
2001
Michal Vaskoea5abea2018-09-18 13:10:54 +02002002/**
2003 * @brief Parse the value or position statement. Substatement of type enum statement.
2004 *
2005 * @param[in] ctx libyang context for logging.
2006 * @param[in,out] data Data to read from, always moved to currently handled character.
2007 * @param[in] val_kw Type of this particular keyword.
2008 * @param[in,out] value Value to write to.
2009 * @param[in,out] flags Flags to write to.
2010 * @param[in,out] exts Extension instances to add to.
2011 *
2012 * @return LY_ERR values.
2013 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002014static LY_ERR
2015parse_type_enum_value_pos(struct ly_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
2016 struct lysp_ext_instance **exts)
2017{
2018 LY_ERR ret = 0;
2019 char *buf, *word, *ptr;
2020 int word_len;
2021 long int num;
2022 unsigned long int unum;
2023 enum yang_keyword kw;
2024
2025 if (*flags & LYS_SET_VALUE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002026 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002027 return LY_EVALID;
2028 }
2029 *flags |= LYS_SET_VALUE;
2030
2031 /* get value */
2032 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002033 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002034
2035 if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_VALUE) && !strncmp(word, "-0", 2))) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002036 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002037 free(buf);
2038 return LY_EVALID;
2039 }
2040
2041 errno = 0;
2042 if (val_kw == YANG_VALUE) {
2043 num = strtol(word, &ptr, 10);
2044 } else {
2045 unum = strtoul(word, &ptr, 10);
2046 }
2047 /* we have not parsed the whole argument */
2048 if (ptr - word != word_len) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002049 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002050 free(buf);
2051 return LY_EVALID;
2052 }
2053 if (errno == ERANGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002054 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002055 free(buf);
2056 return LY_EVALID;
2057 }
2058 if (val_kw == YANG_VALUE) {
2059 *value = num;
2060 } else {
2061 *value = unum;
2062 }
2063 free(buf);
2064
2065 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002066 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002067
2068 switch (kw) {
2069 case YANG_CUSTOM:
2070 ret = parse_ext(ctx, data, word, word_len, val_kw == YANG_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002071 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002072 break;
2073 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002074 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002075 return LY_EVALID;
2076 }
2077 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002078 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002079
2080 return ret;
2081}
2082
Michal Vaskoea5abea2018-09-18 13:10:54 +02002083/**
2084 * @brief Parse the enum or bit statement. Substatement of type statement.
2085 *
2086 * @param[in] ctx libyang context for logging.
2087 * @param[in,out] data Data to read from, always moved to currently handled character.
2088 * @param[in] enum_kw Type of this particular keyword.
2089 * @param[in,out] enums Enums or bits to add to.
2090 *
2091 * @return LY_ERR values.
2092 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002093static LY_ERR
2094parse_type_enum(struct ly_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
2095{
2096 LY_ERR ret = 0;
2097 char *buf, *word;
2098 int word_len;
2099 enum yang_keyword kw;
2100 struct lysp_type_enum *enm;
2101
2102 LYSP_ARRAY_NEW_RET(ctx, enums, enm, LY_EMEM);
2103
2104 /* get value */
2105 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002106 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002107
2108 if (buf) {
2109 enm->name = lydict_insert_zc(ctx, word);
2110 } else {
2111 enm->name = lydict_insert(ctx, word, word_len);
2112 }
2113
2114 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002115 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002116
2117 switch (kw) {
2118 case YANG_DESCRIPTION:
2119 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts);
2120 break;
2121 case YANG_IF_FEATURE:
2122 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts);
2123 break;
2124 case YANG_REFERENCE:
2125 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts);
2126 break;
2127 case YANG_STATUS:
2128 ret = parse_status(ctx, data, &enm->flags, &enm->exts);
2129 break;
2130 case YANG_VALUE:
2131 case YANG_POSITION:
2132 ret = parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts);
2133 break;
2134 case YANG_CUSTOM:
2135 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &enm->exts);
2136 break;
2137 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002138 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002139 return LY_EVALID;
2140 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002141 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002142 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002143 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002144
2145 return ret;
2146}
2147
Michal Vaskoea5abea2018-09-18 13:10:54 +02002148/**
2149 * @brief Parse the fraction-digits statement. Substatement of type statement.
2150 *
2151 * @param[in] ctx libyang context for logging.
2152 * @param[in,out] data Data to read from, always moved to currently handled character.
2153 * @param[in,out] fracdig Value to write to.
2154 * @param[in,out] exts Extension instances to add to.
2155 *
2156 * @return LY_ERR values.
2157 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002158static LY_ERR
2159parse_type_fracdigits(struct ly_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
2160{
2161 LY_ERR ret = 0;
2162 char *buf, *word, *ptr;
2163 int word_len;
2164 unsigned long int num;
2165 enum yang_keyword kw;
2166
2167 if (*fracdig) {
2168 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "fraction-digits");
2169 return LY_EVALID;
2170 }
2171
2172 /* get value */
2173 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002174 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002175
2176 if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
2177 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2178 free(buf);
2179 return LY_EVALID;
2180 }
2181
2182 errno = 0;
2183 num = strtoul(word, &ptr, 10);
2184 /* we have not parsed the whole argument */
2185 if (ptr - word != word_len) {
2186 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2187 free(buf);
2188 return LY_EVALID;
2189 }
2190 if ((errno == ERANGE) || (num > 18)) {
2191 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "fraction-digits");
2192 free(buf);
2193 return LY_EVALID;
2194 }
2195 *fracdig = num;
2196 free(buf);
2197
2198 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002199 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002200
2201 switch (kw) {
2202 case YANG_CUSTOM:
2203 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_FRACDIGITS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002204 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002205 break;
2206 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002207 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002208 return LY_EVALID;
2209 }
2210 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002211 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002212
2213 return ret;
2214}
2215
Michal Vaskoea5abea2018-09-18 13:10:54 +02002216/**
2217 * @brief Parse the require-instance statement. Substatement of type statement.
2218 *
2219 * @param[in] ctx libyang context for logging.
2220 * @param[in,out] data Data to read from, always moved to currently handled character.
2221 * @param[in,out] reqinst Value to write to.
2222 * @param[in,out] flags Flags to write to.
2223 * @param[in,out] exts Extension instances to add to.
2224 *
2225 * @return LY_ERR values.
2226 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002227static LY_ERR
2228parse_type_reqinstance(struct ly_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
2229 struct lysp_ext_instance **exts)
2230{
2231 LY_ERR ret = 0;
2232 char *buf, *word;
2233 int word_len;
2234 enum yang_keyword kw;
2235
2236 if (*flags & LYS_SET_REQINST) {
2237 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "require-instance");
2238 return LY_EVALID;
2239 }
2240 *flags |= LYS_SET_REQINST;
2241
2242 /* get value */
2243 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002244 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002245
2246 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
2247 *reqinst = 1;
2248 } else if ((word_len != 5) || strncmp(word, "false", word_len)) {
2249 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "require-instance");
2250 free(buf);
2251 return LY_EVALID;
2252 }
2253 free(buf);
2254
2255 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002256 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002257
2258 switch (kw) {
2259 case YANG_CUSTOM:
2260 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REQINSTANCE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002261 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002262 break;
2263 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002264 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002265 return LY_EVALID;
2266 }
2267 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002268 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002269
2270 return ret;
2271}
2272
Michal Vaskoea5abea2018-09-18 13:10:54 +02002273/**
2274 * @brief Parse the modifier statement. Substatement of type pattern statement.
2275 *
2276 * @param[in] ctx libyang context for logging.
2277 * @param[in,out] data Data to read from, always moved to currently handled character.
2278 * @param[in,out] pat Value to write to.
2279 * @param[in,out] exts Extension instances to add to.
2280 *
2281 * @return LY_ERR values.
2282 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002283static LY_ERR
2284parse_type_pattern_modifier(struct ly_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
2285{
2286 LY_ERR ret = 0;
2287 char *buf, *word;
2288 int word_len;
2289 enum yang_keyword kw;
2290
2291 if ((*pat)[0] == 0x15) {
2292 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "modifier");
2293 return LY_EVALID;
2294 }
2295
2296 /* get value */
2297 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002298 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002299
2300 if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
2301 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "modifier");
2302 free(buf);
2303 return LY_EVALID;
2304 }
2305 free(buf);
2306
2307 /* replace the value in the dictionary */
2308 buf = malloc(strlen(*pat) + 1);
2309 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2310 strcpy(buf, *pat);
2311 lydict_remove(ctx, *pat);
2312
2313 assert(buf[0] == 0x06);
2314 buf[0] = 0x15;
2315 *pat = lydict_insert_zc(ctx, buf);
2316
2317 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002318 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002319
2320 switch (kw) {
2321 case YANG_CUSTOM:
2322 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MODIFIER, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002323 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002324 break;
2325 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002326 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002327 return LY_EVALID;
2328 }
2329 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002330 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002331
2332 return ret;
2333}
2334
Michal Vaskoea5abea2018-09-18 13:10:54 +02002335/**
2336 * @brief Parse the pattern statement. Substatement of type statement.
2337 *
2338 * @param[in] ctx libyang context for logging.
2339 * @param[in,out] data Data to read from, always moved to currently handled character.
2340 * @param[in,out] patterns Restrictions to add to.
2341 *
2342 * @return LY_ERR values.
2343 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002344static LY_ERR
2345parse_type_pattern(struct ly_ctx *ctx, const char **data, struct lysp_restr **patterns)
2346{
2347 LY_ERR ret = 0;
2348 char *buf, *word;
2349 int word_len;
2350 enum yang_keyword kw;
2351 struct lysp_restr *restr;
2352
2353 LYSP_ARRAY_NEW_RET(ctx, patterns, restr, LY_EMEM);
2354
2355 /* get value */
2356 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002357 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002358
2359 /* add special meaning first byte */
2360 if (buf) {
2361 buf = realloc(buf, word_len + 2);
2362 word = buf;
2363 } else {
2364 buf = malloc(word_len + 2);
2365 }
2366 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2367 memmove(buf + 1, word, word_len + 1);
2368 word[0] = 0x06;
2369 restr->arg = lydict_insert_zc(ctx, word);
2370
2371 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002372 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002373
2374 switch (kw) {
2375 case YANG_DESCRIPTION:
2376 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
2377 break;
2378 case YANG_REFERENCE:
2379 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
2380 break;
2381 case YANG_ERROR_APP_TAG:
2382 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
2383 break;
2384 case YANG_ERROR_MESSAGE:
2385 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
2386 break;
2387 case YANG_MODIFIER:
2388 ret = parse_type_pattern_modifier(ctx, data, &restr->arg, &restr->exts);
2389 break;
2390 case YANG_CUSTOM:
2391 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
2392 break;
2393 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002394 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002395 return LY_EVALID;
2396 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002397 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002398 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002399 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002400
2401 return ret;
2402}
2403
Michal Vaskoea5abea2018-09-18 13:10:54 +02002404/**
2405 * @brief Parse the type statement.
2406 *
2407 * @param[in] ctx libyang context for logging.
2408 * @param[in,out] data Data to read from, always moved to currently handled character.
2409 * @param[in,out] type Type to wrote to.
2410 *
2411 * @return LY_ERR values.
2412 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002413static LY_ERR
2414parse_type(struct ly_ctx *ctx, const char **data, struct lysp_type *type)
2415{
2416 LY_ERR ret = 0;
2417 char *buf, *word;
2418 int word_len;
2419 enum yang_keyword kw;
2420 struct lysp_type *nest_type;
2421
2422 if (type->name) {
2423 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "type");
2424 return LY_EVALID;
2425 }
2426
2427 /* get value */
2428 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002429 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002430
2431 if (buf) {
2432 type->name = lydict_insert_zc(ctx, word);
2433 } else {
2434 type->name = lydict_insert(ctx, word, word_len);
2435 }
2436
2437 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002438 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002439
2440 switch (kw) {
2441 case YANG_BASE:
2442 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts);
2443 break;
2444 case YANG_BIT:
2445 ret = parse_type_enum(ctx, data, kw, &type->bits);
2446 break;
2447 case YANG_ENUM:
2448 ret = parse_type_enum(ctx, data, kw, &type->enums);
2449 break;
2450 case YANG_FRACTION_DIGITS:
2451 ret = parse_type_fracdigits(ctx, data, &type->fraction_digits, &type->exts);
2452 break;
2453 case YANG_LENGTH:
2454 if (type->length) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002455 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002456 return LY_EVALID;
2457 }
2458 type->length = calloc(1, sizeof *type->length);
2459 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
2460
2461 ret = parse_restr(ctx, data, kw, type->length);
2462 break;
2463 case YANG_PATH:
2464 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PATH, 0, &type->path, Y_STR_ARG, &type->exts);
2465 break;
2466 case YANG_PATTERN:
2467 ret = parse_type_pattern(ctx, data, &type->patterns);
2468 break;
2469 case YANG_RANGE:
2470 if (type->range) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002471 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002472 return LY_EVALID;
2473 }
2474 type->range = calloc(1, sizeof *type->range);
2475 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EVALID);
2476
2477 ret = parse_restr(ctx, data, kw, type->range);
2478 break;
2479 case YANG_REQUIRE_INSTANCE:
2480 ret = parse_type_reqinstance(ctx, data, &type->require_instance, &type->flags, &type->exts);
2481 break;
2482 case YANG_TYPE:
2483 {
2484 LYSP_ARRAY_NEW_RET(ctx, &type->types, nest_type, LY_EMEM);
2485 }
2486 ret = parse_type(ctx, data, nest_type);
2487 break;
2488 case YANG_CUSTOM:
2489 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts);
2490 break;
2491 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002492 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002493 return LY_EVALID;
2494 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002495 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002496 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002497 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002498
2499 return ret;
2500}
2501
Michal Vaskoea5abea2018-09-18 13:10:54 +02002502/**
2503 * @brief Parse the leaf statement.
2504 *
2505 * @param[in] ctx libyang context for logging.
2506 * @param[in,out] data Data to read from, always moved to currently handled character.
2507 * @param[in,out] siblings Siblings to add to.
2508 *
2509 * @return LY_ERR values.
2510 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002511static LY_ERR
2512parse_leaf(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2513{
2514 LY_ERR ret = 0;
2515 char *buf, *word;
2516 int word_len;
2517 enum yang_keyword kw;
2518 struct lysp_node *iter;
2519 struct lysp_node_leaf *leaf;
2520
2521 /* create structure */
2522 leaf = calloc(1, sizeof *leaf);
2523 LY_CHECK_ERR_RET(!leaf, LOGMEM(ctx), LY_EMEM);
2524 leaf->nodetype = LYS_LEAF;
2525
2526 /* insert into siblings */
2527 if (!*siblings) {
2528 *siblings = (struct lysp_node *)leaf;
2529 } else {
2530 for (iter = *siblings; iter->next; iter = iter->next);
2531 iter->next = (struct lysp_node *)leaf;
2532 }
2533
2534 /* get name */
2535 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002536 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002537
2538 if (buf) {
2539 leaf->name = lydict_insert_zc(ctx, word);
2540 } else {
2541 leaf->name = lydict_insert(ctx, word, word_len);
2542 }
2543
2544 /* parse substatements */
2545 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002546 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002547
2548 switch (kw) {
2549 case YANG_CONFIG:
2550 ret = parse_config(ctx, data, &leaf->flags, &leaf->exts);
2551 break;
2552 case YANG_DEFAULT:
2553 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &leaf->dflt, Y_STR_ARG, &leaf->exts);
2554 break;
2555 case YANG_DESCRIPTION:
2556 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts);
2557 break;
2558 case YANG_IF_FEATURE:
2559 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &leaf->iffeatures, Y_STR_ARG, &leaf->exts);
2560 break;
2561 case YANG_MANDATORY:
2562 ret = parse_mandatory(ctx, data, &leaf->flags, &leaf->exts);
2563 break;
2564 case YANG_MUST:
2565 ret = parse_restrs(ctx, data, kw, &leaf->musts);
2566 break;
2567 case YANG_REFERENCE:
2568 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts);
2569 break;
2570 case YANG_STATUS:
2571 ret = parse_status(ctx, data, &leaf->flags, &leaf->exts);
2572 break;
2573 case YANG_TYPE:
2574 ret = parse_type(ctx, data, &leaf->type);
2575 break;
2576 case YANG_UNITS:
2577 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts);
2578 break;
2579 case YANG_WHEN:
2580 ret = parse_when(ctx, data, &leaf->when);
2581 break;
2582 case YANG_CUSTOM:
2583 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &leaf->exts);
2584 break;
2585 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002586 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002587 return LY_EVALID;
2588 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002589 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002590 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002591 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002592
2593 /* mandatory substatements */
2594 if (!leaf->type.name) {
2595 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf");
2596 return LY_EVALID;
2597 }
2598
2599 return ret;
2600}
2601
Michal Vaskoea5abea2018-09-18 13:10:54 +02002602/**
2603 * @brief Parse the max-elements statement.
2604 *
2605 * @param[in] ctx libyang context for logging.
2606 * @param[in,out] data Data to read from, always moved to currently handled character.
2607 * @param[in,out] max Value to write to.
2608 * @param[in,out] flags Flags to write to.
2609 * @param[in,out] exts Extension instances to add to.
2610 *
2611 * @return LY_ERR values.
2612 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002613static LY_ERR
2614parse_maxelements(struct ly_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
2615{
2616 LY_ERR ret = 0;
2617 char *buf, *word, *ptr;
2618 int word_len;
2619 unsigned long int num;
2620 enum yang_keyword kw;
2621
2622 if (*flags & LYS_SET_MAX) {
2623 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "max-elements");
2624 return LY_EVALID;
2625 }
2626 *flags |= LYS_SET_MAX;
2627
2628 /* get value */
2629 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002630 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002631
2632 if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
2633 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2634 free(buf);
2635 return LY_EVALID;
2636 }
2637
2638 if (strncmp(word, "unbounded", word_len)) {
2639 errno = 0;
2640 num = strtoul(word, &ptr, 10);
2641 /* we have not parsed the whole argument */
2642 if (ptr - word != word_len) {
2643 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2644 free(buf);
2645 return LY_EVALID;
2646 }
2647 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2648 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "max-elements");
2649 free(buf);
2650 return LY_EVALID;
2651 }
2652
2653 *max = num;
2654 }
2655 free(buf);
2656
2657 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002658 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002659
2660 switch (kw) {
2661 case YANG_CUSTOM:
2662 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MAX, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002663 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002664 break;
2665 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002666 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002667 return LY_EVALID;
2668 }
2669 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002670 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002671
2672 return ret;
2673}
2674
Michal Vaskoea5abea2018-09-18 13:10:54 +02002675/**
2676 * @brief Parse the min-elements statement.
2677 *
2678 * @param[in] ctx libyang context for logging.
2679 * @param[in,out] data Data to read from, always moved to currently handled character.
2680 * @param[in,out] min Value to write to.
2681 * @param[in,out] flags Flags to write to.
2682 * @param[in,out] exts Extension instances to add to.
2683 *
2684 * @return LY_ERR values.
2685 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002686static LY_ERR
2687parse_minelements(struct ly_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
2688{
2689 LY_ERR ret = 0;
2690 char *buf, *word, *ptr;
2691 int word_len;
2692 unsigned long int num;
2693 enum yang_keyword kw;
2694
2695 if (*flags & LYS_SET_MIN) {
2696 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "min-elements");
2697 return LY_EVALID;
2698 }
2699 *flags |= LYS_SET_MIN;
2700
2701 /* get value */
2702 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002703 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002704
2705 if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
2706 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2707 free(buf);
2708 return LY_EVALID;
2709 }
2710
2711 errno = 0;
2712 num = strtoul(word, &ptr, 10);
2713 /* we have not parsed the whole argument */
2714 if (ptr - word != word_len) {
2715 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2716 free(buf);
2717 return LY_EVALID;
2718 }
2719 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2720 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "min-elements");
2721 free(buf);
2722 return LY_EVALID;
2723 }
2724 *min = num;
2725 free(buf);
2726
2727 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002728 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002729
2730 switch (kw) {
2731 case YANG_CUSTOM:
2732 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MIN, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002733 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002734 break;
2735 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002736 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002737 return LY_EVALID;
2738 }
2739 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002740 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002741
2742 return ret;
2743}
2744
Michal Vaskoea5abea2018-09-18 13:10:54 +02002745/**
2746 * @brief Parse the ordered-by statement.
2747 *
2748 * @param[in] ctx libyang context for logging.
2749 * @param[in,out] data Data to read from, always moved to currently handled character.
2750 * @param[in,out] flags Flags to write to.
2751 * @param[in,out] exts Extension instances to add to.
2752 *
2753 * @return LY_ERR values.
2754 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002755static LY_ERR
2756parse_orderedby(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
2757{
2758 LY_ERR ret = 0;
2759 char *buf, *word;
2760 int word_len;
2761 enum yang_keyword kw;
2762
2763 if (*flags & LYS_ORDBY_MASK) {
2764 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "ordered-by");
2765 return LY_EVALID;
2766 }
2767
2768 /* get value */
2769 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002770 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002771
2772 if ((word_len == 6) && !strncmp(word, "system", word_len)) {
2773 *flags |= LYS_ORDBY_SYSTEM;
2774 } else if ((word_len == 4) && !strncmp(word, "user", word_len)) {
2775 *flags |= LYS_ORDBY_USER;
2776 } else {
2777 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "ordered-by");
2778 free(buf);
2779 return LY_EVALID;
2780 }
2781 free(buf);
2782
2783 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002784 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002785
2786 switch (kw) {
2787 case YANG_CUSTOM:
2788 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ORDEREDBY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002789 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002790 break;
2791 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002792 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002793 return LY_EVALID;
2794 }
2795 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002796 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002797
2798 return ret;
2799}
2800
Michal Vaskoea5abea2018-09-18 13:10:54 +02002801/**
2802 * @brief Parse the leaf-list statement.
2803 *
2804 * @param[in] ctx libyang context for logging.
2805 * @param[in,out] data Data to read from, always moved to currently handled character.
2806 * @param[in,out] siblings Siblings to add to.
2807 *
2808 * @return LY_ERR values.
2809 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002810static LY_ERR
2811parse_leaflist(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2812{
2813 LY_ERR ret = 0;
2814 char *buf, *word;
2815 int word_len;
2816 enum yang_keyword kw;
2817 struct lysp_node *iter;
2818 struct lysp_node_leaflist *llist;
2819
2820 /* create structure */
2821 llist = calloc(1, sizeof *llist);
2822 LY_CHECK_ERR_RET(!llist, LOGMEM(ctx), LY_EMEM);
2823 llist->nodetype = LYS_LEAFLIST;
2824
2825 /* insert into siblings */
2826 if (!*siblings) {
2827 *siblings = (struct lysp_node *)llist;
2828 } else {
2829 for (iter = *siblings; iter->next; iter = iter->next);
2830 iter->next = (struct lysp_node *)llist;
2831 }
2832
2833 /* get name */
2834 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002835 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002836
2837 if (buf) {
2838 llist->name = lydict_insert_zc(ctx, word);
2839 } else {
2840 llist->name = lydict_insert(ctx, word, word_len);
2841 }
2842
2843 /* parse substatements */
2844 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002845 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002846
2847 switch (kw) {
2848 case YANG_CONFIG:
2849 ret = parse_config(ctx, data, &llist->flags, &llist->exts);
2850 break;
2851 case YANG_DEFAULT:
2852 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts);
2853 break;
2854 case YANG_DESCRIPTION:
2855 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts);
2856 break;
2857 case YANG_IF_FEATURE:
2858 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &llist->iffeatures, Y_STR_ARG, &llist->exts);
2859 break;
2860 case YANG_MAX_ELEMENTS:
2861 ret = parse_maxelements(ctx, data, &llist->max, &llist->flags, &llist->exts);
2862 break;
2863 case YANG_MIN_ELEMENTS:
2864 ret = parse_minelements(ctx, data, &llist->min, &llist->flags, &llist->exts);
2865 break;
2866 case YANG_MUST:
2867 ret = parse_restrs(ctx, data, kw, &llist->musts);
2868 break;
2869 case YANG_ORDERED_BY:
2870 ret = parse_orderedby(ctx, data, &llist->flags, &llist->exts);
2871 break;
2872 case YANG_REFERENCE:
2873 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts);
2874 break;
2875 case YANG_STATUS:
2876 ret = parse_status(ctx, data, &llist->flags, &llist->exts);
2877 break;
2878 case YANG_TYPE:
2879 ret = parse_type(ctx, data, &llist->type);
2880 break;
2881 case YANG_UNITS:
2882 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts);
2883 break;
2884 case YANG_WHEN:
2885 ret = parse_when(ctx, data, &llist->when);
2886 break;
2887 case YANG_CUSTOM:
2888 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &llist->exts);
2889 break;
2890 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002891 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002892 return LY_EVALID;
2893 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002894 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002895 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002896 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002897
2898 /* mandatory substatements */
2899 if (!llist->type.name) {
2900 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf-list");
2901 return LY_EVALID;
2902 }
2903
2904 return ret;
2905}
2906
Michal Vaskoea5abea2018-09-18 13:10:54 +02002907/**
2908 * @brief Parse the refine statement.
2909 *
2910 * @param[in] ctx libyang context for logging.
2911 * @param[in,out] data Data to read from, always moved to currently handled character.
2912 * @param[in,out] refines Refines to add to.
2913 *
2914 * @return LY_ERR values.
2915 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002916static LY_ERR
2917parse_refine(struct ly_ctx *ctx, const char **data, struct lysp_refine **refines)
2918{
2919 LY_ERR ret = 0;
2920 char *buf, *word;
2921 int word_len;
2922 enum yang_keyword kw;
2923 struct lysp_refine *rf;
2924
2925 LYSP_ARRAY_NEW_RET(ctx, refines, rf, LY_EMEM);
2926
2927 /* get value */
2928 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002929 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002930
2931 if (buf) {
2932 rf->nodeid = lydict_insert_zc(ctx, word);
2933 } else {
2934 rf->nodeid = lydict_insert(ctx, word, word_len);
2935 }
2936
2937 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002938 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002939
2940 switch (kw) {
2941 case YANG_CONFIG:
2942 ret = parse_config(ctx, data, &rf->flags, &rf->exts);
2943 break;
2944 case YANG_DEFAULT:
2945 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &rf->dflts, Y_STR_ARG, &rf->exts);
2946 break;
2947 case YANG_DESCRIPTION:
2948 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts);
2949 break;
2950 case YANG_IF_FEATURE:
2951 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &rf->iffeatures, Y_STR_ARG, &rf->exts);
2952 break;
2953 case YANG_MAX_ELEMENTS:
2954 ret = parse_maxelements(ctx, data, &rf->max, &rf->flags, &rf->exts);
2955 break;
2956 case YANG_MIN_ELEMENTS:
2957 ret = parse_minelements(ctx, data, &rf->min, &rf->flags, &rf->exts);
2958 break;
2959 case YANG_MUST:
2960 ret = parse_restrs(ctx, data, kw, &rf->musts);
2961 break;
2962 case YANG_MANDATORY:
2963 ret = parse_mandatory(ctx, data, &rf->flags, &rf->exts);
2964 break;
2965 case YANG_REFERENCE:
2966 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts);
2967 break;
2968 case YANG_PRESENCE:
2969 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts);
2970 break;
2971 case YANG_CUSTOM:
2972 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rf->exts);
2973 break;
2974 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002975 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002976 return LY_EVALID;
2977 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002978 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002979 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002980 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002981
2982 return ret;
2983}
2984
Michal Vaskoea5abea2018-09-18 13:10:54 +02002985/**
2986 * @brief Parse the typedef statement.
2987 *
2988 * @param[in] ctx libyang context for logging.
2989 * @param[in,out] data Data to read from, always moved to currently handled character.
2990 * @param[in,out] typedefs Typedefs to add to.
2991 *
2992 * @return LY_ERR values.
2993 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002994static LY_ERR
2995parse_typedef(struct ly_ctx *ctx, const char **data, struct lysp_tpdf **typedefs)
2996{
2997 LY_ERR ret = 0;
2998 char *buf, *word;
2999 int word_len;
3000 enum yang_keyword kw;
3001 struct lysp_tpdf *tpdf;
3002
3003 LYSP_ARRAY_NEW_RET(ctx, typedefs, tpdf, LY_EMEM);
3004
3005 /* get value */
3006 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003007 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003008
3009 if (buf) {
3010 tpdf->name = lydict_insert_zc(ctx, word);
3011 } else {
3012 tpdf->name = lydict_insert(ctx, word, word_len);
3013 }
3014
3015 /* parse substatements */
3016 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003017 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003018
3019 switch (kw) {
3020 case YANG_DEFAULT:
3021 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &tpdf->dflt, Y_STR_ARG, &tpdf->exts);
3022 break;
3023 case YANG_DESCRIPTION:
3024 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts);
3025 break;
3026 case YANG_REFERENCE:
3027 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts);
3028 break;
3029 case YANG_STATUS:
3030 ret = parse_status(ctx, data, &tpdf->flags, &tpdf->exts);
3031 break;
3032 case YANG_TYPE:
3033 ret = parse_type(ctx, data, &tpdf->type);
3034 break;
3035 case YANG_UNITS:
3036 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts);
3037 break;
3038 case YANG_CUSTOM:
3039 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &tpdf->exts);
3040 break;
3041 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003042 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003043 return LY_EVALID;
3044 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003045 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003046 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003047 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003048
3049 /* mandatory substatements */
3050 if (!tpdf->type.name) {
3051 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "typedef");
3052 return LY_EVALID;
3053 }
3054
3055 return ret;
3056}
3057
Michal Vaskoea5abea2018-09-18 13:10:54 +02003058/**
3059 * @brief Parse the input or output statement.
3060 *
3061 * @param[in] ctx libyang context for logging.
3062 * @param[in,out] data Data to read from, always moved to currently handled character.
3063 * @param[in] kw Type of this particular keyword
3064 * @param[in,out] inout_p Input/output pointer to write to.
3065 *
3066 * @return LY_ERR values.
3067 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003068static LY_ERR
3069parse_inout(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_action_inout **inout_p)
3070{
3071 LY_ERR ret = 0;
3072 char *word;
3073 int word_len;
3074 struct lysp_action_inout *inout;
3075
3076 if (*inout_p) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003077 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02003078 return LY_EVALID;
3079 }
3080
3081 /* create structure */
3082 inout = calloc(1, sizeof *inout);
3083 LY_CHECK_ERR_RET(!inout, LOGMEM(ctx), LY_EMEM);
3084 *inout_p = inout;
3085
3086 /* parse substatements */
3087 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003088 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003089
3090 switch (kw) {
3091 case YANG_ANYDATA:
3092 case YANG_ANYXML:
3093 ret = parse_any(ctx, data, kw, &inout->data);
3094 break;
3095 case YANG_CHOICE:
3096 ret = parse_choice(ctx, data, &inout->data);
3097 break;
3098 case YANG_CONTAINER:
3099 ret = parse_container(ctx, data, &inout->data);
3100 break;
3101 case YANG_LEAF:
3102 ret = parse_leaf(ctx, data, &inout->data);
3103 break;
3104 case YANG_LEAF_LIST:
3105 ret = parse_leaflist(ctx, data, &inout->data);
3106 break;
3107 case YANG_LIST:
3108 ret = parse_list(ctx, data, &inout->data);
3109 break;
3110 case YANG_USES:
3111 ret = parse_uses(ctx, data, &inout->data);
3112 break;
3113
3114 case YANG_TYPEDEF:
3115 ret = parse_typedef(ctx, data, &inout->typedefs);
3116 break;
3117 case YANG_MUST:
3118 ret = parse_restrs(ctx, data, kw, &inout->musts);
3119 break;
3120 case YANG_GROUPING:
3121 ret = parse_grouping(ctx, data, &inout->groupings);
3122 break;
3123 case YANG_CUSTOM:
3124 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout->exts);
3125 break;
3126 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003127 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "input/output");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003128 return LY_EVALID;
3129 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003130 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003131 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003132 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003133
3134 return ret;
3135}
3136
Michal Vaskoea5abea2018-09-18 13:10:54 +02003137/**
3138 * @brief Parse the action statement.
3139 *
3140 * @param[in] ctx libyang context for logging.
3141 * @param[in,out] data Data to read from, always moved to currently handled character.
3142 * @param[in,out] actions Actions to add to.
3143 *
3144 * @return LY_ERR values.
3145 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003146static LY_ERR
3147parse_action(struct ly_ctx *ctx, const char **data, struct lysp_action **actions)
3148{
3149 LY_ERR ret = 0;
3150 char *buf, *word;
3151 int word_len;
3152 enum yang_keyword kw;
3153 struct lysp_action *act;
3154
3155 LYSP_ARRAY_NEW_RET(ctx, actions, act, LY_EMEM);
3156
3157 /* get value */
3158 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003159 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003160
3161 if (buf) {
3162 act->name = lydict_insert_zc(ctx, word);
3163 } else {
3164 act->name = lydict_insert(ctx, word, word_len);
3165 }
3166
3167 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003168 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003169
3170 switch (kw) {
3171 case YANG_DESCRIPTION:
3172 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts);
3173 break;
3174 case YANG_IF_FEATURE:
3175 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &act->iffeatures, Y_STR_ARG, &act->exts);
3176 break;
3177 case YANG_REFERENCE:
3178 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts);
3179 break;
3180 case YANG_STATUS:
3181 ret = parse_status(ctx, data, &act->flags, &act->exts);
3182 break;
3183
3184 case YANG_INPUT:
3185 ret = parse_inout(ctx, data, kw, &act->input);
3186 break;
3187 case YANG_OUTPUT:
3188 ret = parse_inout(ctx, data, kw, &act->output);
3189 break;
3190
3191 case YANG_TYPEDEF:
3192 ret = parse_typedef(ctx, data, &act->typedefs);
3193 break;
3194 case YANG_GROUPING:
3195 ret = parse_grouping(ctx, data, &act->groupings);
3196 break;
3197 case YANG_CUSTOM:
3198 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts);
3199 break;
3200 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003201 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "action");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003202 return LY_EVALID;
3203 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003204 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003205 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003206 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003207
3208 return ret;
3209}
3210
Michal Vaskoea5abea2018-09-18 13:10:54 +02003211/**
3212 * @brief Parse the notification statement.
3213 *
3214 * @param[in] ctx libyang context for logging.
3215 * @param[in,out] data Data to read from, always moved to currently handled character.
3216 * @param[in,out] notifs Notifications to add to.
3217 *
3218 * @return LY_ERR values.
3219 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003220static LY_ERR
3221parse_notif(struct ly_ctx *ctx, const char **data, struct lysp_notif **notifs)
3222{
3223 LY_ERR ret = 0;
3224 char *buf, *word;
3225 int word_len;
3226 enum yang_keyword kw;
3227 struct lysp_notif *notif;
3228
3229 LYSP_ARRAY_NEW_RET(ctx, notifs, notif, LY_EMEM);
3230
3231 /* get value */
3232 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003233 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003234
3235 if (buf) {
3236 notif->name = lydict_insert_zc(ctx, word);
3237 } else {
3238 notif->name = lydict_insert(ctx, word, word_len);
3239 }
3240
3241 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003242 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003243
3244 switch (kw) {
3245 case YANG_DESCRIPTION:
3246 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts);
3247 break;
3248 case YANG_IF_FEATURE:
3249 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &notif->iffeatures, Y_STR_ARG, &notif->exts);
3250 break;
3251 case YANG_REFERENCE:
3252 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts);
3253 break;
3254 case YANG_STATUS:
3255 ret = parse_status(ctx, data, &notif->flags, &notif->exts);
3256 break;
3257
3258 case YANG_ANYDATA:
3259 case YANG_ANYXML:
3260 ret = parse_any(ctx, data, kw, &notif->data);
3261 break;
3262 case YANG_CHOICE:
3263 ret = parse_case(ctx, data, &notif->data);
3264 break;
3265 case YANG_CONTAINER:
3266 ret = parse_container(ctx, data, &notif->data);
3267 break;
3268 case YANG_LEAF:
3269 ret = parse_leaf(ctx, data, &notif->data);
3270 break;
3271 case YANG_LEAF_LIST:
3272 ret = parse_leaflist(ctx, data, &notif->data);
3273 break;
3274 case YANG_LIST:
3275 ret = parse_list(ctx, data, &notif->data);
3276 break;
3277 case YANG_USES:
3278 ret = parse_uses(ctx, data, &notif->data);
3279 break;
3280
3281 case YANG_MUST:
3282 ret = parse_restrs(ctx, data, kw, &notif->musts);
3283 break;
3284 case YANG_TYPEDEF:
3285 ret = parse_typedef(ctx, data, &notif->typedefs);
3286 break;
3287 case YANG_GROUPING:
3288 ret = parse_grouping(ctx, data, &notif->groupings);
3289 break;
3290 case YANG_CUSTOM:
3291 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &notif->exts);
3292 break;
3293 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003294 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003295 return LY_EVALID;
3296 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003297 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003298 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003299 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003300
3301 return ret;
3302}
3303
Michal Vaskoea5abea2018-09-18 13:10:54 +02003304/**
3305 * @brief Parse the grouping statement.
3306 *
3307 * @param[in] ctx libyang context for logging.
3308 * @param[in,out] data Data to read from, always moved to currently handled character.
3309 * @param[in,out] groupings Groupings to add to.
3310 *
3311 * @return LY_ERR values.
3312 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003313static LY_ERR
3314parse_grouping(struct ly_ctx *ctx, const char **data, struct lysp_grp **groupings)
3315{
3316 LY_ERR ret = 0;
3317 char *buf, *word;
3318 int word_len;
3319 enum yang_keyword kw;
3320 struct lysp_grp *grp;
3321
3322 LYSP_ARRAY_NEW_RET(ctx, groupings, grp, LY_EMEM);
3323
3324 /* get value */
3325 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003326 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003327
3328 if (buf) {
3329 grp->name = lydict_insert_zc(ctx, word);
3330 } else {
3331 grp->name = lydict_insert(ctx, word, word_len);
3332 }
3333
3334 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003335 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003336
3337 switch (kw) {
3338 case YANG_DESCRIPTION:
3339 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts);
3340 break;
3341 case YANG_REFERENCE:
3342 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts);
3343 break;
3344 case YANG_STATUS:
3345 ret = parse_status(ctx, data, &grp->flags, &grp->exts);
3346 break;
3347
3348 case YANG_ANYDATA:
3349 case YANG_ANYXML:
3350 ret = parse_any(ctx, data, kw, &grp->data);
3351 break;
3352 case YANG_CHOICE:
3353 ret = parse_choice(ctx, data, &grp->data);
3354 break;
3355 case YANG_CONTAINER:
3356 ret = parse_container(ctx, data, &grp->data);
3357 break;
3358 case YANG_LEAF:
3359 ret = parse_leaf(ctx, data, &grp->data);
3360 break;
3361 case YANG_LEAF_LIST:
3362 ret = parse_leaflist(ctx, data, &grp->data);
3363 break;
3364 case YANG_LIST:
3365 ret = parse_list(ctx, data, &grp->data);
3366 break;
3367 case YANG_USES:
3368 ret = parse_uses(ctx, data, &grp->data);
3369 break;
3370
3371 case YANG_TYPEDEF:
3372 ret = parse_typedef(ctx, data, &grp->typedefs);
3373 break;
3374 case YANG_ACTION:
3375 ret = parse_action(ctx, data, &grp->actions);
3376 break;
3377 case YANG_GROUPING:
3378 ret = parse_grouping(ctx, data, &grp->groupings);
3379 break;
3380 case YANG_NOTIFICATION:
3381 ret = parse_notif(ctx, data, &grp->notifs);
3382 break;
3383 case YANG_CUSTOM:
3384 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &grp->exts);
3385 break;
3386 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003387 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003388 return LY_EVALID;
3389 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003390 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003391 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003392 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003393
3394 return ret;
3395}
3396
Michal Vaskoea5abea2018-09-18 13:10:54 +02003397/**
3398 * @brief Parse the refine statement.
3399 *
3400 * @param[in] ctx libyang context for logging.
3401 * @param[in,out] data Data to read from, always moved to currently handled character.
3402 * @param[in,out] augments Augments to add to.
3403 *
3404 * @return LY_ERR values.
3405 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003406static LY_ERR
3407parse_augment(struct ly_ctx *ctx, const char **data, struct lysp_augment **augments)
3408{
3409 LY_ERR ret = 0;
3410 char *buf, *word;
3411 int word_len;
3412 enum yang_keyword kw;
3413 struct lysp_augment *aug;
3414
3415 LYSP_ARRAY_NEW_RET(ctx, augments, aug, LY_EMEM);
3416
3417 /* get value */
3418 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003419 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003420
3421 if (buf) {
3422 aug->nodeid = lydict_insert_zc(ctx, word);
3423 } else {
3424 aug->nodeid = lydict_insert(ctx, word, word_len);
3425 }
3426
3427 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003428 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003429
3430 switch (kw) {
3431 case YANG_DESCRIPTION:
3432 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts);
3433 break;
3434 case YANG_IF_FEATURE:
3435 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &aug->iffeatures, Y_STR_ARG, &aug->exts);
3436 break;
3437 case YANG_REFERENCE:
3438 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts);
3439 break;
3440 case YANG_STATUS:
3441 ret = parse_status(ctx, data, &aug->flags, &aug->exts);
3442 break;
3443 case YANG_WHEN:
3444 ret = parse_when(ctx, data, &aug->when);
3445 break;
3446
3447 case YANG_ANYDATA:
3448 case YANG_ANYXML:
3449 ret = parse_any(ctx, data, kw, &aug->child);
3450 break;
3451 case YANG_CASE:
3452 ret = parse_case(ctx, data, &aug->child);
3453 break;
3454 case YANG_CHOICE:
3455 ret = parse_choice(ctx, data, &aug->child);
3456 break;
3457 case YANG_CONTAINER:
3458 ret = parse_container(ctx, data, &aug->child);
3459 break;
3460 case YANG_LEAF:
3461 ret = parse_leaf(ctx, data, &aug->child);
3462 break;
3463 case YANG_LEAF_LIST:
3464 ret = parse_leaflist(ctx, data, &aug->child);
3465 break;
3466 case YANG_LIST:
3467 ret = parse_list(ctx, data, &aug->child);
3468 break;
3469 case YANG_USES:
3470 ret = parse_uses(ctx, data, &aug->child);
3471 break;
3472
3473 case YANG_ACTION:
3474 ret = parse_action(ctx, data, &aug->actions);
3475 break;
3476 case YANG_NOTIFICATION:
3477 ret = parse_notif(ctx, data, &aug->notifs);
3478 break;
3479 case YANG_CUSTOM:
3480 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &aug->exts);
3481 break;
3482 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003483 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003484 return LY_EVALID;
3485 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003486 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003487 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003488 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003489
3490 return ret;
3491}
3492
Michal Vaskoea5abea2018-09-18 13:10:54 +02003493/**
3494 * @brief Parse the uses statement.
3495 *
3496 * @param[in] ctx libyang context for logging.
3497 * @param[in,out] data Data to read from, always moved to currently handled character.
3498 * @param[in,out] siblings Siblings to add to.
3499 *
3500 * @return LY_ERR values.
3501 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003502static LY_ERR
3503parse_uses(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3504{
3505 LY_ERR ret = 0;
3506 char *buf, *word;
3507 int word_len;
3508 enum yang_keyword kw;
3509 struct lysp_node *iter;
3510 struct lysp_node_uses *uses;
3511
3512 /* create structure */
3513 uses = calloc(1, sizeof *uses);
3514 LY_CHECK_ERR_RET(!uses, LOGMEM(ctx), LY_EMEM);
3515 uses->nodetype = LYS_USES;
3516
3517 /* insert into siblings */
3518 if (!*siblings) {
3519 *siblings = (struct lysp_node *)uses;
3520 } else {
3521 for (iter = *siblings; iter->next; iter = iter->next);
3522 iter->next = (struct lysp_node *)uses;
3523 }
3524
3525 /* get name */
3526 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003527 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003528
3529 if (buf) {
3530 uses->name = lydict_insert_zc(ctx, word);
3531 } else {
3532 uses->name = lydict_insert(ctx, word, word_len);
3533 }
3534
3535 /* parse substatements */
3536 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003537 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003538
3539 switch (kw) {
3540 case YANG_DESCRIPTION:
3541 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts);
3542 break;
3543 case YANG_IF_FEATURE:
3544 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &uses->iffeatures, Y_STR_ARG, &uses->exts);
3545 break;
3546 case YANG_REFERENCE:
3547 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts);
3548 break;
3549 case YANG_STATUS:
3550 ret = parse_status(ctx, data, &uses->flags, &uses->exts);
3551 break;
3552 case YANG_WHEN:
3553 ret = parse_when(ctx, data, &uses->when);
3554 break;
3555
3556 case YANG_REFINE:
3557 ret = parse_refine(ctx, data, &uses->refines);
3558 break;
3559 case YANG_AUGMENT:
3560 ret = parse_augment(ctx, data, &uses->augments);
3561 break;
3562 case YANG_CUSTOM:
3563 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &uses->exts);
3564 break;
3565 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003566 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003567 return LY_EVALID;
3568 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003569 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003570 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003571 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003572
3573 return ret;
3574}
3575
Michal Vaskoea5abea2018-09-18 13:10:54 +02003576/**
3577 * @brief Parse the case statement.
3578 *
3579 * @param[in] ctx libyang context for logging.
3580 * @param[in,out] data Data to read from, always moved to currently handled character.
3581 * @param[in,out] siblings Siblings to add to.
3582 *
3583 * @return LY_ERR values.
3584 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003585static LY_ERR
3586parse_case(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3587{
3588 LY_ERR ret = 0;
3589 char *buf, *word;
3590 int word_len;
3591 enum yang_keyword kw;
3592 struct lysp_node *iter;
3593 struct lysp_node_case *cas;
3594
3595 /* create structure */
3596 cas = calloc(1, sizeof *cas);
3597 LY_CHECK_ERR_RET(!cas, LOGMEM(ctx), LY_EMEM);
3598 cas->nodetype = LYS_CASE;
3599
3600 /* insert into siblings */
3601 if (!*siblings) {
3602 *siblings = (struct lysp_node *)cas;
3603 } else {
3604 for (iter = *siblings; iter->next; iter = iter->next);
3605 iter->next = (struct lysp_node *)cas;
3606 }
3607
3608 /* get name */
3609 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003610 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003611
3612 if (buf) {
3613 cas->name = lydict_insert_zc(ctx, word);
3614 } else {
3615 cas->name = lydict_insert(ctx, word, word_len);
3616 }
3617
3618 /* parse substatements */
3619 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003620 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003621
3622 switch (kw) {
3623 case YANG_DESCRIPTION:
3624 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts);
3625 break;
3626 case YANG_IF_FEATURE:
3627 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cas->iffeatures, Y_STR_ARG, &cas->exts);
3628 break;
3629 case YANG_REFERENCE:
3630 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts);
3631 break;
3632 case YANG_STATUS:
3633 ret = parse_status(ctx, data, &cas->flags, &cas->exts);
3634 break;
3635 case YANG_WHEN:
3636 ret = parse_when(ctx, data, &cas->when);
3637 break;
3638
3639 case YANG_ANYDATA:
3640 case YANG_ANYXML:
3641 ret = parse_any(ctx, data, kw, &cas->child);
3642 break;
3643 case YANG_CHOICE:
3644 ret = parse_case(ctx, data, &cas->child);
3645 break;
3646 case YANG_CONTAINER:
3647 ret = parse_container(ctx, data, &cas->child);
3648 break;
3649 case YANG_LEAF:
3650 ret = parse_leaf(ctx, data, &cas->child);
3651 break;
3652 case YANG_LEAF_LIST:
3653 ret = parse_leaflist(ctx, data, &cas->child);
3654 break;
3655 case YANG_LIST:
3656 ret = parse_list(ctx, data, &cas->child);
3657 break;
3658 case YANG_USES:
3659 ret = parse_uses(ctx, data, &cas->child);
3660 break;
3661 case YANG_CUSTOM:
3662 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cas->exts);
3663 break;
3664 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003665 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003666 return LY_EVALID;
3667 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003668 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003669 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003670 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003671
3672 return ret;
3673}
3674
Michal Vaskoea5abea2018-09-18 13:10:54 +02003675/**
3676 * @brief Parse the choice statement.
3677 *
3678 * @param[in] ctx libyang context for logging.
3679 * @param[in,out] data Data to read from, always moved to currently handled character.
3680 * @param[in,out] siblings Siblings to add to.
3681 *
3682 * @return LY_ERR values.
3683 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003684static LY_ERR
3685parse_choice(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3686{
3687 LY_ERR ret = 0;
3688 char *buf, *word;
3689 int word_len;
3690 enum yang_keyword kw;
3691 struct lysp_node *iter;
3692 struct lysp_node_choice *choic;
3693
3694 /* create structure */
3695 choic = calloc(1, sizeof *choic);
3696 LY_CHECK_ERR_RET(!choic, LOGMEM(ctx), LY_EMEM);
3697 choic->nodetype = LYS_CHOICE;
3698
3699 /* insert into siblings */
3700 if (!*siblings) {
3701 *siblings = (struct lysp_node *)choic;
3702 } else {
3703 for (iter = *siblings; iter->next; iter = iter->next);
3704 iter->next = (struct lysp_node *)choic;
3705 }
3706
3707 /* get name */
3708 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003709 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003710
3711 if (buf) {
3712 choic->name = lydict_insert_zc(ctx, word);
3713 } else {
3714 choic->name = lydict_insert(ctx, word, word_len);
3715 }
3716
3717 /* parse substatements */
3718 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003719 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003720
3721 switch (kw) {
3722 case YANG_CONFIG:
3723 ret = parse_config(ctx, data, &choic->flags, &choic->exts);
3724 break;
3725 case YANG_DESCRIPTION:
3726 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &choic->dsc, Y_STR_ARG, &choic->exts);
3727 break;
3728 case YANG_IF_FEATURE:
3729 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &choic->iffeatures, Y_STR_ARG, &choic->exts);
3730 break;
3731 case YANG_MANDATORY:
3732 ret = parse_mandatory(ctx, data, &choic->flags, &choic->exts);
3733 break;
3734 case YANG_REFERENCE:
3735 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &choic->ref, Y_STR_ARG, &choic->exts);
3736 break;
3737 case YANG_STATUS:
3738 ret = parse_status(ctx, data, &choic->flags, &choic->exts);
3739 break;
3740 case YANG_WHEN:
3741 ret = parse_when(ctx, data, &choic->when);
3742 break;
3743 case YANG_DEFAULT:
3744 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &choic->dflt, Y_IDENTIF_ARG, &choic->exts);
3745 break;
3746
3747 case YANG_ANYDATA:
3748 case YANG_ANYXML:
3749 ret = parse_any(ctx, data, kw, &choic->child);
3750 break;
3751 case YANG_CASE:
3752 ret = parse_case(ctx, data, &choic->child);
3753 break;
3754 case YANG_CHOICE:
3755 ret = parse_choice(ctx, data, &choic->child);
3756 break;
3757 case YANG_CONTAINER:
3758 ret = parse_container(ctx, data, &choic->child);
3759 break;
3760 case YANG_LEAF:
3761 ret = parse_leaf(ctx, data, &choic->child);
3762 break;
3763 case YANG_LEAF_LIST:
3764 ret = parse_leaflist(ctx, data, &choic->child);
3765 break;
3766 case YANG_LIST:
3767 ret = parse_list(ctx, data, &choic->child);
3768 break;
3769 case YANG_CUSTOM:
3770 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &choic->exts);
3771 break;
3772 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003773 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003774 return LY_EVALID;
3775 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003776 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003777 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003778 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003779
3780 return ret;
3781}
3782
Michal Vaskoea5abea2018-09-18 13:10:54 +02003783/**
3784 * @brief Parse the container statement.
3785 *
3786 * @param[in] ctx libyang context for logging.
3787 * @param[in,out] data Data to read from, always moved to currently handled character.
3788 * @param[in,out] siblings Siblings to add to.
3789 *
3790 * @return LY_ERR values.
3791 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003792static LY_ERR
3793parse_container(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3794{
3795 LY_ERR ret = 0;
3796 char *buf, *word;
3797 int word_len;
3798 enum yang_keyword kw;
3799 struct lysp_node *iter;
3800 struct lysp_node_container *cont;
3801
3802 /* create structure */
3803 cont = calloc(1, sizeof *cont);
3804 LY_CHECK_ERR_RET(!cont, LOGMEM(ctx), LY_EMEM);
3805 cont->nodetype = LYS_CONTAINER;
3806
3807 /* insert into siblings */
3808 if (!*siblings) {
3809 *siblings = (struct lysp_node *)cont;
3810 } else {
3811 for (iter = *siblings; iter->next; iter = iter->next);
3812 iter->next = (struct lysp_node *)cont;
3813 }
3814
3815 /* get name */
3816 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003817 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003818
3819 if (buf) {
3820 cont->name = lydict_insert_zc(ctx, word);
3821 } else {
3822 cont->name = lydict_insert(ctx, word, word_len);
3823 }
3824
3825 /* parse substatements */
3826 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003827 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003828
3829 switch (kw) {
3830 case YANG_CONFIG:
3831 ret = parse_config(ctx, data, &cont->flags, &cont->exts);
3832 break;
3833 case YANG_DESCRIPTION:
3834 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts);
3835 break;
3836 case YANG_IF_FEATURE:
3837 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cont->iffeatures, Y_STR_ARG, &cont->exts);
3838 break;
3839 case YANG_REFERENCE:
3840 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts);
3841 break;
3842 case YANG_STATUS:
3843 ret = parse_status(ctx, data, &cont->flags, &cont->exts);
3844 break;
3845 case YANG_WHEN:
3846 ret = parse_when(ctx, data, &cont->when);
3847 break;
3848 case YANG_PRESENCE:
3849 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts);
3850 break;
3851
3852 case YANG_ANYDATA:
3853 case YANG_ANYXML:
3854 ret = parse_any(ctx, data, kw, &cont->child);
3855 break;
3856 case YANG_CHOICE:
3857 ret = parse_choice(ctx, data, &cont->child);
3858 break;
3859 case YANG_CONTAINER:
3860 ret = parse_container(ctx, data, &cont->child);
3861 break;
3862 case YANG_LEAF:
3863 ret = parse_leaf(ctx, data, &cont->child);
3864 break;
3865 case YANG_LEAF_LIST:
3866 ret = parse_leaflist(ctx, data, &cont->child);
3867 break;
3868 case YANG_LIST:
3869 ret = parse_list(ctx, data, &cont->child);
3870 break;
3871 case YANG_USES:
3872 ret = parse_uses(ctx, data, &cont->child);
3873 break;
3874
3875 case YANG_TYPEDEF:
3876 ret = parse_typedef(ctx, data, &cont->typedefs);
3877 break;
3878 case YANG_MUST:
3879 ret = parse_restrs(ctx, data, kw, &cont->musts);
3880 break;
3881 case YANG_ACTION:
3882 ret = parse_action(ctx, data, &cont->actions);
3883 break;
3884 case YANG_GROUPING:
3885 ret = parse_grouping(ctx, data, &cont->groupings);
3886 break;
3887 case YANG_NOTIFICATION:
3888 ret = parse_notif(ctx, data, &cont->notifs);
3889 break;
3890 case YANG_CUSTOM:
3891 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cont->exts);
3892 break;
3893 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003894 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003895 return LY_EVALID;
3896 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003897 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003898 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003899 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003900
3901 return ret;
3902}
3903
Michal Vaskoea5abea2018-09-18 13:10:54 +02003904/**
3905 * @brief Parse the list statement.
3906 *
3907 * @param[in] ctx libyang context for logging.
3908 * @param[in,out] data Data to read from, always moved to currently handled character.
3909 * @param[in,out] siblings Siblings to add to.
3910 *
3911 * @return LY_ERR values.
3912 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003913static LY_ERR
3914parse_list(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3915{
3916 LY_ERR ret = 0;
3917 char *buf, *word;
3918 int word_len;
3919 enum yang_keyword kw;
3920 struct lysp_node *iter;
3921 struct lysp_node_list *list;
3922
3923 /* create structure */
3924 list = calloc(1, sizeof *list);
3925 LY_CHECK_ERR_RET(!list, LOGMEM(ctx), LY_EMEM);
3926 list->nodetype = LYS_LIST;
3927
3928 /* insert into siblings */
3929 if (!*siblings) {
3930 *siblings = (struct lysp_node *)list;
3931 } else {
3932 for (iter = *siblings; iter->next; iter = iter->next);
3933 iter->next = (struct lysp_node *)list;
3934 }
3935
3936 /* get name */
3937 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003938 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003939
3940 if (buf) {
3941 list->name = lydict_insert_zc(ctx, word);
3942 } else {
3943 list->name = lydict_insert(ctx, word, word_len);
3944 }
3945
3946 /* parse substatements */
3947 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003948 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003949
3950 switch (kw) {
3951 case YANG_CONFIG:
3952 ret = parse_config(ctx, data, &list->flags, &list->exts);
3953 break;
3954 case YANG_DESCRIPTION:
3955 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts);
3956 break;
3957 case YANG_IF_FEATURE:
3958 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &list->iffeatures, Y_STR_ARG, &list->exts);
3959 break;
3960 case YANG_REFERENCE:
3961 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts);
3962 break;
3963 case YANG_STATUS:
3964 ret = parse_status(ctx, data, &list->flags, &list->exts);
3965 break;
3966 case YANG_WHEN:
3967 ret = parse_when(ctx, data, &list->when);
3968 break;
3969 case YANG_KEY:
3970 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts);
3971 break;
3972 case YANG_MAX_ELEMENTS:
3973 ret = parse_maxelements(ctx, data, &list->max, &list->flags, &list->exts);
3974 break;
3975 case YANG_MIN_ELEMENTS:
3976 ret = parse_minelements(ctx, data, &list->min, &list->flags, &list->exts);
3977 break;
3978 case YANG_ORDERED_BY:
3979 ret = parse_orderedby(ctx, data, &list->flags, &list->exts);
3980 break;
3981 case YANG_UNIQUE:
3982 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, &list->uniques, Y_STR_ARG, &list->exts);
3983 break;
3984
3985 case YANG_ANYDATA:
3986 case YANG_ANYXML:
3987 ret = parse_any(ctx, data, kw, &list->child);
3988 break;
3989 case YANG_CHOICE:
3990 ret = parse_choice(ctx, data, &list->child);
3991 break;
3992 case YANG_CONTAINER:
3993 ret = parse_container(ctx, data, &list->child);
3994 break;
3995 case YANG_LEAF:
3996 ret = parse_leaf(ctx, data, &list->child);
3997 break;
3998 case YANG_LEAF_LIST:
3999 ret = parse_leaflist(ctx, data, &list->child);
4000 break;
4001 case YANG_LIST:
4002 ret = parse_list(ctx, data, &list->child);
4003 break;
4004 case YANG_USES:
4005 ret = parse_uses(ctx, data, &list->child);
4006 break;
4007
4008 case YANG_TYPEDEF:
4009 ret = parse_typedef(ctx, data, &list->typedefs);
4010 break;
4011 case YANG_MUST:
4012 ret = parse_restrs(ctx, data, kw, &list->musts);
4013 break;
4014 case YANG_ACTION:
4015 ret = parse_action(ctx, data, &list->actions);
4016 break;
4017 case YANG_GROUPING:
4018 ret = parse_grouping(ctx, data, &list->groupings);
4019 break;
4020 case YANG_NOTIFICATION:
4021 ret = parse_notif(ctx, data, &list->notifs);
4022 break;
4023 case YANG_CUSTOM:
4024 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &list->exts);
4025 break;
4026 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004027 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004028 return LY_EVALID;
4029 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004030 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004031 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004032 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004033
4034 return ret;
4035}
4036
Michal Vaskoea5abea2018-09-18 13:10:54 +02004037/**
4038 * @brief Parse the yin-element statement.
4039 *
4040 * @param[in] ctx libyang context for logging.
4041 * @param[in,out] data Data to read from, always moved to currently handled character.
4042 * @param[in,out] flags Flags to write to.
4043 * @param[in,out] exts Extension instances to add to.
4044 *
4045 * @return LY_ERR values.
4046 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004047static LY_ERR
4048parse_yinelement(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
4049{
4050 LY_ERR ret = 0;
4051 char *buf, *word;
4052 int word_len;
4053 enum yang_keyword kw;
4054
4055 if (*flags & LYS_YINELEM_MASK) {
4056 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yin-element");
4057 return LY_EVALID;
4058 }
4059
4060 /* get value */
4061 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004062 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004063
4064 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
4065 *flags |= LYS_YINELEM_TRUE;
4066 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
4067 *flags |= LYS_YINELEM_FALSE;
4068 } else {
4069 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yin-element");
4070 free(buf);
4071 return LY_EVALID;
4072 }
4073 free(buf);
4074
4075 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004076 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004077
4078 switch (kw) {
4079 case YANG_CUSTOM:
4080 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_YINELEM, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02004081 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004082 break;
4083 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004084 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004085 return LY_EVALID;
4086 }
4087 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004088 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004089
4090 return ret;
4091}
4092
Michal Vaskoea5abea2018-09-18 13:10:54 +02004093/**
4094 * @brief Parse the yin-element statement.
4095 *
4096 * @param[in] ctx libyang context for logging.
4097 * @param[in,out] data Data to read from, always moved to currently handled character.
4098 * @param[in,out] argument Value to write to.
4099 * @param[in,out] flags Flags to write to.
4100 * @param[in,out] exts Extension instances to add to.
4101 *
4102 * @return LY_ERR values.
4103 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004104static LY_ERR
4105parse_argument(struct ly_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
4106{
4107 LY_ERR ret = 0;
4108 char *buf, *word;
4109 int word_len;
4110 enum yang_keyword kw;
4111
4112 if (*argument) {
4113 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "argument");
4114 return LY_EVALID;
4115 }
4116
4117 /* get value */
4118 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004119 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004120
4121 if (buf) {
4122 *argument = lydict_insert_zc(ctx, word);
4123 } else {
4124 *argument = lydict_insert(ctx, word, word_len);
4125 }
4126
4127 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004128 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004129
4130 switch (kw) {
4131 case YANG_YIN_ELEMENT:
4132 ret = parse_yinelement(ctx, data, flags, exts);
4133 break;
4134 case YANG_CUSTOM:
4135 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ARGUMENT, 0, exts);
4136 break;
4137 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004138 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004139 return LY_EVALID;
4140 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004141 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004142 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004143 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004144
4145 return ret;
4146}
4147
Michal Vaskoea5abea2018-09-18 13:10:54 +02004148/**
4149 * @brief Parse the extension statement.
4150 *
4151 * @param[in] ctx libyang context for logging.
4152 * @param[in,out] data Data to read from, always moved to currently handled character.
4153 * @param[in,out] extensions Extensions to add to.
4154 *
4155 * @return LY_ERR values.
4156 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004157static LY_ERR
4158parse_extension(struct ly_ctx *ctx, const char **data, struct lysp_ext **extensions)
4159{
4160 LY_ERR ret = 0;
4161 char *buf, *word;
4162 int word_len;
4163 enum yang_keyword kw;
4164 struct lysp_ext *ex;
4165
4166 LYSP_ARRAY_NEW_RET(ctx, extensions, ex, LY_EMEM);
4167
4168 /* get value */
4169 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004170 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004171
4172 if (buf) {
4173 ex->name = lydict_insert_zc(ctx, word);
4174 } else {
4175 ex->name = lydict_insert(ctx, word, word_len);
4176 }
4177
4178 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004179 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004180
4181 switch (kw) {
4182 case YANG_DESCRIPTION:
4183 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts);
4184 break;
4185 case YANG_REFERENCE:
4186 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts);
4187 break;
4188 case YANG_STATUS:
4189 ret = parse_status(ctx, data, &ex->flags, &ex->exts);
4190 break;
4191 case YANG_ARGUMENT:
4192 ret = parse_argument(ctx, data, &ex->argument, &ex->flags, &ex->exts);
4193 break;
4194 case YANG_CUSTOM:
4195 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ex->exts);
4196 break;
4197 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004198 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004199 return LY_EVALID;
4200 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004201 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004202 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004203 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004204
4205 return ret;
4206}
4207
Michal Vaskoea5abea2018-09-18 13:10:54 +02004208/**
4209 * @brief Parse the deviate statement.
4210 *
4211 * @param[in] ctx libyang context for logging.
4212 * @param[in,out] data Data to read from, always moved to currently handled character.
4213 * @param[in,out] deviates Deviates to add to.
4214 *
4215 * @return LY_ERR values.
4216 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004217static LY_ERR
4218parse_deviate(struct ly_ctx *ctx, const char **data, struct lysp_deviate **deviates)
4219{
4220 LY_ERR ret = 0;
4221 char *buf, *word;
4222 int word_len, dev_mod;
4223 enum yang_keyword kw;
4224 struct lysp_deviate *iter, *d;
4225 struct lysp_deviate_add *d_add = NULL;
4226 struct lysp_deviate_rpl *d_rpl = NULL;
4227 struct lysp_deviate_del *d_del = NULL;
4228 const char **d_units, ***d_uniques, ***d_dflts;
4229 struct lysp_restr **d_musts;
4230 uint16_t *d_flags;
4231 uint32_t *d_min, *d_max;
4232
4233 /* get value */
4234 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004235 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004236
4237 if ((word_len == 13) && !strncmp(word, "not-supported", word_len)) {
4238 dev_mod = LYS_DEV_NOT_SUPPORTED;
4239 } else if ((word_len == 3) && !strncmp(word, "add", word_len)) {
4240 dev_mod = LYS_DEV_ADD;
4241 } else if ((word_len == 7) && !strncmp(word, "replace", word_len)) {
4242 dev_mod = LYS_DEV_REPLACE;
4243 } else if ((word_len == 6) && !strncmp(word, "delete", word_len)) {
4244 dev_mod = LYS_DEV_DELETE;
4245 } else {
4246 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "deviate");
4247 free(buf);
4248 return LY_EVALID;
4249 }
4250 free(buf);
4251
4252 /* create structure */
4253 switch (dev_mod) {
4254 case LYS_DEV_NOT_SUPPORTED:
4255 d = calloc(1, sizeof *d);
4256 LY_CHECK_ERR_RET(!d, LOGMEM(ctx), LY_EMEM);
4257 break;
4258 case LYS_DEV_ADD:
4259 d_add = calloc(1, sizeof *d_add);
4260 LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx), LY_EMEM);
4261 d = (struct lysp_deviate *)d_add;
4262 d_units = &d_add->units;
4263 d_uniques = &d_add->uniques;
4264 d_dflts = &d_add->dflts;
4265 d_musts = &d_add->musts;
4266 d_flags = &d_add->flags;
4267 d_min = &d_add->min;
4268 d_max = &d_add->max;
4269 break;
4270 case LYS_DEV_REPLACE:
4271 d_rpl = calloc(1, sizeof *d_rpl);
4272 LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx), LY_EMEM);
4273 d = (struct lysp_deviate *)d_rpl;
4274 d_units = &d_rpl->units;
4275 d_flags = &d_rpl->flags;
4276 d_min = &d_rpl->min;
4277 d_max = &d_rpl->max;
4278 break;
4279 case LYS_DEV_DELETE:
4280 d_del = calloc(1, sizeof *d_del);
4281 LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx), LY_EMEM);
4282 d = (struct lysp_deviate *)d_del;
4283 d_units = &d_del->units;
4284 d_uniques = &d_del->uniques;
4285 d_dflts = &d_del->dflts;
4286 d_musts = &d_del->musts;
4287 d_flags = &d_del->flags;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004288 break;
4289 default:
4290 assert(0);
4291 LOGINT_RET(ctx);
4292 }
4293 d->mod = dev_mod;
4294
4295 /* insert into siblings */
4296 if (!*deviates) {
4297 *deviates = d;
4298 } else {
4299 for (iter = *deviates; iter->next; iter = iter->next);
4300 iter->next = d;
4301 }
4302
4303 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004304 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004305
4306 switch (kw) {
4307 case YANG_CONFIG:
4308 switch (dev_mod) {
4309 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004310 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004311 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004312 return LY_EVALID;
4313 default:
4314 ret = parse_config(ctx, data, d_flags, &d->exts);
4315 break;
4316 }
4317 break;
4318 case YANG_DEFAULT:
4319 switch (dev_mod) {
4320 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004321 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004322 return LY_EVALID;
4323 case LYS_DEV_REPLACE:
4324 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &d_rpl->dflt, Y_STR_ARG, &d->exts);
4325 break;
4326 default:
4327 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, d_dflts, Y_STR_ARG, &d->exts);
4328 break;
4329 }
4330 break;
4331 case YANG_MANDATORY:
4332 switch (dev_mod) {
4333 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004334 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004335 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004336 return LY_EVALID;
4337 default:
4338 ret = parse_mandatory(ctx, data, d_flags, &d->exts);
4339 break;
4340 }
4341 break;
4342 case YANG_MAX_ELEMENTS:
4343 switch (dev_mod) {
4344 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004345 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004346 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004347 return LY_EVALID;
4348 default:
4349 ret = parse_maxelements(ctx, data, d_max, d_flags, &d->exts);
4350 break;
4351 }
4352 break;
4353 case YANG_MIN_ELEMENTS:
4354 switch (dev_mod) {
4355 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004356 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004357 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004358 return LY_EVALID;
4359 default:
4360 ret = parse_minelements(ctx, data, d_min, d_flags, &d->exts);
4361 break;
4362 }
4363 break;
4364 case YANG_MUST:
4365 switch (dev_mod) {
4366 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004367 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004368 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004369 return LY_EVALID;
4370 default:
4371 ret = parse_restrs(ctx, data, kw, d_musts);
4372 break;
4373 }
4374 break;
4375 case YANG_TYPE:
4376 switch (dev_mod) {
4377 case LYS_DEV_NOT_SUPPORTED:
4378 case LYS_DEV_ADD:
4379 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004380 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004381 return LY_EVALID;
4382 default:
4383 d_rpl->type = calloc(1, sizeof *d_rpl->type);
4384 LY_CHECK_ERR_RET(!d_rpl->type, LOGMEM(ctx), LY_EMEM);
4385 ret = parse_type(ctx, data, d_rpl->type);
4386 break;
4387 }
4388 break;
4389 case YANG_UNIQUE:
4390 switch (dev_mod) {
4391 case LYS_DEV_NOT_SUPPORTED:
4392 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004393 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004394 return LY_EVALID;
4395 default:
4396 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts);
4397 break;
4398 }
4399 break;
4400 case YANG_UNITS:
4401 switch (dev_mod) {
4402 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004403 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004404 return LY_EVALID;
4405 default:
4406 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts);
4407 break;
4408 }
4409 break;
4410 case YANG_CUSTOM:
4411 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &d->exts);
4412 break;
4413 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004414 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004415 return LY_EVALID;
4416 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004417 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004418 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004419 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004420
4421 return ret;
4422}
4423
Michal Vaskoea5abea2018-09-18 13:10:54 +02004424/**
4425 * @brief Parse the deviation statement.
4426 *
4427 * @param[in] ctx libyang context for logging.
4428 * @param[in,out] data Data to read from, always moved to currently handled character.
4429 * @param[in,out] deviations Deviations to add to.
4430 *
4431 * @return LY_ERR values.
4432 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004433static LY_ERR
4434parse_deviation(struct ly_ctx *ctx, const char **data, struct lysp_deviation **deviations)
4435{
4436 LY_ERR ret = 0;
4437 char *buf, *word;
4438 int word_len;
4439 enum yang_keyword kw;
4440 struct lysp_deviation *dev;
4441
4442 LYSP_ARRAY_NEW_RET(ctx, deviations, dev, LY_EMEM);
4443
4444 /* get value */
4445 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004446 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004447
4448 if (buf) {
4449 dev->nodeid = lydict_insert_zc(ctx, word);
4450 } else {
4451 dev->nodeid = lydict_insert(ctx, word, word_len);
4452 }
4453
4454 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004455 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004456
4457 switch (kw) {
4458 case YANG_DESCRIPTION:
4459 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts);
4460 break;
4461 case YANG_DEVIATE:
4462 ret = parse_deviate(ctx, data, &dev->deviates);
4463 break;
4464 case YANG_REFERENCE:
4465 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts);
4466 break;
4467 case YANG_CUSTOM:
4468 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &dev->exts);
4469 break;
4470 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004471 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004472 return LY_EVALID;
4473 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004474 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004475 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004476 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004477
4478 /* mandatory substatements */
4479 if (!dev->deviates) {
4480 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "deviate", "deviation");
4481 return LY_EVALID;
4482 }
4483
4484 return ret;
4485}
4486
Michal Vaskoea5abea2018-09-18 13:10:54 +02004487/**
4488 * @brief Parse the feature statement.
4489 *
4490 * @param[in] ctx libyang context for logging.
4491 * @param[in,out] data Data to read from, always moved to currently handled character.
4492 * @param[in,out] features Features to add to.
4493 *
4494 * @return LY_ERR values.
4495 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004496static LY_ERR
4497parse_feature(struct ly_ctx *ctx, const char **data, struct lysp_feature **features)
4498{
4499 LY_ERR ret = 0;
4500 char *buf, *word;
4501 int word_len;
4502 enum yang_keyword kw;
4503 struct lysp_feature *feat;
4504
4505 LYSP_ARRAY_NEW_RET(ctx, features, feat, LY_EMEM);
4506
4507 /* get value */
4508 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004509 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004510
4511 if (buf) {
4512 feat->name = lydict_insert_zc(ctx, word);
4513 } else {
4514 feat->name = lydict_insert(ctx, word, word_len);
4515 }
4516
4517 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004518 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004519
4520 switch (kw) {
4521 case YANG_DESCRIPTION:
4522 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts);
4523 break;
4524 case YANG_IF_FEATURE:
4525 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &feat->iffeatures, Y_STR_ARG, &feat->exts);
4526 break;
4527 case YANG_REFERENCE:
4528 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts);
4529 break;
4530 case YANG_STATUS:
4531 ret = parse_status(ctx, data, &feat->flags, &feat->exts);
4532 break;
4533 case YANG_CUSTOM:
4534 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &feat->exts);
4535 break;
4536 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004537 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004538 return LY_EMEM;
4539 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004540 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004541 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004542 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004543
4544 return ret;
4545}
4546
Michal Vaskoea5abea2018-09-18 13:10:54 +02004547/**
4548 * @brief Parse the identity statement.
4549 *
4550 * @param[in] ctx libyang context for logging.
4551 * @param[in,out] data Data to read from, always moved to currently handled character.
4552 * @param[in,out] identities Identities to add to.
4553 *
4554 * @return LY_ERR values.
4555 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004556static LY_ERR
4557parse_identity(struct ly_ctx *ctx, const char **data, struct lysp_ident **identities)
4558{
4559 LY_ERR ret = 0;
4560 char *buf, *word;
4561 int word_len;
4562 enum yang_keyword kw;
4563 struct lysp_ident *ident;
4564
4565 LYSP_ARRAY_NEW_RET(ctx, identities, ident, LY_EMEM);
4566
4567 /* get value */
4568 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004569 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004570
4571 if (buf) {
4572 ident->name = lydict_insert_zc(ctx, word);
4573 } else {
4574 ident->name = lydict_insert(ctx, word, word_len);
4575 }
4576
4577 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004578 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004579
4580 switch (kw) {
4581 case YANG_DESCRIPTION:
4582 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts);
4583 break;
4584 case YANG_IF_FEATURE:
4585 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts);
4586 break;
4587 case YANG_REFERENCE:
4588 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts);
4589 break;
4590 case YANG_STATUS:
4591 ret = parse_status(ctx, data, &ident->flags, &ident->exts);
4592 break;
4593 case YANG_BASE:
4594 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts);
4595 break;
4596 case YANG_CUSTOM:
4597 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ident->exts);
4598 break;
4599 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004600 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004601 return LY_EVALID;
4602 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004603 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004604 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004605 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004606
4607 return ret;
4608}
4609
Michal Vaskoea5abea2018-09-18 13:10:54 +02004610/**
4611 * @brief Parse the module or submodule statement.
4612 *
4613 * @param[in] ctx libyang context for logging.
4614 * @param[in,out] data Data to read from, always moved to currently handled character.
4615 * @param[in,out] mod Module to write to.
4616 *
4617 * @return LY_ERR values.
4618 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004619static LY_ERR
4620parse_sub_module(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
4621{
4622 LY_ERR ret = 0;
4623 char *buf, *word;
4624 int word_len;
4625 enum yang_keyword kw, prev_kw = 0;
4626 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
4627
4628 /* (sub)module name */
4629 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004630 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004631
4632 if (buf) {
4633 mod->name = lydict_insert_zc(ctx, word);
4634 } else {
4635 mod->name = lydict_insert(ctx, word, word_len);
4636 }
4637
4638 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004639 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004640
4641 switch (kw) {
4642 /* module header */
4643 case YANG_NAMESPACE:
4644 case YANG_PREFIX:
4645 if (mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004646 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004647 return LY_EVALID;
4648 }
4649 /* fallthrough */
4650 case YANG_BELONGS_TO:
4651 if ((kw == YANG_BELONGS_TO) && !mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004652 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004653 return LY_EVALID;
4654 }
4655 /* fallthrough */
4656 case YANG_YANG_VERSION:
4657 if (mod_stmt > Y_MOD_MODULE_HEADER) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004658 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004659 return LY_EVALID;
4660 }
4661 break;
4662 /* linkage */
4663 case YANG_INCLUDE:
4664 case YANG_IMPORT:
4665 if (mod_stmt > Y_MOD_LINKAGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004666 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004667 return LY_EVALID;
4668 }
4669 mod_stmt = Y_MOD_LINKAGE;
4670 break;
4671 /* meta */
4672 case YANG_ORGANIZATION:
4673 case YANG_CONTACT:
4674 case YANG_DESCRIPTION:
4675 case YANG_REFERENCE:
4676 if (mod_stmt > Y_MOD_META) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004677 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004678 return LY_EVALID;
4679 }
4680 mod_stmt = Y_MOD_META;
4681 break;
4682
4683 /* revision */
4684 case YANG_REVISION:
4685 if (mod_stmt > Y_MOD_REVISION) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004686 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004687 return LY_EVALID;
4688 }
4689 mod_stmt = Y_MOD_REVISION;
4690 break;
4691
4692 /* body */
4693 case YANG_ANYDATA:
4694 case YANG_ANYXML:
4695 case YANG_AUGMENT:
4696 case YANG_CHOICE:
4697 case YANG_CONTAINER:
4698 case YANG_DEVIATION:
4699 case YANG_EXTENSION:
4700 case YANG_FEATURE:
4701 case YANG_GROUPING:
4702 case YANG_IDENTITY:
4703 case YANG_LEAF:
4704 case YANG_LEAF_LIST:
4705 case YANG_LIST:
4706 case YANG_NOTIFICATION:
4707 case YANG_RPC:
4708 case YANG_TYPEDEF:
4709 case YANG_USES:
4710 case YANG_CUSTOM:
4711 mod_stmt = Y_MOD_BODY;
4712 break;
4713 default:
4714 /* error handled in the next switch */
4715 break;
4716 }
4717 prev_kw = kw;
4718
4719 switch (kw) {
4720 /* module header */
4721 case YANG_YANG_VERSION:
4722 ret = parse_yangversion(ctx, data, mod);
4723 break;
4724 case YANG_NAMESPACE:
4725 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_NAMESPACE, 0, &mod->ns, Y_STR_ARG, &mod->exts);
4726 break;
4727 case YANG_PREFIX:
4728 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &mod->prefix, Y_IDENTIF_ARG, &mod->exts);
4729 break;
4730 case YANG_BELONGS_TO:
4731 ret = parse_belongsto(ctx, data, &mod->belongsto, &mod->prefix, &mod->exts);
4732 break;
4733
4734 /* linkage */
4735 case YANG_INCLUDE:
4736 ret = parse_include(ctx, data, &mod->includes);
4737 break;
4738 case YANG_IMPORT:
4739 ret = parse_import(ctx, data, &mod->imports);
4740 break;
4741
4742 /* meta */
4743 case YANG_ORGANIZATION:
4744 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &mod->org, Y_STR_ARG, &mod->exts);
4745 break;
4746 case YANG_CONTACT:
4747 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &mod->contact, Y_STR_ARG, &mod->exts);
4748 break;
4749 case YANG_DESCRIPTION:
4750 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &mod->dsc, Y_STR_ARG, &mod->exts);
4751 break;
4752 case YANG_REFERENCE:
4753 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &mod->ref, Y_STR_ARG, &mod->exts);
4754 break;
4755
4756 /* revision */
4757 case YANG_REVISION:
4758 ret = parse_revision(ctx, data, &mod->revs);
4759 break;
4760
4761 /* body */
4762 case YANG_ANYDATA:
4763 case YANG_ANYXML:
4764 ret = parse_any(ctx, data, kw, &mod->data);
4765 break;
4766 case YANG_CHOICE:
4767 ret = parse_choice(ctx, data, &mod->data);
4768 break;
4769 case YANG_CONTAINER:
4770 ret = parse_container(ctx, data, &mod->data);
4771 break;
4772 case YANG_LEAF:
4773 ret = parse_leaf(ctx, data, &mod->data);
4774 break;
4775 case YANG_LEAF_LIST:
4776 ret = parse_leaflist(ctx, data, &mod->data);
4777 break;
4778 case YANG_LIST:
4779 ret = parse_list(ctx, data, &mod->data);
4780 break;
4781 case YANG_USES:
4782 ret = parse_uses(ctx, data, &mod->data);
4783 break;
4784
4785 case YANG_AUGMENT:
4786 ret = parse_augment(ctx, data, &mod->augments);
4787 break;
4788 case YANG_DEVIATION:
4789 ret = parse_deviation(ctx, data, &mod->deviations);
4790 break;
4791 case YANG_EXTENSION:
4792 ret = parse_extension(ctx, data, &mod->extensions);
4793 break;
4794 case YANG_FEATURE:
4795 ret = parse_feature(ctx, data, &mod->features);
4796 break;
4797 case YANG_GROUPING:
4798 ret = parse_grouping(ctx, data, &mod->groupings);
4799 break;
4800 case YANG_IDENTITY:
4801 ret = parse_identity(ctx, data, &mod->identities);
4802 break;
4803 case YANG_NOTIFICATION:
4804 ret = parse_notif(ctx, data, &mod->notifs);
4805 break;
4806 case YANG_RPC:
4807 ret = parse_action(ctx, data, &mod->rpcs);
4808 break;
4809 case YANG_TYPEDEF:
4810 ret = parse_typedef(ctx, data, &mod->typedefs);
4811 break;
4812 case YANG_CUSTOM:
4813 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &mod->exts);
4814 break;
4815
4816 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004817 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), mod->submodule ? "submodule" : "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004818 return LY_EVALID;
4819 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004820 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004821 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004822 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004823
4824 /* mandatory substatements */
4825 if (mod->submodule) {
4826 if (!mod->belongsto) {
4827 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "belongs-to", "submodule");
4828 return LY_EVALID;
4829 }
4830 } else {
4831 if (!mod->ns) {
4832 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "namespace", "module");
4833 return LY_EVALID;
4834 } else if (!mod->prefix) {
4835 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "module");
4836 return LY_EVALID;
4837 }
4838 }
4839
4840 return ret;
4841}
4842
Radek Krejcid4557c62018-09-17 11:42:09 +02004843LY_ERR
Michal Vasko7fbc8162018-09-17 10:35:16 +02004844yang_parse(struct ly_ctx *ctx, const char *data, struct lysp_module **mod_p)
4845{
4846 LY_ERR ret = 0;
4847 char *word, *buf;
4848 int word_len;
4849 const char *data_start;
4850 enum yang_keyword kw;
4851 struct lysp_module *mod;
4852
4853 data_start = data;
4854
4855 /* "module"/"submodule" */
4856 ret = get_keyword(ctx, &data, &kw, &word, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004857 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004858
4859 if ((kw != YANG_MODULE) && (kw != YANG_SUBMODULE)) {
4860 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".\n",
Radek Krejcic59bc972018-09-17 16:13:06 +02004861 ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004862 goto error;
4863 }
4864
4865 mod = calloc(1, sizeof *mod);
4866 LY_CHECK_ERR_GOTO(!mod, LOGMEM(ctx), error);
4867 if (kw == YANG_SUBMODULE) {
4868 mod->submodule = 1;
4869 }
4870
4871 /* substatements */
4872 ret = parse_sub_module(ctx, &data, mod);
Radek Krejcic59bc972018-09-17 16:13:06 +02004873 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004874
4875 /* read some trailing spaces or new lines */
4876 ret = get_string(ctx, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004877 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004878
4879 if (word) {
4880 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected end-of-file.",
4881 word_len, word);
4882 free(buf);
4883 goto error;
4884 }
4885 assert(!buf);
4886
4887 *mod_p = mod;
4888 return ret;
4889
4890error:
4891 LOGERR(ctx, LY_EINVAL, "Module parsing failed on line %d.", lysp_get_data_line(data_start, data - data_start));
4892 /* TODO free module */
4893 return ret;
4894}