blob: 6067f6eff666960ebaeecc401811f284450d20e7 [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
Radek Krejciefd22f62018-09-27 11:47:58 +0200106buf_store_char(struct ly_ctx *ctx, const char *c, char **word_p, size_t *word_len, char **word_b, int *buf_len, int need_buf)
Michal Vasko7fbc8162018-09-17 10:35:16 +0200107{
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{
Radek Krejci80dd33e2018-09-26 15:57:18 +0200206 /* internal statuses: 0 - comment ended,
207 * 1 - in line comment,
208 * 2 - in block comment,
209 * 3 - in block comment with last read character '*'
210 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200211 while (**data && comment) {
212 switch (comment) {
213 case 1:
214 if (**data == '\n') {
215 comment = 0;
216 }
217 break;
218 case 2:
219 if (**data == '*') {
220 comment = 3;
221 }
222 break;
223 case 3:
224 if (**data == '/') {
225 comment = 0;
226 } else {
227 comment = 2;
228 }
229 break;
230 default:
231 LOGINT_RET(ctx);
232 }
233
234 ++(*data);
235 }
236
237 if (!**data && (comment > 1)) {
238 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Unexpected end-of-file, non-terminated comment.");
239 return LY_EVALID;
240 }
241
242 return LY_SUCCESS;
243}
244
Michal Vaskoea5abea2018-09-18 13:10:54 +0200245/**
246 * @brief Read a quoted string from data.
247 *
248 * @param[in] ctx libyang context for logging.
249 * @param[in,out] data Data to read from, always moved to currently handled character.
250 * @param[in] arg Type of YANG keyword argument expected.
251 * @param[out] word_p Pointer to the read quoted string.
252 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read quoted string. If not needed,
253 * set to NULL. Otherwise equal to \p word_p.
254 * @param[out] word_len Length of the read quoted string.
255 * @param[out] buf_len Length of the dynamically-allocated buffer \p word_b.
256 * @param[in] indent Current indent (number of YANG spaces). Needed for correct multi-line string
257 * indenation in the final quoted string.
258 *
259 * @return LY_ERR values.
260 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200261static LY_ERR
Radek Krejciefd22f62018-09-27 11:47:58 +0200262read_qstring(struct ly_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
Michal Vasko7fbc8162018-09-17 10:35:16 +0200263 int *buf_len, int indent)
264{
265 /* string: 0 - string ended, 1 - string with ', 2 - string with ", 3 - string with " with last character \,
266 * 4 - string finished, now skipping whitespaces looking for +,
267 * 5 - string continues after +, skipping whitespaces */
268 int string, str_nl_indent = 0, need_buf = 0, prefix = 0;
269 const char *c;
270
271 if (**data == '\"') {
272 /* indent of the " itself */
273 ++indent;
274 string = 2;
275 } else {
276 assert(**data == '\'');
277 string = 1;
278 }
279 ++(*data);
280
281 while (**data && string) {
282 switch (string) {
283 case 1:
284 switch (**data) {
285 case '\'':
286 /* string may be finished, but check for + */
287 string = 4;
288 break;
289 default:
290 /* check and store character */
291 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
292 return LY_EVALID;
293 }
294 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
295 return LY_EMEM;
296 }
297 break;
298 }
299 break;
300 case 2:
301 switch (**data) {
302 case '\"':
303 /* string may be finished, but check for + */
304 string = 4;
305 break;
306 case '\\':
307 /* special character following */
308 string = 3;
309 break;
310 case ' ':
311 if (str_nl_indent) {
312 --str_nl_indent;
313 } else {
314 /* check and store character */
315 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
316 return LY_EVALID;
317 }
318 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
319 return LY_EMEM;
320 }
321 }
322 break;
323 case '\t':
324 if (str_nl_indent) {
325 if (str_nl_indent < 9) {
326 str_nl_indent = 0;
327 } else {
328 str_nl_indent -= 8;
329 }
330 } else {
331 /* check and store character */
332 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
333 return LY_EVALID;
334 }
335 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
336 return LY_EMEM;
337 }
338 }
339 break;
340 case '\n':
341 str_nl_indent = indent;
342 if (indent) {
343 /* we will be removing the indents so we need our own buffer */
344 need_buf = 1;
345 }
346
347 /* check and store character */
348 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
349 return LY_EVALID;
350 }
351 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
352 return LY_EMEM;
353 }
354 break;
355 default:
356 /* first non-whitespace character, clear current indent */
357 str_nl_indent = 0;
358
359 /* check and store character */
360 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
361 return LY_EVALID;
362 }
363 if (buf_store_char(ctx, *data, word_p, word_len, word_b, buf_len, need_buf)) {
364 return LY_EMEM;
365 }
366 break;
367 }
368 break;
369 case 3:
370 /* string encoded characters */
371 switch (**data) {
372 case 'n':
373 c = "\n";
374 break;
375 case 't':
376 c = "\t";
377 break;
378 case '\"':
379 c = *data;
380 break;
381 case '\\':
382 c = *data;
383 break;
384 default:
385 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG,
386 "Double-quoted string unknown special character '\\%c'.\n", **data);
387 return LY_EVALID;
388 }
389
390 /* check and store character */
391 if (check_char(ctx, *c, arg, !*word_len, &prefix)) {
392 return LY_EVALID;
393 }
394 if (buf_store_char(ctx, c, word_p, word_len, word_b, buf_len, need_buf)) {
395 return LY_EMEM;
396 }
397
398 string = 2;
399 break;
400 case 4:
401 switch (**data) {
402 case '+':
403 /* string continues */
404 string = 5;
Radek Krejciefd22f62018-09-27 11:47:58 +0200405 need_buf = 1;
Michal Vasko7fbc8162018-09-17 10:35:16 +0200406 break;
407 case ' ':
408 case '\t':
409 case '\n':
410 /* just skip */
411 break;
412 default:
413 /* string is finished */
414 goto string_end;
415 }
416 break;
417 case 5:
418 switch (**data) {
419 case ' ':
420 case '\t':
421 case '\n':
422 /* skip */
423 break;
424 case '\'':
425 string = 1;
426 break;
427 case '\"':
428 string = 2;
429 break;
430 default:
431 /* it must be quoted again */
432 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX_YANG,
433 "Both string parts divided by '+' must be quoted.\n");
434 return LY_EVALID;
435 }
436 break;
437 default:
438 return LY_EINT;
439 }
440
441 ++(*data);
442 }
443
444string_end:
445 return LY_SUCCESS;
446}
447
Michal Vaskoea5abea2018-09-18 13:10:54 +0200448/**
449 * @brief Get another YANG string from the raw data.
450 *
451 * @param[in] ctx libyang context for logging.
452 * @param[in,out] data Data to read from, always moved to currently handled character.
453 * @param[in] arg Type of YANG keyword argument expected.
Michal Vasko2ca70f52018-09-27 11:04:51 +0200454 * @param[out] word_p Pointer to the read string. Can return NULL if \p arg is #Y_MAYBE_STR_ARG.
Michal Vaskoea5abea2018-09-18 13:10:54 +0200455 * @param[out] word_b Pointer to a dynamically-allocated buffer holding the read string. If not needed,
456 * set to NULL. Otherwise equal to \p word_p.
457 * @param[out] word_len Length of the read string.
458 *
459 * @return LY_ERR values.
Michal Vasko7fbc8162018-09-17 10:35:16 +0200460 */
461static LY_ERR
Radek Krejciefd22f62018-09-27 11:47:58 +0200462get_string(struct ly_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len)
Michal Vasko7fbc8162018-09-17 10:35:16 +0200463{
464 int buf_len = 0, slash = 0, indent = 0, prefix = 0;
465 LY_ERR ret;
466
467 /* word buffer - dynamically allocated */
468 *word_b = NULL;
469
470 /* word pointer - just a pointer to data */
471 *word_p = NULL;
472
473 *word_len = 0;
474 while (**data) {
475 if (slash) {
476 if (**data == '/') {
477 /* one-line comment */
478 ret = skip_comment(ctx, data, 1);
479 if (ret) {
480 return ret;
481 }
482 } else if (**data == '*') {
483 /* block comment */
484 ret = skip_comment(ctx, data, 2);
485 if (ret) {
486 return ret;
487 }
488 } else {
489 /* not a comment after all */
490 ret = buf_store_char(ctx, (*data) - 1, word_p, word_len, word_b, &buf_len, 0);
491 if (ret) {
492 return ret;
493 }
494 }
495 slash = 0;
496 }
497
498 switch (**data) {
499 case '\'':
500 case '\"':
501 if (*word_len) {
502 /* we want strings always in a separate word, leave it */
503 goto str_end;
504 }
505 ret = read_qstring(ctx, data, arg, word_p, word_b, word_len, &buf_len, indent);
506 if (ret) {
507 return ret;
508 }
509 goto str_end;
510 case '/':
511 slash = 1;
512 break;
513 case ' ':
514 if (*word_len) {
515 /* word is finished */
516 goto str_end;
517 }
518 /* increase indent */
519 ++indent;
520 break;
521 case '\t':
522 if (*word_len) {
523 /* word is finished */
524 goto str_end;
525 }
526 /* tabs count for 8 spaces */
527 indent += 8;
528 break;
529 case '\n':
530 if (*word_len) {
531 /* word is finished */
532 goto str_end;
533 }
534 /* reset indent */
535 indent = 0;
536 break;
537 case ';':
538 case '{':
539 if (*word_len || (arg == Y_MAYBE_STR_ARG)) {
540 /* word is finished */
541 goto str_end;
542 }
543
544 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, 1, *data, "an argument");
545 return LY_EVALID;
546 default:
547 if (check_char(ctx, **data, arg, !*word_len, &prefix)) {
548 return LY_EVALID;
549 }
550
551 if (buf_store_char(ctx, *data, word_p, word_len, word_b, &buf_len, 0)) {
552 return LY_EMEM;
553 }
554 break;
555 }
556
557 ++(*data);
558 }
559
560str_end:
561 /* ending '\0' for buf */
562 if (*word_b) {
563 if (buf_add_char(ctx, '\0', word_b, &buf_len, *word_len)) {
564 return LY_EMEM;
565 }
566 *word_p = *word_b;
567 }
568
569 return LY_SUCCESS;
570}
571
Michal Vaskoea5abea2018-09-18 13:10:54 +0200572/**
573 * @brief Get another YANG keyword from the raw data.
574 *
575 * @param[in] ctx libyang context for logging.
576 * @param[in,out] data Data to read from, always moved to currently handled character.
577 * @param[out] kw YANG keyword read.
578 * @param[out] word_p Pointer to the keyword in the data. Useful for extension instances.
579 * @param[out] word_len Length of the keyword in the data. Useful for extension instances.
580 *
581 * @return LY_ERR values.
582 */
Michal Vasko7fbc8162018-09-17 10:35:16 +0200583static LY_ERR
Radek Krejciefd22f62018-09-27 11:47:58 +0200584get_keyword(struct ly_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len)
Michal Vasko7fbc8162018-09-17 10:35:16 +0200585{
586 LY_ERR ret;
587 int prefix;
588 const char *word_start;
589 /* slash: 0 - nothing, 1 - last character was '/' */
590 int slash = 0;
591
592 if (word_p) {
593 *word_p = NULL;
594 *word_len = 0;
595 }
596
597 /* first skip "optsep", comments */
598 while (**data) {
599 if (slash) {
600 if (**data == '/') {
601 /* one-line comment */
602 ret = skip_comment(ctx, data, 1);
603 if (ret) {
604 return ret;
605 }
606 } else if (**data == '*') {
607 /* block comment */
608 ret = skip_comment(ctx, data, 2);
609 if (ret) {
610 return ret;
611 }
612 } else {
613 /* not a comment after all */
614 goto keyword_start;
615 }
616 slash = 0;
617 }
618
619 switch (**data) {
620 case '/':
621 slash = 1;
622 break;
623 case ' ':
624 case '\t':
625 case '\n':
626 /* skip whitespaces (optsep) */
627 break;
628 default:
629 /* either a keyword start or an invalid character */
630 goto keyword_start;
631 }
632
633 ++(*data);
634 }
635
636keyword_start:
637 word_start = *data;
638 *kw = YANG_NONE;
639
640 /* read the keyword itself */
641 switch (**data) {
642 case 'a':
643 ++(*data);
644 if (!strncmp(*data, "rgument", 7)) {
645 *data += 7;
646 *kw = YANG_ARGUMENT;
647 } else if (!strncmp(*data, "ugment", 6)) {
648 *data += 6;
649 *kw = YANG_AUGMENT;
650 } else if (!strncmp(*data, "ction", 5)) {
651 *data += 5;
652 *kw = YANG_ACTION;
653 } else if (!strncmp(*data, "ny", 2)) {
654 *data += 2;
655 if (!strncmp(*data, "data", 4)) {
656 *data += 4;
657 *kw = YANG_ANYDATA;
658 } else if (!strncmp(*data, "xml", 3)) {
659 *data += 3;
660 *kw = YANG_ANYXML;
661 }
662 }
663 break;
664 case 'b':
665 ++(*data);
666 if (!strncmp(*data, "ase", 3)) {
667 *data += 3;
668 *kw = YANG_BASE;
669 } else if (!strncmp(*data, "elongs-to", 9)) {
670 *data += 9;
671 *kw = YANG_BELONGS_TO;
672 } else if (!strncmp(*data, "it", 2)) {
673 *data += 2;
674 *kw = YANG_BIT;
675 }
676 break;
677 case 'c':
678 ++(*data);
679 if (!strncmp(*data, "ase", 3)) {
680 *data += 3;
681 *kw = YANG_CASE;
682 } else if (!strncmp(*data, "hoice", 5)) {
683 *data += 5;
684 *kw = YANG_CHOICE;
685 } else if (!strncmp(*data, "on", 2)) {
686 *data += 2;
687 if (!strncmp(*data, "fig", 3)) {
688 *data += 3;
689 *kw = YANG_CONFIG;
690 } else if (!strncmp(*data, "ta", 2)) {
691 *data += 2;
692 if (!strncmp(*data, "ct", 2)) {
693 *data += 2;
694 *kw = YANG_CONTACT;
695 } else if (!strncmp(*data, "iner", 4)) {
696 *data += 4;
697 *kw = YANG_CONTAINER;
698 }
699 }
700 }
701 break;
702 case 'd':
703 ++(*data);
704 if (**data == 'e') {
705 ++(*data);
706 if (!strncmp(*data, "fault", 5)) {
707 *data += 5;
708 *kw = YANG_DEFAULT;
709 } else if (!strncmp(*data, "scription", 9)) {
710 *data += 9;
711 *kw = YANG_DESCRIPTION;
712 } else if (!strncmp(*data, "viat", 4)) {
713 *data += 4;
714 if (**data == 'e') {
715 ++(*data);
716 *kw = YANG_DEVIATE;
717 } else if (!strncmp(*data, "ion", 3)) {
718 *data += 3;
719 *kw = YANG_DEVIATION;
720 }
721 }
722 }
723 break;
724 case 'e':
725 ++(*data);
726 if (!strncmp(*data, "num", 3)) {
727 *data += 3;
728 *kw = YANG_ENUM;
729 } else if (!strncmp(*data, "rror-", 5)) {
730 *data += 5;
731 if (!strncmp(*data, "app-tag", 7)) {
732 *data += 7;
733 *kw = YANG_ERROR_APP_TAG;
734 } else if (!strncmp(*data, "message", 7)) {
735 *data += 7;
736 *kw = YANG_ERROR_MESSAGE;
737 }
738 } else if (!strncmp(*data, "xtension", 8)) {
739 *data += 8;
740 *kw = YANG_EXTENSION;
741 }
742 break;
743 case 'f':
744 ++(*data);
745 if (!strncmp(*data, "eature", 6)) {
746 *data += 6;
747 *kw = YANG_FEATURE;
748 } else if (!strncmp(*data, "raction-digits", 14)) {
749 *data += 14;
750 *kw = YANG_FRACTION_DIGITS;
751 }
752 break;
753 case 'g':
754 ++(*data);
755 if (!strncmp(*data, "rouping", 7)) {
756 *data += 7;
757 *kw = YANG_GROUPING;
758 }
759 break;
760 case 'i':
761 ++(*data);
762 if (!strncmp(*data, "dentity", 7)) {
763 *data += 7;
764 *kw = YANG_IDENTITY;
765 } else if (!strncmp(*data, "f-feature", 9)) {
766 *data += 9;
767 *kw = YANG_IF_FEATURE;
768 } else if (!strncmp(*data, "mport", 5)) {
769 *data += 5;
770 *kw = YANG_IMPORT;
771 } else if (**data == 'n') {
772 ++(*data);
773 if (!strncmp(*data, "clude", 5)) {
774 *data += 5;
775 *kw = YANG_INCLUDE;
776 } else if (!strncmp(*data, "put", 3)) {
777 *data += 3;
778 *kw = YANG_INPUT;
779 }
780 }
781 break;
782 case 'k':
783 ++(*data);
784 if (!strncmp(*data, "ey", 2)) {
785 *data += 2;
786 *kw = YANG_KEY;
787 }
788 break;
789 case 'l':
790 ++(*data);
791 if (**data == 'e') {
792 ++(*data);
793 if (!strncmp(*data, "af", 2)) {
794 *data += 2;
795 if (**data != '-') {
796 *kw = YANG_LEAF;
797 } else if (!strncmp(*data, "-list", 5)) {
798 *data += 5;
799 *kw = YANG_LEAF_LIST;
800 }
801 } else if (!strncmp(*data, "ngth", 4)) {
802 *data += 4;
803 *kw = YANG_LENGTH;
804 }
805 } else if (!strncmp(*data, "ist", 3)) {
806 *data += 3;
807 *kw = YANG_LIST;
808 }
809 break;
810 case 'm':
811 ++(*data);
812 if (**data == 'a') {
813 ++(*data);
814 if (!strncmp(*data, "ndatory", 7)) {
815 *data += 7;
816 *kw = YANG_MANDATORY;
817 } else if (!strncmp(*data, "x-elements", 10)) {
818 *data += 10;
819 *kw = YANG_MAX_ELEMENTS;
820 }
821 } else if (!strncmp(*data, "in-elements", 11)) {
822 *data += 11;
823 *kw = YANG_MIN_ELEMENTS;
824 } else if (!strncmp(*data, "ust", 3)) {
825 *data += 3;
826 *kw = YANG_MUST;
827 } else if (!strncmp(*data, "od", 2)) {
828 *data += 2;
829 if (!strncmp(*data, "ule", 3)) {
830 *data += 3;
831 *kw = YANG_MODULE;
832 } else if (!strncmp(*data, "ifier", 5)) {
833 *data += 3;
834 *kw = YANG_MODIFIER;
835 }
836 }
837 break;
838 case 'n':
839 ++(*data);
840 if (!strncmp(*data, "amespace", 8)) {
841 *data += 8;
842 *kw = YANG_NAMESPACE;
843 } else if (!strncmp(*data, "otification", 11)) {
844 *data += 11;
845 *kw = YANG_NOTIFICATION;
846 }
847 break;
848 case 'o':
849 ++(*data);
850 if (**data == 'r') {
851 ++(*data);
852 if (!strncmp(*data, "dered-by", 8)) {
853 *data += 8;
854 *kw = YANG_ORDERED_BY;
855 } else if (!strncmp(*data, "ganization", 10)) {
856 *data += 10;
857 *kw = YANG_ORGANIZATION;
858 }
859 } else if (!strncmp(*data, "utput", 5)) {
860 *data += 5;
861 *kw = YANG_OUTPUT;
862 }
863 break;
864 case 'p':
865 ++(*data);
866 if (!strncmp(*data, "at", 2)) {
867 *data += 2;
868 if (**data == 'h') {
869 ++(*data);
870 *kw = YANG_PATH;
871 } else if (!strncmp(*data, "tern", 4)) {
872 *data += 4;
873 *kw = YANG_PATTERN;
874 }
875 } else if (!strncmp(*data, "osition", 7)) {
876 *data += 7;
877 *kw = YANG_POSITION;
878 } else if (!strncmp(*data, "re", 2)) {
879 *data += 2;
880 if (!strncmp(*data, "fix", 3)) {
881 *data += 3;
882 *kw = YANG_PREFIX;
883 } else if (!strncmp(*data, "sence", 5)) {
884 *data += 5;
885 *kw = YANG_PRESENCE;
886 }
887 }
888 break;
889 case 'r':
890 ++(*data);
891 if (!strncmp(*data, "ange", 4)) {
892 *data += 4;
893 *kw = YANG_RANGE;
894 } else if (**data == 'e') {
895 ++(*data);
896 if (**data == 'f') {
897 ++(*data);
898 if (!strncmp(*data, "erence", 6)) {
899 *data += 6;
900 *kw = YANG_REFERENCE;
901 } else if (!strncmp(*data, "ine", 3)) {
902 *data += 3;
903 *kw = YANG_REFINE;
904 }
905 } else if (!strncmp(*data, "quire-instance", 14)) {
906 *data += 14;
907 *kw = YANG_REQUIRE_INSTANCE;
908 } else if (!strncmp(*data, "vision", 6)) {
909 *data += 6;
910 if (**data != '-') {
911 *kw = YANG_REVISION;
912 } else if (!strncmp(*data, "-date", 5)) {
913 *data += 5;
914 *kw = YANG_REVISION_DATE;
915 }
916 }
917 } else if (!strncmp(*data, "pc", 2)) {
918 *data += 2;
919 *kw = YANG_RPC;
920 }
921 break;
922 case 's':
923 ++(*data);
924 if (!strncmp(*data, "tatus", 5)) {
925 *data += 5;
926 *kw = YANG_STATUS;
927 } else if (!strncmp(*data, "ubmodule", 8)) {
928 *data += 8;
929 *kw = YANG_SUBMODULE;
930 }
931 break;
932 case 't':
933 ++(*data);
934 if (!strncmp(*data, "ype", 3)) {
935 *data += 3;
936 if (**data != 'd') {
937 *kw = YANG_TYPE;
938 } else if (!strncmp(*data, "def", 3)) {
939 *data += 3;
940 *kw = YANG_TYPEDEF;
941 }
942 }
943 break;
944 case 'u':
945 ++(*data);
946 if (!strncmp(*data, "ni", 2)) {
947 *data += 2;
948 if (!strncmp(*data, "que", 3)) {
949 *data += 3;
950 *kw = YANG_UNIQUE;
951 } else if (!strncmp(*data, "ts", 2)) {
952 *data += 2;
953 *kw = YANG_UNITS;
954 }
955 } else if (!strncmp(*data, "ses", 3)) {
956 *data += 3;
957 *kw = YANG_USES;
958 }
959 break;
960 case 'v':
961 ++(*data);
962 if (!strncmp(*data, "alue", 4)) {
963 *data += 4;
964 *kw = YANG_VALUE;
965 }
966 break;
967 case 'w':
968 ++(*data);
969 if (!strncmp(*data, "hen", 3)) {
970 *data += 3;
971 *kw = YANG_WHEN;
972 }
973 break;
974 case 'y':
975 ++(*data);
976 if (!strncmp(*data, "ang-version", 11)) {
977 *data += 11;
978 *kw = YANG_YANG_VERSION;
979 } else if (!strncmp(*data, "in-element", 10)) {
980 *data += 10;
981 *kw = YANG_YIN_ELEMENT;
982 }
983 break;
984 case ';':
985 ++(*data);
986 *kw = YANG_SEMICOLON;
987 break;
988 case '{':
989 ++(*data);
990 *kw = YANG_LEFT_BRACE;
991 break;
992 case '}':
993 ++(*data);
994 *kw = YANG_RIGHT_BRACE;
995 break;
996 default:
997 break;
998 }
999
1000 if (*kw != YANG_NONE) {
1001 /* make sure we have the whole keyword */
1002 switch (**data) {
1003 case ' ':
1004 case '\t':
1005 case '\n':
1006 /* mandatory "sep" */
1007 break;
1008 default:
1009 ++(*data);
1010 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
1011 "a keyword followed by a separator");
1012 return LY_EVALID;
1013 }
1014 } else {
1015 /* still can be an extension */
1016 prefix = 0;
1017 while (**data && (**data != ' ') && (**data != '\t') && (**data != '\n') && (**data != '{') && (**data != ';')) {
1018 if (check_char(ctx, **data, Y_PREF_IDENTIF_ARG, *data == word_start ? 1 : 0, &prefix)) {
1019 return LY_EVALID;
1020 }
1021 ++(*data);
1022 }
1023 if (!**data) {
Radek Krejcic07921a2018-09-17 11:40:15 +02001024 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_EOF);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001025 return LY_EVALID;
1026 }
1027
1028 /* prefix is mandatory for extension instances */
1029 if (prefix != 1) {
1030 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
1031 return LY_EVALID;
1032 }
1033
1034 *kw = YANG_CUSTOM;
1035 }
1036
1037 if (word_p) {
1038 *word_p = (char *)word_start;
1039 *word_len = *data - word_start;
1040 }
1041
1042 return LY_SUCCESS;
1043}
1044
Michal Vaskoea5abea2018-09-18 13:10:54 +02001045/**
1046 * @brief Parse extension instance substatements.
1047 *
1048 * @param[in] ctx libyang context for logging.
1049 * @param[in,out] data Data to read from, always moved to currently handled character.
1050 * @param[in] word Extension instance substatement name (keyword).
1051 * @param[in] word_len Extension instance substatement name length.
1052 * @param[in,out] child Children of this extension instance to add to.
1053 *
1054 * @return LY_ERR values.
1055 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001056static LY_ERR
Radek Krejciefd22f62018-09-27 11:47:58 +02001057parse_ext_substmt(struct ly_ctx *ctx, const char **data, char *word, size_t word_len,
Michal Vasko7fbc8162018-09-17 10:35:16 +02001058 struct lysp_stmt **child)
1059{
1060 char *buf;
1061 LY_ERR ret = 0;
1062 enum yang_keyword kw;
1063 struct lysp_stmt *stmt, *par_child;
1064
1065 stmt = calloc(1, sizeof *stmt);
1066 LY_CHECK_ERR_RET(!stmt, LOGMEM(NULL), LY_EMEM);
1067
1068 stmt->stmt = lydict_insert(ctx, word, word_len);
1069
1070 /* get optional argument */
1071 ret = get_string(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001072 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001073
Radek Krejci0ae092d2018-09-20 16:43:19 +02001074 if (word) {
1075 if (buf) {
1076 stmt->arg = lydict_insert_zc(ctx, word);
1077 } else {
1078 stmt->arg = lydict_insert(ctx, word, word_len);
1079 }
Michal Vasko7fbc8162018-09-17 10:35:16 +02001080 }
1081
1082 /* insert into parent statements */
1083 if (!*child) {
1084 *child = stmt;
1085 } else {
1086 for (par_child = *child; par_child->next; par_child = par_child->next);
1087 par_child->next = stmt;
1088 }
1089
1090 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001091 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001092
1093 ret = parse_ext_substmt(ctx, data, word, word_len, &stmt->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001094 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001095 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001096 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001097
1098 return ret;
1099}
1100
Michal Vaskoea5abea2018-09-18 13:10:54 +02001101/**
1102 * @brief Parse extension instance.
1103 *
1104 * @param[in] ctx libyang context for logging.
1105 * @param[in,out] data Data to read from, always moved to currently handled character.
1106 * @param[in] ext_name Extension instance substatement name (keyword).
1107 * @param[in] ext_name_len Extension instance substatement name length.
1108 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
1109 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
1110 * @param[in,out] exts Extension instances to add to.
1111 *
1112 * @return LY_ERR values.
1113 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001114static LY_ERR
1115parse_ext(struct ly_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
1116 uint32_t insubstmt_index, struct lysp_ext_instance **exts)
1117{
1118 LY_ERR ret = 0;
1119 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001120 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001121 struct lysp_ext_instance *e;
1122 enum yang_keyword kw;
1123
1124 LYSP_ARRAY_NEW_RET(ctx, exts, e, LY_EMEM);
1125
1126 /* store name and insubstmt info */
1127 e->name = lydict_insert(ctx, ext_name, ext_name_len);
1128 e->insubstmt = insubstmt;
1129 e->insubstmt_index = insubstmt_index;
1130
1131 /* get optional argument */
1132 ret = get_string(ctx, data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001133 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001134
Radek Krejci0ae092d2018-09-20 16:43:19 +02001135 if (word) {
1136 if (buf) {
1137 e->argument = lydict_insert_zc(ctx, word);
1138 } else {
1139 e->argument = lydict_insert(ctx, word, word_len);
1140 }
Michal Vasko7fbc8162018-09-17 10:35:16 +02001141 }
1142
1143 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001144 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001145
1146 ret = parse_ext_substmt(ctx, data, word, word_len, &e->child);
Radek Krejcic59bc972018-09-17 16:13:06 +02001147 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001148 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001149 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001150
1151 return ret;
1152}
1153
Michal Vaskoea5abea2018-09-18 13:10:54 +02001154/**
1155 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
1156 * description, etc...
1157 *
1158 * @param[in] ctx libyang context for logging.
1159 * @param[in,out] data Data to read from, always moved to currently handled character.
1160 * @param[in] substmt Type of this substatement.
1161 * @param[in] substmt_index Index of this substatement.
1162 * @param[in,out] value Place to store the parsed value.
1163 * @param[in] arg Type of the YANG keyword argument (of the value).
1164 * @param[in,out] exts Extension instances to add to.
1165 *
1166 * @return LY_ERR values.
1167 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001168static LY_ERR
1169parse_text_field(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
1170 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
1171{
1172 LY_ERR ret = 0;
1173 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001174 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001175 enum yang_keyword kw;
1176
1177 if (*value) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001178 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001179 return LY_EVALID;
1180 }
1181
1182 /* get value */
1183 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001184 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001185
1186 /* store value and spend buf if allocated */
1187 if (buf) {
1188 *value = lydict_insert_zc(ctx, word);
1189 } else {
1190 *value = lydict_insert(ctx, word, word_len);
1191 }
1192
1193 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001194 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001195
1196 switch (kw) {
1197 case YANG_CUSTOM:
1198 ret = parse_ext(ctx, data, word, word_len, substmt, substmt_index, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001199 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001200 break;
1201 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001202 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001203 return LY_EVALID;
1204 }
1205 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001206 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001207
1208 return ret;
1209}
1210
Michal Vaskoea5abea2018-09-18 13:10:54 +02001211/**
1212 * @brief Parse the yang-version statement.
1213 *
1214 * @param[in] ctx libyang context for logging.
1215 * @param[in,out] data Data to read from, always moved to currently handled character.
1216 * @param[in] mod Module to store the parsed information in.
1217 *
1218 * @return LY_ERR values.
1219 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001220static LY_ERR
1221parse_yangversion(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
1222{
1223 LY_ERR ret = 0;
1224 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001225 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001226 enum yang_keyword kw;
1227
1228 if (mod->version) {
1229 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yang-version");
1230 return LY_EVALID;
1231 }
1232
1233 /* get value */
1234 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001235 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001236
1237 if ((word_len == 3) && !strncmp(word, "1.0", word_len)) {
1238 mod->version = LYS_VERSION_1_0;
1239 } else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
1240 mod->version = LYS_VERSION_1_1;
1241 } else {
1242 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yang-version");
1243 free(buf);
1244 return LY_EVALID;
1245 }
1246 free(buf);
1247
1248 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001249 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001250
1251 switch (kw) {
1252 case YANG_CUSTOM:
1253 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, &mod->exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001254 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001255 break;
1256 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001257 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001258 return LY_EVALID;
1259 }
1260 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001261 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001262
1263 return ret;
1264}
1265
Michal Vaskoea5abea2018-09-18 13:10:54 +02001266/**
1267 * @brief Parse the belongs-to statement.
1268 *
1269 * @param[in] ctx libyang context for logging.
1270 * @param[in,out] data Data to read from, always moved to currently handled character.
1271 * @param[in,out] belongsto Place to store the parsed value.
1272 * @param[in,out] prefix Place to store the parsed belongs-to prefix value.
1273 * @param[in,out] exts Extension instances to add to.
1274 *
1275 * @return LY_ERR values.
1276 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001277static LY_ERR
1278parse_belongsto(struct ly_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
1279{
1280 LY_ERR ret = 0;
1281 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001282 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001283 enum yang_keyword kw;
1284
1285 if (*belongsto) {
1286 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "belongs-to");
1287 return LY_EVALID;
1288 }
1289
1290 /* get value */
1291 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001292 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001293
1294 if (buf) {
1295 *belongsto = lydict_insert_zc(ctx, word);
1296 } else {
1297 *belongsto = lydict_insert(ctx, word, word_len);
1298 }
1299
1300 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001301 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001302
1303 switch (kw) {
1304 case YANG_PREFIX:
1305 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts);
1306 break;
1307 case YANG_CUSTOM:
1308 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_BELONGSTO, 0, exts);
1309 break;
1310 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001311 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001312 return LY_EVALID;
1313 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001314 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001315 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001316 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001317
1318 /* mandatory substatements */
1319 if (!*prefix) {
1320 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "belongs-to");
1321 return LY_EVALID;
1322 }
1323
1324 return ret;
1325}
1326
Michal Vaskoea5abea2018-09-18 13:10:54 +02001327/**
1328 * @brief Parse the revision-date statement.
1329 *
1330 * @param[in] ctx libyang context for logging.
1331 * @param[in,out] data Data to read from, always moved to currently handled character.
1332 * @param[in,out] rev Array to store the parsed value in.
1333 * @param[in,out] exts Extension instances to add to.
1334 *
1335 * @return LY_ERR values.
1336 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001337static LY_ERR
1338parse_revisiondate(struct ly_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
1339{
1340 LY_ERR ret = 0;
1341 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001342 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001343 enum yang_keyword kw;
1344
1345 if (rev[0]) {
1346 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "revision-date");
1347 return LY_EVALID;
1348 }
1349
1350 /* get value */
1351 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001352 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001353
1354 /* check value */
1355 if (lysp_check_date(ctx, word, word_len, "revision-date")) {
1356 free(buf);
1357 return LY_EVALID;
1358 }
1359
1360 /* store value and spend buf if allocated */
1361 strncpy(rev, word, word_len);
1362 free(buf);
1363
1364 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001365 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001366
1367 switch (kw) {
1368 case YANG_CUSTOM:
1369 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REVISIONDATE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001370 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001371 break;
1372 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001373 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001374 return LY_EVALID;
1375 }
1376 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001377 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001378
1379 return ret;
1380}
1381
Michal Vaskoea5abea2018-09-18 13:10:54 +02001382/**
1383 * @brief Parse the include statement.
1384 *
1385 * @param[in] ctx libyang context for logging.
1386 * @param[in,out] data Data to read from, always moved to currently handled character.
1387 * @param[in,out] includes Parsed includes to add to.
1388 *
1389 * @return LY_ERR values.
1390 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001391static LY_ERR
1392parse_include(struct ly_ctx *ctx, const char **data, struct lysp_include **includes)
1393{
1394 LY_ERR ret = 0;
1395 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001396 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001397 enum yang_keyword kw;
1398 struct lysp_include *inc;
1399
1400 LYSP_ARRAY_NEW_RET(ctx, includes, inc, LY_EMEM);
1401
1402 /* get value */
1403 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001404 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001405
1406 if (buf) {
1407 inc->name = lydict_insert_zc(ctx, word);
1408 } else {
1409 inc->name = lydict_insert(ctx, word, word_len);
1410 }
1411
1412 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001413 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001414
1415 switch (kw) {
1416 case YANG_DESCRIPTION:
1417 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &inc->dsc, Y_STR_ARG, &inc->exts);
1418 break;
1419 case YANG_REFERENCE:
1420 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &inc->ref, Y_STR_ARG, &inc->exts);
1421 break;
1422 case YANG_REVISION_DATE:
1423 ret = parse_revisiondate(ctx, data, inc->rev, &inc->exts);
1424 break;
1425 case YANG_CUSTOM:
1426 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inc->exts);
1427 break;
1428 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001429 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001430 return LY_EVALID;
1431 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001432 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001433 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001434 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001435
1436 return ret;
1437}
1438
Michal Vaskoea5abea2018-09-18 13:10:54 +02001439/**
1440 * @brief Parse the import statement.
1441 *
1442 * @param[in] ctx libyang context for logging.
1443 * @param[in,out] data Data to read from, always moved to currently handled character.
1444 * @param[in,out] imports Parsed imports to add to.
1445 *
1446 * @return LY_ERR values.
1447 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001448static LY_ERR
1449parse_import(struct ly_ctx *ctx, const char **data, struct lysp_import **imports)
1450{
1451 LY_ERR ret = 0;
1452 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001453 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001454 enum yang_keyword kw;
1455 struct lysp_import *imp;
1456
1457 LYSP_ARRAY_NEW_RET(ctx, imports, imp, LY_EVALID);
1458
1459 /* get value */
1460 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001461 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001462
1463 if (buf) {
1464 imp->name = lydict_insert_zc(ctx, word);
1465 } else {
1466 imp->name = lydict_insert(ctx, word, word_len);
1467 }
1468
1469 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001470 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001471
1472 switch (kw) {
1473 case YANG_PREFIX:
1474 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts);
1475 break;
1476 case YANG_DESCRIPTION:
1477 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &imp->dsc, Y_STR_ARG, &imp->exts);
1478 break;
1479 case YANG_REFERENCE:
1480 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &imp->ref, Y_STR_ARG, &imp->exts);
1481 break;
1482 case YANG_REVISION_DATE:
1483 ret = parse_revisiondate(ctx, data, imp->rev, &imp->exts);
1484 break;
1485 case YANG_CUSTOM:
1486 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &imp->exts);
1487 break;
1488 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001489 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001490 return LY_EVALID;
1491 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001492 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001493 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001494 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001495
1496 /* mandatory substatements */
1497 if (!imp->prefix) {
1498 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "import");
1499 return LY_EVALID;
1500 }
1501
1502 return ret;
1503}
1504
Michal Vaskoea5abea2018-09-18 13:10:54 +02001505/**
1506 * @brief Parse the revision statement.
1507 *
1508 * @param[in] ctx libyang context for logging.
1509 * @param[in,out] data Data to read from, always moved to currently handled character.
1510 * @param[in,out] revs Parsed revisions to add to.
1511 *
1512 * @return LY_ERR values.
1513 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001514static LY_ERR
1515parse_revision(struct ly_ctx *ctx, const char **data, struct lysp_revision **revs)
1516{
1517 LY_ERR ret = 0;
1518 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001519 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001520 enum yang_keyword kw;
1521 struct lysp_revision *rev;
1522
1523 LYSP_ARRAY_NEW_RET(ctx, revs, rev, LY_EMEM);
1524
1525 /* get value */
1526 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001527 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001528
1529 /* check value */
1530 if (lysp_check_date(ctx, word, word_len, "revision")) {
1531 return LY_EVALID;
1532 }
1533
1534 strncpy(rev->rev, word, word_len);
1535 free(buf);
1536
1537 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001538 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001539
1540 switch (kw) {
1541 case YANG_DESCRIPTION:
1542 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts);
1543 break;
1544 case YANG_REFERENCE:
1545 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rev->ref, Y_STR_ARG, &rev->exts);
1546 break;
1547 case YANG_CUSTOM:
1548 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rev->exts);
1549 break;
1550 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001551 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001552 return LY_EVALID;
1553 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001554 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001555 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001556 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001557
1558 return ret;
1559}
1560
Michal Vaskoea5abea2018-09-18 13:10:54 +02001561/**
1562 * @brief Parse a generic text field that can have more instances such as base.
1563 *
1564 * @param[in] ctx libyang context for logging.
1565 * @param[in,out] data Data to read from, always moved to currently handled character.
1566 * @param[in] substmt Type of this substatement.
1567 * @param[in,out] texts Parsed values to add to.
1568 * @param[in] arg Type of the expected argument.
1569 * @param[in,out] exts Extension instances to add to.
1570 *
1571 * @return LY_ERR values.
1572 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001573static LY_ERR
1574parse_text_fields(struct ly_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
1575 struct lysp_ext_instance **exts)
1576{
1577 LY_ERR ret = 0;
1578 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001579 size_t count, word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001580 enum yang_keyword kw;
1581
1582 /* allocate new pointer */
1583 for (count = 1; (*texts) && (*texts)[count - 1]; ++count);
1584 *texts = realloc(*texts, count * sizeof **texts);
1585 LY_CHECK_ERR_RET(!*texts, LOGMEM(ctx), LY_EMEM);
1586
1587 /* get value */
1588 ret = get_string(ctx, data, arg, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001589 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001590
1591 if (buf) {
1592 (*texts)[count - 1] = lydict_insert_zc(ctx, word);
1593 } else {
1594 (*texts)[count - 1] = lydict_insert(ctx, word, word_len);
1595 }
1596
1597 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001598 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001599
1600 switch (kw) {
1601 case YANG_CUSTOM:
1602 ret = parse_ext(ctx, data, word, word_len, substmt, count - 1, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001603 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001604 break;
1605 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001606 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001607 return LY_EVALID;
1608 }
1609 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001610 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001611
1612 return ret;
1613}
1614
Michal Vaskoea5abea2018-09-18 13:10:54 +02001615/**
1616 * @brief Parse the config statement.
1617 *
1618 * @param[in] ctx libyang context for logging.
1619 * @param[in,out] data Data to read from, always moved to currently handled character.
1620 * @param[in,out] flags Flags to add to.
1621 * @param[in,out] exts Extension instances to add to.
1622 *
1623 * @return LY_ERR values.
1624 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001625static LY_ERR
1626parse_config(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1627{
1628 LY_ERR ret = 0;
1629 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001630 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001631 enum yang_keyword kw;
1632
1633 if (*flags & LYS_CONFIG_MASK) {
1634 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "config");
1635 return LY_EVALID;
1636 }
1637
1638 /* get value */
1639 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001640 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001641
1642 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1643 *flags |= LYS_CONFIG_W;
1644 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1645 *flags |= LYS_CONFIG_R;
1646 } else {
1647 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "config");
1648 free(buf);
1649 return LY_EVALID;
1650 }
1651 free(buf);
1652
1653 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001654 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001655
1656 switch (kw) {
1657 case YANG_CUSTOM:
1658 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_CONFIG, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001659 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001660 break;
1661 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001662 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001663 return LY_EVALID;
1664 }
1665 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001666 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001667
1668 return ret;
1669}
1670
Michal Vaskoea5abea2018-09-18 13:10:54 +02001671/**
1672 * @brief Parse the mandatory statement.
1673 *
1674 * @param[in] ctx libyang context for logging.
1675 * @param[in,out] data Data to read from, always moved to currently handled character.
1676 * @param[in,out] flags Flags to add to.
1677 * @param[in,out] exts Extension instances to add to.
1678 *
1679 * @return LY_ERR values.
1680 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001681static LY_ERR
1682parse_mandatory(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1683{
1684 LY_ERR ret = 0;
1685 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001686 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001687 enum yang_keyword kw;
1688
1689 if (*flags & LYS_MAND_MASK) {
1690 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "mandatory");
1691 return LY_EVALID;
1692 }
1693
1694 /* get value */
1695 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001696 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001697
1698 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
1699 *flags |= LYS_MAND_TRUE;
1700 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
1701 *flags |= LYS_MAND_FALSE;
1702 } else {
1703 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "mandatory");
1704 free(buf);
1705 return LY_EVALID;
1706 }
1707 free(buf);
1708
1709 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001710 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001711
1712 switch (kw) {
1713 case YANG_CUSTOM:
1714 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MANDATORY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001715 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001716 break;
1717 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001718 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001719 return LY_EVALID;
1720 }
1721 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001722 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001723
1724 return ret;
1725}
1726
Michal Vaskoea5abea2018-09-18 13:10:54 +02001727/**
1728 * @brief Parse a restriction such as range or length.
1729 *
1730 * @param[in] ctx libyang context for logging.
1731 * @param[in,out] data Data to read from, always moved to currently handled character.
1732 * @param[in] restr_kw Type of this particular restriction.
1733 * @param[in,out] exts Extension instances to add to.
1734 *
1735 * @return LY_ERR values.
1736 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001737static LY_ERR
1738parse_restr(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
1739{
1740 LY_ERR ret = 0;
1741 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001742 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001743 enum yang_keyword kw;
1744
1745 /* get value */
1746 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001747 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001748
1749 if (buf) {
1750 restr->arg = lydict_insert_zc(ctx, word);
1751 } else {
1752 restr->arg = lydict_insert(ctx, word, word_len);
1753 }
1754
1755 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001756 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001757
1758 switch (kw) {
1759 case YANG_DESCRIPTION:
1760 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
1761 break;
1762 case YANG_REFERENCE:
1763 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
1764 break;
1765 case YANG_ERROR_APP_TAG:
1766 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
1767 break;
1768 case YANG_ERROR_MESSAGE:
1769 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
1770 break;
1771 case YANG_CUSTOM:
1772 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
1773 break;
1774 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001775 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02001776 return LY_EVALID;
1777 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001778 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001779 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001780 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001781
1782 return ret;
1783}
1784
Michal Vaskoea5abea2018-09-18 13:10:54 +02001785/**
1786 * @brief Parse a restriction that can have more instances such as must.
1787 *
1788 * @param[in] ctx libyang context for logging.
1789 * @param[in,out] data Data to read from, always moved to currently handled character.
1790 * @param[in] restr_kw Type of this particular restriction.
1791 * @param[in,out] restrs Restrictions to add to.
1792 *
1793 * @return LY_ERR values.
1794 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001795static LY_ERR
1796parse_restrs(struct ly_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
1797{
1798 struct lysp_restr *restr;
1799
1800 LYSP_ARRAY_NEW_RET(ctx, restrs, restr, LY_EMEM);
1801
1802 return parse_restr(ctx, data, restr_kw, restr);
1803}
1804
Michal Vaskoea5abea2018-09-18 13:10:54 +02001805/**
1806 * @brief Parse the status statement.
1807 *
1808 * @param[in] ctx libyang context for logging.
1809 * @param[in,out] data Data to read from, always moved to currently handled character.
1810 * @param[in,out] flags Flags to add to.
1811 * @param[in,out] exts Extension instances to add to.
1812 *
1813 * @return LY_ERR values.
1814 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001815static LY_ERR
1816parse_status(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
1817{
1818 LY_ERR ret = 0;
1819 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001820 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001821 enum yang_keyword kw;
1822
1823 if (*flags & LYS_STATUS_MASK) {
1824 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "status");
1825 return LY_EVALID;
1826 }
1827
1828 /* get value */
1829 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001830 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001831
1832 if ((word_len == 7) && !strncmp(word, "current", word_len)) {
1833 *flags |= LYS_STATUS_CURR;
1834 } else if ((word_len == 10) && !strncmp(word, "deprecated", word_len)) {
1835 *flags |= LYS_STATUS_DEPRC;
1836 } else if ((word_len == 8) && !strncmp(word, "obsolete", word_len)) {
1837 *flags |= LYS_STATUS_OBSLT;
1838 } else {
1839 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "status");
1840 free(buf);
1841 return LY_EVALID;
1842 }
1843 free(buf);
1844
1845 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001846 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001847
1848 switch (kw) {
1849 case YANG_CUSTOM:
1850 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_STATUS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02001851 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001852 break;
1853 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001854 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001855 return LY_EVALID;
1856 }
1857 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001858 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001859
1860 return ret;
1861}
1862
Michal Vaskoea5abea2018-09-18 13:10:54 +02001863/**
1864 * @brief Parse the when statement.
1865 *
1866 * @param[in] ctx libyang context for logging.
1867 * @param[in,out] data Data to read from, always moved to currently handled character.
1868 * @param[in,out] when_p When pointer to parse to.
1869 *
1870 * @return LY_ERR values.
1871 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001872static LY_ERR
1873parse_when(struct ly_ctx *ctx, const char **data, struct lysp_when **when_p)
1874{
1875 LY_ERR ret = 0;
1876 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001877 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001878 enum yang_keyword kw;
1879 struct lysp_when *when;
1880
1881 if (*when_p) {
1882 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "when");
1883 return LY_EVALID;
1884 }
1885
1886 when = calloc(1, sizeof *when);
1887 LY_CHECK_ERR_RET(!when, LOGMEM(ctx), LY_EMEM);
1888 *when_p = when;
1889
1890 /* get value */
1891 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001892 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001893
1894 if (buf) {
1895 when->cond = lydict_insert_zc(ctx, word);
1896 } else {
1897 when->cond = lydict_insert(ctx, word, word_len);
1898 }
1899
1900 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001901 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001902
1903 switch (kw) {
1904 case YANG_DESCRIPTION:
1905 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts);
1906 break;
1907 case YANG_REFERENCE:
1908 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &when->ref, Y_STR_ARG, &when->exts);
1909 break;
1910 case YANG_CUSTOM:
1911 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &when->exts);
1912 break;
1913 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001914 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02001915 return LY_EVALID;
1916 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001917 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001918 }
Radek Krejcic59bc972018-09-17 16:13:06 +02001919 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001920
1921 return ret;
1922}
1923
Michal Vaskoea5abea2018-09-18 13:10:54 +02001924/**
1925 * @brief Parse the anydata or anyxml statement.
1926 *
1927 * @param[in] ctx libyang context for logging.
1928 * @param[in,out] data Data to read from, always moved to currently handled character.
1929 * @param[in] kw Type of this particular keyword.
1930 * @param[in,out] siblings Siblings to add to.
1931 *
1932 * @return LY_ERR values.
1933 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02001934static LY_ERR
1935parse_any(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node **siblings)
1936{
1937 LY_ERR ret = 0;
1938 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02001939 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02001940 struct lysp_node *iter;
1941 struct lysp_node_anydata *any;
1942
1943 /* create structure */
1944 any = calloc(1, sizeof *any);
1945 LY_CHECK_ERR_RET(!any, LOGMEM(ctx), LY_EMEM);
1946 any->nodetype = kw == YANG_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
1947
1948 /* insert into siblings */
1949 if (!*siblings) {
1950 *siblings = (struct lysp_node *)any;
1951 } else {
1952 for (iter = *siblings; iter->next; iter = iter->next);
1953 iter->next = (struct lysp_node *)any;
1954 }
1955
1956 /* get name */
1957 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02001958 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001959
1960 if (buf) {
1961 any->name = lydict_insert_zc(ctx, word);
1962 } else {
1963 any->name = lydict_insert(ctx, word, word_len);
1964 }
1965
1966 /* parse substatements */
1967 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02001968 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02001969
1970 switch (kw) {
1971 case YANG_CONFIG:
1972 ret = parse_config(ctx, data, &any->flags, &any->exts);
1973 break;
1974 case YANG_DESCRIPTION:
1975 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &any->dsc, Y_STR_ARG, &any->exts);
1976 break;
1977 case YANG_IF_FEATURE:
1978 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &any->iffeatures, Y_STR_ARG, &any->exts);
1979 break;
1980 case YANG_MANDATORY:
1981 ret = parse_mandatory(ctx, data, &any->flags, &any->exts);
1982 break;
1983 case YANG_MUST:
1984 ret = parse_restrs(ctx, data, kw, &any->musts);
1985 break;
1986 case YANG_REFERENCE:
1987 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &any->ref, Y_STR_ARG, &any->exts);
1988 break;
1989 case YANG_STATUS:
1990 ret = parse_status(ctx, data, &any->flags, &any->exts);
1991 break;
1992 case YANG_WHEN:
1993 ret = parse_when(ctx, data, &any->when);
1994 break;
1995 case YANG_CUSTOM:
1996 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &any->exts);
1997 break;
1998 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02001999 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
2000 (any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(YANG_ANYDATA) : ly_stmt2str(YANG_ANYXML));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002001 return LY_EVALID;
2002 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002003 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002004 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002005 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002006
2007 return ret;
2008}
2009
Michal Vaskoea5abea2018-09-18 13:10:54 +02002010/**
2011 * @brief Parse the value or position statement. Substatement of type enum statement.
2012 *
2013 * @param[in] ctx libyang context for logging.
2014 * @param[in,out] data Data to read from, always moved to currently handled character.
2015 * @param[in] val_kw Type of this particular keyword.
2016 * @param[in,out] value Value to write to.
2017 * @param[in,out] flags Flags to write to.
2018 * @param[in,out] exts Extension instances to add to.
2019 *
2020 * @return LY_ERR values.
2021 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002022static LY_ERR
2023parse_type_enum_value_pos(struct ly_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
2024 struct lysp_ext_instance **exts)
2025{
2026 LY_ERR ret = 0;
2027 char *buf, *word, *ptr;
Radek Krejciefd22f62018-09-27 11:47:58 +02002028 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002029 long int num;
2030 unsigned long int unum;
2031 enum yang_keyword kw;
2032
2033 if (*flags & LYS_SET_VALUE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002034 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002035 return LY_EVALID;
2036 }
2037 *flags |= LYS_SET_VALUE;
2038
2039 /* get value */
2040 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002041 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002042
2043 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 +02002044 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002045 free(buf);
2046 return LY_EVALID;
2047 }
2048
2049 errno = 0;
2050 if (val_kw == YANG_VALUE) {
2051 num = strtol(word, &ptr, 10);
2052 } else {
2053 unum = strtoul(word, &ptr, 10);
2054 }
2055 /* we have not parsed the whole argument */
Radek Krejciefd22f62018-09-27 11:47:58 +02002056 if ((size_t)(ptr - word) != word_len) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002057 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002058 free(buf);
2059 return LY_EVALID;
2060 }
2061 if (errno == ERANGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002062 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002063 free(buf);
2064 return LY_EVALID;
2065 }
2066 if (val_kw == YANG_VALUE) {
2067 *value = num;
2068 } else {
2069 *value = unum;
2070 }
2071 free(buf);
2072
2073 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002074 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002075
2076 switch (kw) {
2077 case YANG_CUSTOM:
2078 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 +02002079 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002080 break;
2081 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002082 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002083 return LY_EVALID;
2084 }
2085 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002086 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002087
2088 return ret;
2089}
2090
Michal Vaskoea5abea2018-09-18 13:10:54 +02002091/**
2092 * @brief Parse the enum or bit statement. Substatement of type statement.
2093 *
2094 * @param[in] ctx libyang context for logging.
2095 * @param[in,out] data Data to read from, always moved to currently handled character.
2096 * @param[in] enum_kw Type of this particular keyword.
2097 * @param[in,out] enums Enums or bits to add to.
2098 *
2099 * @return LY_ERR values.
2100 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002101static LY_ERR
2102parse_type_enum(struct ly_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
2103{
2104 LY_ERR ret = 0;
2105 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002106 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002107 enum yang_keyword kw;
2108 struct lysp_type_enum *enm;
2109
2110 LYSP_ARRAY_NEW_RET(ctx, enums, enm, LY_EMEM);
2111
2112 /* get value */
2113 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002114 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002115
2116 if (buf) {
2117 enm->name = lydict_insert_zc(ctx, word);
2118 } else {
2119 enm->name = lydict_insert(ctx, word, word_len);
2120 }
2121
2122 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002123 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002124
2125 switch (kw) {
2126 case YANG_DESCRIPTION:
2127 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts);
2128 break;
2129 case YANG_IF_FEATURE:
2130 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts);
2131 break;
2132 case YANG_REFERENCE:
2133 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts);
2134 break;
2135 case YANG_STATUS:
2136 ret = parse_status(ctx, data, &enm->flags, &enm->exts);
2137 break;
2138 case YANG_VALUE:
2139 case YANG_POSITION:
2140 ret = parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts);
2141 break;
2142 case YANG_CUSTOM:
2143 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &enm->exts);
2144 break;
2145 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002146 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002147 return LY_EVALID;
2148 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002149 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002150 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002151 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002152
2153 return ret;
2154}
2155
Michal Vaskoea5abea2018-09-18 13:10:54 +02002156/**
2157 * @brief Parse the fraction-digits statement. Substatement of type statement.
2158 *
2159 * @param[in] ctx libyang context for logging.
2160 * @param[in,out] data Data to read from, always moved to currently handled character.
2161 * @param[in,out] fracdig Value to write to.
2162 * @param[in,out] exts Extension instances to add to.
2163 *
2164 * @return LY_ERR values.
2165 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002166static LY_ERR
2167parse_type_fracdigits(struct ly_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
2168{
2169 LY_ERR ret = 0;
2170 char *buf, *word, *ptr;
Radek Krejciefd22f62018-09-27 11:47:58 +02002171 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002172 unsigned long int num;
2173 enum yang_keyword kw;
2174
2175 if (*fracdig) {
2176 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "fraction-digits");
2177 return LY_EVALID;
2178 }
2179
2180 /* get value */
2181 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002182 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002183
2184 if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
2185 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2186 free(buf);
2187 return LY_EVALID;
2188 }
2189
2190 errno = 0;
2191 num = strtoul(word, &ptr, 10);
2192 /* we have not parsed the whole argument */
Radek Krejciefd22f62018-09-27 11:47:58 +02002193 if ((size_t)(ptr - word) != word_len) {
Michal Vasko7fbc8162018-09-17 10:35:16 +02002194 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "fraction-digits");
2195 free(buf);
2196 return LY_EVALID;
2197 }
2198 if ((errno == ERANGE) || (num > 18)) {
2199 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "fraction-digits");
2200 free(buf);
2201 return LY_EVALID;
2202 }
2203 *fracdig = num;
2204 free(buf);
2205
2206 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002207 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002208
2209 switch (kw) {
2210 case YANG_CUSTOM:
2211 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_FRACDIGITS, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002212 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002213 break;
2214 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002215 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002216 return LY_EVALID;
2217 }
2218 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002219 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002220
2221 return ret;
2222}
2223
Michal Vaskoea5abea2018-09-18 13:10:54 +02002224/**
2225 * @brief Parse the require-instance statement. Substatement of type statement.
2226 *
2227 * @param[in] ctx libyang context for logging.
2228 * @param[in,out] data Data to read from, always moved to currently handled character.
2229 * @param[in,out] reqinst Value to write to.
2230 * @param[in,out] flags Flags to write to.
2231 * @param[in,out] exts Extension instances to add to.
2232 *
2233 * @return LY_ERR values.
2234 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002235static LY_ERR
2236parse_type_reqinstance(struct ly_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
2237 struct lysp_ext_instance **exts)
2238{
2239 LY_ERR ret = 0;
2240 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002241 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002242 enum yang_keyword kw;
2243
2244 if (*flags & LYS_SET_REQINST) {
2245 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "require-instance");
2246 return LY_EVALID;
2247 }
2248 *flags |= LYS_SET_REQINST;
2249
2250 /* get value */
2251 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002252 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002253
2254 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
2255 *reqinst = 1;
2256 } else if ((word_len != 5) || strncmp(word, "false", word_len)) {
2257 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "require-instance");
2258 free(buf);
2259 return LY_EVALID;
2260 }
2261 free(buf);
2262
2263 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002264 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002265
2266 switch (kw) {
2267 case YANG_CUSTOM:
2268 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REQINSTANCE, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002269 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002270 break;
2271 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002272 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002273 return LY_EVALID;
2274 }
2275 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002276 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002277
2278 return ret;
2279}
2280
Michal Vaskoea5abea2018-09-18 13:10:54 +02002281/**
2282 * @brief Parse the modifier statement. Substatement of type pattern statement.
2283 *
2284 * @param[in] ctx libyang context for logging.
2285 * @param[in,out] data Data to read from, always moved to currently handled character.
2286 * @param[in,out] pat Value to write to.
2287 * @param[in,out] exts Extension instances to add to.
2288 *
2289 * @return LY_ERR values.
2290 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002291static LY_ERR
2292parse_type_pattern_modifier(struct ly_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
2293{
2294 LY_ERR ret = 0;
2295 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002296 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002297 enum yang_keyword kw;
2298
2299 if ((*pat)[0] == 0x15) {
2300 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "modifier");
2301 return LY_EVALID;
2302 }
2303
2304 /* get value */
2305 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002306 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002307
2308 if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
2309 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "modifier");
2310 free(buf);
2311 return LY_EVALID;
2312 }
2313 free(buf);
2314
2315 /* replace the value in the dictionary */
2316 buf = malloc(strlen(*pat) + 1);
2317 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2318 strcpy(buf, *pat);
2319 lydict_remove(ctx, *pat);
2320
2321 assert(buf[0] == 0x06);
2322 buf[0] = 0x15;
2323 *pat = lydict_insert_zc(ctx, buf);
2324
2325 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002326 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002327
2328 switch (kw) {
2329 case YANG_CUSTOM:
2330 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MODIFIER, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002331 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002332 break;
2333 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002334 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002335 return LY_EVALID;
2336 }
2337 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002338 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002339
2340 return ret;
2341}
2342
Michal Vaskoea5abea2018-09-18 13:10:54 +02002343/**
2344 * @brief Parse the pattern statement. Substatement of type statement.
2345 *
2346 * @param[in] ctx libyang context for logging.
2347 * @param[in,out] data Data to read from, always moved to currently handled character.
2348 * @param[in,out] patterns Restrictions to add to.
2349 *
2350 * @return LY_ERR values.
2351 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002352static LY_ERR
2353parse_type_pattern(struct ly_ctx *ctx, const char **data, struct lysp_restr **patterns)
2354{
2355 LY_ERR ret = 0;
2356 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002357 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002358 enum yang_keyword kw;
2359 struct lysp_restr *restr;
2360
2361 LYSP_ARRAY_NEW_RET(ctx, patterns, restr, LY_EMEM);
2362
2363 /* get value */
2364 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002365 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002366
2367 /* add special meaning first byte */
2368 if (buf) {
2369 buf = realloc(buf, word_len + 2);
2370 word = buf;
2371 } else {
2372 buf = malloc(word_len + 2);
2373 }
2374 LY_CHECK_ERR_RET(!buf, LOGMEM(ctx), LY_EMEM);
2375 memmove(buf + 1, word, word_len + 1);
2376 word[0] = 0x06;
2377 restr->arg = lydict_insert_zc(ctx, word);
2378
2379 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002380 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002381
2382 switch (kw) {
2383 case YANG_DESCRIPTION:
2384 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts);
2385 break;
2386 case YANG_REFERENCE:
2387 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts);
2388 break;
2389 case YANG_ERROR_APP_TAG:
2390 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts);
2391 break;
2392 case YANG_ERROR_MESSAGE:
2393 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts);
2394 break;
2395 case YANG_MODIFIER:
2396 ret = parse_type_pattern_modifier(ctx, data, &restr->arg, &restr->exts);
2397 break;
2398 case YANG_CUSTOM:
2399 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts);
2400 break;
2401 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002402 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002403 return LY_EVALID;
2404 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002405 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002406 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002407 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002408
2409 return ret;
2410}
2411
Michal Vaskoea5abea2018-09-18 13:10:54 +02002412/**
2413 * @brief Parse the type statement.
2414 *
2415 * @param[in] ctx libyang context for logging.
2416 * @param[in,out] data Data to read from, always moved to currently handled character.
2417 * @param[in,out] type Type to wrote to.
2418 *
2419 * @return LY_ERR values.
2420 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002421static LY_ERR
2422parse_type(struct ly_ctx *ctx, const char **data, struct lysp_type *type)
2423{
2424 LY_ERR ret = 0;
2425 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002426 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002427 enum yang_keyword kw;
2428 struct lysp_type *nest_type;
2429
2430 if (type->name) {
2431 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "type");
2432 return LY_EVALID;
2433 }
2434
2435 /* get value */
2436 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002437 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002438
2439 if (buf) {
2440 type->name = lydict_insert_zc(ctx, word);
2441 } else {
2442 type->name = lydict_insert(ctx, word, word_len);
2443 }
2444
2445 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002446 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002447
2448 switch (kw) {
2449 case YANG_BASE:
2450 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts);
2451 break;
2452 case YANG_BIT:
2453 ret = parse_type_enum(ctx, data, kw, &type->bits);
2454 break;
2455 case YANG_ENUM:
2456 ret = parse_type_enum(ctx, data, kw, &type->enums);
2457 break;
2458 case YANG_FRACTION_DIGITS:
2459 ret = parse_type_fracdigits(ctx, data, &type->fraction_digits, &type->exts);
2460 break;
2461 case YANG_LENGTH:
2462 if (type->length) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002463 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002464 return LY_EVALID;
2465 }
2466 type->length = calloc(1, sizeof *type->length);
2467 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
2468
2469 ret = parse_restr(ctx, data, kw, type->length);
2470 break;
2471 case YANG_PATH:
2472 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PATH, 0, &type->path, Y_STR_ARG, &type->exts);
2473 break;
2474 case YANG_PATTERN:
2475 ret = parse_type_pattern(ctx, data, &type->patterns);
2476 break;
2477 case YANG_RANGE:
2478 if (type->range) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002479 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02002480 return LY_EVALID;
2481 }
2482 type->range = calloc(1, sizeof *type->range);
2483 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EVALID);
2484
2485 ret = parse_restr(ctx, data, kw, type->range);
2486 break;
2487 case YANG_REQUIRE_INSTANCE:
2488 ret = parse_type_reqinstance(ctx, data, &type->require_instance, &type->flags, &type->exts);
2489 break;
2490 case YANG_TYPE:
2491 {
2492 LYSP_ARRAY_NEW_RET(ctx, &type->types, nest_type, LY_EMEM);
2493 }
2494 ret = parse_type(ctx, data, nest_type);
2495 break;
2496 case YANG_CUSTOM:
2497 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts);
2498 break;
2499 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002500 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002501 return LY_EVALID;
2502 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002503 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002504 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002505 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002506
2507 return ret;
2508}
2509
Michal Vaskoea5abea2018-09-18 13:10:54 +02002510/**
2511 * @brief Parse the leaf statement.
2512 *
2513 * @param[in] ctx libyang context for logging.
2514 * @param[in,out] data Data to read from, always moved to currently handled character.
2515 * @param[in,out] siblings Siblings to add to.
2516 *
2517 * @return LY_ERR values.
2518 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002519static LY_ERR
2520parse_leaf(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2521{
2522 LY_ERR ret = 0;
2523 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002524 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002525 enum yang_keyword kw;
2526 struct lysp_node *iter;
2527 struct lysp_node_leaf *leaf;
2528
2529 /* create structure */
2530 leaf = calloc(1, sizeof *leaf);
2531 LY_CHECK_ERR_RET(!leaf, LOGMEM(ctx), LY_EMEM);
2532 leaf->nodetype = LYS_LEAF;
2533
2534 /* insert into siblings */
2535 if (!*siblings) {
2536 *siblings = (struct lysp_node *)leaf;
2537 } else {
2538 for (iter = *siblings; iter->next; iter = iter->next);
2539 iter->next = (struct lysp_node *)leaf;
2540 }
2541
2542 /* get name */
2543 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002544 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002545
2546 if (buf) {
2547 leaf->name = lydict_insert_zc(ctx, word);
2548 } else {
2549 leaf->name = lydict_insert(ctx, word, word_len);
2550 }
2551
2552 /* parse substatements */
2553 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002554 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002555
2556 switch (kw) {
2557 case YANG_CONFIG:
2558 ret = parse_config(ctx, data, &leaf->flags, &leaf->exts);
2559 break;
2560 case YANG_DEFAULT:
2561 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &leaf->dflt, Y_STR_ARG, &leaf->exts);
2562 break;
2563 case YANG_DESCRIPTION:
2564 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts);
2565 break;
2566 case YANG_IF_FEATURE:
2567 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &leaf->iffeatures, Y_STR_ARG, &leaf->exts);
2568 break;
2569 case YANG_MANDATORY:
2570 ret = parse_mandatory(ctx, data, &leaf->flags, &leaf->exts);
2571 break;
2572 case YANG_MUST:
2573 ret = parse_restrs(ctx, data, kw, &leaf->musts);
2574 break;
2575 case YANG_REFERENCE:
2576 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &leaf->ref, Y_STR_ARG, &leaf->exts);
2577 break;
2578 case YANG_STATUS:
2579 ret = parse_status(ctx, data, &leaf->flags, &leaf->exts);
2580 break;
2581 case YANG_TYPE:
2582 ret = parse_type(ctx, data, &leaf->type);
2583 break;
2584 case YANG_UNITS:
2585 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &leaf->units, Y_STR_ARG, &leaf->exts);
2586 break;
2587 case YANG_WHEN:
2588 ret = parse_when(ctx, data, &leaf->when);
2589 break;
2590 case YANG_CUSTOM:
2591 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &leaf->exts);
2592 break;
2593 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002594 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002595 return LY_EVALID;
2596 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002597 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002598 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002599 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002600
2601 /* mandatory substatements */
2602 if (!leaf->type.name) {
2603 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf");
2604 return LY_EVALID;
2605 }
2606
2607 return ret;
2608}
2609
Michal Vaskoea5abea2018-09-18 13:10:54 +02002610/**
2611 * @brief Parse the max-elements statement.
2612 *
2613 * @param[in] ctx libyang context for logging.
2614 * @param[in,out] data Data to read from, always moved to currently handled character.
2615 * @param[in,out] max Value to write to.
2616 * @param[in,out] flags Flags to write to.
2617 * @param[in,out] exts Extension instances to add to.
2618 *
2619 * @return LY_ERR values.
2620 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002621static LY_ERR
2622parse_maxelements(struct ly_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
2623{
2624 LY_ERR ret = 0;
2625 char *buf, *word, *ptr;
Radek Krejciefd22f62018-09-27 11:47:58 +02002626 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002627 unsigned long int num;
2628 enum yang_keyword kw;
2629
2630 if (*flags & LYS_SET_MAX) {
2631 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "max-elements");
2632 return LY_EVALID;
2633 }
2634 *flags |= LYS_SET_MAX;
2635
2636 /* get value */
2637 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002638 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002639
2640 if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
2641 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2642 free(buf);
2643 return LY_EVALID;
2644 }
2645
2646 if (strncmp(word, "unbounded", word_len)) {
2647 errno = 0;
2648 num = strtoul(word, &ptr, 10);
2649 /* we have not parsed the whole argument */
Radek Krejciefd22f62018-09-27 11:47:58 +02002650 if ((size_t)(ptr - word) != word_len) {
Michal Vasko7fbc8162018-09-17 10:35:16 +02002651 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "max-elements");
2652 free(buf);
2653 return LY_EVALID;
2654 }
2655 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2656 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "max-elements");
2657 free(buf);
2658 return LY_EVALID;
2659 }
2660
2661 *max = num;
2662 }
2663 free(buf);
2664
2665 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002666 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002667
2668 switch (kw) {
2669 case YANG_CUSTOM:
2670 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MAX, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002671 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002672 break;
2673 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002674 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002675 return LY_EVALID;
2676 }
2677 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002678 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002679
2680 return ret;
2681}
2682
Michal Vaskoea5abea2018-09-18 13:10:54 +02002683/**
2684 * @brief Parse the min-elements statement.
2685 *
2686 * @param[in] ctx libyang context for logging.
2687 * @param[in,out] data Data to read from, always moved to currently handled character.
2688 * @param[in,out] min Value to write to.
2689 * @param[in,out] flags Flags to write to.
2690 * @param[in,out] exts Extension instances to add to.
2691 *
2692 * @return LY_ERR values.
2693 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002694static LY_ERR
2695parse_minelements(struct ly_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
2696{
2697 LY_ERR ret = 0;
2698 char *buf, *word, *ptr;
Radek Krejciefd22f62018-09-27 11:47:58 +02002699 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002700 unsigned long int num;
2701 enum yang_keyword kw;
2702
2703 if (*flags & LYS_SET_MIN) {
2704 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "min-elements");
2705 return LY_EVALID;
2706 }
2707 *flags |= LYS_SET_MIN;
2708
2709 /* get value */
2710 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002711 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002712
2713 if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
2714 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2715 free(buf);
2716 return LY_EVALID;
2717 }
2718
2719 errno = 0;
2720 num = strtoul(word, &ptr, 10);
2721 /* we have not parsed the whole argument */
Radek Krejciefd22f62018-09-27 11:47:58 +02002722 if ((size_t)(ptr - word) != word_len) {
Michal Vasko7fbc8162018-09-17 10:35:16 +02002723 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "min-elements");
2724 free(buf);
2725 return LY_EVALID;
2726 }
2727 if ((errno == ERANGE) || (num > UINT32_MAX)) {
2728 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_OOB, word_len, word, "min-elements");
2729 free(buf);
2730 return LY_EVALID;
2731 }
2732 *min = num;
2733 free(buf);
2734
2735 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002736 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002737
2738 switch (kw) {
2739 case YANG_CUSTOM:
2740 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MIN, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002741 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002742 break;
2743 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002744 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002745 return LY_EVALID;
2746 }
2747 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002748 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002749
2750 return ret;
2751}
2752
Michal Vaskoea5abea2018-09-18 13:10:54 +02002753/**
2754 * @brief Parse the ordered-by statement.
2755 *
2756 * @param[in] ctx libyang context for logging.
2757 * @param[in,out] data Data to read from, always moved to currently handled character.
2758 * @param[in,out] flags Flags to write to.
2759 * @param[in,out] exts Extension instances to add to.
2760 *
2761 * @return LY_ERR values.
2762 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002763static LY_ERR
2764parse_orderedby(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
2765{
2766 LY_ERR ret = 0;
2767 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002768 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002769 enum yang_keyword kw;
2770
2771 if (*flags & LYS_ORDBY_MASK) {
2772 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "ordered-by");
2773 return LY_EVALID;
2774 }
2775
2776 /* get value */
2777 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002778 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002779
2780 if ((word_len == 6) && !strncmp(word, "system", word_len)) {
2781 *flags |= LYS_ORDBY_SYSTEM;
2782 } else if ((word_len == 4) && !strncmp(word, "user", word_len)) {
2783 *flags |= LYS_ORDBY_USER;
2784 } else {
2785 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "ordered-by");
2786 free(buf);
2787 return LY_EVALID;
2788 }
2789 free(buf);
2790
2791 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002792 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002793
2794 switch (kw) {
2795 case YANG_CUSTOM:
2796 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ORDEREDBY, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02002797 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002798 break;
2799 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002800 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002801 return LY_EVALID;
2802 }
2803 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002804 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002805
2806 return ret;
2807}
2808
Michal Vaskoea5abea2018-09-18 13:10:54 +02002809/**
2810 * @brief Parse the leaf-list statement.
2811 *
2812 * @param[in] ctx libyang context for logging.
2813 * @param[in,out] data Data to read from, always moved to currently handled character.
2814 * @param[in,out] siblings Siblings to add to.
2815 *
2816 * @return LY_ERR values.
2817 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002818static LY_ERR
2819parse_leaflist(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
2820{
2821 LY_ERR ret = 0;
2822 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002823 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002824 enum yang_keyword kw;
2825 struct lysp_node *iter;
2826 struct lysp_node_leaflist *llist;
2827
2828 /* create structure */
2829 llist = calloc(1, sizeof *llist);
2830 LY_CHECK_ERR_RET(!llist, LOGMEM(ctx), LY_EMEM);
2831 llist->nodetype = LYS_LEAFLIST;
2832
2833 /* insert into siblings */
2834 if (!*siblings) {
2835 *siblings = (struct lysp_node *)llist;
2836 } else {
2837 for (iter = *siblings; iter->next; iter = iter->next);
2838 iter->next = (struct lysp_node *)llist;
2839 }
2840
2841 /* get name */
2842 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002843 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002844
2845 if (buf) {
2846 llist->name = lydict_insert_zc(ctx, word);
2847 } else {
2848 llist->name = lydict_insert(ctx, word, word_len);
2849 }
2850
2851 /* parse substatements */
2852 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002853 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002854
2855 switch (kw) {
2856 case YANG_CONFIG:
2857 ret = parse_config(ctx, data, &llist->flags, &llist->exts);
2858 break;
2859 case YANG_DEFAULT:
2860 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &llist->dflts, Y_STR_ARG, &llist->exts);
2861 break;
2862 case YANG_DESCRIPTION:
2863 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &llist->dsc, Y_STR_ARG, &llist->exts);
2864 break;
2865 case YANG_IF_FEATURE:
2866 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &llist->iffeatures, Y_STR_ARG, &llist->exts);
2867 break;
2868 case YANG_MAX_ELEMENTS:
2869 ret = parse_maxelements(ctx, data, &llist->max, &llist->flags, &llist->exts);
2870 break;
2871 case YANG_MIN_ELEMENTS:
2872 ret = parse_minelements(ctx, data, &llist->min, &llist->flags, &llist->exts);
2873 break;
2874 case YANG_MUST:
2875 ret = parse_restrs(ctx, data, kw, &llist->musts);
2876 break;
2877 case YANG_ORDERED_BY:
2878 ret = parse_orderedby(ctx, data, &llist->flags, &llist->exts);
2879 break;
2880 case YANG_REFERENCE:
2881 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &llist->ref, Y_STR_ARG, &llist->exts);
2882 break;
2883 case YANG_STATUS:
2884 ret = parse_status(ctx, data, &llist->flags, &llist->exts);
2885 break;
2886 case YANG_TYPE:
2887 ret = parse_type(ctx, data, &llist->type);
2888 break;
2889 case YANG_UNITS:
2890 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &llist->units, Y_STR_ARG, &llist->exts);
2891 break;
2892 case YANG_WHEN:
2893 ret = parse_when(ctx, data, &llist->when);
2894 break;
2895 case YANG_CUSTOM:
2896 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &llist->exts);
2897 break;
2898 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002899 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002900 return LY_EVALID;
2901 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002902 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002903 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002904 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002905
2906 /* mandatory substatements */
2907 if (!llist->type.name) {
2908 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "leaf-list");
2909 return LY_EVALID;
2910 }
2911
2912 return ret;
2913}
2914
Michal Vaskoea5abea2018-09-18 13:10:54 +02002915/**
2916 * @brief Parse the refine statement.
2917 *
2918 * @param[in] ctx libyang context for logging.
2919 * @param[in,out] data Data to read from, always moved to currently handled character.
2920 * @param[in,out] refines Refines to add to.
2921 *
2922 * @return LY_ERR values.
2923 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02002924static LY_ERR
2925parse_refine(struct ly_ctx *ctx, const char **data, struct lysp_refine **refines)
2926{
2927 LY_ERR ret = 0;
2928 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02002929 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02002930 enum yang_keyword kw;
2931 struct lysp_refine *rf;
2932
2933 LYSP_ARRAY_NEW_RET(ctx, refines, rf, LY_EMEM);
2934
2935 /* get value */
2936 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02002937 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002938
2939 if (buf) {
2940 rf->nodeid = lydict_insert_zc(ctx, word);
2941 } else {
2942 rf->nodeid = lydict_insert(ctx, word, word_len);
2943 }
2944
2945 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02002946 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002947
2948 switch (kw) {
2949 case YANG_CONFIG:
2950 ret = parse_config(ctx, data, &rf->flags, &rf->exts);
2951 break;
2952 case YANG_DEFAULT:
2953 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, &rf->dflts, Y_STR_ARG, &rf->exts);
2954 break;
2955 case YANG_DESCRIPTION:
2956 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &rf->dsc, Y_STR_ARG, &rf->exts);
2957 break;
2958 case YANG_IF_FEATURE:
2959 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &rf->iffeatures, Y_STR_ARG, &rf->exts);
2960 break;
2961 case YANG_MAX_ELEMENTS:
2962 ret = parse_maxelements(ctx, data, &rf->max, &rf->flags, &rf->exts);
2963 break;
2964 case YANG_MIN_ELEMENTS:
2965 ret = parse_minelements(ctx, data, &rf->min, &rf->flags, &rf->exts);
2966 break;
2967 case YANG_MUST:
2968 ret = parse_restrs(ctx, data, kw, &rf->musts);
2969 break;
2970 case YANG_MANDATORY:
2971 ret = parse_mandatory(ctx, data, &rf->flags, &rf->exts);
2972 break;
2973 case YANG_REFERENCE:
2974 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &rf->ref, Y_STR_ARG, &rf->exts);
2975 break;
2976 case YANG_PRESENCE:
2977 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &rf->presence, Y_STR_ARG, &rf->exts);
2978 break;
2979 case YANG_CUSTOM:
2980 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rf->exts);
2981 break;
2982 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02002983 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
Michal Vasko7fbc8162018-09-17 10:35:16 +02002984 return LY_EVALID;
2985 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002986 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002987 }
Radek Krejcic59bc972018-09-17 16:13:06 +02002988 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02002989
2990 return ret;
2991}
2992
Michal Vaskoea5abea2018-09-18 13:10:54 +02002993/**
2994 * @brief Parse the typedef statement.
2995 *
2996 * @param[in] ctx libyang context for logging.
2997 * @param[in,out] data Data to read from, always moved to currently handled character.
2998 * @param[in,out] typedefs Typedefs to add to.
2999 *
3000 * @return LY_ERR values.
3001 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003002static LY_ERR
3003parse_typedef(struct ly_ctx *ctx, const char **data, struct lysp_tpdf **typedefs)
3004{
3005 LY_ERR ret = 0;
3006 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003007 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003008 enum yang_keyword kw;
3009 struct lysp_tpdf *tpdf;
3010
3011 LYSP_ARRAY_NEW_RET(ctx, typedefs, tpdf, LY_EMEM);
3012
3013 /* get value */
3014 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003015 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003016
3017 if (buf) {
3018 tpdf->name = lydict_insert_zc(ctx, word);
3019 } else {
3020 tpdf->name = lydict_insert(ctx, word, word_len);
3021 }
3022
3023 /* parse substatements */
3024 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003025 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003026
3027 switch (kw) {
3028 case YANG_DEFAULT:
3029 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &tpdf->dflt, Y_STR_ARG, &tpdf->exts);
3030 break;
3031 case YANG_DESCRIPTION:
3032 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts);
3033 break;
3034 case YANG_REFERENCE:
3035 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &tpdf->ref, Y_STR_ARG, &tpdf->exts);
3036 break;
3037 case YANG_STATUS:
3038 ret = parse_status(ctx, data, &tpdf->flags, &tpdf->exts);
3039 break;
3040 case YANG_TYPE:
3041 ret = parse_type(ctx, data, &tpdf->type);
3042 break;
3043 case YANG_UNITS:
3044 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, &tpdf->units, Y_STR_ARG, &tpdf->exts);
3045 break;
3046 case YANG_CUSTOM:
3047 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &tpdf->exts);
3048 break;
3049 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003050 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003051 return LY_EVALID;
3052 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003053 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003054 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003055 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003056
3057 /* mandatory substatements */
3058 if (!tpdf->type.name) {
3059 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "type", "typedef");
3060 return LY_EVALID;
3061 }
3062
3063 return ret;
3064}
3065
Michal Vaskoea5abea2018-09-18 13:10:54 +02003066/**
3067 * @brief Parse the input or output statement.
3068 *
3069 * @param[in] ctx libyang context for logging.
3070 * @param[in,out] data Data to read from, always moved to currently handled character.
3071 * @param[in] kw Type of this particular keyword
3072 * @param[in,out] inout_p Input/output pointer to write to.
3073 *
3074 * @return LY_ERR values.
3075 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003076static LY_ERR
3077parse_inout(struct ly_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_action_inout **inout_p)
3078{
3079 LY_ERR ret = 0;
3080 char *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003081 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003082 struct lysp_action_inout *inout;
3083
3084 if (*inout_p) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003085 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02003086 return LY_EVALID;
3087 }
3088
3089 /* create structure */
3090 inout = calloc(1, sizeof *inout);
3091 LY_CHECK_ERR_RET(!inout, LOGMEM(ctx), LY_EMEM);
3092 *inout_p = inout;
3093
3094 /* parse substatements */
3095 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003096 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003097
3098 switch (kw) {
3099 case YANG_ANYDATA:
3100 case YANG_ANYXML:
3101 ret = parse_any(ctx, data, kw, &inout->data);
3102 break;
3103 case YANG_CHOICE:
3104 ret = parse_choice(ctx, data, &inout->data);
3105 break;
3106 case YANG_CONTAINER:
3107 ret = parse_container(ctx, data, &inout->data);
3108 break;
3109 case YANG_LEAF:
3110 ret = parse_leaf(ctx, data, &inout->data);
3111 break;
3112 case YANG_LEAF_LIST:
3113 ret = parse_leaflist(ctx, data, &inout->data);
3114 break;
3115 case YANG_LIST:
3116 ret = parse_list(ctx, data, &inout->data);
3117 break;
3118 case YANG_USES:
3119 ret = parse_uses(ctx, data, &inout->data);
3120 break;
3121
3122 case YANG_TYPEDEF:
3123 ret = parse_typedef(ctx, data, &inout->typedefs);
3124 break;
3125 case YANG_MUST:
3126 ret = parse_restrs(ctx, data, kw, &inout->musts);
3127 break;
3128 case YANG_GROUPING:
3129 ret = parse_grouping(ctx, data, &inout->groupings);
3130 break;
3131 case YANG_CUSTOM:
3132 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout->exts);
3133 break;
3134 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003135 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "input/output");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003136 return LY_EVALID;
3137 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003138 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003139 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003140 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003141
3142 return ret;
3143}
3144
Michal Vaskoea5abea2018-09-18 13:10:54 +02003145/**
3146 * @brief Parse the action statement.
3147 *
3148 * @param[in] ctx libyang context for logging.
3149 * @param[in,out] data Data to read from, always moved to currently handled character.
3150 * @param[in,out] actions Actions to add to.
3151 *
3152 * @return LY_ERR values.
3153 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003154static LY_ERR
3155parse_action(struct ly_ctx *ctx, const char **data, struct lysp_action **actions)
3156{
3157 LY_ERR ret = 0;
3158 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003159 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003160 enum yang_keyword kw;
3161 struct lysp_action *act;
3162
3163 LYSP_ARRAY_NEW_RET(ctx, actions, act, LY_EMEM);
3164
3165 /* get value */
3166 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003167 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003168
3169 if (buf) {
3170 act->name = lydict_insert_zc(ctx, word);
3171 } else {
3172 act->name = lydict_insert(ctx, word, word_len);
3173 }
3174
3175 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003176 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003177
3178 switch (kw) {
3179 case YANG_DESCRIPTION:
3180 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts);
3181 break;
3182 case YANG_IF_FEATURE:
3183 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &act->iffeatures, Y_STR_ARG, &act->exts);
3184 break;
3185 case YANG_REFERENCE:
3186 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &act->ref, Y_STR_ARG, &act->exts);
3187 break;
3188 case YANG_STATUS:
3189 ret = parse_status(ctx, data, &act->flags, &act->exts);
3190 break;
3191
3192 case YANG_INPUT:
3193 ret = parse_inout(ctx, data, kw, &act->input);
3194 break;
3195 case YANG_OUTPUT:
3196 ret = parse_inout(ctx, data, kw, &act->output);
3197 break;
3198
3199 case YANG_TYPEDEF:
3200 ret = parse_typedef(ctx, data, &act->typedefs);
3201 break;
3202 case YANG_GROUPING:
3203 ret = parse_grouping(ctx, data, &act->groupings);
3204 break;
3205 case YANG_CUSTOM:
3206 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts);
3207 break;
3208 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003209 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "action");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003210 return LY_EVALID;
3211 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003212 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003213 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003214 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003215
3216 return ret;
3217}
3218
Michal Vaskoea5abea2018-09-18 13:10:54 +02003219/**
3220 * @brief Parse the notification statement.
3221 *
3222 * @param[in] ctx libyang context for logging.
3223 * @param[in,out] data Data to read from, always moved to currently handled character.
3224 * @param[in,out] notifs Notifications to add to.
3225 *
3226 * @return LY_ERR values.
3227 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003228static LY_ERR
3229parse_notif(struct ly_ctx *ctx, const char **data, struct lysp_notif **notifs)
3230{
3231 LY_ERR ret = 0;
3232 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003233 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003234 enum yang_keyword kw;
3235 struct lysp_notif *notif;
3236
3237 LYSP_ARRAY_NEW_RET(ctx, notifs, notif, LY_EMEM);
3238
3239 /* get value */
3240 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003241 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003242
3243 if (buf) {
3244 notif->name = lydict_insert_zc(ctx, word);
3245 } else {
3246 notif->name = lydict_insert(ctx, word, word_len);
3247 }
3248
3249 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003250 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003251
3252 switch (kw) {
3253 case YANG_DESCRIPTION:
3254 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts);
3255 break;
3256 case YANG_IF_FEATURE:
3257 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &notif->iffeatures, Y_STR_ARG, &notif->exts);
3258 break;
3259 case YANG_REFERENCE:
3260 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &notif->ref, Y_STR_ARG, &notif->exts);
3261 break;
3262 case YANG_STATUS:
3263 ret = parse_status(ctx, data, &notif->flags, &notif->exts);
3264 break;
3265
3266 case YANG_ANYDATA:
3267 case YANG_ANYXML:
3268 ret = parse_any(ctx, data, kw, &notif->data);
3269 break;
3270 case YANG_CHOICE:
3271 ret = parse_case(ctx, data, &notif->data);
3272 break;
3273 case YANG_CONTAINER:
3274 ret = parse_container(ctx, data, &notif->data);
3275 break;
3276 case YANG_LEAF:
3277 ret = parse_leaf(ctx, data, &notif->data);
3278 break;
3279 case YANG_LEAF_LIST:
3280 ret = parse_leaflist(ctx, data, &notif->data);
3281 break;
3282 case YANG_LIST:
3283 ret = parse_list(ctx, data, &notif->data);
3284 break;
3285 case YANG_USES:
3286 ret = parse_uses(ctx, data, &notif->data);
3287 break;
3288
3289 case YANG_MUST:
3290 ret = parse_restrs(ctx, data, kw, &notif->musts);
3291 break;
3292 case YANG_TYPEDEF:
3293 ret = parse_typedef(ctx, data, &notif->typedefs);
3294 break;
3295 case YANG_GROUPING:
3296 ret = parse_grouping(ctx, data, &notif->groupings);
3297 break;
3298 case YANG_CUSTOM:
3299 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &notif->exts);
3300 break;
3301 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003302 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003303 return LY_EVALID;
3304 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003305 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003306 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003307 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003308
3309 return ret;
3310}
3311
Michal Vaskoea5abea2018-09-18 13:10:54 +02003312/**
3313 * @brief Parse the grouping statement.
3314 *
3315 * @param[in] ctx libyang context for logging.
3316 * @param[in,out] data Data to read from, always moved to currently handled character.
3317 * @param[in,out] groupings Groupings to add to.
3318 *
3319 * @return LY_ERR values.
3320 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003321static LY_ERR
3322parse_grouping(struct ly_ctx *ctx, const char **data, struct lysp_grp **groupings)
3323{
3324 LY_ERR ret = 0;
3325 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003326 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003327 enum yang_keyword kw;
3328 struct lysp_grp *grp;
3329
3330 LYSP_ARRAY_NEW_RET(ctx, groupings, grp, LY_EMEM);
3331
3332 /* get value */
3333 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003334 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003335
3336 if (buf) {
3337 grp->name = lydict_insert_zc(ctx, word);
3338 } else {
3339 grp->name = lydict_insert(ctx, word, word_len);
3340 }
3341
3342 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003343 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003344
3345 switch (kw) {
3346 case YANG_DESCRIPTION:
3347 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts);
3348 break;
3349 case YANG_REFERENCE:
3350 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &grp->ref, Y_STR_ARG, &grp->exts);
3351 break;
3352 case YANG_STATUS:
3353 ret = parse_status(ctx, data, &grp->flags, &grp->exts);
3354 break;
3355
3356 case YANG_ANYDATA:
3357 case YANG_ANYXML:
3358 ret = parse_any(ctx, data, kw, &grp->data);
3359 break;
3360 case YANG_CHOICE:
3361 ret = parse_choice(ctx, data, &grp->data);
3362 break;
3363 case YANG_CONTAINER:
3364 ret = parse_container(ctx, data, &grp->data);
3365 break;
3366 case YANG_LEAF:
3367 ret = parse_leaf(ctx, data, &grp->data);
3368 break;
3369 case YANG_LEAF_LIST:
3370 ret = parse_leaflist(ctx, data, &grp->data);
3371 break;
3372 case YANG_LIST:
3373 ret = parse_list(ctx, data, &grp->data);
3374 break;
3375 case YANG_USES:
3376 ret = parse_uses(ctx, data, &grp->data);
3377 break;
3378
3379 case YANG_TYPEDEF:
3380 ret = parse_typedef(ctx, data, &grp->typedefs);
3381 break;
3382 case YANG_ACTION:
3383 ret = parse_action(ctx, data, &grp->actions);
3384 break;
3385 case YANG_GROUPING:
3386 ret = parse_grouping(ctx, data, &grp->groupings);
3387 break;
3388 case YANG_NOTIFICATION:
3389 ret = parse_notif(ctx, data, &grp->notifs);
3390 break;
3391 case YANG_CUSTOM:
3392 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &grp->exts);
3393 break;
3394 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003395 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003396 return LY_EVALID;
3397 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003398 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003399 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003400 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003401
3402 return ret;
3403}
3404
Michal Vaskoea5abea2018-09-18 13:10:54 +02003405/**
3406 * @brief Parse the refine statement.
3407 *
3408 * @param[in] ctx libyang context for logging.
3409 * @param[in,out] data Data to read from, always moved to currently handled character.
3410 * @param[in,out] augments Augments to add to.
3411 *
3412 * @return LY_ERR values.
3413 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003414static LY_ERR
3415parse_augment(struct ly_ctx *ctx, const char **data, struct lysp_augment **augments)
3416{
3417 LY_ERR ret = 0;
3418 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003419 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003420 enum yang_keyword kw;
3421 struct lysp_augment *aug;
3422
3423 LYSP_ARRAY_NEW_RET(ctx, augments, aug, LY_EMEM);
3424
3425 /* get value */
3426 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003427 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003428
3429 if (buf) {
3430 aug->nodeid = lydict_insert_zc(ctx, word);
3431 } else {
3432 aug->nodeid = lydict_insert(ctx, word, word_len);
3433 }
3434
3435 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003436 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003437
3438 switch (kw) {
3439 case YANG_DESCRIPTION:
3440 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts);
3441 break;
3442 case YANG_IF_FEATURE:
3443 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &aug->iffeatures, Y_STR_ARG, &aug->exts);
3444 break;
3445 case YANG_REFERENCE:
3446 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &aug->ref, Y_STR_ARG, &aug->exts);
3447 break;
3448 case YANG_STATUS:
3449 ret = parse_status(ctx, data, &aug->flags, &aug->exts);
3450 break;
3451 case YANG_WHEN:
3452 ret = parse_when(ctx, data, &aug->when);
3453 break;
3454
3455 case YANG_ANYDATA:
3456 case YANG_ANYXML:
3457 ret = parse_any(ctx, data, kw, &aug->child);
3458 break;
3459 case YANG_CASE:
3460 ret = parse_case(ctx, data, &aug->child);
3461 break;
3462 case YANG_CHOICE:
3463 ret = parse_choice(ctx, data, &aug->child);
3464 break;
3465 case YANG_CONTAINER:
3466 ret = parse_container(ctx, data, &aug->child);
3467 break;
3468 case YANG_LEAF:
3469 ret = parse_leaf(ctx, data, &aug->child);
3470 break;
3471 case YANG_LEAF_LIST:
3472 ret = parse_leaflist(ctx, data, &aug->child);
3473 break;
3474 case YANG_LIST:
3475 ret = parse_list(ctx, data, &aug->child);
3476 break;
3477 case YANG_USES:
3478 ret = parse_uses(ctx, data, &aug->child);
3479 break;
3480
3481 case YANG_ACTION:
3482 ret = parse_action(ctx, data, &aug->actions);
3483 break;
3484 case YANG_NOTIFICATION:
3485 ret = parse_notif(ctx, data, &aug->notifs);
3486 break;
3487 case YANG_CUSTOM:
3488 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &aug->exts);
3489 break;
3490 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003491 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003492 return LY_EVALID;
3493 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003494 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003495 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003496 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003497
3498 return ret;
3499}
3500
Michal Vaskoea5abea2018-09-18 13:10:54 +02003501/**
3502 * @brief Parse the uses statement.
3503 *
3504 * @param[in] ctx libyang context for logging.
3505 * @param[in,out] data Data to read from, always moved to currently handled character.
3506 * @param[in,out] siblings Siblings to add to.
3507 *
3508 * @return LY_ERR values.
3509 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003510static LY_ERR
3511parse_uses(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3512{
3513 LY_ERR ret = 0;
3514 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003515 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003516 enum yang_keyword kw;
3517 struct lysp_node *iter;
3518 struct lysp_node_uses *uses;
3519
3520 /* create structure */
3521 uses = calloc(1, sizeof *uses);
3522 LY_CHECK_ERR_RET(!uses, LOGMEM(ctx), LY_EMEM);
3523 uses->nodetype = LYS_USES;
3524
3525 /* insert into siblings */
3526 if (!*siblings) {
3527 *siblings = (struct lysp_node *)uses;
3528 } else {
3529 for (iter = *siblings; iter->next; iter = iter->next);
3530 iter->next = (struct lysp_node *)uses;
3531 }
3532
3533 /* get name */
3534 ret = get_string(ctx, data, Y_PREF_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003535 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003536
3537 if (buf) {
3538 uses->name = lydict_insert_zc(ctx, word);
3539 } else {
3540 uses->name = lydict_insert(ctx, word, word_len);
3541 }
3542
3543 /* parse substatements */
3544 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003545 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003546
3547 switch (kw) {
3548 case YANG_DESCRIPTION:
3549 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts);
3550 break;
3551 case YANG_IF_FEATURE:
3552 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &uses->iffeatures, Y_STR_ARG, &uses->exts);
3553 break;
3554 case YANG_REFERENCE:
3555 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &uses->ref, Y_STR_ARG, &uses->exts);
3556 break;
3557 case YANG_STATUS:
3558 ret = parse_status(ctx, data, &uses->flags, &uses->exts);
3559 break;
3560 case YANG_WHEN:
3561 ret = parse_when(ctx, data, &uses->when);
3562 break;
3563
3564 case YANG_REFINE:
3565 ret = parse_refine(ctx, data, &uses->refines);
3566 break;
3567 case YANG_AUGMENT:
3568 ret = parse_augment(ctx, data, &uses->augments);
3569 break;
3570 case YANG_CUSTOM:
3571 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &uses->exts);
3572 break;
3573 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003574 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003575 return LY_EVALID;
3576 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003577 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003578 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003579 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003580
3581 return ret;
3582}
3583
Michal Vaskoea5abea2018-09-18 13:10:54 +02003584/**
3585 * @brief Parse the case statement.
3586 *
3587 * @param[in] ctx libyang context for logging.
3588 * @param[in,out] data Data to read from, always moved to currently handled character.
3589 * @param[in,out] siblings Siblings to add to.
3590 *
3591 * @return LY_ERR values.
3592 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003593static LY_ERR
3594parse_case(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3595{
3596 LY_ERR ret = 0;
3597 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003598 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003599 enum yang_keyword kw;
3600 struct lysp_node *iter;
3601 struct lysp_node_case *cas;
3602
3603 /* create structure */
3604 cas = calloc(1, sizeof *cas);
3605 LY_CHECK_ERR_RET(!cas, LOGMEM(ctx), LY_EMEM);
3606 cas->nodetype = LYS_CASE;
3607
3608 /* insert into siblings */
3609 if (!*siblings) {
3610 *siblings = (struct lysp_node *)cas;
3611 } else {
3612 for (iter = *siblings; iter->next; iter = iter->next);
3613 iter->next = (struct lysp_node *)cas;
3614 }
3615
3616 /* get name */
3617 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003618 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003619
3620 if (buf) {
3621 cas->name = lydict_insert_zc(ctx, word);
3622 } else {
3623 cas->name = lydict_insert(ctx, word, word_len);
3624 }
3625
3626 /* parse substatements */
3627 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003628 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003629
3630 switch (kw) {
3631 case YANG_DESCRIPTION:
3632 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts);
3633 break;
3634 case YANG_IF_FEATURE:
3635 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cas->iffeatures, Y_STR_ARG, &cas->exts);
3636 break;
3637 case YANG_REFERENCE:
3638 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cas->ref, Y_STR_ARG, &cas->exts);
3639 break;
3640 case YANG_STATUS:
3641 ret = parse_status(ctx, data, &cas->flags, &cas->exts);
3642 break;
3643 case YANG_WHEN:
3644 ret = parse_when(ctx, data, &cas->when);
3645 break;
3646
3647 case YANG_ANYDATA:
3648 case YANG_ANYXML:
3649 ret = parse_any(ctx, data, kw, &cas->child);
3650 break;
3651 case YANG_CHOICE:
3652 ret = parse_case(ctx, data, &cas->child);
3653 break;
3654 case YANG_CONTAINER:
3655 ret = parse_container(ctx, data, &cas->child);
3656 break;
3657 case YANG_LEAF:
3658 ret = parse_leaf(ctx, data, &cas->child);
3659 break;
3660 case YANG_LEAF_LIST:
3661 ret = parse_leaflist(ctx, data, &cas->child);
3662 break;
3663 case YANG_LIST:
3664 ret = parse_list(ctx, data, &cas->child);
3665 break;
3666 case YANG_USES:
3667 ret = parse_uses(ctx, data, &cas->child);
3668 break;
3669 case YANG_CUSTOM:
3670 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cas->exts);
3671 break;
3672 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003673 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003674 return LY_EVALID;
3675 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003676 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003677 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003678 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003679
3680 return ret;
3681}
3682
Michal Vaskoea5abea2018-09-18 13:10:54 +02003683/**
3684 * @brief Parse the choice statement.
3685 *
3686 * @param[in] ctx libyang context for logging.
3687 * @param[in,out] data Data to read from, always moved to currently handled character.
3688 * @param[in,out] siblings Siblings to add to.
3689 *
3690 * @return LY_ERR values.
3691 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003692static LY_ERR
3693parse_choice(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3694{
3695 LY_ERR ret = 0;
3696 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003697 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003698 enum yang_keyword kw;
3699 struct lysp_node *iter;
3700 struct lysp_node_choice *choic;
3701
3702 /* create structure */
3703 choic = calloc(1, sizeof *choic);
3704 LY_CHECK_ERR_RET(!choic, LOGMEM(ctx), LY_EMEM);
3705 choic->nodetype = LYS_CHOICE;
3706
3707 /* insert into siblings */
3708 if (!*siblings) {
3709 *siblings = (struct lysp_node *)choic;
3710 } else {
3711 for (iter = *siblings; iter->next; iter = iter->next);
3712 iter->next = (struct lysp_node *)choic;
3713 }
3714
3715 /* get name */
3716 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003717 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003718
3719 if (buf) {
3720 choic->name = lydict_insert_zc(ctx, word);
3721 } else {
3722 choic->name = lydict_insert(ctx, word, word_len);
3723 }
3724
3725 /* parse substatements */
3726 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003727 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003728
3729 switch (kw) {
3730 case YANG_CONFIG:
3731 ret = parse_config(ctx, data, &choic->flags, &choic->exts);
3732 break;
3733 case YANG_DESCRIPTION:
3734 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &choic->dsc, Y_STR_ARG, &choic->exts);
3735 break;
3736 case YANG_IF_FEATURE:
3737 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &choic->iffeatures, Y_STR_ARG, &choic->exts);
3738 break;
3739 case YANG_MANDATORY:
3740 ret = parse_mandatory(ctx, data, &choic->flags, &choic->exts);
3741 break;
3742 case YANG_REFERENCE:
3743 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &choic->ref, Y_STR_ARG, &choic->exts);
3744 break;
3745 case YANG_STATUS:
3746 ret = parse_status(ctx, data, &choic->flags, &choic->exts);
3747 break;
3748 case YANG_WHEN:
3749 ret = parse_when(ctx, data, &choic->when);
3750 break;
3751 case YANG_DEFAULT:
3752 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &choic->dflt, Y_IDENTIF_ARG, &choic->exts);
3753 break;
3754
3755 case YANG_ANYDATA:
3756 case YANG_ANYXML:
3757 ret = parse_any(ctx, data, kw, &choic->child);
3758 break;
3759 case YANG_CASE:
3760 ret = parse_case(ctx, data, &choic->child);
3761 break;
3762 case YANG_CHOICE:
3763 ret = parse_choice(ctx, data, &choic->child);
3764 break;
3765 case YANG_CONTAINER:
3766 ret = parse_container(ctx, data, &choic->child);
3767 break;
3768 case YANG_LEAF:
3769 ret = parse_leaf(ctx, data, &choic->child);
3770 break;
3771 case YANG_LEAF_LIST:
3772 ret = parse_leaflist(ctx, data, &choic->child);
3773 break;
3774 case YANG_LIST:
3775 ret = parse_list(ctx, data, &choic->child);
3776 break;
3777 case YANG_CUSTOM:
3778 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &choic->exts);
3779 break;
3780 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003781 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003782 return LY_EVALID;
3783 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003784 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003785 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003786 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003787
3788 return ret;
3789}
3790
Michal Vaskoea5abea2018-09-18 13:10:54 +02003791/**
3792 * @brief Parse the container statement.
3793 *
3794 * @param[in] ctx libyang context for logging.
3795 * @param[in,out] data Data to read from, always moved to currently handled character.
3796 * @param[in,out] siblings Siblings to add to.
3797 *
3798 * @return LY_ERR values.
3799 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003800static LY_ERR
3801parse_container(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3802{
3803 LY_ERR ret = 0;
3804 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003805 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003806 enum yang_keyword kw;
3807 struct lysp_node *iter;
3808 struct lysp_node_container *cont;
3809
3810 /* create structure */
3811 cont = calloc(1, sizeof *cont);
3812 LY_CHECK_ERR_RET(!cont, LOGMEM(ctx), LY_EMEM);
3813 cont->nodetype = LYS_CONTAINER;
3814
3815 /* insert into siblings */
3816 if (!*siblings) {
3817 *siblings = (struct lysp_node *)cont;
3818 } else {
3819 for (iter = *siblings; iter->next; iter = iter->next);
3820 iter->next = (struct lysp_node *)cont;
3821 }
3822
3823 /* get name */
3824 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003825 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003826
3827 if (buf) {
3828 cont->name = lydict_insert_zc(ctx, word);
3829 } else {
3830 cont->name = lydict_insert(ctx, word, word_len);
3831 }
3832
3833 /* parse substatements */
3834 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003835 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003836
3837 switch (kw) {
3838 case YANG_CONFIG:
3839 ret = parse_config(ctx, data, &cont->flags, &cont->exts);
3840 break;
3841 case YANG_DESCRIPTION:
3842 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &cont->dsc, Y_STR_ARG, &cont->exts);
3843 break;
3844 case YANG_IF_FEATURE:
3845 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &cont->iffeatures, Y_STR_ARG, &cont->exts);
3846 break;
3847 case YANG_REFERENCE:
3848 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &cont->ref, Y_STR_ARG, &cont->exts);
3849 break;
3850 case YANG_STATUS:
3851 ret = parse_status(ctx, data, &cont->flags, &cont->exts);
3852 break;
3853 case YANG_WHEN:
3854 ret = parse_when(ctx, data, &cont->when);
3855 break;
3856 case YANG_PRESENCE:
3857 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PRESENCE, 0, &cont->presence, Y_STR_ARG, &cont->exts);
3858 break;
3859
3860 case YANG_ANYDATA:
3861 case YANG_ANYXML:
3862 ret = parse_any(ctx, data, kw, &cont->child);
3863 break;
3864 case YANG_CHOICE:
3865 ret = parse_choice(ctx, data, &cont->child);
3866 break;
3867 case YANG_CONTAINER:
3868 ret = parse_container(ctx, data, &cont->child);
3869 break;
3870 case YANG_LEAF:
3871 ret = parse_leaf(ctx, data, &cont->child);
3872 break;
3873 case YANG_LEAF_LIST:
3874 ret = parse_leaflist(ctx, data, &cont->child);
3875 break;
3876 case YANG_LIST:
3877 ret = parse_list(ctx, data, &cont->child);
3878 break;
3879 case YANG_USES:
3880 ret = parse_uses(ctx, data, &cont->child);
3881 break;
3882
3883 case YANG_TYPEDEF:
3884 ret = parse_typedef(ctx, data, &cont->typedefs);
3885 break;
3886 case YANG_MUST:
3887 ret = parse_restrs(ctx, data, kw, &cont->musts);
3888 break;
3889 case YANG_ACTION:
3890 ret = parse_action(ctx, data, &cont->actions);
3891 break;
3892 case YANG_GROUPING:
3893 ret = parse_grouping(ctx, data, &cont->groupings);
3894 break;
3895 case YANG_NOTIFICATION:
3896 ret = parse_notif(ctx, data, &cont->notifs);
3897 break;
3898 case YANG_CUSTOM:
3899 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cont->exts);
3900 break;
3901 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02003902 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02003903 return LY_EVALID;
3904 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003905 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003906 }
Radek Krejcic59bc972018-09-17 16:13:06 +02003907 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003908
3909 return ret;
3910}
3911
Michal Vaskoea5abea2018-09-18 13:10:54 +02003912/**
3913 * @brief Parse the list statement.
3914 *
3915 * @param[in] ctx libyang context for logging.
3916 * @param[in,out] data Data to read from, always moved to currently handled character.
3917 * @param[in,out] siblings Siblings to add to.
3918 *
3919 * @return LY_ERR values.
3920 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02003921static LY_ERR
3922parse_list(struct ly_ctx *ctx, const char **data, struct lysp_node **siblings)
3923{
3924 LY_ERR ret = 0;
3925 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02003926 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02003927 enum yang_keyword kw;
3928 struct lysp_node *iter;
3929 struct lysp_node_list *list;
3930
3931 /* create structure */
3932 list = calloc(1, sizeof *list);
3933 LY_CHECK_ERR_RET(!list, LOGMEM(ctx), LY_EMEM);
3934 list->nodetype = LYS_LIST;
3935
3936 /* insert into siblings */
3937 if (!*siblings) {
3938 *siblings = (struct lysp_node *)list;
3939 } else {
3940 for (iter = *siblings; iter->next; iter = iter->next);
3941 iter->next = (struct lysp_node *)list;
3942 }
3943
3944 /* get name */
3945 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02003946 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003947
3948 if (buf) {
3949 list->name = lydict_insert_zc(ctx, word);
3950 } else {
3951 list->name = lydict_insert(ctx, word, word_len);
3952 }
3953
3954 /* parse substatements */
3955 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02003956 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02003957
3958 switch (kw) {
3959 case YANG_CONFIG:
3960 ret = parse_config(ctx, data, &list->flags, &list->exts);
3961 break;
3962 case YANG_DESCRIPTION:
3963 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &list->dsc, Y_STR_ARG, &list->exts);
3964 break;
3965 case YANG_IF_FEATURE:
3966 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &list->iffeatures, Y_STR_ARG, &list->exts);
3967 break;
3968 case YANG_REFERENCE:
3969 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &list->ref, Y_STR_ARG, &list->exts);
3970 break;
3971 case YANG_STATUS:
3972 ret = parse_status(ctx, data, &list->flags, &list->exts);
3973 break;
3974 case YANG_WHEN:
3975 ret = parse_when(ctx, data, &list->when);
3976 break;
3977 case YANG_KEY:
3978 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_KEY, 0, &list->key, Y_STR_ARG, &list->exts);
3979 break;
3980 case YANG_MAX_ELEMENTS:
3981 ret = parse_maxelements(ctx, data, &list->max, &list->flags, &list->exts);
3982 break;
3983 case YANG_MIN_ELEMENTS:
3984 ret = parse_minelements(ctx, data, &list->min, &list->flags, &list->exts);
3985 break;
3986 case YANG_ORDERED_BY:
3987 ret = parse_orderedby(ctx, data, &list->flags, &list->exts);
3988 break;
3989 case YANG_UNIQUE:
3990 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, &list->uniques, Y_STR_ARG, &list->exts);
3991 break;
3992
3993 case YANG_ANYDATA:
3994 case YANG_ANYXML:
3995 ret = parse_any(ctx, data, kw, &list->child);
3996 break;
3997 case YANG_CHOICE:
3998 ret = parse_choice(ctx, data, &list->child);
3999 break;
4000 case YANG_CONTAINER:
4001 ret = parse_container(ctx, data, &list->child);
4002 break;
4003 case YANG_LEAF:
4004 ret = parse_leaf(ctx, data, &list->child);
4005 break;
4006 case YANG_LEAF_LIST:
4007 ret = parse_leaflist(ctx, data, &list->child);
4008 break;
4009 case YANG_LIST:
4010 ret = parse_list(ctx, data, &list->child);
4011 break;
4012 case YANG_USES:
4013 ret = parse_uses(ctx, data, &list->child);
4014 break;
4015
4016 case YANG_TYPEDEF:
4017 ret = parse_typedef(ctx, data, &list->typedefs);
4018 break;
4019 case YANG_MUST:
4020 ret = parse_restrs(ctx, data, kw, &list->musts);
4021 break;
4022 case YANG_ACTION:
4023 ret = parse_action(ctx, data, &list->actions);
4024 break;
4025 case YANG_GROUPING:
4026 ret = parse_grouping(ctx, data, &list->groupings);
4027 break;
4028 case YANG_NOTIFICATION:
4029 ret = parse_notif(ctx, data, &list->notifs);
4030 break;
4031 case YANG_CUSTOM:
4032 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &list->exts);
4033 break;
4034 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004035 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004036 return LY_EVALID;
4037 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004038 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004039 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004040 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004041
4042 return ret;
4043}
4044
Michal Vaskoea5abea2018-09-18 13:10:54 +02004045/**
4046 * @brief Parse the yin-element statement.
4047 *
4048 * @param[in] ctx libyang context for logging.
4049 * @param[in,out] data Data to read from, always moved to currently handled character.
4050 * @param[in,out] flags Flags to write to.
4051 * @param[in,out] exts Extension instances to add to.
4052 *
4053 * @return LY_ERR values.
4054 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004055static LY_ERR
4056parse_yinelement(struct ly_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
4057{
4058 LY_ERR ret = 0;
4059 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004060 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004061 enum yang_keyword kw;
4062
4063 if (*flags & LYS_YINELEM_MASK) {
4064 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "yin-element");
4065 return LY_EVALID;
4066 }
4067
4068 /* get value */
4069 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004070 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004071
4072 if ((word_len == 4) && !strncmp(word, "true", word_len)) {
4073 *flags |= LYS_YINELEM_TRUE;
4074 } else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
4075 *flags |= LYS_YINELEM_FALSE;
4076 } else {
4077 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "yin-element");
4078 free(buf);
4079 return LY_EVALID;
4080 }
4081 free(buf);
4082
4083 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004084 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004085
4086 switch (kw) {
4087 case YANG_CUSTOM:
4088 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_YINELEM, 0, exts);
Radek Krejcic59bc972018-09-17 16:13:06 +02004089 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004090 break;
4091 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004092 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004093 return LY_EVALID;
4094 }
4095 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004096 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004097
4098 return ret;
4099}
4100
Michal Vaskoea5abea2018-09-18 13:10:54 +02004101/**
4102 * @brief Parse the yin-element statement.
4103 *
4104 * @param[in] ctx libyang context for logging.
4105 * @param[in,out] data Data to read from, always moved to currently handled character.
4106 * @param[in,out] argument Value to write to.
4107 * @param[in,out] flags Flags to write to.
4108 * @param[in,out] exts Extension instances to add to.
4109 *
4110 * @return LY_ERR values.
4111 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004112static LY_ERR
4113parse_argument(struct ly_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
4114{
4115 LY_ERR ret = 0;
4116 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004117 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004118 enum yang_keyword kw;
4119
4120 if (*argument) {
4121 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_DUPSTMT, "argument");
4122 return LY_EVALID;
4123 }
4124
4125 /* get value */
4126 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004127 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004128
4129 if (buf) {
4130 *argument = lydict_insert_zc(ctx, word);
4131 } else {
4132 *argument = lydict_insert(ctx, word, word_len);
4133 }
4134
4135 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004136 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004137
4138 switch (kw) {
4139 case YANG_YIN_ELEMENT:
4140 ret = parse_yinelement(ctx, data, flags, exts);
4141 break;
4142 case YANG_CUSTOM:
4143 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ARGUMENT, 0, exts);
4144 break;
4145 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004146 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004147 return LY_EVALID;
4148 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004149 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004150 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004151 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004152
4153 return ret;
4154}
4155
Michal Vaskoea5abea2018-09-18 13:10:54 +02004156/**
4157 * @brief Parse the extension statement.
4158 *
4159 * @param[in] ctx libyang context for logging.
4160 * @param[in,out] data Data to read from, always moved to currently handled character.
4161 * @param[in,out] extensions Extensions to add to.
4162 *
4163 * @return LY_ERR values.
4164 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004165static LY_ERR
4166parse_extension(struct ly_ctx *ctx, const char **data, struct lysp_ext **extensions)
4167{
4168 LY_ERR ret = 0;
4169 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004170 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004171 enum yang_keyword kw;
4172 struct lysp_ext *ex;
4173
4174 LYSP_ARRAY_NEW_RET(ctx, extensions, ex, LY_EMEM);
4175
4176 /* get value */
4177 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004178 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004179
4180 if (buf) {
4181 ex->name = lydict_insert_zc(ctx, word);
4182 } else {
4183 ex->name = lydict_insert(ctx, word, word_len);
4184 }
4185
4186 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004187 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004188
4189 switch (kw) {
4190 case YANG_DESCRIPTION:
4191 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts);
4192 break;
4193 case YANG_REFERENCE:
4194 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ex->ref, Y_STR_ARG, &ex->exts);
4195 break;
4196 case YANG_STATUS:
4197 ret = parse_status(ctx, data, &ex->flags, &ex->exts);
4198 break;
4199 case YANG_ARGUMENT:
4200 ret = parse_argument(ctx, data, &ex->argument, &ex->flags, &ex->exts);
4201 break;
4202 case YANG_CUSTOM:
4203 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ex->exts);
4204 break;
4205 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004206 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004207 return LY_EVALID;
4208 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004209 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004210 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004211 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004212
4213 return ret;
4214}
4215
Michal Vaskoea5abea2018-09-18 13:10:54 +02004216/**
4217 * @brief Parse the deviate statement.
4218 *
4219 * @param[in] ctx libyang context for logging.
4220 * @param[in,out] data Data to read from, always moved to currently handled character.
4221 * @param[in,out] deviates Deviates to add to.
4222 *
4223 * @return LY_ERR values.
4224 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004225static LY_ERR
4226parse_deviate(struct ly_ctx *ctx, const char **data, struct lysp_deviate **deviates)
4227{
4228 LY_ERR ret = 0;
4229 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004230 size_t word_len, dev_mod;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004231 enum yang_keyword kw;
4232 struct lysp_deviate *iter, *d;
4233 struct lysp_deviate_add *d_add = NULL;
4234 struct lysp_deviate_rpl *d_rpl = NULL;
4235 struct lysp_deviate_del *d_del = NULL;
4236 const char **d_units, ***d_uniques, ***d_dflts;
4237 struct lysp_restr **d_musts;
4238 uint16_t *d_flags;
4239 uint32_t *d_min, *d_max;
4240
4241 /* get value */
4242 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004243 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004244
4245 if ((word_len == 13) && !strncmp(word, "not-supported", word_len)) {
4246 dev_mod = LYS_DEV_NOT_SUPPORTED;
4247 } else if ((word_len == 3) && !strncmp(word, "add", word_len)) {
4248 dev_mod = LYS_DEV_ADD;
4249 } else if ((word_len == 7) && !strncmp(word, "replace", word_len)) {
4250 dev_mod = LYS_DEV_REPLACE;
4251 } else if ((word_len == 6) && !strncmp(word, "delete", word_len)) {
4252 dev_mod = LYS_DEV_DELETE;
4253 } else {
4254 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, word_len, word, "deviate");
4255 free(buf);
4256 return LY_EVALID;
4257 }
4258 free(buf);
4259
4260 /* create structure */
4261 switch (dev_mod) {
4262 case LYS_DEV_NOT_SUPPORTED:
4263 d = calloc(1, sizeof *d);
4264 LY_CHECK_ERR_RET(!d, LOGMEM(ctx), LY_EMEM);
4265 break;
4266 case LYS_DEV_ADD:
4267 d_add = calloc(1, sizeof *d_add);
4268 LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx), LY_EMEM);
4269 d = (struct lysp_deviate *)d_add;
4270 d_units = &d_add->units;
4271 d_uniques = &d_add->uniques;
4272 d_dflts = &d_add->dflts;
4273 d_musts = &d_add->musts;
4274 d_flags = &d_add->flags;
4275 d_min = &d_add->min;
4276 d_max = &d_add->max;
4277 break;
4278 case LYS_DEV_REPLACE:
4279 d_rpl = calloc(1, sizeof *d_rpl);
4280 LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx), LY_EMEM);
4281 d = (struct lysp_deviate *)d_rpl;
4282 d_units = &d_rpl->units;
4283 d_flags = &d_rpl->flags;
4284 d_min = &d_rpl->min;
4285 d_max = &d_rpl->max;
4286 break;
4287 case LYS_DEV_DELETE:
4288 d_del = calloc(1, sizeof *d_del);
4289 LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx), LY_EMEM);
4290 d = (struct lysp_deviate *)d_del;
4291 d_units = &d_del->units;
4292 d_uniques = &d_del->uniques;
4293 d_dflts = &d_del->dflts;
4294 d_musts = &d_del->musts;
4295 d_flags = &d_del->flags;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004296 break;
4297 default:
4298 assert(0);
4299 LOGINT_RET(ctx);
4300 }
4301 d->mod = dev_mod;
4302
4303 /* insert into siblings */
4304 if (!*deviates) {
4305 *deviates = d;
4306 } else {
4307 for (iter = *deviates; iter->next; iter = iter->next);
4308 iter->next = d;
4309 }
4310
4311 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004312 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004313
4314 switch (kw) {
4315 case YANG_CONFIG:
4316 switch (dev_mod) {
4317 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004318 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004319 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004320 return LY_EVALID;
4321 default:
4322 ret = parse_config(ctx, data, d_flags, &d->exts);
4323 break;
4324 }
4325 break;
4326 case YANG_DEFAULT:
4327 switch (dev_mod) {
4328 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004329 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004330 return LY_EVALID;
4331 case LYS_DEV_REPLACE:
4332 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &d_rpl->dflt, Y_STR_ARG, &d->exts);
4333 break;
4334 default:
4335 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_DEFAULT, d_dflts, Y_STR_ARG, &d->exts);
4336 break;
4337 }
4338 break;
4339 case YANG_MANDATORY:
4340 switch (dev_mod) {
4341 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004342 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004343 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004344 return LY_EVALID;
4345 default:
4346 ret = parse_mandatory(ctx, data, d_flags, &d->exts);
4347 break;
4348 }
4349 break;
4350 case YANG_MAX_ELEMENTS:
4351 switch (dev_mod) {
4352 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004353 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004354 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004355 return LY_EVALID;
4356 default:
4357 ret = parse_maxelements(ctx, data, d_max, d_flags, &d->exts);
4358 break;
4359 }
4360 break;
4361 case YANG_MIN_ELEMENTS:
4362 switch (dev_mod) {
4363 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004364 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004365 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004366 return LY_EVALID;
4367 default:
4368 ret = parse_minelements(ctx, data, d_min, d_flags, &d->exts);
4369 break;
4370 }
4371 break;
4372 case YANG_MUST:
4373 switch (dev_mod) {
4374 case LYS_DEV_NOT_SUPPORTED:
Michal Vasko492bec72018-09-18 13:11:10 +02004375 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004376 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004377 return LY_EVALID;
4378 default:
4379 ret = parse_restrs(ctx, data, kw, d_musts);
4380 break;
4381 }
4382 break;
4383 case YANG_TYPE:
4384 switch (dev_mod) {
4385 case LYS_DEV_NOT_SUPPORTED:
4386 case LYS_DEV_ADD:
4387 case LYS_DEV_DELETE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004388 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004389 return LY_EVALID;
4390 default:
4391 d_rpl->type = calloc(1, sizeof *d_rpl->type);
4392 LY_CHECK_ERR_RET(!d_rpl->type, LOGMEM(ctx), LY_EMEM);
4393 ret = parse_type(ctx, data, d_rpl->type);
4394 break;
4395 }
4396 break;
4397 case YANG_UNIQUE:
4398 switch (dev_mod) {
4399 case LYS_DEV_NOT_SUPPORTED:
4400 case LYS_DEV_REPLACE:
Radek Krejcic59bc972018-09-17 16:13:06 +02004401 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004402 return LY_EVALID;
4403 default:
4404 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts);
4405 break;
4406 }
4407 break;
4408 case YANG_UNITS:
4409 switch (dev_mod) {
4410 case LYS_DEV_NOT_SUPPORTED:
Radek Krejcic59bc972018-09-17 16:13:06 +02004411 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004412 return LY_EVALID;
4413 default:
4414 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts);
4415 break;
4416 }
4417 break;
4418 case YANG_CUSTOM:
4419 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &d->exts);
4420 break;
4421 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004422 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004423 return LY_EVALID;
4424 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004425 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004426 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004427 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004428
4429 return ret;
4430}
4431
Michal Vaskoea5abea2018-09-18 13:10:54 +02004432/**
4433 * @brief Parse the deviation statement.
4434 *
4435 * @param[in] ctx libyang context for logging.
4436 * @param[in,out] data Data to read from, always moved to currently handled character.
4437 * @param[in,out] deviations Deviations to add to.
4438 *
4439 * @return LY_ERR values.
4440 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004441static LY_ERR
4442parse_deviation(struct ly_ctx *ctx, const char **data, struct lysp_deviation **deviations)
4443{
4444 LY_ERR ret = 0;
4445 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004446 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004447 enum yang_keyword kw;
4448 struct lysp_deviation *dev;
4449
4450 LYSP_ARRAY_NEW_RET(ctx, deviations, dev, LY_EMEM);
4451
4452 /* get value */
4453 ret = get_string(ctx, data, Y_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004454 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004455
4456 if (buf) {
4457 dev->nodeid = lydict_insert_zc(ctx, word);
4458 } else {
4459 dev->nodeid = lydict_insert(ctx, word, word_len);
4460 }
4461
4462 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004463 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004464
4465 switch (kw) {
4466 case YANG_DESCRIPTION:
4467 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts);
4468 break;
4469 case YANG_DEVIATE:
4470 ret = parse_deviate(ctx, data, &dev->deviates);
4471 break;
4472 case YANG_REFERENCE:
4473 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &dev->ref, Y_STR_ARG, &dev->exts);
4474 break;
4475 case YANG_CUSTOM:
4476 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &dev->exts);
4477 break;
4478 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004479 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004480 return LY_EVALID;
4481 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004482 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004483 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004484 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004485
4486 /* mandatory substatements */
4487 if (!dev->deviates) {
4488 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "deviate", "deviation");
4489 return LY_EVALID;
4490 }
4491
4492 return ret;
4493}
4494
Michal Vaskoea5abea2018-09-18 13:10:54 +02004495/**
4496 * @brief Parse the feature statement.
4497 *
4498 * @param[in] ctx libyang context for logging.
4499 * @param[in,out] data Data to read from, always moved to currently handled character.
4500 * @param[in,out] features Features to add to.
4501 *
4502 * @return LY_ERR values.
4503 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004504static LY_ERR
4505parse_feature(struct ly_ctx *ctx, const char **data, struct lysp_feature **features)
4506{
4507 LY_ERR ret = 0;
4508 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004509 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004510 enum yang_keyword kw;
4511 struct lysp_feature *feat;
4512
4513 LYSP_ARRAY_NEW_RET(ctx, features, feat, LY_EMEM);
4514
4515 /* get value */
4516 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004517 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004518
4519 if (buf) {
4520 feat->name = lydict_insert_zc(ctx, word);
4521 } else {
4522 feat->name = lydict_insert(ctx, word, word_len);
4523 }
4524
4525 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004526 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004527
4528 switch (kw) {
4529 case YANG_DESCRIPTION:
4530 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts);
4531 break;
4532 case YANG_IF_FEATURE:
4533 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &feat->iffeatures, Y_STR_ARG, &feat->exts);
4534 break;
4535 case YANG_REFERENCE:
4536 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &feat->ref, Y_STR_ARG, &feat->exts);
4537 break;
4538 case YANG_STATUS:
4539 ret = parse_status(ctx, data, &feat->flags, &feat->exts);
4540 break;
4541 case YANG_CUSTOM:
4542 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &feat->exts);
4543 break;
4544 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004545 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004546 return LY_EMEM;
4547 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004548 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004549 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004550 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004551
4552 return ret;
4553}
4554
Michal Vaskoea5abea2018-09-18 13:10:54 +02004555/**
4556 * @brief Parse the identity statement.
4557 *
4558 * @param[in] ctx libyang context for logging.
4559 * @param[in,out] data Data to read from, always moved to currently handled character.
4560 * @param[in,out] identities Identities to add to.
4561 *
4562 * @return LY_ERR values.
4563 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004564static LY_ERR
4565parse_identity(struct ly_ctx *ctx, const char **data, struct lysp_ident **identities)
4566{
4567 LY_ERR ret = 0;
4568 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004569 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004570 enum yang_keyword kw;
4571 struct lysp_ident *ident;
4572
4573 LYSP_ARRAY_NEW_RET(ctx, identities, ident, LY_EMEM);
4574
4575 /* get value */
4576 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004577 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004578
4579 if (buf) {
4580 ident->name = lydict_insert_zc(ctx, word);
4581 } else {
4582 ident->name = lydict_insert(ctx, word, word_len);
4583 }
4584
4585 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004586 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004587
4588 switch (kw) {
4589 case YANG_DESCRIPTION:
4590 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts);
4591 break;
4592 case YANG_IF_FEATURE:
4593 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_IFFEATURE, &ident->iffeatures, Y_STR_ARG, &ident->exts);
4594 break;
4595 case YANG_REFERENCE:
4596 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &ident->ref, Y_STR_ARG, &ident->exts);
4597 break;
4598 case YANG_STATUS:
4599 ret = parse_status(ctx, data, &ident->flags, &ident->exts);
4600 break;
4601 case YANG_BASE:
4602 ret = parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts);
4603 break;
4604 case YANG_CUSTOM:
4605 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ident->exts);
4606 break;
4607 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004608 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004609 return LY_EVALID;
4610 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004611 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004612 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004613 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004614
4615 return ret;
4616}
4617
Michal Vaskoea5abea2018-09-18 13:10:54 +02004618/**
4619 * @brief Parse the module or submodule statement.
4620 *
4621 * @param[in] ctx libyang context for logging.
4622 * @param[in,out] data Data to read from, always moved to currently handled character.
4623 * @param[in,out] mod Module to write to.
4624 *
4625 * @return LY_ERR values.
4626 */
Michal Vasko7fbc8162018-09-17 10:35:16 +02004627static LY_ERR
4628parse_sub_module(struct ly_ctx *ctx, const char **data, struct lysp_module *mod)
4629{
4630 LY_ERR ret = 0;
4631 char *buf, *word;
Radek Krejciefd22f62018-09-27 11:47:58 +02004632 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004633 enum yang_keyword kw, prev_kw = 0;
4634 enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
4635
4636 /* (sub)module name */
4637 ret = get_string(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004638 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004639
4640 if (buf) {
4641 mod->name = lydict_insert_zc(ctx, word);
4642 } else {
4643 mod->name = lydict_insert(ctx, word, word_len);
4644 }
4645
4646 YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004647 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004648
4649 switch (kw) {
4650 /* module header */
4651 case YANG_NAMESPACE:
4652 case YANG_PREFIX:
4653 if (mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004654 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004655 return LY_EVALID;
4656 }
4657 /* fallthrough */
4658 case YANG_BELONGS_TO:
4659 if ((kw == YANG_BELONGS_TO) && !mod->submodule) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004660 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004661 return LY_EVALID;
4662 }
4663 /* fallthrough */
4664 case YANG_YANG_VERSION:
4665 if (mod_stmt > Y_MOD_MODULE_HEADER) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004666 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004667 return LY_EVALID;
4668 }
4669 break;
4670 /* linkage */
4671 case YANG_INCLUDE:
4672 case YANG_IMPORT:
4673 if (mod_stmt > Y_MOD_LINKAGE) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004674 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004675 return LY_EVALID;
4676 }
4677 mod_stmt = Y_MOD_LINKAGE;
4678 break;
4679 /* meta */
4680 case YANG_ORGANIZATION:
4681 case YANG_CONTACT:
4682 case YANG_DESCRIPTION:
4683 case YANG_REFERENCE:
4684 if (mod_stmt > Y_MOD_META) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004685 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004686 return LY_EVALID;
4687 }
4688 mod_stmt = Y_MOD_META;
4689 break;
4690
4691 /* revision */
4692 case YANG_REVISION:
4693 if (mod_stmt > Y_MOD_REVISION) {
Radek Krejcic59bc972018-09-17 16:13:06 +02004694 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004695 return LY_EVALID;
4696 }
4697 mod_stmt = Y_MOD_REVISION;
4698 break;
4699
4700 /* body */
4701 case YANG_ANYDATA:
4702 case YANG_ANYXML:
4703 case YANG_AUGMENT:
4704 case YANG_CHOICE:
4705 case YANG_CONTAINER:
4706 case YANG_DEVIATION:
4707 case YANG_EXTENSION:
4708 case YANG_FEATURE:
4709 case YANG_GROUPING:
4710 case YANG_IDENTITY:
4711 case YANG_LEAF:
4712 case YANG_LEAF_LIST:
4713 case YANG_LIST:
4714 case YANG_NOTIFICATION:
4715 case YANG_RPC:
4716 case YANG_TYPEDEF:
4717 case YANG_USES:
4718 case YANG_CUSTOM:
4719 mod_stmt = Y_MOD_BODY;
4720 break;
4721 default:
4722 /* error handled in the next switch */
4723 break;
4724 }
4725 prev_kw = kw;
4726
4727 switch (kw) {
4728 /* module header */
4729 case YANG_YANG_VERSION:
4730 ret = parse_yangversion(ctx, data, mod);
4731 break;
4732 case YANG_NAMESPACE:
4733 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_NAMESPACE, 0, &mod->ns, Y_STR_ARG, &mod->exts);
4734 break;
4735 case YANG_PREFIX:
4736 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_PREFIX, 0, &mod->prefix, Y_IDENTIF_ARG, &mod->exts);
4737 break;
4738 case YANG_BELONGS_TO:
4739 ret = parse_belongsto(ctx, data, &mod->belongsto, &mod->prefix, &mod->exts);
4740 break;
4741
4742 /* linkage */
4743 case YANG_INCLUDE:
4744 ret = parse_include(ctx, data, &mod->includes);
4745 break;
4746 case YANG_IMPORT:
4747 ret = parse_import(ctx, data, &mod->imports);
4748 break;
4749
4750 /* meta */
4751 case YANG_ORGANIZATION:
4752 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_ORGANIZATION, 0, &mod->org, Y_STR_ARG, &mod->exts);
4753 break;
4754 case YANG_CONTACT:
4755 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_CONTACT, 0, &mod->contact, Y_STR_ARG, &mod->exts);
4756 break;
4757 case YANG_DESCRIPTION:
4758 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &mod->dsc, Y_STR_ARG, &mod->exts);
4759 break;
4760 case YANG_REFERENCE:
4761 ret = parse_text_field(ctx, data, LYEXT_SUBSTMT_REFERENCE, 0, &mod->ref, Y_STR_ARG, &mod->exts);
4762 break;
4763
4764 /* revision */
4765 case YANG_REVISION:
4766 ret = parse_revision(ctx, data, &mod->revs);
4767 break;
4768
4769 /* body */
4770 case YANG_ANYDATA:
4771 case YANG_ANYXML:
4772 ret = parse_any(ctx, data, kw, &mod->data);
4773 break;
4774 case YANG_CHOICE:
4775 ret = parse_choice(ctx, data, &mod->data);
4776 break;
4777 case YANG_CONTAINER:
4778 ret = parse_container(ctx, data, &mod->data);
4779 break;
4780 case YANG_LEAF:
4781 ret = parse_leaf(ctx, data, &mod->data);
4782 break;
4783 case YANG_LEAF_LIST:
4784 ret = parse_leaflist(ctx, data, &mod->data);
4785 break;
4786 case YANG_LIST:
4787 ret = parse_list(ctx, data, &mod->data);
4788 break;
4789 case YANG_USES:
4790 ret = parse_uses(ctx, data, &mod->data);
4791 break;
4792
4793 case YANG_AUGMENT:
4794 ret = parse_augment(ctx, data, &mod->augments);
4795 break;
4796 case YANG_DEVIATION:
4797 ret = parse_deviation(ctx, data, &mod->deviations);
4798 break;
4799 case YANG_EXTENSION:
4800 ret = parse_extension(ctx, data, &mod->extensions);
4801 break;
4802 case YANG_FEATURE:
4803 ret = parse_feature(ctx, data, &mod->features);
4804 break;
4805 case YANG_GROUPING:
4806 ret = parse_grouping(ctx, data, &mod->groupings);
4807 break;
4808 case YANG_IDENTITY:
4809 ret = parse_identity(ctx, data, &mod->identities);
4810 break;
4811 case YANG_NOTIFICATION:
4812 ret = parse_notif(ctx, data, &mod->notifs);
4813 break;
4814 case YANG_RPC:
4815 ret = parse_action(ctx, data, &mod->rpcs);
4816 break;
4817 case YANG_TYPEDEF:
4818 ret = parse_typedef(ctx, data, &mod->typedefs);
4819 break;
4820 case YANG_CUSTOM:
4821 ret = parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &mod->exts);
4822 break;
4823
4824 default:
Radek Krejcic59bc972018-09-17 16:13:06 +02004825 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), mod->submodule ? "submodule" : "module");
Michal Vasko7fbc8162018-09-17 10:35:16 +02004826 return LY_EVALID;
4827 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004828 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004829 }
Radek Krejcic59bc972018-09-17 16:13:06 +02004830 LY_CHECK_RET(ret);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004831
4832 /* mandatory substatements */
4833 if (mod->submodule) {
4834 if (!mod->belongsto) {
4835 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "belongs-to", "submodule");
4836 return LY_EVALID;
4837 }
4838 } else {
4839 if (!mod->ns) {
4840 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "namespace", "module");
4841 return LY_EVALID;
4842 } else if (!mod->prefix) {
4843 LOGVAL(ctx, LY_VLOG_NONE, NULL, LY_VCODE_MISSTMT, "prefix", "module");
4844 return LY_EVALID;
4845 }
4846 }
4847
4848 return ret;
4849}
4850
Radek Krejci531fe5b2018-09-19 11:14:13 +02004851static unsigned int
4852lysp_get_data_line(const char *start, const char *stop)
4853{
4854 unsigned int i, length, line = 1;
4855
4856 length = stop - start;
4857 for (i = 0; i < length; ++i) {
4858 if (start[i] == '\n') {
4859 ++line;
4860 }
4861 }
4862
4863 return line;
4864}
4865
Radek Krejcid4557c62018-09-17 11:42:09 +02004866LY_ERR
Michal Vasko7fbc8162018-09-17 10:35:16 +02004867yang_parse(struct ly_ctx *ctx, const char *data, struct lysp_module **mod_p)
4868{
4869 LY_ERR ret = 0;
4870 char *word, *buf;
Radek Krejciefd22f62018-09-27 11:47:58 +02004871 size_t word_len;
Michal Vasko7fbc8162018-09-17 10:35:16 +02004872 const char *data_start;
4873 enum yang_keyword kw;
4874 struct lysp_module *mod;
4875
4876 data_start = data;
4877
4878 /* "module"/"submodule" */
4879 ret = get_keyword(ctx, &data, &kw, &word, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004880 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004881
4882 if ((kw != YANG_MODULE) && (kw != YANG_SUBMODULE)) {
4883 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".\n",
Radek Krejcic59bc972018-09-17 16:13:06 +02004884 ly_stmt2str(kw));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004885 goto error;
4886 }
4887
4888 mod = calloc(1, sizeof *mod);
4889 LY_CHECK_ERR_GOTO(!mod, LOGMEM(ctx), error);
4890 if (kw == YANG_SUBMODULE) {
4891 mod->submodule = 1;
4892 }
4893
4894 /* substatements */
4895 ret = parse_sub_module(ctx, &data, mod);
Radek Krejcic59bc972018-09-17 16:13:06 +02004896 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004897
4898 /* read some trailing spaces or new lines */
4899 ret = get_string(ctx, &data, Y_MAYBE_STR_ARG, &word, &buf, &word_len);
Radek Krejcic59bc972018-09-17 16:13:06 +02004900 LY_CHECK_GOTO(ret, error);
Michal Vasko7fbc8162018-09-17 10:35:16 +02004901
4902 if (word) {
4903 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected end-of-file.",
4904 word_len, word);
4905 free(buf);
4906 goto error;
4907 }
4908 assert(!buf);
4909
4910 *mod_p = mod;
4911 return ret;
4912
4913error:
Radek Krejci531fe5b2018-09-19 11:14:13 +02004914 LOGERR(ctx, LY_EINVAL, "Module parsing failed on line %u.", lysp_get_data_line(data_start, data));
Michal Vasko7fbc8162018-09-17 10:35:16 +02004915 /* TODO free module */
4916 return ret;
4917}