blob: 9ad5ca2a8c3f9590f05c32300a41a225f6a809f1 [file] [log] [blame]
Radek Krejci335332a2019-09-05 13:03:35 +02001/**
2 * @file parser_stmt.c
3 * @author Radek Krejčí <rkrejci@cesnet.cz>
4 * @brief Parser of the extension substatements.
5 *
6 * Copyright (c) 2019 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
Radek Krejci335332a2019-09-05 13:03:35 +020015#include <assert.h>
16#include <ctype.h>
17#include <errno.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020018#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
Radek Krejci335332a2019-09-05 13:03:35 +020021
Radek Krejci535ea9f2020-05-29 16:01:05 +020022#include "common.h"
23#include "dict.h"
24#include "log.h"
Michal Vasko004d3152020-06-11 19:59:22 +020025#include "path.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020026#include "parser_schema.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "tree.h"
Radek Krejci335332a2019-09-05 13:03:35 +020028#include "tree_schema.h"
29#include "tree_schema_internal.h"
30
31static LY_ERR
32lysp_stmt_validate_value(struct lys_parser_ctx *ctx, enum yang_arg val_type, const char *val)
33{
34 int prefix = 0, first = 1;
35 unsigned int c;
36 size_t utf8_char_len;
37
38 while (*val) {
39 LY_CHECK_ERR_RET(ly_getutf8(&val, &c, &utf8_char_len),
40 LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
41
42 switch (val_type) {
43 case Y_IDENTIF_ARG:
44 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, NULL));
45 break;
46 case Y_PREF_IDENTIF_ARG:
47 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, &prefix));
48 break;
49 case Y_STR_ARG:
50 case Y_MAYBE_STR_ARG:
51 LY_CHECK_RET(lysp_check_stringchar(ctx, c));
52 break;
53 }
54 first = 0;
55 }
56
57 return LY_SUCCESS;
58}
59
60/**
61 * @brief Parse extension instance.
62 *
63 * @param[in] ctx yang parser context for logging.
64 * @param[in,out] data Data to read from, always moved to currently handled character.
65 * @param[in] ext_name Extension instance substatement name (keyword).
66 * @param[in] ext_name_len Extension instance substatement name length.
67 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
68 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
69 * @param[in,out] exts Extension instances to add to.
70 *
71 * @return LY_ERR values.
72 */
73static LY_ERR
74lysp_stmt_ext(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT insubstmt,
Radek Krejci7eb54ba2020-05-18 16:30:04 +020075 LY_ARRAY_SIZE_TYPE insubstmt_index, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +020076{
77 struct lysp_ext_instance *e;
78
Michal Vaskob36053d2020-03-26 15:49:30 +010079 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *exts, e, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +020080
81 /* store name and insubstmt info */
Michal Vaskob36053d2020-03-26 15:49:30 +010082 e->name = lydict_insert(PARSER_CTX(ctx), stmt->stmt, 0);
Radek Krejci335332a2019-09-05 13:03:35 +020083 e->insubstmt = insubstmt;
84 e->insubstmt_index = insubstmt_index;
85 /* TODO (duplicate) e->child = stmt->child; */
86
87 /* get optional argument */
88 if (stmt->arg) {
Michal Vaskob36053d2020-03-26 15:49:30 +010089 e->argument = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +020090 }
91
92 return LY_SUCCESS;
93}
94
95/**
96 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
97 * description, etc...
98 *
99 * @param[in] ctx yang parser context for logging.
100 * @param[in,out] data Data to read from, always moved to currently handled character.
101 * @param[in] substmt Type of this substatement.
102 * @param[in] substmt_index Index of this substatement.
103 * @param[in,out] value Place to store the parsed value.
104 * @param[in] arg Type of the YANG keyword argument (of the value).
105 * @param[in,out] exts Extension instances to add to.
106 *
107 * @return LY_ERR values.
108 */
109static LY_ERR
110lysp_stmt_text_field(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
111 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
112{
113 const struct lysp_stmt *child;
114
115 if (*value) {
116 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
117 return LY_EVALID;
118 }
119
120 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100121 *value = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200122
123 for (child = stmt->child; child; child = child->next) {
124 const char *s = child->stmt;
125 enum ly_stmt kw = lysp_match_kw(NULL, &s);
126
127 switch (kw) {
128 case LY_STMT_EXTENSION_INSTANCE:
129 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, substmt_index, exts));
130 break;
131 default:
132 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
133 return LY_EVALID;
134 }
135 }
136 return LY_SUCCESS;
137}
138
139/**
140 * @brief Parse a generic text field that can have more instances such as base.
141 *
142 * @param[in] ctx yang parser context for logging.
143 * @param[in,out] data Data to read from, always moved to currently handled character.
144 * @param[in] substmt Type of this substatement.
145 * @param[in,out] texts Parsed values to add to.
146 * @param[in] arg Type of the expected argument.
147 * @param[in,out] exts Extension instances to add to.
148 *
149 * @return LY_ERR values.
150 */
151static LY_ERR
152lysp_stmt_text_fields(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
153 struct lysp_ext_instance **exts)
154{
155 const char **item;
156 const struct lysp_stmt *child;
157
158 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
159
160 /* allocate new pointer */
Michal Vaskob36053d2020-03-26 15:49:30 +0100161 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
162 *item = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200163
164 for (child = stmt->child; child; child = child->next) {
165 const char *s = child->stmt;
166 enum ly_stmt kw = lysp_match_kw(NULL, &s);
167
168 switch (kw) {
169 case LY_STMT_EXTENSION_INSTANCE:
170 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, LY_ARRAY_SIZE(*texts) - 1, exts));
171 break;
172 default:
173 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
174 return LY_EVALID;
175 }
176 }
177 return LY_SUCCESS;
178}
179
180/**
181 * @brief Parse the status statement.
182 *
183 * @param[in] ctx yang parser context for logging.
184 * @param[in,out] data Data to read from, always moved to currently handled character.
185 * @param[in,out] flags Flags to add to.
186 * @param[in,out] exts Extension instances to add to.
187 *
188 * @return LY_ERR values.
189 */
190static LY_ERR
191lysp_stmt_status(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint16_t *flags, struct lysp_ext_instance **exts)
192{
193 size_t arg_len;
194 const struct lysp_stmt *child;
195
196 if (*flags & LYS_STATUS_MASK) {
197 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
198 return LY_EVALID;
199 }
200
201 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
202 arg_len = strlen(stmt->arg);
203 if ((arg_len == 7) && !strncmp(stmt->arg, "current", arg_len)) {
204 *flags |= LYS_STATUS_CURR;
205 } else if ((arg_len == 10) && !strncmp(stmt->arg, "deprecated", arg_len)) {
206 *flags |= LYS_STATUS_DEPRC;
207 } else if ((arg_len == 8) && !strncmp(stmt->arg, "obsolete", arg_len)) {
208 *flags |= LYS_STATUS_OBSLT;
209 } else {
210 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "status");
211 return LY_EVALID;
212 }
213
214 for (child = stmt->child; child; child = child->next) {
215 const char *s = child->stmt;
216 enum ly_stmt kw = lysp_match_kw(NULL, &s);
217
218 switch (kw) {
219 case LY_STMT_EXTENSION_INSTANCE:
220 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_STATUS, 0, exts));
221 break;
222 default:
223 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
224 return LY_EVALID;
225 }
226 }
227 return LY_SUCCESS;
228}
229
230/**
231 * @brief Parse a restriction such as range or length.
232 *
233 * @param[in] ctx yang parser context for logging.
234 * @param[in,out] data Data to read from, always moved to currently handled character.
235 * @param[in] restr_kw Type of this particular restriction.
236 * @param[in,out] exts Extension instances to add to.
237 *
238 * @return LY_ERR values.
239 */
240static LY_ERR
241lysp_stmt_restr(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr *restr)
242{
243 const struct lysp_stmt *child;
244
245 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100246 restr->arg = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200247
248 for (child = stmt->child; child; child = child->next) {
249 const char *s = child->stmt;
250 enum ly_stmt kw = lysp_match_kw(NULL, &s);
251
252 switch (kw) {
253 case LY_STMT_DESCRIPTION:
254 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
255 break;
256 case LY_STMT_REFERENCE:
257 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
258 break;
259 case LY_STMT_ERROR_APP_TAG:
260 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
261 break;
262 case LY_STMT_ERROR_MESSAGE:
263 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
264 break;
265 case LY_STMT_EXTENSION_INSTANCE:
266 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
267 break;
268 default:
269 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
270 return LY_EVALID;
271 }
272 }
273 return LY_SUCCESS;
274}
275
276/**
277 * @brief Parse a restriction that can have more instances such as must.
278 *
279 * @param[in] ctx yang parser context for logging.
280 * @param[in,out] data Data to read from, always moved to currently handled character.
281 * @param[in] restr_kw Type of this particular restriction.
282 * @param[in,out] restrs Restrictions to add to.
283 *
284 * @return LY_ERR values.
285 */
286static LY_ERR
287lysp_stmt_restrs(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr **restrs)
288{
289 struct lysp_restr *restr;
290
Michal Vaskob36053d2020-03-26 15:49:30 +0100291 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200292 return lysp_stmt_restr(ctx, stmt, restr_kw, restr);
293}
294
295/**
296 * @brief Parse the value or position statement. Substatement of type enum statement.
297 *
298 * @param[in] ctx yang parser context for logging.
299 * @param[in,out] data Data to read from, always moved to currently handled character.
300 * @param[in] val_kw Type of this particular keyword.
301 * @param[in,out] value Value to write to.
302 * @param[in,out] flags Flags to write to.
303 * @param[in,out] exts Extension instances to add to.
304 *
305 * @return LY_ERR values.
306 */
307static LY_ERR
308lysp_stmt_type_enum_value_pos(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt val_kw, int64_t *value, uint16_t *flags,
309 struct lysp_ext_instance **exts)
310{
311 size_t arg_len;
312 char *ptr = NULL;
313 long int num = 0;
314 unsigned long int unum = 0;
315 struct lysp_stmt *child;
316
317 if (*flags & LYS_SET_VALUE) {
318 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
319 return LY_EVALID;
320 }
321 *flags |= LYS_SET_VALUE;
322
323 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
324
325 arg_len = strlen(stmt->arg);
326 if (!arg_len || (stmt->arg[0] == '+') || ((stmt->arg[0] == '0') && (arg_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(stmt->arg, "-0", 2))) {
327 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
328 goto error;
329 }
330
331 errno = 0;
332 if (val_kw == LY_STMT_VALUE) {
333 num = strtol(stmt->arg, &ptr, 10);
334 if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
335 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
336 goto error;
337 }
338 } else {
339 unum = strtoul(stmt->arg, &ptr, 10);
340 if (unum > UINT64_C(4294967295)) {
341 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
342 goto error;
343 }
344 }
345 /* we have not parsed the whole argument */
346 if ((size_t)(ptr - stmt->arg) != arg_len) {
347 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
348 goto error;
349 }
350 if (errno == ERANGE) {
351 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, ly_stmt2str(val_kw));
352 goto error;
353 }
354 if (val_kw == LY_STMT_VALUE) {
355 *value = num;
356 } else {
357 *value = unum;
358 }
359
360 for (child = stmt->child; child; child = child->next) {
361 const char *s = child->stmt;
362 enum ly_stmt kw = lysp_match_kw(NULL, &s);
363
364 switch (kw) {
365 case LY_STMT_EXTENSION_INSTANCE:
366 LY_CHECK_RET(lysp_stmt_ext(ctx, child, val_kw == LY_STMT_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
367 break;
368 default:
369 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
370 return LY_EVALID;
371 }
372 }
373 return LY_SUCCESS;
374
375error:
376 return LY_EVALID;
377}
378
379/**
380 * @brief Parse the enum or bit statement. Substatement of type statement.
381 *
382 * @param[in] ctx yang parser context for logging.
383 * @param[in,out] data Data to read from, always moved to currently handled character.
384 * @param[in] enum_kw Type of this particular keyword.
385 * @param[in,out] enums Enums or bits to add to.
386 *
387 * @return LY_ERR values.
388 */
389static LY_ERR
390lysp_stmt_type_enum(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
391{
392 struct lysp_type_enum *enm;
393 const struct lysp_stmt *child;
394
395 LY_CHECK_RET(lysp_stmt_validate_value(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, stmt->arg));
396
Michal Vaskob36053d2020-03-26 15:49:30 +0100397 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200398
399 if (enum_kw == LY_STMT_ENUM) {
400 LY_CHECK_RET(lysp_check_enum_name(ctx, stmt->arg, strlen(stmt->arg)));
401 } /* else nothing specific for YANG_BIT */
402
Michal Vaskob36053d2020-03-26 15:49:30 +0100403 enm->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200404 CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
405
406 for (child = stmt->child; child; child = child->next) {
407 const char *s = child->stmt;
408 enum ly_stmt kw = lysp_match_kw(NULL, &s);
409
410 switch (kw) {
411 case LY_STMT_DESCRIPTION:
412 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
413 break;
414 case LY_STMT_IF_FEATURE:
415 PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
416 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
417 break;
418 case LY_STMT_REFERENCE:
419 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
420 break;
421 case LY_STMT_STATUS:
422 LY_CHECK_RET(lysp_stmt_status(ctx, child, &enm->flags, &enm->exts));
423 break;
424 case LY_STMT_VALUE:
425 LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
426 ly_stmt2str(enum_kw)), LY_EVALID);
427 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
428 break;
429 case LY_STMT_POSITION:
430 LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
431 ly_stmt2str(enum_kw)), LY_EVALID);
432 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
433 break;
434 case LY_STMT_EXTENSION_INSTANCE:
435 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
436 break;
437 default:
438 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
439 return LY_EVALID;
440 }
441 }
442 return LY_SUCCESS;
443}
444
445/**
446 * @brief Parse the fraction-digits statement. Substatement of type statement.
447 *
448 * @param[in] ctx yang parser context for logging.
449 * @param[in,out] data Data to read from, always moved to currently handled character.
450 * @param[in,out] fracdig Value to write to.
451 * @param[in,out] exts Extension instances to add to.
452 *
453 * @return LY_ERR values.
454 */
455static LY_ERR
456lysp_stmt_type_fracdigits(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *fracdig, struct lysp_ext_instance **exts)
457{
458 char *ptr;
459 size_t arg_len;
460 unsigned long int num;
461 const struct lysp_stmt *child;
462
463 if (*fracdig) {
464 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
465 return LY_EVALID;
466 }
467
468 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
469 arg_len = strlen(stmt->arg);
470 if (!arg_len || (stmt->arg[0] == '0') || !isdigit(stmt->arg[0])) {
471 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
472 return LY_EVALID;
473 }
474
475 errno = 0;
476 num = strtoul(stmt->arg, &ptr, 10);
477 /* we have not parsed the whole argument */
478 if ((size_t)(ptr - stmt->arg) != arg_len) {
479 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
480 return LY_EVALID;
481 }
482 if ((errno == ERANGE) || (num > 18)) {
483 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, "fraction-digits");
484 return LY_EVALID;
485 }
486 *fracdig = num;
487
488 for (child = stmt->child; child; child = child->next) {
489 const char *s = child->stmt;
490 enum ly_stmt kw = lysp_match_kw(NULL, &s);
491
492 switch (kw) {
493 case LY_STMT_EXTENSION_INSTANCE:
494 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
495 break;
496 default:
497 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
498 return LY_EVALID;
499 }
500 }
501 return LY_SUCCESS;
502}
503
504/**
505 * @brief Parse the require-instance statement. Substatement of type statement.
506 *
507 * @param[in] ctx yang parser context for logging.
508 * @param[in,out] data Data to read from, always moved to currently handled character.
509 * @param[in,out] reqinst Value to write to.
510 * @param[in,out] flags Flags to write to.
511 * @param[in,out] exts Extension instances to add to.
512 *
513 * @return LY_ERR values.
514 */
515static LY_ERR
516lysp_stmt_type_reqinstance(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *reqinst, uint16_t *flags,
517 struct lysp_ext_instance **exts)
518{
519 size_t arg_len;
520 struct lysp_stmt *child;
521
522 if (*flags & LYS_SET_REQINST) {
523 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
524 return LY_EVALID;
525 }
526 *flags |= LYS_SET_REQINST;
527
528 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
529 arg_len = strlen(stmt->arg);
530 if ((arg_len == 4) && !strncmp(stmt->arg, "true", arg_len)) {
531 *reqinst = 1;
532 } else if ((arg_len != 5) || strncmp(stmt->arg, "false", arg_len)) {
533 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "require-instance");
534 return LY_EVALID;
535 }
536
537 for (child = stmt->child; child; child = child->next) {
538 const char *s = child->stmt;
539 enum ly_stmt kw = lysp_match_kw(NULL, &s);
540
541 switch (kw) {
542 case LY_STMT_EXTENSION_INSTANCE:
543 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
544 break;
545 default:
546 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
547 return LY_EVALID;
548 }
549 }
550 return LY_SUCCESS;
551}
552
553/**
554 * @brief Parse the modifier statement. Substatement of type pattern statement.
555 *
556 * @param[in] ctx yang parser context for logging.
557 * @param[in,out] data Data to read from, always moved to currently handled character.
558 * @param[in,out] pat Value to write to.
559 * @param[in,out] exts Extension instances to add to.
560 *
561 * @return LY_ERR values.
562 */
563static LY_ERR
564lysp_stmt_type_pattern_modifier(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, const char **pat, struct lysp_ext_instance **exts)
565{
566 size_t arg_len;
567 char *buf;
568 const struct lysp_stmt *child;
569
570 if ((*pat)[0] == 0x15) {
571 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
572 return LY_EVALID;
573 }
574
575 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
576 arg_len = strlen(stmt->arg);
577 if ((arg_len != 12) || strncmp(stmt->arg, "invert-match", arg_len)) {
578 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "modifier");
579 return LY_EVALID;
580 }
581
582 /* replace the value in the dictionary */
583 buf = malloc(strlen(*pat) + 1);
Michal Vaskob36053d2020-03-26 15:49:30 +0100584 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200585 strcpy(buf, *pat);
Michal Vaskob36053d2020-03-26 15:49:30 +0100586 lydict_remove(PARSER_CTX(ctx), *pat);
Radek Krejci335332a2019-09-05 13:03:35 +0200587
588 assert(buf[0] == 0x06);
589 buf[0] = 0x15;
Michal Vaskob36053d2020-03-26 15:49:30 +0100590 *pat = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200591
592 for (child = stmt->child; child; child = child->next) {
593 const char *s = child->stmt;
594 enum ly_stmt kw = lysp_match_kw(NULL, &s);
595
596 switch (kw) {
597 case LY_STMT_EXTENSION_INSTANCE:
598 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_MODIFIER, 0, exts));
599 break;
600 default:
601 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
602 return LY_EVALID;
603 }
604 }
605 return LY_SUCCESS;
606}
607
608/**
609 * @brief Parse the pattern statement. Substatement of type statement.
610 *
611 * @param[in] ctx yang parser context for logging.
612 * @param[in,out] data Data to read from, always moved to currently handled character.
613 * @param[in,out] patterns Restrictions to add to.
614 *
615 * @return LY_ERR values.
616 */
617static LY_ERR
618lysp_stmt_type_pattern(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_restr **patterns)
619{
620 char *buf;
621 size_t arg_len;
622 const struct lysp_stmt *child;
623 struct lysp_restr *restr;
624
625 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100626 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200627 arg_len = strlen(stmt->arg);
628
629 /* add special meaning first byte */
630 buf = malloc(arg_len + 2);
Michal Vaskob36053d2020-03-26 15:49:30 +0100631 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200632 memmove(buf + 1, stmt->arg, arg_len);
633 buf[0] = 0x06; /* pattern's default regular-match flag */
634 buf[arg_len + 1] = '\0'; /* terminating NULL byte */
Michal Vaskob36053d2020-03-26 15:49:30 +0100635 restr->arg = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200636
637 for (child = stmt->child; child; child = child->next) {
638 const char *s = child->stmt;
639 enum ly_stmt kw = lysp_match_kw(NULL, &s);
640
641 switch (kw) {
642 case LY_STMT_DESCRIPTION:
643 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
644 break;
645 case LY_STMT_REFERENCE:
646 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
647 break;
648 case LY_STMT_ERROR_APP_TAG:
649 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
650 break;
651 case LY_STMT_ERROR_MESSAGE:
652 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
653 break;
654 case LY_STMT_MODIFIER:
655 PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
656 LY_CHECK_RET(lysp_stmt_type_pattern_modifier(ctx, child, &restr->arg, &restr->exts));
657 break;
658 case LY_STMT_EXTENSION_INSTANCE:
659 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
660 break;
661 default:
662 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
663 return LY_EVALID;
664 }
665 }
666 return LY_SUCCESS;
667}
668
669/**
670 * @brief Parse the type statement.
671 *
672 * @param[in] ctx yang parser context for logging.
673 * @param[in,out] data Data to read from, always moved to currently handled character.
674 * @param[in,out] type Type to wrote to.
675 *
676 * @return LY_ERR values.
677 */
678static LY_ERR
679lysp_stmt_type(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_type *type)
680{
681 struct lysp_type *nest_type;
682 const struct lysp_stmt *child;
Radek Krejcib1247842020-07-02 16:22:38 +0200683 const char *str_path = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200684 LY_ERR ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200685
686 if (type->name) {
687 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
688 return LY_EVALID;
689 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100690 type->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200691
692 for (child = stmt->child; child; child = child->next) {
693 const char *s = child->stmt;
694 enum ly_stmt kw = lysp_match_kw(NULL, &s);
695
696 switch (kw) {
697 case LY_STMT_BASE:
698 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
699 type->flags |= LYS_SET_BASE;
700 break;
701 case LY_STMT_BIT:
702 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->bits));
703 type->flags |= LYS_SET_BIT;
704 break;
705 case LY_STMT_ENUM:
706 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->enums));
707 type->flags |= LYS_SET_ENUM;
708 break;
709 case LY_STMT_FRACTION_DIGITS:
710 LY_CHECK_RET(lysp_stmt_type_fracdigits(ctx, child, &type->fraction_digits, &type->exts));
711 type->flags |= LYS_SET_FRDIGITS;
712 break;
713 case LY_STMT_LENGTH:
714 if (type->length) {
715 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
716 return LY_EVALID;
717 }
718 type->length = calloc(1, sizeof *type->length);
Michal Vaskob36053d2020-03-26 15:49:30 +0100719 LY_CHECK_ERR_RET(!type->length, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200720
721 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->length));
722 type->flags |= LYS_SET_LENGTH;
723 break;
724 case LY_STMT_PATH:
Michal Vasko004d3152020-06-11 19:59:22 +0200725 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts));
726 ret = ly_path_parse(PARSER_CTX(ctx), str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
727 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
728 lydict_remove(PARSER_CTX(ctx), str_path);
729 LY_CHECK_RET(ret);
Radek Krejci335332a2019-09-05 13:03:35 +0200730 type->flags |= LYS_SET_PATH;
731 break;
732 case LY_STMT_PATTERN:
733 LY_CHECK_RET(lysp_stmt_type_pattern(ctx, child, &type->patterns));
734 type->flags |= LYS_SET_PATTERN;
735 break;
736 case LY_STMT_RANGE:
737 if (type->range) {
738 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
739 return LY_EVALID;
740 }
741 type->range = calloc(1, sizeof *type->range);
Michal Vaskob36053d2020-03-26 15:49:30 +0100742 LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200743
744 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->range));
745 type->flags |= LYS_SET_RANGE;
746 break;
747 case LY_STMT_REQUIRE_INSTANCE:
748 LY_CHECK_RET(lysp_stmt_type_reqinstance(ctx, child, &type->require_instance, &type->flags, &type->exts));
749 /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
750 break;
751 case LY_STMT_TYPE:
Michal Vaskob36053d2020-03-26 15:49:30 +0100752 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200753 LY_CHECK_RET(lysp_stmt_type(ctx, child, nest_type));
754 type->flags |= LYS_SET_TYPE;
755 break;
756 case LY_STMT_EXTENSION_INSTANCE:
757 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &type->exts));
758 break;
759 default:
760 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
761 return LY_EVALID;
762 }
763 }
764 return LY_SUCCESS;
765}
766
767LY_ERR
Radek Krejciad5963b2019-09-06 16:03:05 +0200768lysp_stmt_parse(struct lysc_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt kw, void **result, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200769{
Radek Krejciad5963b2019-09-06 16:03:05 +0200770 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100771 struct lys_yang_parser_ctx pctx = {0};
Radek Krejci335332a2019-09-05 13:03:35 +0200772
Michal Vaskob36053d2020-03-26 15:49:30 +0100773 pctx.format = LYS_IN_YANG;
Radek Krejci335332a2019-09-05 13:03:35 +0200774 pctx.ctx = ctx->ctx;
775 pctx.mod_version = ctx->mod->version;
776 pctx.pos_type = LY_VLOG_STR;
777 pctx.path = ctx->path;
778
779 switch(kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200780 case LY_STMT_STATUS: {
Michal Vaskob36053d2020-03-26 15:49:30 +0100781 ret = lysp_stmt_status((struct lys_parser_ctx *)&pctx, stmt, *(uint16_t**)result, exts);
Radek Krejciad5963b2019-09-06 16:03:05 +0200782 break;
783 }
Radek Krejci335332a2019-09-05 13:03:35 +0200784 case LY_STMT_TYPE: {
785 struct lysp_type *type;
786 type = calloc(1, sizeof *type);
787
Michal Vaskob36053d2020-03-26 15:49:30 +0100788 ret = lysp_stmt_type((struct lys_parser_ctx *)&pctx, stmt, type);
Radek Krejci335332a2019-09-05 13:03:35 +0200789 (*result) = type;
790 break;
791 }
792 default:
793 LOGINT(ctx->ctx);
794 return LY_EINT;
795 }
796
Radek Krejciad5963b2019-09-06 16:03:05 +0200797 return ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200798}