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