blob: a80a62cb8cc1dfe189312c86fa6c3c8e3d6038e0 [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
Radek Krejci0ae092d2018-09-20 16:43:19 +02001070 if (word) {
1071 if (buf) {
1072 stmt->arg = lydict_insert_zc(ctx, word);
1073 } else {
1074 stmt->arg = lydict_insert(ctx, word, word_len);
1075 }
Michal Vasko7fbc8162018-09-17 10:35:16 +02001076 }
1077
1078 /* insert into parent statements */
1079 if (!*child) {
1080 *child = stmt;
1081 } else {
1082 for (par_child = *child; par_child->next; par_child = par_child->next);
1083 par_child->next = stmt;
1084 }
1085
1086 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001087 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001088
1089 ret = parse_ext_substmt(ctx, data, word, word_len, &stmt->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001090 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001091 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001092 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001093
1094 return ret;
1095}
1096
Michal Vaskoea5abea2018-09-18 13:10:54 +02001097/**
1098 * @brief Parse extension instance.
1099 *
1100 * @param[in] ctx libyang context for logging.
1101 * @param[in,out] data Data to read from, always moved to currently handled character.
1102 * @param[in] ext_name Extension instance substatement name (keyword).
1103 * @param[in] ext_name_len Extension instance substatement name length.
1104 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
1105 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
1106 * @param[in,out] exts Extension instances to add to.
1107 *
1108 * @return LY_ERR values.
1109 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001110static LY_ERR
1111parse_ext(struct ly_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
1112 uint32_t insubstmt_index, struct lysp_ext_instance **exts)
1113{
1114 LY_ERR ret = 0;
1115 char *buf, *word;
1116 int word_len;
1117 struct lysp_ext_instance *e;
1118 enum yang_keyword kw;
1119
1120 LYSP_ARRAY_NEW_RET(ctx, exts, e, LY_EMEM);
1121
1122 /* store name and insubstmt info */
1123 e->name = lydict_insert(ctx, ext_name, ext_name_len);
1124 e->insubstmt = insubstmt;
1125 e->insubstmt_index = insubstmt_index;
1126
1127 /* get optional argument */
1128 ret = get_string(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001129 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001130
Radek Krejci0ae092d2018-09-20 16:43:19 +02001131 if (word) {
1132 if (buf) {
1133 e->argument = lydict_insert_zc(ctx, word);
1134 } else {
1135 e->argument = lydict_insert(ctx, word, word_len);
1136 }
Michal Vasko7fbc8162018-09-17 10:35:16 +02001137 }
1138
1139 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001140 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001141
1142 ret = parse_ext_substmt(ctx, data, word, word_len, &e->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001143 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001144 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001145 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001146
1147 return ret;
1148}
1149
Michal Vaskoea5abea2018-09-18 13:10:54 +02001150/**
1151 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
1152 * description, etc...
1153 *
1154 * @param[in] ctx libyang context for logging.
1155 * @param[in,out] data Data to read from, always moved to currently handled character.
1156 * @param[in] substmt Type of this substatement.
1157 * @param[in] substmt_index Index of this substatement.
1158 * @param[in,out] value Place to store the parsed value.
1159 * @param[in] arg Type of the YANG keyword argument (of the value).
1160 * @param[in,out] exts Extension instances to add to.
1161 *
1162 * @return LY_ERR values.
1163 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001164static LY_ERR
1165parse_text_field(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
1166 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
1167{
1168 LY_ERR ret = 0;
1169 char *buf, *word;
1170 int word_len;
1171 enum yang_keyword kw;
1172
1173 if (*value) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001174 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001175 return LY_EVALID;
1176 }
1177
1178 /* get value */
1179 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001180 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001181
1182 /* store value and spend buf if allocated */
1183 if (buf) {
1184 *value = lydict_insert_zc(ctx, word);
1185 } else {
1186 *value = lydict_insert(ctx, word, word_len);
1187 }
1188
1189 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001190 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001191
1192 switch (kw) {
1193 case YANG_CUSTOM:
1194 ret = parse_ext(ctx, data, word, word_len, substmt, substmt_index, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001195 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001196 break;
1197 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001198 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001199 return LY_EVALID;
1200 }
1201 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001202 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001203
1204 return ret;
1205}
1206
Michal Vaskoea5abea2018-09-18 13:10:54 +02001207/**
1208 * @brief Parse the yang-version statement.
1209 *
1210 * @param[in] ctx libyang context for logging.
1211 * @param[in,out] data Data to read from, always moved to currently handled character.
1212 * @param[in] mod Module to store the parsed information in.
1213 *
1214 * @return LY_ERR values.
1215 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001216static LY_ERR
1217parse_yangversion(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
1218{
1219 LY_ERR ret = 0;
1220 char *buf, *word;
1221 int word_len;
1222 enum yang_keyword kw;
1223
1224 if (mod->version) {
1225 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yang-version");
1226 return LY_EVALID;
1227 }
1228
1229 /* get value */
1230 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001231 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001232
1233 if ((word_len == 3) && !strncmp(word, "1.0", word_len)) {
1234 mod->version = LYS_VERSION_1_0;
1235 } else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
1236 mod->version = LYS_VERSION_1_1;
1237 } else {
1238 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yang-version");
1239 free(buf);
1240 return LY_EVALID;
1241 }
1242 free(buf);
1243
1244 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001245 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001246
1247 switch (kw) {
1248 case YANG_CUSTOM:
1249 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, &mod->exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001250 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001251 break;
1252 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001253 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001254 return LY_EVALID;
1255 }
1256 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001257 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001258
1259 return ret;
1260}
1261
Michal Vaskoea5abea2018-09-18 13:10:54 +02001262/**
1263 * @brief Parse the belongs-to statement.
1264 *
1265 * @param[in] ctx libyang context for logging.
1266 * @param[in,out] data Data to read from, always moved to currently handled character.
1267 * @param[in,out] belongsto Place to store the parsed value.
1268 * @param[in,out] prefix Place to store the parsed belongs-to prefix value.
1269 * @param[in,out] exts Extension instances to add to.
1270 *
1271 * @return LY_ERR values.
1272 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001273static LY_ERR
1274parse_belongsto(struct ly_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
1275{
1276 LY_ERR ret = 0;
1277 char *buf, *word;
1278 int word_len;
1279 enum yang_keyword kw;
1280
1281 if (*belongsto) {
1282 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "belongs-to");
1283 return LY_EVALID;
1284 }
1285
1286 /* get value */
1287 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001288 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001289
1290 if (buf) {
1291 *belongsto = lydict_insert_zc(ctx, word);
1292 } else {
1293 *belongsto = lydict_insert(ctx, word, word_len);
1294 }
1295
1296 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001297 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001298
1299 switch (kw) {
1300 case YANG_PREFIX:
1301 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts);
1302 break;
1303 case YANG_CUSTOM:
1304 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_BELONGSTO, 0, exts);
1305 break;
1306 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001307 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001308 return LY_EVALID;
1309 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001310 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001311 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001312 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001313
1314 /* mandatory substatements */
1315 if (!*prefix) {
1316 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "belongs-to");
1317 return LY_EVALID;
1318 }
1319
1320 return ret;
1321}
1322
Michal Vaskoea5abea2018-09-18 13:10:54 +02001323/**
1324 * @brief Parse the revision-date statement.
1325 *
1326 * @param[in] ctx libyang context for logging.
1327 * @param[in,out] data Data to read from, always moved to currently handled character.
1328 * @param[in,out] rev Array to store the parsed value in.
1329 * @param[in,out] exts Extension instances to add to.
1330 *
1331 * @return LY_ERR values.
1332 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001333static LY_ERR
1334parse_revisiondate(struct ly_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
1335{
1336 LY_ERR ret = 0;
1337 char *buf, *word;
1338 int word_len;
1339 enum yang_keyword kw;
1340
1341 if (rev[0]) {
1342 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "revision-date");
1343 return LY_EVALID;
1344 }
1345
1346 /* get value */
1347 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001348 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001349
1350 /* check value */
1351 if (lysp_check_date(ctx, word, word_len, "revision-date")) {
1352 free(buf);
1353 return LY_EVALID;
1354 }
1355
1356 /* store value and spend buf if allocated */
1357 strncpy(rev, word, word_len);
1358 free(buf);
1359
1360 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001361 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001362
1363 switch (kw) {
1364 case YANG_CUSTOM:
1365 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REVISIONDATE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001366 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001367 break;
1368 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001369 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001370 return LY_EVALID;
1371 }
1372 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001373 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001374
1375 return ret;
1376}
1377
Michal Vaskoea5abea2018-09-18 13:10:54 +02001378/**
1379 * @brief Parse the include statement.
1380 *
1381 * @param[in] ctx libyang context for logging.
1382 * @param[in,out] data Data to read from, always moved to currently handled character.
1383 * @param[in,out] includes Parsed includes to add to.
1384 *
1385 * @return LY_ERR values.
1386 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001387static LY_ERR
1388parse_include(struct ly_ctx *ctx, const char **data, struct lysp_include **includes)
1389{
1390 LY_ERR ret = 0;
1391 char *buf, *word;
1392 int word_len;
1393 enum yang_keyword kw;
1394 struct lysp_include *inc;
1395
1396 LYSP_ARRAY_NEW_RET(ctx, includes, inc, LY_EMEM);
1397
1398 /* get value */
1399 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001400 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001401
1402 if (buf) {
1403 inc->name = lydict_insert_zc(ctx, word);
1404 } else {
1405 inc->name = lydict_insert(ctx, word, word_len);
1406 }
1407
1408 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001409 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001410
1411 switch (kw) {
1412 case YANG_DESCRIPTION:
1413 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts);
1414 break;
1415 case YANG_REFERENCE:
1416 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts);
1417 break;
1418 case YANG_REVISION_DATE:
1419 ret = parse_revisiondate(ctx, data, inc->rev, &inc->exts);
1420 break;
1421 case YANG_CUSTOM:
1422 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inc->exts);
1423 break;
1424 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001425 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001426 return LY_EVALID;
1427 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001428 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001429 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001430 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001431
1432 return ret;
1433}
1434
Michal Vaskoea5abea2018-09-18 13:10:54 +02001435/**
1436 * @brief Parse the import statement.
1437 *
1438 * @param[in] ctx libyang context for logging.
1439 * @param[in,out] data Data to read from, always moved to currently handled character.
1440 * @param[in,out] imports Parsed imports to add to.
1441 *
1442 * @return LY_ERR values.
1443 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001444static LY_ERR
1445parse_import(struct ly_ctx *ctx, const char **data, struct lysp_import **imports)
1446{
1447 LY_ERR ret = 0;
1448 char *buf, *word;
1449 int word_len;
1450 enum yang_keyword kw;
1451 struct lysp_import *imp;
1452
1453 LYSP_ARRAY_NEW_RET(ctx, imports, imp, LY_EVALID);
1454
1455 /* get value */
1456 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001457 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001458
1459 if (buf) {
1460 imp->name = lydict_insert_zc(ctx, word);
1461 } else {
1462 imp->name = lydict_insert(ctx, word, word_len);
1463 }
1464
1465 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001466 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001467
1468 switch (kw) {
1469 case YANG_PREFIX:
1470 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts);
1471 break;
1472 case YANG_DESCRIPTION:
1473 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts);
1474 break;
1475 case YANG_REFERENCE:
1476 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts);
1477 break;
1478 case YANG_REVISION_DATE:
1479 ret = parse_revisiondate(ctx, data, imp->rev, &imp->exts);
1480 break;
1481 case YANG_CUSTOM:
1482 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &imp->exts);
1483 break;
1484 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001485 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001486 return LY_EVALID;
1487 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001488 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001489 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001490 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001491
1492 /* mandatory substatements */
1493 if (!imp->prefix) {
1494 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "import");
1495 return LY_EVALID;
1496 }
1497
1498 return ret;
1499}
1500
Michal Vaskoea5abea2018-09-18 13:10:54 +02001501/**
1502 * @brief Parse the revision statement.
1503 *
1504 * @param[in] ctx libyang context for logging.
1505 * @param[in,out] data Data to read from, always moved to currently handled character.
1506 * @param[in,out] revs Parsed revisions to add to.
1507 *
1508 * @return LY_ERR values.
1509 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001510static LY_ERR
1511parse_revision(struct ly_ctx *ctx, const char **data, struct lysp_revision **revs)
1512{
1513 LY_ERR ret = 0;
1514 char *buf, *word;
1515 int word_len;
1516 enum yang_keyword kw;
1517 struct lysp_revision *rev;
1518
1519 LYSP_ARRAY_NEW_RET(ctx, revs, rev, LY_EMEM);
1520
1521 /* get value */
1522 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001523 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001524
1525 /* check value */
1526 if (lysp_check_date(ctx, word, word_len, "revision")) {
1527 return LY_EVALID;
1528 }
1529
1530 strncpy(rev->rev, word, word_len);
1531 free(buf);
1532
1533 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001534 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001535
1536 switch (kw) {
1537 case YANG_DESCRIPTION:
1538 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts);
1539 break;
1540 case YANG_REFERENCE:
1541 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts);
1542 break;
1543 case YANG_CUSTOM:
1544 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rev->exts);
1545 break;
1546 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001547 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001548 return LY_EVALID;
1549 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001550 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001551 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001552 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001553
1554 return ret;
1555}
1556
Michal Vaskoea5abea2018-09-18 13:10:54 +02001557/**
1558 * @brief Parse a generic text field that can have more instances such as base.
1559 *
1560 * @param[in] ctx libyang context for logging.
1561 * @param[in,out] data Data to read from, always moved to currently handled character.
1562 * @param[in] substmt Type of this substatement.
1563 * @param[in,out] texts Parsed values to add to.
1564 * @param[in] arg Type of the expected argument.
1565 * @param[in,out] exts Extension instances to add to.
1566 *
1567 * @return LY_ERR values.
1568 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001569static LY_ERR
1570parse_text_fields(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
1571 struct lysp_ext_instance **exts)
1572{
1573 LY_ERR ret = 0;
1574 char *buf, *word;
1575 int count, word_len;
1576 enum yang_keyword kw;
1577
1578 /* allocate new pointer */
1579 for (count = 1; (*texts) && (*texts)[count - 1]; ++count);
1580 *texts = realloc(*texts, count * sizeof **texts);
1581 LY_CHECK_ERR_RET(!*texts, LOGMEM(ctx), LY_EMEM);
1582
1583 /* get value */
1584 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001585 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001586
1587 if (buf) {
1588 (*texts)[count - 1] = lydict_insert_zc(ctx, word);
1589 } else {
1590 (*texts)[count - 1] = lydict_insert(ctx, word, word_len);
1591 }
1592
1593 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001594 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001595
1596 switch (kw) {
1597 case YANG_CUSTOM:
1598 ret = parse_ext(ctx, data, word, word_len, substmt, count - 1, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001599 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001600 break;
1601 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001602 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001603 return LY_EVALID;
1604 }
1605 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001606 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001607
1608 return ret;
1609}
1610
Michal Vaskoea5abea2018-09-18 13:10:54 +02001611/**
1612 * @brief Parse the config statement.
1613 *
1614 * @param[in] ctx libyang context for logging.
1615 * @param[in,out] data Data to read from, always moved to currently handled character.
1616 * @param[in,out] flags Flags to add to.
1617 * @param[in,out] exts Extension instances to add to.
1618 *
1619 * @return LY_ERR values.
1620 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001621static LY_ERR
1622parse_config(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1623{
1624 LY_ERR ret = 0;
1625 char *buf, *word;
1626 int word_len;
1627 enum yang_keyword kw;
1628
1629 if (*flags & LYS_CONFIG_MASK) {
1630 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "config");
1631 return LY_EVALID;
1632 }
1633
1634 /* get value */
1635 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001636 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001637
1638 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1639 *flags |= LYS_CONFIG_W;
1640 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1641 *flags |= LYS_CONFIG_R;
1642 } else {
1643 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "config");
1644 free(buf);
1645 return LY_EVALID;
1646 }
1647 free(buf);
1648
1649 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001650 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001651
1652 switch (kw) {
1653 case YANG_CUSTOM:
1654 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_CONFIG, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001655 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001656 break;
1657 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001658 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001659 return LY_EVALID;
1660 }
1661 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001662 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001663
1664 return ret;
1665}
1666
Michal Vaskoea5abea2018-09-18 13:10:54 +02001667/**
1668 * @brief Parse the mandatory statement.
1669 *
1670 * @param[in] ctx libyang context for logging.
1671 * @param[in,out] data Data to read from, always moved to currently handled character.
1672 * @param[in,out] flags Flags to add to.
1673 * @param[in,out] exts Extension instances to add to.
1674 *
1675 * @return LY_ERR values.
1676 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001677static LY_ERR
1678parse_mandatory(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1679{
1680 LY_ERR ret = 0;
1681 char *buf, *word;
1682 int word_len;
1683 enum yang_keyword kw;
1684
1685 if (*flags & LYS_MAND_MASK) {
1686 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "mandatory");
1687 return LY_EVALID;
1688 }
1689
1690 /* get value */
1691 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001692 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001693
1694 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1695 *flags |= LYS_MAND_TRUE;
1696 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1697 *flags |= LYS_MAND_FALSE;
1698 } else {
1699 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "mandatory");
1700 free(buf);
1701 return LY_EVALID;
1702 }
1703 free(buf);
1704
1705 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001706 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001707
1708 switch (kw) {
1709 case YANG_CUSTOM:
1710 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MANDATORY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001711 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001712 break;
1713 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001714 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001715 return LY_EVALID;
1716 }
1717 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001718 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001719
1720 return ret;
1721}
1722
Michal Vaskoea5abea2018-09-18 13:10:54 +02001723/**
1724 * @brief Parse a restriction such as range or length.
1725 *
1726 * @param[in] ctx libyang context for logging.
1727 * @param[in,out] data Data to read from, always moved to currently handled character.
1728 * @param[in] restr_kw Type of this particular restriction.
1729 * @param[in,out] exts Extension instances to add to.
1730 *
1731 * @return LY_ERR values.
1732 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001733static LY_ERR
1734parse_restr(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
1735{
1736 LY_ERR ret = 0;
1737 char *buf, *word;
1738 int word_len;
1739 enum yang_keyword kw;
1740
1741 /* get value */
1742 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001743 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001744
1745 if (buf) {
1746 restr->arg = lydict_insert_zc(ctx, word);
1747 } else {
1748 restr->arg = lydict_insert(ctx, word, word_len);
1749 }
1750
1751 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001752 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001753
1754 switch (kw) {
1755 case YANG_DESCRIPTION:
1756 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
1757 break;
1758 case YANG_REFERENCE:
1759 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
1760 break;
1761 case YANG_ERROR_APP_TAG:
1762 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
1763 break;
1764 case YANG_ERROR_MESSAGE:
1765 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
1766 break;
1767 case YANG_CUSTOM:
1768 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
1769 break;
1770 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001771 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001772 return LY_EVALID;
1773 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001774 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001775 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001776 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001777
1778 return ret;
1779}
1780
Michal Vaskoea5abea2018-09-18 13:10:54 +02001781/**
1782 * @brief Parse a restriction that can have more instances such as must.
1783 *
1784 * @param[in] ctx libyang context for logging.
1785 * @param[in,out] data Data to read from, always moved to currently handled character.
1786 * @param[in] restr_kw Type of this particular restriction.
1787 * @param[in,out] restrs Restrictions to add to.
1788 *
1789 * @return LY_ERR values.
1790 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001791static LY_ERR
1792parse_restrs(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
1793{
1794 struct lysp_restr *restr;
1795
1796 LYSP_ARRAY_NEW_RET(ctx, restrs, restr, LY_EMEM);
1797
1798 return parse_restr(ctx, data, restr_kw, restr);
1799}
1800
Michal Vaskoea5abea2018-09-18 13:10:54 +02001801/**
1802 * @brief Parse the status statement.
1803 *
1804 * @param[in] ctx libyang context for logging.
1805 * @param[in,out] data Data to read from, always moved to currently handled character.
1806 * @param[in,out] flags Flags to add to.
1807 * @param[in,out] exts Extension instances to add to.
1808 *
1809 * @return LY_ERR values.
1810 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001811static LY_ERR
1812parse_status(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1813{
1814 LY_ERR ret = 0;
1815 char *buf, *word;
1816 int word_len;
1817 enum yang_keyword kw;
1818
1819 if (*flags & LYS_STATUS_MASK) {
1820 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "status");
1821 return LY_EVALID;
1822 }
1823
1824 /* get value */
1825 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001826 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001827
1828 if ((word_len == 7) && !strncmp(word, "current", word_len)) {
1829 *flags |= LYS_STATUS_CURR;
1830 } else if ((word_len == 10) && !strncmp(word, "deprecated", word_len)) {
1831 *flags |= LYS_STATUS_DEPRC;
1832 } else if ((word_len == 8) && !strncmp(word, "obsolete", word_len)) {
1833 *flags |= LYS_STATUS_OBSLT;
1834 } else {
1835 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "status");
1836 free(buf);
1837 return LY_EVALID;
1838 }
1839 free(buf);
1840
1841 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001842 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001843
1844 switch (kw) {
1845 case YANG_CUSTOM:
1846 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_STATUS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001847 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001848 break;
1849 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001850 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001851 return LY_EVALID;
1852 }
1853 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001854 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001855
1856 return ret;
1857}
1858
Michal Vaskoea5abea2018-09-18 13:10:54 +02001859/**
1860 * @brief Parse the when statement.
1861 *
1862 * @param[in] ctx libyang context for logging.
1863 * @param[in,out] data Data to read from, always moved to currently handled character.
1864 * @param[in,out] when_p When pointer to parse to.
1865 *
1866 * @return LY_ERR values.
1867 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001868static LY_ERR
1869parse_when(struct ly_ctx *ctx, const char **data, struct lysp_when **when_p)
1870{
1871 LY_ERR ret = 0;
1872 char *buf, *word;
1873 int word_len;
1874 enum yang_keyword kw;
1875 struct lysp_when *when;
1876
1877 if (*when_p) {
1878 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "when");
1879 return LY_EVALID;
1880 }
1881
1882 when = calloc(1, sizeof *when);
1883 LY_CHECK_ERR_RET(!when, LOGMEM(ctx), LY_EMEM);
1884 *when_p = when;
1885
1886 /* get value */
1887 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001888 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001889
1890 if (buf) {
1891 when->cond = lydict_insert_zc(ctx, word);
1892 } else {
1893 when->cond = lydict_insert(ctx, word, word_len);
1894 }
1895
1896 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001897 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001898
1899 switch (kw) {
1900 case YANG_DESCRIPTION:
1901 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts);
1902 break;
1903 case YANG_REFERENCE:
1904 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts);
1905 break;
1906 case YANG_CUSTOM:
1907 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &when->exts);
1908 break;
1909 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001910 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001911 return LY_EVALID;
1912 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001913 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001914 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001915 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001916
1917 return ret;
1918}
1919
Michal Vaskoea5abea2018-09-18 13:10:54 +02001920/**
1921 * @brief Parse the anydata or anyxml statement.
1922 *
1923 * @param[in] ctx libyang context for logging.
1924 * @param[in,out] data Data to read from, always moved to currently handled character.
1925 * @param[in] kw Type of this particular keyword.
1926 * @param[in,out] siblings Siblings to add to.
1927 *
1928 * @return LY_ERR values.
1929 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001930static LY_ERR
1931parse_any(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node **siblings)
1932{
1933 LY_ERR ret = 0;
1934 char *buf, *word;
1935 int word_len;
1936 struct lysp_node *iter;
1937 struct lysp_node_anydata *any;
1938
1939 /* create structure */
1940 any = calloc(1, sizeof *any);
1941 LY_CHECK_ERR_RET(!any, LOGMEM(ctx), LY_EMEM);
1942 any->nodetype = kw == YANG_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
1943
1944 /* insert into siblings */
1945 if (!*siblings) {
1946 *siblings = (struct lysp_node *)any;
1947 } else {
1948 for (iter = *siblings; iter->next; iter = iter->next);
1949 iter->next = (struct lysp_node *)any;
1950 }
1951
1952 /* get name */
1953 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001954 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001955
1956 if (buf) {
1957 any->name = lydict_insert_zc(ctx, word);
1958 } else {
1959 any->name = lydict_insert(ctx, word, word_len);
1960 }
1961
1962 /* parse substatements */
1963 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001964 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001965
1966 switch (kw) {
1967 case YANG_CONFIG:
1968 ret = parse_config(ctx, data, &any->flags, &any->exts);
1969 break;
1970 case YANG_DESCRIPTION:
1971 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts);
1972 break;
1973 case YANG_IF_FEATURE:
1974 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &any->iffeatures, Y_STR_ARG, &any->exts);
1975 break;
1976 case YANG_MANDATORY:
1977 ret = parse_mandatory(ctx, data, &any->flags, &any->exts);
1978 break;
1979 case YANG_MUST:
1980 ret = parse_restrs(ctx, data, kw, &any->musts);
1981 break;
1982 case YANG_REFERENCE:
1983 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts);
1984 break;
1985 case YANG_STATUS:
1986 ret = parse_status(ctx, data, &any->flags, &any->exts);
1987 break;
1988 case YANG_WHEN:
1989 ret = parse_when(ctx, data, &any->when);
1990 break;
1991 case YANG_CUSTOM:
1992 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &any->exts);
1993 break;
1994 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001995 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
1996 (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(YANG_ANYDATA) : ly_stmt2str(YANG_ANYXML));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001997 return LY_EVALID;
1998 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001999 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002000 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002001 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002002
2003 return ret;
2004}
2005
Michal Vaskoea5abea2018-09-18 13:10:54 +02002006/**
2007 * @brief Parse the value or position statement. Substatement of type enum statement.
2008 *
2009 * @param[in] ctx libyang context for logging.
2010 * @param[in,out] data Data to read from, always moved to currently handled character.
2011 * @param[in] val_kw Type of this particular keyword.
2012 * @param[in,out] value Value to write to.
2013 * @param[in,out] flags Flags to write to.
2014 * @param[in,out] exts Extension instances to add to.
2015 *
2016 * @return LY_ERR values.
2017 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002018static LY_ERR
2019parse_type_enum_value_pos(struct ly_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
2020 struct lysp_ext_instance **exts)
2021{
2022 LY_ERR ret = 0;
2023 char *buf, *word, *ptr;
2024 int word_len;
2025 long int num;
2026 unsigned long int unum;
2027 enum yang_keyword kw;
2028
2029 if (*flags & LYS_SET_VALUE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002030 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002031 return LY_EVALID;
2032 }
2033 *flags |= LYS_SET_VALUE;
2034
2035 /* get value */
2036 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002037 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002038
2039 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 +02002040 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002041 free(buf);
2042 return LY_EVALID;
2043 }
2044
2045 errno = 0;
2046 if (val_kw == YANG_VALUE) {
2047 num = strtol(word, &ptr, 10);
2048 } else {
2049 unum = strtoul(word, &ptr, 10);
2050 }
2051 /* we have not parsed the whole argument */
2052 if (ptr - word != word_len) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002053 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002054 free(buf);
2055 return LY_EVALID;
2056 }
2057 if (errno == ERANGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002058 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002059 free(buf);
2060 return LY_EVALID;
2061 }
2062 if (val_kw == YANG_VALUE) {
2063 *value = num;
2064 } else {
2065 *value = unum;
2066 }
2067 free(buf);
2068
2069 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002070 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002071
2072 switch (kw) {
2073 case YANG_CUSTOM:
2074 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 +02002075 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002076 break;
2077 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002078 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002079 return LY_EVALID;
2080 }
2081 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002082 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002083
2084 return ret;
2085}
2086
Michal Vaskoea5abea2018-09-18 13:10:54 +02002087/**
2088 * @brief Parse the enum or bit statement. Substatement of type statement.
2089 *
2090 * @param[in] ctx libyang context for logging.
2091 * @param[in,out] data Data to read from, always moved to currently handled character.
2092 * @param[in] enum_kw Type of this particular keyword.
2093 * @param[in,out] enums Enums or bits to add to.
2094 *
2095 * @return LY_ERR values.
2096 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002097static LY_ERR
2098parse_type_enum(struct ly_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
2099{
2100 LY_ERR ret = 0;
2101 char *buf, *word;
2102 int word_len;
2103 enum yang_keyword kw;
2104 struct lysp_type_enum *enm;
2105
2106 LYSP_ARRAY_NEW_RET(ctx, enums, enm, LY_EMEM);
2107
2108 /* get value */
2109 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002110 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002111
2112 if (buf) {
2113 enm->name = lydict_insert_zc(ctx, word);
2114 } else {
2115 enm->name = lydict_insert(ctx, word, word_len);
2116 }
2117
2118 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002119 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002120
2121 switch (kw) {
2122 case YANG_DESCRIPTION:
2123 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts);
2124 break;
2125 case YANG_IF_FEATURE:
2126 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts);
2127 break;
2128 case YANG_REFERENCE:
2129 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts);
2130 break;
2131 case YANG_STATUS:
2132 ret = parse_status(ctx, data, &enm->flags, &enm->exts);
2133 break;
2134 case YANG_VALUE:
2135 case YANG_POSITION:
2136 ret = parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts);
2137 break;
2138 case YANG_CUSTOM:
2139 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &enm->exts);
2140 break;
2141 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002142 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002143 return LY_EVALID;
2144 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002145 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002146 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002147 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002148
2149 return ret;
2150}
2151
Michal Vaskoea5abea2018-09-18 13:10:54 +02002152/**
2153 * @brief Parse the fraction-digits statement. Substatement of type statement.
2154 *
2155 * @param[in] ctx libyang context for logging.
2156 * @param[in,out] data Data to read from, always moved to currently handled character.
2157 * @param[in,out] fracdig Value to write to.
2158 * @param[in,out] exts Extension instances to add to.
2159 *
2160 * @return LY_ERR values.
2161 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002162static LY_ERR
2163parse_type_fracdigits(struct ly_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
2164{
2165 LY_ERR ret = 0;
2166 char *buf, *word, *ptr;
2167 int word_len;
2168 unsigned long int num;
2169 enum yang_keyword kw;
2170
2171 if (*fracdig) {
2172 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "fraction-digits");
2173 return LY_EVALID;
2174 }
2175
2176 /* get value */
2177 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002178 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002179
2180 if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
2181 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2182 free(buf);
2183 return LY_EVALID;
2184 }
2185
2186 errno = 0;
2187 num = strtoul(word, &ptr, 10);
2188 /* we have not parsed the whole argument */
2189 if (ptr - word != word_len) {
2190 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2191 free(buf);
2192 return LY_EVALID;
2193 }
2194 if ((errno == ERANGE) || (num > 18)) {
2195 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "fraction-digits");
2196 free(buf);
2197 return LY_EVALID;
2198 }
2199 *fracdig = num;
2200 free(buf);
2201
2202 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002203 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002204
2205 switch (kw) {
2206 case YANG_CUSTOM:
2207 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_FRACDIGITS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002208 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002209 break;
2210 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002211 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002212 return LY_EVALID;
2213 }
2214 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002215 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002216
2217 return ret;
2218}
2219
Michal Vaskoea5abea2018-09-18 13:10:54 +02002220/**
2221 * @brief Parse the require-instance statement. Substatement of type statement.
2222 *
2223 * @param[in] ctx libyang context for logging.
2224 * @param[in,out] data Data to read from, always moved to currently handled character.
2225 * @param[in,out] reqinst Value to write to.
2226 * @param[in,out] flags Flags to write to.
2227 * @param[in,out] exts Extension instances to add to.
2228 *
2229 * @return LY_ERR values.
2230 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002231static LY_ERR
2232parse_type_reqinstance(struct ly_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
2233 struct lysp_ext_instance **exts)
2234{
2235 LY_ERR ret = 0;
2236 char *buf, *word;
2237 int word_len;
2238 enum yang_keyword kw;
2239
2240 if (*flags & LYS_SET_REQINST) {
2241 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "require-instance");
2242 return LY_EVALID;
2243 }
2244 *flags |= LYS_SET_REQINST;
2245
2246 /* get value */
2247 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002248 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002249
2250 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
2251 *reqinst = 1;
2252 } else if ((word_len != 5) || strncmp(word, "false", word_len)) {
2253 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "require-instance");
2254 free(buf);
2255 return LY_EVALID;
2256 }
2257 free(buf);
2258
2259 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002260 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002261
2262 switch (kw) {
2263 case YANG_CUSTOM:
2264 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REQINSTANCE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002265 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002266 break;
2267 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002268 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002269 return LY_EVALID;
2270 }
2271 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002272 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002273
2274 return ret;
2275}
2276
Michal Vaskoea5abea2018-09-18 13:10:54 +02002277/**
2278 * @brief Parse the modifier statement. Substatement of type pattern statement.
2279 *
2280 * @param[in] ctx libyang context for logging.
2281 * @param[in,out] data Data to read from, always moved to currently handled character.
2282 * @param[in,out] pat Value to write to.
2283 * @param[in,out] exts Extension instances to add to.
2284 *
2285 * @return LY_ERR values.
2286 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002287static LY_ERR
2288parse_type_pattern_modifier(struct ly_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
2289{
2290 LY_ERR ret = 0;
2291 char *buf, *word;
2292 int word_len;
2293 enum yang_keyword kw;
2294
2295 if ((*pat)[0] == 0x15) {
2296 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "modifier");
2297 return LY_EVALID;
2298 }
2299
2300 /* get value */
2301 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002302 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002303
2304 if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
2305 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "modifier");
2306 free(buf);
2307 return LY_EVALID;
2308 }
2309 free(buf);
2310
2311 /* replace the value in the dictionary */
2312 buf = malloc(strlen(*pat) + 1);
2313 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2314 strcpy(buf, *pat);
2315 lydict_remove(ctx, *pat);
2316
2317 assert(buf[0] == 0x06);
2318 buf[0] = 0x15;
2319 *pat = lydict_insert_zc(ctx, buf);
2320
2321 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002322 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002323
2324 switch (kw) {
2325 case YANG_CUSTOM:
2326 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MODIFIER, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002327 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002328 break;
2329 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002330 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002331 return LY_EVALID;
2332 }
2333 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002334 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002335
2336 return ret;
2337}
2338
Michal Vaskoea5abea2018-09-18 13:10:54 +02002339/**
2340 * @brief Parse the pattern statement. Substatement of type statement.
2341 *
2342 * @param[in] ctx libyang context for logging.
2343 * @param[in,out] data Data to read from, always moved to currently handled character.
2344 * @param[in,out] patterns Restrictions to add to.
2345 *
2346 * @return LY_ERR values.
2347 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002348static LY_ERR
2349parse_type_pattern(struct ly_ctx *ctx, const char **data, struct lysp_restr **patterns)
2350{
2351 LY_ERR ret = 0;
2352 char *buf, *word;
2353 int word_len;
2354 enum yang_keyword kw;
2355 struct lysp_restr *restr;
2356
2357 LYSP_ARRAY_NEW_RET(ctx, patterns, restr, LY_EMEM);
2358
2359 /* get value */
2360 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002361 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002362
2363 /* add special meaning first byte */
2364 if (buf) {
2365 buf = realloc(buf, word_len + 2);
2366 word = buf;
2367 } else {
2368 buf = malloc(word_len + 2);
2369 }
2370 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2371 memmove(buf + 1, word, word_len + 1);
2372 word[0] = 0x06;
2373 restr->arg = lydict_insert_zc(ctx, word);
2374
2375 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002376 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002377
2378 switch (kw) {
2379 case YANG_DESCRIPTION:
2380 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
2381 break;
2382 case YANG_REFERENCE:
2383 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
2384 break;
2385 case YANG_ERROR_APP_TAG:
2386 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
2387 break;
2388 case YANG_ERROR_MESSAGE:
2389 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
2390 break;
2391 case YANG_MODIFIER:
2392 ret = parse_type_pattern_modifier(ctx, data, &restr->arg, &restr->exts);
2393 break;
2394 case YANG_CUSTOM:
2395 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
2396 break;
2397 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002398 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002399 return LY_EVALID;
2400 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002401 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002402 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002403 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002404
2405 return ret;
2406}
2407
Michal Vaskoea5abea2018-09-18 13:10:54 +02002408/**
2409 * @brief Parse the type statement.
2410 *
2411 * @param[in] ctx libyang context for logging.
2412 * @param[in,out] data Data to read from, always moved to currently handled character.
2413 * @param[in,out] type Type to wrote to.
2414 *
2415 * @return LY_ERR values.
2416 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002417static LY_ERR
2418parse_type(struct ly_ctx *ctx, const char **data, struct lysp_type *type)
2419{
2420 LY_ERR ret = 0;
2421 char *buf, *word;
2422 int word_len;
2423 enum yang_keyword kw;
2424 struct lysp_type *nest_type;
2425
2426 if (type->name) {
2427 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "type");
2428 return LY_EVALID;
2429 }
2430
2431 /* get value */
2432 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002433 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002434
2435 if (buf) {
2436 type->name = lydict_insert_zc(ctx, word);
2437 } else {
2438 type->name = lydict_insert(ctx, word, word_len);
2439 }
2440
2441 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002442 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002443
2444 switch (kw) {
2445 case YANG_BASE:
2446 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts);
2447 break;
2448 case YANG_BIT:
2449 ret = parse_type_enum(ctx, data, kw, &type->bits);
2450 break;
2451 case YANG_ENUM:
2452 ret = parse_type_enum(ctx, data, kw, &type->enums);
2453 break;
2454 case YANG_FRACTION_DIGITS:
2455 ret = parse_type_fracdigits(ctx, data, &type->fraction_digits, &type->exts);
2456 break;
2457 case YANG_LENGTH:
2458 if (type->length) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002459 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002460 return LY_EVALID;
2461 }
2462 type->length = calloc(1, sizeof *type->length);
2463 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
2464
2465 ret = parse_restr(ctx, data, kw, type->length);
2466 break;
2467 case YANG_PATH:
2468 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PATH, 0, &type->path, Y_STR_ARG, &type->exts);
2469 break;
2470 case YANG_PATTERN:
2471 ret = parse_type_pattern(ctx, data, &type->patterns);
2472 break;
2473 case YANG_RANGE:
2474 if (type->range) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002475 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002476 return LY_EVALID;
2477 }
2478 type->range = calloc(1, sizeof *type->range);
2479 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EVALID);
2480
2481 ret = parse_restr(ctx, data, kw, type->range);
2482 break;
2483 case YANG_REQUIRE_INSTANCE:
2484 ret = parse_type_reqinstance(ctx, data, &type->require_instance, &type->flags, &type->exts);
2485 break;
2486 case YANG_TYPE:
2487 {
2488 LYSP_ARRAY_NEW_RET(ctx, &type->types, nest_type, LY_EMEM);
2489 }
2490 ret = parse_type(ctx, data, nest_type);
2491 break;
2492 case YANG_CUSTOM:
2493 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts);
2494 break;
2495 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002496 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002497 return LY_EVALID;
2498 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002499 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002500 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002501 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002502
2503 return ret;
2504}
2505
Michal Vaskoea5abea2018-09-18 13:10:54 +02002506/**
2507 * @brief Parse the leaf statement.
2508 *
2509 * @param[in] ctx libyang context for logging.
2510 * @param[in,out] data Data to read from, always moved to currently handled character.
2511 * @param[in,out] siblings Siblings to add to.
2512 *
2513 * @return LY_ERR values.
2514 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002515static LY_ERR
2516parse_leaf(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2517{
2518 LY_ERR ret = 0;
2519 char *buf, *word;
2520 int word_len;
2521 enum yang_keyword kw;
2522 struct lysp_node *iter;
2523 struct lysp_node_leaf *leaf;
2524
2525 /* create structure */
2526 leaf = calloc(1, sizeof *leaf);
2527 LY_CHECK_ERR_RET(!leaf, LOGMEM(ctx), LY_EMEM);
2528 leaf->nodetype = LYS_LEAF;
2529
2530 /* insert into siblings */
2531 if (!*siblings) {
2532 *siblings = (struct lysp_node *)leaf;
2533 } else {
2534 for (iter = *siblings; iter->next; iter = iter->next);
2535 iter->next = (struct lysp_node *)leaf;
2536 }
2537
2538 /* get name */
2539 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002540 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002541
2542 if (buf) {
2543 leaf->name = lydict_insert_zc(ctx, word);
2544 } else {
2545 leaf->name = lydict_insert(ctx, word, word_len);
2546 }
2547
2548 /* parse substatements */
2549 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002550 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002551
2552 switch (kw) {
2553 case YANG_CONFIG:
2554 ret = parse_config(ctx, data, &leaf->flags, &leaf->exts);
2555 break;
2556 case YANG_DEFAULT:
2557 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &leaf->dflt, Y_STR_ARG, &leaf->exts);
2558 break;
2559 case YANG_DESCRIPTION:
2560 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts);
2561 break;
2562 case YANG_IF_FEATURE:
2563 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &leaf->iffeatures, Y_STR_ARG, &leaf->exts);
2564 break;
2565 case YANG_MANDATORY:
2566 ret = parse_mandatory(ctx, data, &leaf->flags, &leaf->exts);
2567 break;
2568 case YANG_MUST:
2569 ret = parse_restrs(ctx, data, kw, &leaf->musts);
2570 break;
2571 case YANG_REFERENCE:
2572 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts);
2573 break;
2574 case YANG_STATUS:
2575 ret = parse_status(ctx, data, &leaf->flags, &leaf->exts);
2576 break;
2577 case YANG_TYPE:
2578 ret = parse_type(ctx, data, &leaf->type);
2579 break;
2580 case YANG_UNITS:
2581 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts);
2582 break;
2583 case YANG_WHEN:
2584 ret = parse_when(ctx, data, &leaf->when);
2585 break;
2586 case YANG_CUSTOM:
2587 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &leaf->exts);
2588 break;
2589 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002590 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002591 return LY_EVALID;
2592 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002593 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002594 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002595 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002596
2597 /* mandatory substatements */
2598 if (!leaf->type.name) {
2599 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf");
2600 return LY_EVALID;
2601 }
2602
2603 return ret;
2604}
2605
Michal Vaskoea5abea2018-09-18 13:10:54 +02002606/**
2607 * @brief Parse the max-elements statement.
2608 *
2609 * @param[in] ctx libyang context for logging.
2610 * @param[in,out] data Data to read from, always moved to currently handled character.
2611 * @param[in,out] max Value to write to.
2612 * @param[in,out] flags Flags to write to.
2613 * @param[in,out] exts Extension instances to add to.
2614 *
2615 * @return LY_ERR values.
2616 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002617static LY_ERR
2618parse_maxelements(struct ly_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
2619{
2620 LY_ERR ret = 0;
2621 char *buf, *word, *ptr;
2622 int word_len;
2623 unsigned long int num;
2624 enum yang_keyword kw;
2625
2626 if (*flags & LYS_SET_MAX) {
2627 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "max-elements");
2628 return LY_EVALID;
2629 }
2630 *flags |= LYS_SET_MAX;
2631
2632 /* get value */
2633 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002634 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002635
2636 if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
2637 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2638 free(buf);
2639 return LY_EVALID;
2640 }
2641
2642 if (strncmp(word, "unbounded", word_len)) {
2643 errno = 0;
2644 num = strtoul(word, &ptr, 10);
2645 /* we have not parsed the whole argument */
2646 if (ptr - word != word_len) {
2647 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2648 free(buf);
2649 return LY_EVALID;
2650 }
2651 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2652 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "max-elements");
2653 free(buf);
2654 return LY_EVALID;
2655 }
2656
2657 *max = num;
2658 }
2659 free(buf);
2660
2661 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002662 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002663
2664 switch (kw) {
2665 case YANG_CUSTOM:
2666 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MAX, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002667 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002668 break;
2669 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002670 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002671 return LY_EVALID;
2672 }
2673 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002674 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002675
2676 return ret;
2677}
2678
Michal Vaskoea5abea2018-09-18 13:10:54 +02002679/**
2680 * @brief Parse the min-elements statement.
2681 *
2682 * @param[in] ctx libyang context for logging.
2683 * @param[in,out] data Data to read from, always moved to currently handled character.
2684 * @param[in,out] min Value to write to.
2685 * @param[in,out] flags Flags to write to.
2686 * @param[in,out] exts Extension instances to add to.
2687 *
2688 * @return LY_ERR values.
2689 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002690static LY_ERR
2691parse_minelements(struct ly_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
2692{
2693 LY_ERR ret = 0;
2694 char *buf, *word, *ptr;
2695 int word_len;
2696 unsigned long int num;
2697 enum yang_keyword kw;
2698
2699 if (*flags & LYS_SET_MIN) {
2700 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "min-elements");
2701 return LY_EVALID;
2702 }
2703 *flags |= LYS_SET_MIN;
2704
2705 /* get value */
2706 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002707 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002708
2709 if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
2710 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2711 free(buf);
2712 return LY_EVALID;
2713 }
2714
2715 errno = 0;
2716 num = strtoul(word, &ptr, 10);
2717 /* we have not parsed the whole argument */
2718 if (ptr - word != word_len) {
2719 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2720 free(buf);
2721 return LY_EVALID;
2722 }
2723 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2724 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "min-elements");
2725 free(buf);
2726 return LY_EVALID;
2727 }
2728 *min = num;
2729 free(buf);
2730
2731 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002732 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002733
2734 switch (kw) {
2735 case YANG_CUSTOM:
2736 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MIN, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002737 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002738 break;
2739 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002740 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002741 return LY_EVALID;
2742 }
2743 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002744 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002745
2746 return ret;
2747}
2748
Michal Vaskoea5abea2018-09-18 13:10:54 +02002749/**
2750 * @brief Parse the ordered-by statement.
2751 *
2752 * @param[in] ctx libyang context for logging.
2753 * @param[in,out] data Data to read from, always moved to currently handled character.
2754 * @param[in,out] flags Flags to write to.
2755 * @param[in,out] exts Extension instances to add to.
2756 *
2757 * @return LY_ERR values.
2758 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002759static LY_ERR
2760parse_orderedby(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
2761{
2762 LY_ERR ret = 0;
2763 char *buf, *word;
2764 int word_len;
2765 enum yang_keyword kw;
2766
2767 if (*flags & LYS_ORDBY_MASK) {
2768 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "ordered-by");
2769 return LY_EVALID;
2770 }
2771
2772 /* get value */
2773 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002774 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002775
2776 if ((word_len == 6) && !strncmp(word, "system", word_len)) {
2777 *flags |= LYS_ORDBY_SYSTEM;
2778 } else if ((word_len == 4) && !strncmp(word, "user", word_len)) {
2779 *flags |= LYS_ORDBY_USER;
2780 } else {
2781 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "ordered-by");
2782 free(buf);
2783 return LY_EVALID;
2784 }
2785 free(buf);
2786
2787 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002788 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002789
2790 switch (kw) {
2791 case YANG_CUSTOM:
2792 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ORDEREDBY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002793 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002794 break;
2795 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002796 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002797 return LY_EVALID;
2798 }
2799 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002800 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002801
2802 return ret;
2803}
2804
Michal Vaskoea5abea2018-09-18 13:10:54 +02002805/**
2806 * @brief Parse the leaf-list statement.
2807 *
2808 * @param[in] ctx libyang context for logging.
2809 * @param[in,out] data Data to read from, always moved to currently handled character.
2810 * @param[in,out] siblings Siblings to add to.
2811 *
2812 * @return LY_ERR values.
2813 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002814static LY_ERR
2815parse_leaflist(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2816{
2817 LY_ERR ret = 0;
2818 char *buf, *word;
2819 int word_len;
2820 enum yang_keyword kw;
2821 struct lysp_node *iter;
2822 struct lysp_node_leaflist *llist;
2823
2824 /* create structure */
2825 llist = calloc(1, sizeof *llist);
2826 LY_CHECK_ERR_RET(!llist, LOGMEM(ctx), LY_EMEM);
2827 llist->nodetype = LYS_LEAFLIST;
2828
2829 /* insert into siblings */
2830 if (!*siblings) {
2831 *siblings = (struct lysp_node *)llist;
2832 } else {
2833 for (iter = *siblings; iter->next; iter = iter->next);
2834 iter->next = (struct lysp_node *)llist;
2835 }
2836
2837 /* get name */
2838 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002839 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002840
2841 if (buf) {
2842 llist->name = lydict_insert_zc(ctx, word);
2843 } else {
2844 llist->name = lydict_insert(ctx, word, word_len);
2845 }
2846
2847 /* parse substatements */
2848 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002849 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002850
2851 switch (kw) {
2852 case YANG_CONFIG:
2853 ret = parse_config(ctx, data, &llist->flags, &llist->exts);
2854 break;
2855 case YANG_DEFAULT:
2856 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts);
2857 break;
2858 case YANG_DESCRIPTION:
2859 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts);
2860 break;
2861 case YANG_IF_FEATURE:
2862 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &llist->iffeatures, Y_STR_ARG, &llist->exts);
2863 break;
2864 case YANG_MAX_ELEMENTS:
2865 ret = parse_maxelements(ctx, data, &llist->max, &llist->flags, &llist->exts);
2866 break;
2867 case YANG_MIN_ELEMENTS:
2868 ret = parse_minelements(ctx, data, &llist->min, &llist->flags, &llist->exts);
2869 break;
2870 case YANG_MUST:
2871 ret = parse_restrs(ctx, data, kw, &llist->musts);
2872 break;
2873 case YANG_ORDERED_BY:
2874 ret = parse_orderedby(ctx, data, &llist->flags, &llist->exts);
2875 break;
2876 case YANG_REFERENCE:
2877 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts);
2878 break;
2879 case YANG_STATUS:
2880 ret = parse_status(ctx, data, &llist->flags, &llist->exts);
2881 break;
2882 case YANG_TYPE:
2883 ret = parse_type(ctx, data, &llist->type);
2884 break;
2885 case YANG_UNITS:
2886 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts);
2887 break;
2888 case YANG_WHEN:
2889 ret = parse_when(ctx, data, &llist->when);
2890 break;
2891 case YANG_CUSTOM:
2892 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &llist->exts);
2893 break;
2894 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002895 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002896 return LY_EVALID;
2897 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002898 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002899 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002900 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002901
2902 /* mandatory substatements */
2903 if (!llist->type.name) {
2904 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf-list");
2905 return LY_EVALID;
2906 }
2907
2908 return ret;
2909}
2910
Michal Vaskoea5abea2018-09-18 13:10:54 +02002911/**
2912 * @brief Parse the refine statement.
2913 *
2914 * @param[in] ctx libyang context for logging.
2915 * @param[in,out] data Data to read from, always moved to currently handled character.
2916 * @param[in,out] refines Refines to add to.
2917 *
2918 * @return LY_ERR values.
2919 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002920static LY_ERR
2921parse_refine(struct ly_ctx *ctx, const char **data, struct lysp_refine **refines)
2922{
2923 LY_ERR ret = 0;
2924 char *buf, *word;
2925 int word_len;
2926 enum yang_keyword kw;
2927 struct lysp_refine *rf;
2928
2929 LYSP_ARRAY_NEW_RET(ctx, refines, rf, LY_EMEM);
2930
2931 /* get value */
2932 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002933 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002934
2935 if (buf) {
2936 rf->nodeid = lydict_insert_zc(ctx, word);
2937 } else {
2938 rf->nodeid = lydict_insert(ctx, word, word_len);
2939 }
2940
2941 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002942 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002943
2944 switch (kw) {
2945 case YANG_CONFIG:
2946 ret = parse_config(ctx, data, &rf->flags, &rf->exts);
2947 break;
2948 case YANG_DEFAULT:
2949 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &rf->dflts, Y_STR_ARG, &rf->exts);
2950 break;
2951 case YANG_DESCRIPTION:
2952 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts);
2953 break;
2954 case YANG_IF_FEATURE:
2955 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &rf->iffeatures, Y_STR_ARG, &rf->exts);
2956 break;
2957 case YANG_MAX_ELEMENTS:
2958 ret = parse_maxelements(ctx, data, &rf->max, &rf->flags, &rf->exts);
2959 break;
2960 case YANG_MIN_ELEMENTS:
2961 ret = parse_minelements(ctx, data, &rf->min, &rf->flags, &rf->exts);
2962 break;
2963 case YANG_MUST:
2964 ret = parse_restrs(ctx, data, kw, &rf->musts);
2965 break;
2966 case YANG_MANDATORY:
2967 ret = parse_mandatory(ctx, data, &rf->flags, &rf->exts);
2968 break;
2969 case YANG_REFERENCE:
2970 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts);
2971 break;
2972 case YANG_PRESENCE:
2973 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts);
2974 break;
2975 case YANG_CUSTOM:
2976 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rf->exts);
2977 break;
2978 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002979 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002980 return LY_EVALID;
2981 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002982 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002983 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002984 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002985
2986 return ret;
2987}
2988
Michal Vaskoea5abea2018-09-18 13:10:54 +02002989/**
2990 * @brief Parse the typedef statement.
2991 *
2992 * @param[in] ctx libyang context for logging.
2993 * @param[in,out] data Data to read from, always moved to currently handled character.
2994 * @param[in,out] typedefs Typedefs to add to.
2995 *
2996 * @return LY_ERR values.
2997 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002998static LY_ERR
2999parse_typedef(struct ly_ctx *ctx, const char **data, struct lysp_tpdf **typedefs)
3000{
3001 LY_ERR ret = 0;
3002 char *buf, *word;
3003 int word_len;
3004 enum yang_keyword kw;
3005 struct lysp_tpdf *tpdf;
3006
3007 LYSP_ARRAY_NEW_RET(ctx, typedefs, tpdf, LY_EMEM);
3008
3009 /* get value */
3010 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003011 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003012
3013 if (buf) {
3014 tpdf->name = lydict_insert_zc(ctx, word);
3015 } else {
3016 tpdf->name = lydict_insert(ctx, word, word_len);
3017 }
3018
3019 /* parse substatements */
3020 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003021 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003022
3023 switch (kw) {
3024 case YANG_DEFAULT:
3025 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &tpdf->dflt, Y_STR_ARG, &tpdf->exts);
3026 break;
3027 case YANG_DESCRIPTION:
3028 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts);
3029 break;
3030 case YANG_REFERENCE:
3031 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts);
3032 break;
3033 case YANG_STATUS:
3034 ret = parse_status(ctx, data, &tpdf->flags, &tpdf->exts);
3035 break;
3036 case YANG_TYPE:
3037 ret = parse_type(ctx, data, &tpdf->type);
3038 break;
3039 case YANG_UNITS:
3040 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts);
3041 break;
3042 case YANG_CUSTOM:
3043 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &tpdf->exts);
3044 break;
3045 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003046 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003047 return LY_EVALID;
3048 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003049 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003050 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003051 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003052
3053 /* mandatory substatements */
3054 if (!tpdf->type.name) {
3055 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "typedef");
3056 return LY_EVALID;
3057 }
3058
3059 return ret;
3060}
3061
Michal Vaskoea5abea2018-09-18 13:10:54 +02003062/**
3063 * @brief Parse the input or output statement.
3064 *
3065 * @param[in] ctx libyang context for logging.
3066 * @param[in,out] data Data to read from, always moved to currently handled character.
3067 * @param[in] kw Type of this particular keyword
3068 * @param[in,out] inout_p Input/output pointer to write to.
3069 *
3070 * @return LY_ERR values.
3071 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003072static LY_ERR
3073parse_inout(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_action_inout **inout_p)
3074{
3075 LY_ERR ret = 0;
3076 char *word;
3077 int word_len;
3078 struct lysp_action_inout *inout;
3079
3080 if (*inout_p) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003081 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02003082 return LY_EVALID;
3083 }
3084
3085 /* create structure */
3086 inout = calloc(1, sizeof *inout);
3087 LY_CHECK_ERR_RET(!inout, LOGMEM(ctx), LY_EMEM);
3088 *inout_p = inout;
3089
3090 /* parse substatements */
3091 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003092 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003093
3094 switch (kw) {
3095 case YANG_ANYDATA:
3096 case YANG_ANYXML:
3097 ret = parse_any(ctx, data, kw, &inout->data);
3098 break;
3099 case YANG_CHOICE:
3100 ret = parse_choice(ctx, data, &inout->data);
3101 break;
3102 case YANG_CONTAINER:
3103 ret = parse_container(ctx, data, &inout->data);
3104 break;
3105 case YANG_LEAF:
3106 ret = parse_leaf(ctx, data, &inout->data);
3107 break;
3108 case YANG_LEAF_LIST:
3109 ret = parse_leaflist(ctx, data, &inout->data);
3110 break;
3111 case YANG_LIST:
3112 ret = parse_list(ctx, data, &inout->data);
3113 break;
3114 case YANG_USES:
3115 ret = parse_uses(ctx, data, &inout->data);
3116 break;
3117
3118 case YANG_TYPEDEF:
3119 ret = parse_typedef(ctx, data, &inout->typedefs);
3120 break;
3121 case YANG_MUST:
3122 ret = parse_restrs(ctx, data, kw, &inout->musts);
3123 break;
3124 case YANG_GROUPING:
3125 ret = parse_grouping(ctx, data, &inout->groupings);
3126 break;
3127 case YANG_CUSTOM:
3128 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout->exts);
3129 break;
3130 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003131 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "input/output");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003132 return LY_EVALID;
3133 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003134 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003135 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003136 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003137
3138 return ret;
3139}
3140
Michal Vaskoea5abea2018-09-18 13:10:54 +02003141/**
3142 * @brief Parse the action statement.
3143 *
3144 * @param[in] ctx libyang context for logging.
3145 * @param[in,out] data Data to read from, always moved to currently handled character.
3146 * @param[in,out] actions Actions to add to.
3147 *
3148 * @return LY_ERR values.
3149 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003150static LY_ERR
3151parse_action(struct ly_ctx *ctx, const char **data, struct lysp_action **actions)
3152{
3153 LY_ERR ret = 0;
3154 char *buf, *word;
3155 int word_len;
3156 enum yang_keyword kw;
3157 struct lysp_action *act;
3158
3159 LYSP_ARRAY_NEW_RET(ctx, actions, act, LY_EMEM);
3160
3161 /* get value */
3162 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003163 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003164
3165 if (buf) {
3166 act->name = lydict_insert_zc(ctx, word);
3167 } else {
3168 act->name = lydict_insert(ctx, word, word_len);
3169 }
3170
3171 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003172 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003173
3174 switch (kw) {
3175 case YANG_DESCRIPTION:
3176 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts);
3177 break;
3178 case YANG_IF_FEATURE:
3179 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &act->iffeatures, Y_STR_ARG, &act->exts);
3180 break;
3181 case YANG_REFERENCE:
3182 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts);
3183 break;
3184 case YANG_STATUS:
3185 ret = parse_status(ctx, data, &act->flags, &act->exts);
3186 break;
3187
3188 case YANG_INPUT:
3189 ret = parse_inout(ctx, data, kw, &act->input);
3190 break;
3191 case YANG_OUTPUT:
3192 ret = parse_inout(ctx, data, kw, &act->output);
3193 break;
3194
3195 case YANG_TYPEDEF:
3196 ret = parse_typedef(ctx, data, &act->typedefs);
3197 break;
3198 case YANG_GROUPING:
3199 ret = parse_grouping(ctx, data, &act->groupings);
3200 break;
3201 case YANG_CUSTOM:
3202 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts);
3203 break;
3204 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003205 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "action");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003206 return LY_EVALID;
3207 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003208 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003209 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003210 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003211
3212 return ret;
3213}
3214
Michal Vaskoea5abea2018-09-18 13:10:54 +02003215/**
3216 * @brief Parse the notification statement.
3217 *
3218 * @param[in] ctx libyang context for logging.
3219 * @param[in,out] data Data to read from, always moved to currently handled character.
3220 * @param[in,out] notifs Notifications to add to.
3221 *
3222 * @return LY_ERR values.
3223 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003224static LY_ERR
3225parse_notif(struct ly_ctx *ctx, const char **data, struct lysp_notif **notifs)
3226{
3227 LY_ERR ret = 0;
3228 char *buf, *word;
3229 int word_len;
3230 enum yang_keyword kw;
3231 struct lysp_notif *notif;
3232
3233 LYSP_ARRAY_NEW_RET(ctx, notifs, notif, LY_EMEM);
3234
3235 /* get value */
3236 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003237 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003238
3239 if (buf) {
3240 notif->name = lydict_insert_zc(ctx, word);
3241 } else {
3242 notif->name = lydict_insert(ctx, word, word_len);
3243 }
3244
3245 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003246 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003247
3248 switch (kw) {
3249 case YANG_DESCRIPTION:
3250 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts);
3251 break;
3252 case YANG_IF_FEATURE:
3253 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &notif->iffeatures, Y_STR_ARG, &notif->exts);
3254 break;
3255 case YANG_REFERENCE:
3256 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts);
3257 break;
3258 case YANG_STATUS:
3259 ret = parse_status(ctx, data, &notif->flags, &notif->exts);
3260 break;
3261
3262 case YANG_ANYDATA:
3263 case YANG_ANYXML:
3264 ret = parse_any(ctx, data, kw, &notif->data);
3265 break;
3266 case YANG_CHOICE:
3267 ret = parse_case(ctx, data, &notif->data);
3268 break;
3269 case YANG_CONTAINER:
3270 ret = parse_container(ctx, data, &notif->data);
3271 break;
3272 case YANG_LEAF:
3273 ret = parse_leaf(ctx, data, &notif->data);
3274 break;
3275 case YANG_LEAF_LIST:
3276 ret = parse_leaflist(ctx, data, &notif->data);
3277 break;
3278 case YANG_LIST:
3279 ret = parse_list(ctx, data, &notif->data);
3280 break;
3281 case YANG_USES:
3282 ret = parse_uses(ctx, data, &notif->data);
3283 break;
3284
3285 case YANG_MUST:
3286 ret = parse_restrs(ctx, data, kw, &notif->musts);
3287 break;
3288 case YANG_TYPEDEF:
3289 ret = parse_typedef(ctx, data, &notif->typedefs);
3290 break;
3291 case YANG_GROUPING:
3292 ret = parse_grouping(ctx, data, &notif->groupings);
3293 break;
3294 case YANG_CUSTOM:
3295 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &notif->exts);
3296 break;
3297 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003298 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003299 return LY_EVALID;
3300 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003301 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003302 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003303 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003304
3305 return ret;
3306}
3307
Michal Vaskoea5abea2018-09-18 13:10:54 +02003308/**
3309 * @brief Parse the grouping statement.
3310 *
3311 * @param[in] ctx libyang context for logging.
3312 * @param[in,out] data Data to read from, always moved to currently handled character.
3313 * @param[in,out] groupings Groupings to add to.
3314 *
3315 * @return LY_ERR values.
3316 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003317static LY_ERR
3318parse_grouping(struct ly_ctx *ctx, const char **data, struct lysp_grp **groupings)
3319{
3320 LY_ERR ret = 0;
3321 char *buf, *word;
3322 int word_len;
3323 enum yang_keyword kw;
3324 struct lysp_grp *grp;
3325
3326 LYSP_ARRAY_NEW_RET(ctx, groupings, grp, LY_EMEM);
3327
3328 /* get value */
3329 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003330 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003331
3332 if (buf) {
3333 grp->name = lydict_insert_zc(ctx, word);
3334 } else {
3335 grp->name = lydict_insert(ctx, word, word_len);
3336 }
3337
3338 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003339 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003340
3341 switch (kw) {
3342 case YANG_DESCRIPTION:
3343 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts);
3344 break;
3345 case YANG_REFERENCE:
3346 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts);
3347 break;
3348 case YANG_STATUS:
3349 ret = parse_status(ctx, data, &grp->flags, &grp->exts);
3350 break;
3351
3352 case YANG_ANYDATA:
3353 case YANG_ANYXML:
3354 ret = parse_any(ctx, data, kw, &grp->data);
3355 break;
3356 case YANG_CHOICE:
3357 ret = parse_choice(ctx, data, &grp->data);
3358 break;
3359 case YANG_CONTAINER:
3360 ret = parse_container(ctx, data, &grp->data);
3361 break;
3362 case YANG_LEAF:
3363 ret = parse_leaf(ctx, data, &grp->data);
3364 break;
3365 case YANG_LEAF_LIST:
3366 ret = parse_leaflist(ctx, data, &grp->data);
3367 break;
3368 case YANG_LIST:
3369 ret = parse_list(ctx, data, &grp->data);
3370 break;
3371 case YANG_USES:
3372 ret = parse_uses(ctx, data, &grp->data);
3373 break;
3374
3375 case YANG_TYPEDEF:
3376 ret = parse_typedef(ctx, data, &grp->typedefs);
3377 break;
3378 case YANG_ACTION:
3379 ret = parse_action(ctx, data, &grp->actions);
3380 break;
3381 case YANG_GROUPING:
3382 ret = parse_grouping(ctx, data, &grp->groupings);
3383 break;
3384 case YANG_NOTIFICATION:
3385 ret = parse_notif(ctx, data, &grp->notifs);
3386 break;
3387 case YANG_CUSTOM:
3388 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &grp->exts);
3389 break;
3390 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003391 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003392 return LY_EVALID;
3393 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003394 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003395 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003396 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003397
3398 return ret;
3399}
3400
Michal Vaskoea5abea2018-09-18 13:10:54 +02003401/**
3402 * @brief Parse the refine statement.
3403 *
3404 * @param[in] ctx libyang context for logging.
3405 * @param[in,out] data Data to read from, always moved to currently handled character.
3406 * @param[in,out] augments Augments to add to.
3407 *
3408 * @return LY_ERR values.
3409 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003410static LY_ERR
3411parse_augment(struct ly_ctx *ctx, const char **data, struct lysp_augment **augments)
3412{
3413 LY_ERR ret = 0;
3414 char *buf, *word;
3415 int word_len;
3416 enum yang_keyword kw;
3417 struct lysp_augment *aug;
3418
3419 LYSP_ARRAY_NEW_RET(ctx, augments, aug, LY_EMEM);
3420
3421 /* get value */
3422 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003423 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003424
3425 if (buf) {
3426 aug->nodeid = lydict_insert_zc(ctx, word);
3427 } else {
3428 aug->nodeid = lydict_insert(ctx, word, word_len);
3429 }
3430
3431 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003432 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003433
3434 switch (kw) {
3435 case YANG_DESCRIPTION:
3436 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts);
3437 break;
3438 case YANG_IF_FEATURE:
3439 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &aug->iffeatures, Y_STR_ARG, &aug->exts);
3440 break;
3441 case YANG_REFERENCE:
3442 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts);
3443 break;
3444 case YANG_STATUS:
3445 ret = parse_status(ctx, data, &aug->flags, &aug->exts);
3446 break;
3447 case YANG_WHEN:
3448 ret = parse_when(ctx, data, &aug->when);
3449 break;
3450
3451 case YANG_ANYDATA:
3452 case YANG_ANYXML:
3453 ret = parse_any(ctx, data, kw, &aug->child);
3454 break;
3455 case YANG_CASE:
3456 ret = parse_case(ctx, data, &aug->child);
3457 break;
3458 case YANG_CHOICE:
3459 ret = parse_choice(ctx, data, &aug->child);
3460 break;
3461 case YANG_CONTAINER:
3462 ret = parse_container(ctx, data, &aug->child);
3463 break;
3464 case YANG_LEAF:
3465 ret = parse_leaf(ctx, data, &aug->child);
3466 break;
3467 case YANG_LEAF_LIST:
3468 ret = parse_leaflist(ctx, data, &aug->child);
3469 break;
3470 case YANG_LIST:
3471 ret = parse_list(ctx, data, &aug->child);
3472 break;
3473 case YANG_USES:
3474 ret = parse_uses(ctx, data, &aug->child);
3475 break;
3476
3477 case YANG_ACTION:
3478 ret = parse_action(ctx, data, &aug->actions);
3479 break;
3480 case YANG_NOTIFICATION:
3481 ret = parse_notif(ctx, data, &aug->notifs);
3482 break;
3483 case YANG_CUSTOM:
3484 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &aug->exts);
3485 break;
3486 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003487 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003488 return LY_EVALID;
3489 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003490 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003491 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003492 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003493
3494 return ret;
3495}
3496
Michal Vaskoea5abea2018-09-18 13:10:54 +02003497/**
3498 * @brief Parse the uses statement.
3499 *
3500 * @param[in] ctx libyang context for logging.
3501 * @param[in,out] data Data to read from, always moved to currently handled character.
3502 * @param[in,out] siblings Siblings to add to.
3503 *
3504 * @return LY_ERR values.
3505 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003506static LY_ERR
3507parse_uses(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3508{
3509 LY_ERR ret = 0;
3510 char *buf, *word;
3511 int word_len;
3512 enum yang_keyword kw;
3513 struct lysp_node *iter;
3514 struct lysp_node_uses *uses;
3515
3516 /* create structure */
3517 uses = calloc(1, sizeof *uses);
3518 LY_CHECK_ERR_RET(!uses, LOGMEM(ctx), LY_EMEM);
3519 uses->nodetype = LYS_USES;
3520
3521 /* insert into siblings */
3522 if (!*siblings) {
3523 *siblings = (struct lysp_node *)uses;
3524 } else {
3525 for (iter = *siblings; iter->next; iter = iter->next);
3526 iter->next = (struct lysp_node *)uses;
3527 }
3528
3529 /* get name */
3530 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003531 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003532
3533 if (buf) {
3534 uses->name = lydict_insert_zc(ctx, word);
3535 } else {
3536 uses->name = lydict_insert(ctx, word, word_len);
3537 }
3538
3539 /* parse substatements */
3540 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003541 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003542
3543 switch (kw) {
3544 case YANG_DESCRIPTION:
3545 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts);
3546 break;
3547 case YANG_IF_FEATURE:
3548 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &uses->iffeatures, Y_STR_ARG, &uses->exts);
3549 break;
3550 case YANG_REFERENCE:
3551 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts);
3552 break;
3553 case YANG_STATUS:
3554 ret = parse_status(ctx, data, &uses->flags, &uses->exts);
3555 break;
3556 case YANG_WHEN:
3557 ret = parse_when(ctx, data, &uses->when);
3558 break;
3559
3560 case YANG_REFINE:
3561 ret = parse_refine(ctx, data, &uses->refines);
3562 break;
3563 case YANG_AUGMENT:
3564 ret = parse_augment(ctx, data, &uses->augments);
3565 break;
3566 case YANG_CUSTOM:
3567 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &uses->exts);
3568 break;
3569 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003570 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003571 return LY_EVALID;
3572 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003573 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003574 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003575 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003576
3577 return ret;
3578}
3579
Michal Vaskoea5abea2018-09-18 13:10:54 +02003580/**
3581 * @brief Parse the case statement.
3582 *
3583 * @param[in] ctx libyang context for logging.
3584 * @param[in,out] data Data to read from, always moved to currently handled character.
3585 * @param[in,out] siblings Siblings to add to.
3586 *
3587 * @return LY_ERR values.
3588 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003589static LY_ERR
3590parse_case(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3591{
3592 LY_ERR ret = 0;
3593 char *buf, *word;
3594 int word_len;
3595 enum yang_keyword kw;
3596 struct lysp_node *iter;
3597 struct lysp_node_case *cas;
3598
3599 /* create structure */
3600 cas = calloc(1, sizeof *cas);
3601 LY_CHECK_ERR_RET(!cas, LOGMEM(ctx), LY_EMEM);
3602 cas->nodetype = LYS_CASE;
3603
3604 /* insert into siblings */
3605 if (!*siblings) {
3606 *siblings = (struct lysp_node *)cas;
3607 } else {
3608 for (iter = *siblings; iter->next; iter = iter->next);
3609 iter->next = (struct lysp_node *)cas;
3610 }
3611
3612 /* get name */
3613 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003614 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003615
3616 if (buf) {
3617 cas->name = lydict_insert_zc(ctx, word);
3618 } else {
3619 cas->name = lydict_insert(ctx, word, word_len);
3620 }
3621
3622 /* parse substatements */
3623 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003624 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003625
3626 switch (kw) {
3627 case YANG_DESCRIPTION:
3628 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts);
3629 break;
3630 case YANG_IF_FEATURE:
3631 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cas->iffeatures, Y_STR_ARG, &cas->exts);
3632 break;
3633 case YANG_REFERENCE:
3634 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts);
3635 break;
3636 case YANG_STATUS:
3637 ret = parse_status(ctx, data, &cas->flags, &cas->exts);
3638 break;
3639 case YANG_WHEN:
3640 ret = parse_when(ctx, data, &cas->when);
3641 break;
3642
3643 case YANG_ANYDATA:
3644 case YANG_ANYXML:
3645 ret = parse_any(ctx, data, kw, &cas->child);
3646 break;
3647 case YANG_CHOICE:
3648 ret = parse_case(ctx, data, &cas->child);
3649 break;
3650 case YANG_CONTAINER:
3651 ret = parse_container(ctx, data, &cas->child);
3652 break;
3653 case YANG_LEAF:
3654 ret = parse_leaf(ctx, data, &cas->child);
3655 break;
3656 case YANG_LEAF_LIST:
3657 ret = parse_leaflist(ctx, data, &cas->child);
3658 break;
3659 case YANG_LIST:
3660 ret = parse_list(ctx, data, &cas->child);
3661 break;
3662 case YANG_USES:
3663 ret = parse_uses(ctx, data, &cas->child);
3664 break;
3665 case YANG_CUSTOM:
3666 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cas->exts);
3667 break;
3668 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003669 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003670 return LY_EVALID;
3671 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003672 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003673 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003674 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003675
3676 return ret;
3677}
3678
Michal Vaskoea5abea2018-09-18 13:10:54 +02003679/**
3680 * @brief Parse the choice statement.
3681 *
3682 * @param[in] ctx libyang context for logging.
3683 * @param[in,out] data Data to read from, always moved to currently handled character.
3684 * @param[in,out] siblings Siblings to add to.
3685 *
3686 * @return LY_ERR values.
3687 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003688static LY_ERR
3689parse_choice(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3690{
3691 LY_ERR ret = 0;
3692 char *buf, *word;
3693 int word_len;
3694 enum yang_keyword kw;
3695 struct lysp_node *iter;
3696 struct lysp_node_choice *choic;
3697
3698 /* create structure */
3699 choic = calloc(1, sizeof *choic);
3700 LY_CHECK_ERR_RET(!choic, LOGMEM(ctx), LY_EMEM);
3701 choic->nodetype = LYS_CHOICE;
3702
3703 /* insert into siblings */
3704 if (!*siblings) {
3705 *siblings = (struct lysp_node *)choic;
3706 } else {
3707 for (iter = *siblings; iter->next; iter = iter->next);
3708 iter->next = (struct lysp_node *)choic;
3709 }
3710
3711 /* get name */
3712 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003713 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003714
3715 if (buf) {
3716 choic->name = lydict_insert_zc(ctx, word);
3717 } else {
3718 choic->name = lydict_insert(ctx, word, word_len);
3719 }
3720
3721 /* parse substatements */
3722 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003723 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003724
3725 switch (kw) {
3726 case YANG_CONFIG:
3727 ret = parse_config(ctx, data, &choic->flags, &choic->exts);
3728 break;
3729 case YANG_DESCRIPTION:
3730 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &choic->dsc, Y_STR_ARG, &choic->exts);
3731 break;
3732 case YANG_IF_FEATURE:
3733 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &choic->iffeatures, Y_STR_ARG, &choic->exts);
3734 break;
3735 case YANG_MANDATORY:
3736 ret = parse_mandatory(ctx, data, &choic->flags, &choic->exts);
3737 break;
3738 case YANG_REFERENCE:
3739 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &choic->ref, Y_STR_ARG, &choic->exts);
3740 break;
3741 case YANG_STATUS:
3742 ret = parse_status(ctx, data, &choic->flags, &choic->exts);
3743 break;
3744 case YANG_WHEN:
3745 ret = parse_when(ctx, data, &choic->when);
3746 break;
3747 case YANG_DEFAULT:
3748 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &choic->dflt, Y_IDENTIF_ARG, &choic->exts);
3749 break;
3750
3751 case YANG_ANYDATA:
3752 case YANG_ANYXML:
3753 ret = parse_any(ctx, data, kw, &choic->child);
3754 break;
3755 case YANG_CASE:
3756 ret = parse_case(ctx, data, &choic->child);
3757 break;
3758 case YANG_CHOICE:
3759 ret = parse_choice(ctx, data, &choic->child);
3760 break;
3761 case YANG_CONTAINER:
3762 ret = parse_container(ctx, data, &choic->child);
3763 break;
3764 case YANG_LEAF:
3765 ret = parse_leaf(ctx, data, &choic->child);
3766 break;
3767 case YANG_LEAF_LIST:
3768 ret = parse_leaflist(ctx, data, &choic->child);
3769 break;
3770 case YANG_LIST:
3771 ret = parse_list(ctx, data, &choic->child);
3772 break;
3773 case YANG_CUSTOM:
3774 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &choic->exts);
3775 break;
3776 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003777 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003778 return LY_EVALID;
3779 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003780 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003781 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003782 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003783
3784 return ret;
3785}
3786
Michal Vaskoea5abea2018-09-18 13:10:54 +02003787/**
3788 * @brief Parse the container statement.
3789 *
3790 * @param[in] ctx libyang context for logging.
3791 * @param[in,out] data Data to read from, always moved to currently handled character.
3792 * @param[in,out] siblings Siblings to add to.
3793 *
3794 * @return LY_ERR values.
3795 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003796static LY_ERR
3797parse_container(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3798{
3799 LY_ERR ret = 0;
3800 char *buf, *word;
3801 int word_len;
3802 enum yang_keyword kw;
3803 struct lysp_node *iter;
3804 struct lysp_node_container *cont;
3805
3806 /* create structure */
3807 cont = calloc(1, sizeof *cont);
3808 LY_CHECK_ERR_RET(!cont, LOGMEM(ctx), LY_EMEM);
3809 cont->nodetype = LYS_CONTAINER;
3810
3811 /* insert into siblings */
3812 if (!*siblings) {
3813 *siblings = (struct lysp_node *)cont;
3814 } else {
3815 for (iter = *siblings; iter->next; iter = iter->next);
3816 iter->next = (struct lysp_node *)cont;
3817 }
3818
3819 /* get name */
3820 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003821 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003822
3823 if (buf) {
3824 cont->name = lydict_insert_zc(ctx, word);
3825 } else {
3826 cont->name = lydict_insert(ctx, word, word_len);
3827 }
3828
3829 /* parse substatements */
3830 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003831 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003832
3833 switch (kw) {
3834 case YANG_CONFIG:
3835 ret = parse_config(ctx, data, &cont->flags, &cont->exts);
3836 break;
3837 case YANG_DESCRIPTION:
3838 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts);
3839 break;
3840 case YANG_IF_FEATURE:
3841 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cont->iffeatures, Y_STR_ARG, &cont->exts);
3842 break;
3843 case YANG_REFERENCE:
3844 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts);
3845 break;
3846 case YANG_STATUS:
3847 ret = parse_status(ctx, data, &cont->flags, &cont->exts);
3848 break;
3849 case YANG_WHEN:
3850 ret = parse_when(ctx, data, &cont->when);
3851 break;
3852 case YANG_PRESENCE:
3853 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts);
3854 break;
3855
3856 case YANG_ANYDATA:
3857 case YANG_ANYXML:
3858 ret = parse_any(ctx, data, kw, &cont->child);
3859 break;
3860 case YANG_CHOICE:
3861 ret = parse_choice(ctx, data, &cont->child);
3862 break;
3863 case YANG_CONTAINER:
3864 ret = parse_container(ctx, data, &cont->child);
3865 break;
3866 case YANG_LEAF:
3867 ret = parse_leaf(ctx, data, &cont->child);
3868 break;
3869 case YANG_LEAF_LIST:
3870 ret = parse_leaflist(ctx, data, &cont->child);
3871 break;
3872 case YANG_LIST:
3873 ret = parse_list(ctx, data, &cont->child);
3874 break;
3875 case YANG_USES:
3876 ret = parse_uses(ctx, data, &cont->child);
3877 break;
3878
3879 case YANG_TYPEDEF:
3880 ret = parse_typedef(ctx, data, &cont->typedefs);
3881 break;
3882 case YANG_MUST:
3883 ret = parse_restrs(ctx, data, kw, &cont->musts);
3884 break;
3885 case YANG_ACTION:
3886 ret = parse_action(ctx, data, &cont->actions);
3887 break;
3888 case YANG_GROUPING:
3889 ret = parse_grouping(ctx, data, &cont->groupings);
3890 break;
3891 case YANG_NOTIFICATION:
3892 ret = parse_notif(ctx, data, &cont->notifs);
3893 break;
3894 case YANG_CUSTOM:
3895 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cont->exts);
3896 break;
3897 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003898 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003899 return LY_EVALID;
3900 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003901 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003902 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003903 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003904
3905 return ret;
3906}
3907
Michal Vaskoea5abea2018-09-18 13:10:54 +02003908/**
3909 * @brief Parse the list statement.
3910 *
3911 * @param[in] ctx libyang context for logging.
3912 * @param[in,out] data Data to read from, always moved to currently handled character.
3913 * @param[in,out] siblings Siblings to add to.
3914 *
3915 * @return LY_ERR values.
3916 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003917static LY_ERR
3918parse_list(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3919{
3920 LY_ERR ret = 0;
3921 char *buf, *word;
3922 int word_len;
3923 enum yang_keyword kw;
3924 struct lysp_node *iter;
3925 struct lysp_node_list *list;
3926
3927 /* create structure */
3928 list = calloc(1, sizeof *list);
3929 LY_CHECK_ERR_RET(!list, LOGMEM(ctx), LY_EMEM);
3930 list->nodetype = LYS_LIST;
3931
3932 /* insert into siblings */
3933 if (!*siblings) {
3934 *siblings = (struct lysp_node *)list;
3935 } else {
3936 for (iter = *siblings; iter->next; iter = iter->next);
3937 iter->next = (struct lysp_node *)list;
3938 }
3939
3940 /* get name */
3941 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003942 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003943
3944 if (buf) {
3945 list->name = lydict_insert_zc(ctx, word);
3946 } else {
3947 list->name = lydict_insert(ctx, word, word_len);
3948 }
3949
3950 /* parse substatements */
3951 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003952 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003953
3954 switch (kw) {
3955 case YANG_CONFIG:
3956 ret = parse_config(ctx, data, &list->flags, &list->exts);
3957 break;
3958 case YANG_DESCRIPTION:
3959 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts);
3960 break;
3961 case YANG_IF_FEATURE:
3962 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &list->iffeatures, Y_STR_ARG, &list->exts);
3963 break;
3964 case YANG_REFERENCE:
3965 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts);
3966 break;
3967 case YANG_STATUS:
3968 ret = parse_status(ctx, data, &list->flags, &list->exts);
3969 break;
3970 case YANG_WHEN:
3971 ret = parse_when(ctx, data, &list->when);
3972 break;
3973 case YANG_KEY:
3974 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts);
3975 break;
3976 case YANG_MAX_ELEMENTS:
3977 ret = parse_maxelements(ctx, data, &list->max, &list->flags, &list->exts);
3978 break;
3979 case YANG_MIN_ELEMENTS:
3980 ret = parse_minelements(ctx, data, &list->min, &list->flags, &list->exts);
3981 break;
3982 case YANG_ORDERED_BY:
3983 ret = parse_orderedby(ctx, data, &list->flags, &list->exts);
3984 break;
3985 case YANG_UNIQUE:
3986 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, &list->uniques, Y_STR_ARG, &list->exts);
3987 break;
3988
3989 case YANG_ANYDATA:
3990 case YANG_ANYXML:
3991 ret = parse_any(ctx, data, kw, &list->child);
3992 break;
3993 case YANG_CHOICE:
3994 ret = parse_choice(ctx, data, &list->child);
3995 break;
3996 case YANG_CONTAINER:
3997 ret = parse_container(ctx, data, &list->child);
3998 break;
3999 case YANG_LEAF:
4000 ret = parse_leaf(ctx, data, &list->child);
4001 break;
4002 case YANG_LEAF_LIST:
4003 ret = parse_leaflist(ctx, data, &list->child);
4004 break;
4005 case YANG_LIST:
4006 ret = parse_list(ctx, data, &list->child);
4007 break;
4008 case YANG_USES:
4009 ret = parse_uses(ctx, data, &list->child);
4010 break;
4011
4012 case YANG_TYPEDEF:
4013 ret = parse_typedef(ctx, data, &list->typedefs);
4014 break;
4015 case YANG_MUST:
4016 ret = parse_restrs(ctx, data, kw, &list->musts);
4017 break;
4018 case YANG_ACTION:
4019 ret = parse_action(ctx, data, &list->actions);
4020 break;
4021 case YANG_GROUPING:
4022 ret = parse_grouping(ctx, data, &list->groupings);
4023 break;
4024 case YANG_NOTIFICATION:
4025 ret = parse_notif(ctx, data, &list->notifs);
4026 break;
4027 case YANG_CUSTOM:
4028 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &list->exts);
4029 break;
4030 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004031 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004032 return LY_EVALID;
4033 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004034 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004035 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004036 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004037
4038 return ret;
4039}
4040
Michal Vaskoea5abea2018-09-18 13:10:54 +02004041/**
4042 * @brief Parse the yin-element statement.
4043 *
4044 * @param[in] ctx libyang context for logging.
4045 * @param[in,out] data Data to read from, always moved to currently handled character.
4046 * @param[in,out] flags Flags to write to.
4047 * @param[in,out] exts Extension instances to add to.
4048 *
4049 * @return LY_ERR values.
4050 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004051static LY_ERR
4052parse_yinelement(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
4053{
4054 LY_ERR ret = 0;
4055 char *buf, *word;
4056 int word_len;
4057 enum yang_keyword kw;
4058
4059 if (*flags & LYS_YINELEM_MASK) {
4060 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yin-element");
4061 return LY_EVALID;
4062 }
4063
4064 /* get value */
4065 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004066 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004067
4068 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
4069 *flags |= LYS_YINELEM_TRUE;
4070 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
4071 *flags |= LYS_YINELEM_FALSE;
4072 } else {
4073 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yin-element");
4074 free(buf);
4075 return LY_EVALID;
4076 }
4077 free(buf);
4078
4079 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004080 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004081
4082 switch (kw) {
4083 case YANG_CUSTOM:
4084 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_YINELEM, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02004085 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004086 break;
4087 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004088 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004089 return LY_EVALID;
4090 }
4091 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004092 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004093
4094 return ret;
4095}
4096
Michal Vaskoea5abea2018-09-18 13:10:54 +02004097/**
4098 * @brief Parse the yin-element statement.
4099 *
4100 * @param[in] ctx libyang context for logging.
4101 * @param[in,out] data Data to read from, always moved to currently handled character.
4102 * @param[in,out] argument Value to write to.
4103 * @param[in,out] flags Flags to write to.
4104 * @param[in,out] exts Extension instances to add to.
4105 *
4106 * @return LY_ERR values.
4107 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004108static LY_ERR
4109parse_argument(struct ly_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
4110{
4111 LY_ERR ret = 0;
4112 char *buf, *word;
4113 int word_len;
4114 enum yang_keyword kw;
4115
4116 if (*argument) {
4117 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "argument");
4118 return LY_EVALID;
4119 }
4120
4121 /* get value */
4122 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004123 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004124
4125 if (buf) {
4126 *argument = lydict_insert_zc(ctx, word);
4127 } else {
4128 *argument = lydict_insert(ctx, word, word_len);
4129 }
4130
4131 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004132 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004133
4134 switch (kw) {
4135 case YANG_YIN_ELEMENT:
4136 ret = parse_yinelement(ctx, data, flags, exts);
4137 break;
4138 case YANG_CUSTOM:
4139 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ARGUMENT, 0, exts);
4140 break;
4141 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004142 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004143 return LY_EVALID;
4144 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004145 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004146 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004147 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004148
4149 return ret;
4150}
4151
Michal Vaskoea5abea2018-09-18 13:10:54 +02004152/**
4153 * @brief Parse the extension statement.
4154 *
4155 * @param[in] ctx libyang context for logging.
4156 * @param[in,out] data Data to read from, always moved to currently handled character.
4157 * @param[in,out] extensions Extensions to add to.
4158 *
4159 * @return LY_ERR values.
4160 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004161static LY_ERR
4162parse_extension(struct ly_ctx *ctx, const char **data, struct lysp_ext **extensions)
4163{
4164 LY_ERR ret = 0;
4165 char *buf, *word;
4166 int word_len;
4167 enum yang_keyword kw;
4168 struct lysp_ext *ex;
4169
4170 LYSP_ARRAY_NEW_RET(ctx, extensions, ex, LY_EMEM);
4171
4172 /* get value */
4173 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004174 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004175
4176 if (buf) {
4177 ex->name = lydict_insert_zc(ctx, word);
4178 } else {
4179 ex->name = lydict_insert(ctx, word, word_len);
4180 }
4181
4182 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004183 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004184
4185 switch (kw) {
4186 case YANG_DESCRIPTION:
4187 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts);
4188 break;
4189 case YANG_REFERENCE:
4190 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts);
4191 break;
4192 case YANG_STATUS:
4193 ret = parse_status(ctx, data, &ex->flags, &ex->exts);
4194 break;
4195 case YANG_ARGUMENT:
4196 ret = parse_argument(ctx, data, &ex->argument, &ex->flags, &ex->exts);
4197 break;
4198 case YANG_CUSTOM:
4199 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ex->exts);
4200 break;
4201 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004202 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004203 return LY_EVALID;
4204 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004205 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004206 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004207 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004208
4209 return ret;
4210}
4211
Michal Vaskoea5abea2018-09-18 13:10:54 +02004212/**
4213 * @brief Parse the deviate statement.
4214 *
4215 * @param[in] ctx libyang context for logging.
4216 * @param[in,out] data Data to read from, always moved to currently handled character.
4217 * @param[in,out] deviates Deviates to add to.
4218 *
4219 * @return LY_ERR values.
4220 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004221static LY_ERR
4222parse_deviate(struct ly_ctx *ctx, const char **data, struct lysp_deviate **deviates)
4223{
4224 LY_ERR ret = 0;
4225 char *buf, *word;
4226 int word_len, dev_mod;
4227 enum yang_keyword kw;
4228 struct lysp_deviate *iter, *d;
4229 struct lysp_deviate_add *d_add = NULL;
4230 struct lysp_deviate_rpl *d_rpl = NULL;
4231 struct lysp_deviate_del *d_del = NULL;
4232 const char **d_units, ***d_uniques, ***d_dflts;
4233 struct lysp_restr **d_musts;
4234 uint16_t *d_flags;
4235 uint32_t *d_min, *d_max;
4236
4237 /* get value */
4238 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004239 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004240
4241 if ((word_len == 13) && !strncmp(word, "not-supported", word_len)) {
4242 dev_mod = LYS_DEV_NOT_SUPPORTED;
4243 } else if ((word_len == 3) && !strncmp(word, "add", word_len)) {
4244 dev_mod = LYS_DEV_ADD;
4245 } else if ((word_len == 7) && !strncmp(word, "replace", word_len)) {
4246 dev_mod = LYS_DEV_REPLACE;
4247 } else if ((word_len == 6) && !strncmp(word, "delete", word_len)) {
4248 dev_mod = LYS_DEV_DELETE;
4249 } else {
4250 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "deviate");
4251 free(buf);
4252 return LY_EVALID;
4253 }
4254 free(buf);
4255
4256 /* create structure */
4257 switch (dev_mod) {
4258 case LYS_DEV_NOT_SUPPORTED:
4259 d = calloc(1, sizeof *d);
4260 LY_CHECK_ERR_RET(!d, LOGMEM(ctx), LY_EMEM);
4261 break;
4262 case LYS_DEV_ADD:
4263 d_add = calloc(1, sizeof *d_add);
4264 LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx), LY_EMEM);
4265 d = (struct lysp_deviate *)d_add;
4266 d_units = &d_add->units;
4267 d_uniques = &d_add->uniques;
4268 d_dflts = &d_add->dflts;
4269 d_musts = &d_add->musts;
4270 d_flags = &d_add->flags;
4271 d_min = &d_add->min;
4272 d_max = &d_add->max;
4273 break;
4274 case LYS_DEV_REPLACE:
4275 d_rpl = calloc(1, sizeof *d_rpl);
4276 LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx), LY_EMEM);
4277 d = (struct lysp_deviate *)d_rpl;
4278 d_units = &d_rpl->units;
4279 d_flags = &d_rpl->flags;
4280 d_min = &d_rpl->min;
4281 d_max = &d_rpl->max;
4282 break;
4283 case LYS_DEV_DELETE:
4284 d_del = calloc(1, sizeof *d_del);
4285 LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx), LY_EMEM);
4286 d = (struct lysp_deviate *)d_del;
4287 d_units = &d_del->units;
4288 d_uniques = &d_del->uniques;
4289 d_dflts = &d_del->dflts;
4290 d_musts = &d_del->musts;
4291 d_flags = &d_del->flags;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004292 break;
4293 default:
4294 assert(0);
4295 LOGINT_RET(ctx);
4296 }
4297 d->mod = dev_mod;
4298
4299 /* insert into siblings */
4300 if (!*deviates) {
4301 *deviates = d;
4302 } else {
4303 for (iter = *deviates; iter->next; iter = iter->next);
4304 iter->next = d;
4305 }
4306
4307 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004308 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004309
4310 switch (kw) {
4311 case YANG_CONFIG:
4312 switch (dev_mod) {
4313 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004314 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004315 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004316 return LY_EVALID;
4317 default:
4318 ret = parse_config(ctx, data, d_flags, &d->exts);
4319 break;
4320 }
4321 break;
4322 case YANG_DEFAULT:
4323 switch (dev_mod) {
4324 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004325 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004326 return LY_EVALID;
4327 case LYS_DEV_REPLACE:
4328 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &d_rpl->dflt, Y_STR_ARG, &d->exts);
4329 break;
4330 default:
4331 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, d_dflts, Y_STR_ARG, &d->exts);
4332 break;
4333 }
4334 break;
4335 case YANG_MANDATORY:
4336 switch (dev_mod) {
4337 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004338 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004339 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004340 return LY_EVALID;
4341 default:
4342 ret = parse_mandatory(ctx, data, d_flags, &d->exts);
4343 break;
4344 }
4345 break;
4346 case YANG_MAX_ELEMENTS:
4347 switch (dev_mod) {
4348 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004349 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004350 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004351 return LY_EVALID;
4352 default:
4353 ret = parse_maxelements(ctx, data, d_max, d_flags, &d->exts);
4354 break;
4355 }
4356 break;
4357 case YANG_MIN_ELEMENTS:
4358 switch (dev_mod) {
4359 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004360 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004361 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004362 return LY_EVALID;
4363 default:
4364 ret = parse_minelements(ctx, data, d_min, d_flags, &d->exts);
4365 break;
4366 }
4367 break;
4368 case YANG_MUST:
4369 switch (dev_mod) {
4370 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004371 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004372 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004373 return LY_EVALID;
4374 default:
4375 ret = parse_restrs(ctx, data, kw, d_musts);
4376 break;
4377 }
4378 break;
4379 case YANG_TYPE:
4380 switch (dev_mod) {
4381 case LYS_DEV_NOT_SUPPORTED:
4382 case LYS_DEV_ADD:
4383 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004384 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004385 return LY_EVALID;
4386 default:
4387 d_rpl->type = calloc(1, sizeof *d_rpl->type);
4388 LY_CHECK_ERR_RET(!d_rpl->type, LOGMEM(ctx), LY_EMEM);
4389 ret = parse_type(ctx, data, d_rpl->type);
4390 break;
4391 }
4392 break;
4393 case YANG_UNIQUE:
4394 switch (dev_mod) {
4395 case LYS_DEV_NOT_SUPPORTED:
4396 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004397 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004398 return LY_EVALID;
4399 default:
4400 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts);
4401 break;
4402 }
4403 break;
4404 case YANG_UNITS:
4405 switch (dev_mod) {
4406 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004407 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004408 return LY_EVALID;
4409 default:
4410 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts);
4411 break;
4412 }
4413 break;
4414 case YANG_CUSTOM:
4415 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &d->exts);
4416 break;
4417 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004418 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004419 return LY_EVALID;
4420 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004421 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004422 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004423 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004424
4425 return ret;
4426}
4427
Michal Vaskoea5abea2018-09-18 13:10:54 +02004428/**
4429 * @brief Parse the deviation statement.
4430 *
4431 * @param[in] ctx libyang context for logging.
4432 * @param[in,out] data Data to read from, always moved to currently handled character.
4433 * @param[in,out] deviations Deviations to add to.
4434 *
4435 * @return LY_ERR values.
4436 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004437static LY_ERR
4438parse_deviation(struct ly_ctx *ctx, const char **data, struct lysp_deviation **deviations)
4439{
4440 LY_ERR ret = 0;
4441 char *buf, *word;
4442 int word_len;
4443 enum yang_keyword kw;
4444 struct lysp_deviation *dev;
4445
4446 LYSP_ARRAY_NEW_RET(ctx, deviations, dev, LY_EMEM);
4447
4448 /* get value */
4449 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004450 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004451
4452 if (buf) {
4453 dev->nodeid = lydict_insert_zc(ctx, word);
4454 } else {
4455 dev->nodeid = lydict_insert(ctx, word, word_len);
4456 }
4457
4458 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004459 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004460
4461 switch (kw) {
4462 case YANG_DESCRIPTION:
4463 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts);
4464 break;
4465 case YANG_DEVIATE:
4466 ret = parse_deviate(ctx, data, &dev->deviates);
4467 break;
4468 case YANG_REFERENCE:
4469 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts);
4470 break;
4471 case YANG_CUSTOM:
4472 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &dev->exts);
4473 break;
4474 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004475 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004476 return LY_EVALID;
4477 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004478 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004479 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004480 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004481
4482 /* mandatory substatements */
4483 if (!dev->deviates) {
4484 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "deviate", "deviation");
4485 return LY_EVALID;
4486 }
4487
4488 return ret;
4489}
4490
Michal Vaskoea5abea2018-09-18 13:10:54 +02004491/**
4492 * @brief Parse the feature statement.
4493 *
4494 * @param[in] ctx libyang context for logging.
4495 * @param[in,out] data Data to read from, always moved to currently handled character.
4496 * @param[in,out] features Features to add to.
4497 *
4498 * @return LY_ERR values.
4499 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004500static LY_ERR
4501parse_feature(struct ly_ctx *ctx, const char **data, struct lysp_feature **features)
4502{
4503 LY_ERR ret = 0;
4504 char *buf, *word;
4505 int word_len;
4506 enum yang_keyword kw;
4507 struct lysp_feature *feat;
4508
4509 LYSP_ARRAY_NEW_RET(ctx, features, feat, LY_EMEM);
4510
4511 /* get value */
4512 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004513 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004514
4515 if (buf) {
4516 feat->name = lydict_insert_zc(ctx, word);
4517 } else {
4518 feat->name = lydict_insert(ctx, word, word_len);
4519 }
4520
4521 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004522 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004523
4524 switch (kw) {
4525 case YANG_DESCRIPTION:
4526 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts);
4527 break;
4528 case YANG_IF_FEATURE:
4529 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &feat->iffeatures, Y_STR_ARG, &feat->exts);
4530 break;
4531 case YANG_REFERENCE:
4532 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts);
4533 break;
4534 case YANG_STATUS:
4535 ret = parse_status(ctx, data, &feat->flags, &feat->exts);
4536 break;
4537 case YANG_CUSTOM:
4538 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &feat->exts);
4539 break;
4540 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004541 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004542 return LY_EMEM;
4543 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004544 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004545 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004546 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004547
4548 return ret;
4549}
4550
Michal Vaskoea5abea2018-09-18 13:10:54 +02004551/**
4552 * @brief Parse the identity statement.
4553 *
4554 * @param[in] ctx libyang context for logging.
4555 * @param[in,out] data Data to read from, always moved to currently handled character.
4556 * @param[in,out] identities Identities to add to.
4557 *
4558 * @return LY_ERR values.
4559 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004560static LY_ERR
4561parse_identity(struct ly_ctx *ctx, const char **data, struct lysp_ident **identities)
4562{
4563 LY_ERR ret = 0;
4564 char *buf, *word;
4565 int word_len;
4566 enum yang_keyword kw;
4567 struct lysp_ident *ident;
4568
4569 LYSP_ARRAY_NEW_RET(ctx, identities, ident, LY_EMEM);
4570
4571 /* get value */
4572 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004573 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004574
4575 if (buf) {
4576 ident->name = lydict_insert_zc(ctx, word);
4577 } else {
4578 ident->name = lydict_insert(ctx, word, word_len);
4579 }
4580
4581 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004582 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004583
4584 switch (kw) {
4585 case YANG_DESCRIPTION:
4586 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts);
4587 break;
4588 case YANG_IF_FEATURE:
4589 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts);
4590 break;
4591 case YANG_REFERENCE:
4592 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts);
4593 break;
4594 case YANG_STATUS:
4595 ret = parse_status(ctx, data, &ident->flags, &ident->exts);
4596 break;
4597 case YANG_BASE:
4598 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts);
4599 break;
4600 case YANG_CUSTOM:
4601 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ident->exts);
4602 break;
4603 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004604 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004605 return LY_EVALID;
4606 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004607 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004608 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004609 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004610
4611 return ret;
4612}
4613
Michal Vaskoea5abea2018-09-18 13:10:54 +02004614/**
4615 * @brief Parse the module or submodule statement.
4616 *
4617 * @param[in] ctx libyang context for logging.
4618 * @param[in,out] data Data to read from, always moved to currently handled character.
4619 * @param[in,out] mod Module to write to.
4620 *
4621 * @return LY_ERR values.
4622 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004623static LY_ERR
4624parse_sub_module(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
4625{
4626 LY_ERR ret = 0;
4627 char *buf, *word;
4628 int word_len;
4629 enum yang_keyword kw, prev_kw = 0;
4630 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
4631
4632 /* (sub)module name */
4633 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004634 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004635
4636 if (buf) {
4637 mod->name = lydict_insert_zc(ctx, word);
4638 } else {
4639 mod->name = lydict_insert(ctx, word, word_len);
4640 }
4641
4642 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004643 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004644
4645 switch (kw) {
4646 /* module header */
4647 case YANG_NAMESPACE:
4648 case YANG_PREFIX:
4649 if (mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004650 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004651 return LY_EVALID;
4652 }
4653 /* fallthrough */
4654 case YANG_BELONGS_TO:
4655 if ((kw == YANG_BELONGS_TO) && !mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004656 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004657 return LY_EVALID;
4658 }
4659 /* fallthrough */
4660 case YANG_YANG_VERSION:
4661 if (mod_stmt > Y_MOD_MODULE_HEADER) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004662 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004663 return LY_EVALID;
4664 }
4665 break;
4666 /* linkage */
4667 case YANG_INCLUDE:
4668 case YANG_IMPORT:
4669 if (mod_stmt > Y_MOD_LINKAGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004670 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004671 return LY_EVALID;
4672 }
4673 mod_stmt = Y_MOD_LINKAGE;
4674 break;
4675 /* meta */
4676 case YANG_ORGANIZATION:
4677 case YANG_CONTACT:
4678 case YANG_DESCRIPTION:
4679 case YANG_REFERENCE:
4680 if (mod_stmt > Y_MOD_META) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004681 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004682 return LY_EVALID;
4683 }
4684 mod_stmt = Y_MOD_META;
4685 break;
4686
4687 /* revision */
4688 case YANG_REVISION:
4689 if (mod_stmt > Y_MOD_REVISION) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004690 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004691 return LY_EVALID;
4692 }
4693 mod_stmt = Y_MOD_REVISION;
4694 break;
4695
4696 /* body */
4697 case YANG_ANYDATA:
4698 case YANG_ANYXML:
4699 case YANG_AUGMENT:
4700 case YANG_CHOICE:
4701 case YANG_CONTAINER:
4702 case YANG_DEVIATION:
4703 case YANG_EXTENSION:
4704 case YANG_FEATURE:
4705 case YANG_GROUPING:
4706 case YANG_IDENTITY:
4707 case YANG_LEAF:
4708 case YANG_LEAF_LIST:
4709 case YANG_LIST:
4710 case YANG_NOTIFICATION:
4711 case YANG_RPC:
4712 case YANG_TYPEDEF:
4713 case YANG_USES:
4714 case YANG_CUSTOM:
4715 mod_stmt = Y_MOD_BODY;
4716 break;
4717 default:
4718 /* error handled in the next switch */
4719 break;
4720 }
4721 prev_kw = kw;
4722
4723 switch (kw) {
4724 /* module header */
4725 case YANG_YANG_VERSION:
4726 ret = parse_yangversion(ctx, data, mod);
4727 break;
4728 case YANG_NAMESPACE:
4729 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_NAMESPACE, 0, &mod->ns, Y_STR_ARG, &mod->exts);
4730 break;
4731 case YANG_PREFIX:
4732 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &mod->prefix, Y_IDENTIF_ARG, &mod->exts);
4733 break;
4734 case YANG_BELONGS_TO:
4735 ret = parse_belongsto(ctx, data, &mod->belongsto, &mod->prefix, &mod->exts);
4736 break;
4737
4738 /* linkage */
4739 case YANG_INCLUDE:
4740 ret = parse_include(ctx, data, &mod->includes);
4741 break;
4742 case YANG_IMPORT:
4743 ret = parse_import(ctx, data, &mod->imports);
4744 break;
4745
4746 /* meta */
4747 case YANG_ORGANIZATION:
4748 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &mod->org, Y_STR_ARG, &mod->exts);
4749 break;
4750 case YANG_CONTACT:
4751 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &mod->contact, Y_STR_ARG, &mod->exts);
4752 break;
4753 case YANG_DESCRIPTION:
4754 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &mod->dsc, Y_STR_ARG, &mod->exts);
4755 break;
4756 case YANG_REFERENCE:
4757 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &mod->ref, Y_STR_ARG, &mod->exts);
4758 break;
4759
4760 /* revision */
4761 case YANG_REVISION:
4762 ret = parse_revision(ctx, data, &mod->revs);
4763 break;
4764
4765 /* body */
4766 case YANG_ANYDATA:
4767 case YANG_ANYXML:
4768 ret = parse_any(ctx, data, kw, &mod->data);
4769 break;
4770 case YANG_CHOICE:
4771 ret = parse_choice(ctx, data, &mod->data);
4772 break;
4773 case YANG_CONTAINER:
4774 ret = parse_container(ctx, data, &mod->data);
4775 break;
4776 case YANG_LEAF:
4777 ret = parse_leaf(ctx, data, &mod->data);
4778 break;
4779 case YANG_LEAF_LIST:
4780 ret = parse_leaflist(ctx, data, &mod->data);
4781 break;
4782 case YANG_LIST:
4783 ret = parse_list(ctx, data, &mod->data);
4784 break;
4785 case YANG_USES:
4786 ret = parse_uses(ctx, data, &mod->data);
4787 break;
4788
4789 case YANG_AUGMENT:
4790 ret = parse_augment(ctx, data, &mod->augments);
4791 break;
4792 case YANG_DEVIATION:
4793 ret = parse_deviation(ctx, data, &mod->deviations);
4794 break;
4795 case YANG_EXTENSION:
4796 ret = parse_extension(ctx, data, &mod->extensions);
4797 break;
4798 case YANG_FEATURE:
4799 ret = parse_feature(ctx, data, &mod->features);
4800 break;
4801 case YANG_GROUPING:
4802 ret = parse_grouping(ctx, data, &mod->groupings);
4803 break;
4804 case YANG_IDENTITY:
4805 ret = parse_identity(ctx, data, &mod->identities);
4806 break;
4807 case YANG_NOTIFICATION:
4808 ret = parse_notif(ctx, data, &mod->notifs);
4809 break;
4810 case YANG_RPC:
4811 ret = parse_action(ctx, data, &mod->rpcs);
4812 break;
4813 case YANG_TYPEDEF:
4814 ret = parse_typedef(ctx, data, &mod->typedefs);
4815 break;
4816 case YANG_CUSTOM:
4817 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &mod->exts);
4818 break;
4819
4820 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004821 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), mod->submodule ? "submodule" : "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004822 return LY_EVALID;
4823 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004824 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004825 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004826 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004827
4828 /* mandatory substatements */
4829 if (mod->submodule) {
4830 if (!mod->belongsto) {
4831 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "belongs-to", "submodule");
4832 return LY_EVALID;
4833 }
4834 } else {
4835 if (!mod->ns) {
4836 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "namespace", "module");
4837 return LY_EVALID;
4838 } else if (!mod->prefix) {
4839 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "module");
4840 return LY_EVALID;
4841 }
4842 }
4843
4844 return ret;
4845}
4846
Radek Krejci531fe5b2018-09-19 11:14:13 +02004847static unsigned int
4848lysp_get_data_line(const char *start, const char *stop)
4849{
4850 unsigned int i, length, line = 1;
4851
4852 length = stop - start;
4853 for (i = 0; i < length; ++i) {
4854 if (start[i] == '\n') {
4855 ++line;
4856 }
4857 }
4858
4859 return line;
4860}
4861
Radek Krejcid4557c62018-09-17 11:42:09 +02004862LY_ERR
Michal Vasko7fbc8162018-09-17 10:35:16 +02004863yang_parse(struct ly_ctx *ctx, const char *data, struct lysp_module **mod_p)
4864{
4865 LY_ERR ret = 0;
4866 char *word, *buf;
4867 int word_len;
4868 const char *data_start;
4869 enum yang_keyword kw;
4870 struct lysp_module *mod;
4871
4872 data_start = data;
4873
4874 /* "module"/"submodule" */
4875 ret = get_keyword(ctx, &data, &kw, &word, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004876 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004877
4878 if ((kw != YANG_MODULE) && (kw != YANG_SUBMODULE)) {
4879 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".\n",
Radek Krejcic59bc972018-09-17 16:13:06 +02004880 ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004881 goto error;
4882 }
4883
4884 mod = calloc(1, sizeof *mod);
4885 LY_CHECK_ERR_GOTO(!mod, LOGMEM(ctx), error);
4886 if (kw == YANG_SUBMODULE) {
4887 mod->submodule = 1;
4888 }
4889
4890 /* substatements */
4891 ret = parse_sub_module(ctx, &data, mod);
Radek Krejcic59bc972018-09-17 16:13:06 +02004892 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004893
4894 /* read some trailing spaces or new lines */
4895 ret = get_string(ctx, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004896 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004897
4898 if (word) {
4899 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected end-of-file.",
4900 word_len, word);
4901 free(buf);
4902 goto error;
4903 }
4904 assert(!buf);
4905
4906 *mod_p = mod;
4907 return ret;
4908
4909error:
Radek Krejci531fe5b2018-09-19 11:14:13 +02004910 LOGERR(ctx, LY_EINVAL, "Module parsing failed on line %u.", lysp_get_data_line(data_start, data));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004911 /* TODO free module */
4912 return ret;
4913}