blob: d66f4109b130c56019e7cb9561b57aea9a74b370 [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 Vasko63f3d842020-07-08 10:10:14 +020025#include "parser.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020026#include "parser_schema.h"
Michal Vasko69730152020-10-09 16:30:07 +020027#include "path.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020028#include "tree.h"
Radek Krejci335332a2019-09-05 13:03:35 +020029#include "tree_schema.h"
30#include "tree_schema_internal.h"
31
32static LY_ERR
33lysp_stmt_validate_value(struct lys_parser_ctx *ctx, enum yang_arg val_type, const char *val)
34{
Radek Krejci857189e2020-09-01 13:26:36 +020035 uint8_t prefix = 0;
36 ly_bool first = 1;
Radek Krejci1deb5be2020-08-26 16:43:36 +020037 uint32_t c;
Radek Krejci335332a2019-09-05 13:03:35 +020038 size_t utf8_char_len;
39
40 while (*val) {
41 LY_CHECK_ERR_RET(ly_getutf8(&val, &c, &utf8_char_len),
Michal Vasko69730152020-10-09 16:30:07 +020042 LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
Radek Krejci335332a2019-09-05 13:03:35 +020043
44 switch (val_type) {
45 case Y_IDENTIF_ARG:
46 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, NULL));
47 break;
48 case Y_PREF_IDENTIF_ARG:
49 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, &prefix));
50 break;
51 case Y_STR_ARG:
52 case Y_MAYBE_STR_ARG:
53 LY_CHECK_RET(lysp_check_stringchar(ctx, c));
54 break;
55 }
56 first = 0;
57 }
58
59 return LY_SUCCESS;
60}
61
62/**
63 * @brief Parse extension instance.
64 *
65 * @param[in] ctx yang parser context for logging.
66 * @param[in,out] data Data to read from, always moved to currently handled character.
67 * @param[in] ext_name Extension instance substatement name (keyword).
68 * @param[in] ext_name_len Extension instance substatement name length.
69 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
70 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
71 * @param[in,out] exts Extension instances to add to.
72 *
73 * @return LY_ERR values.
74 */
75static LY_ERR
76lysp_stmt_ext(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT insubstmt,
Radek Krejci0f969882020-08-21 16:56:47 +020077 LY_ARRAY_COUNT_TYPE insubstmt_index, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +020078{
79 struct lysp_ext_instance *e;
80
Michal Vaskob36053d2020-03-26 15:49:30 +010081 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *exts, e, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +020082
83 /* store name and insubstmt info */
Radek Krejci011e4aa2020-09-04 15:22:31 +020084 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->stmt, 0, &e->name));
Radek Krejci335332a2019-09-05 13:03:35 +020085 e->insubstmt = insubstmt;
86 e->insubstmt_index = insubstmt_index;
87 /* TODO (duplicate) e->child = stmt->child; */
88
89 /* get optional argument */
90 if (stmt->arg) {
Radek Krejci011e4aa2020-09-04 15:22:31 +020091 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &e->argument));
Radek Krejci335332a2019-09-05 13:03:35 +020092 }
93
94 return LY_SUCCESS;
95}
96
97/**
98 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
99 * description, etc...
100 *
101 * @param[in] ctx yang parser context for logging.
Michal Vasko63f3d842020-07-08 10:10:14 +0200102 * @param[in] stmt Statement structure.
Radek Krejci335332a2019-09-05 13:03:35 +0200103 * @param[in] substmt Type of this substatement.
104 * @param[in] substmt_index Index of this substatement.
105 * @param[in,out] value Place to store the parsed value.
106 * @param[in] arg Type of the YANG keyword argument (of the value).
107 * @param[in,out] exts Extension instances to add to.
108 *
109 * @return LY_ERR values.
110 */
111static LY_ERR
112lysp_stmt_text_field(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
Radek Krejci0f969882020-08-21 16:56:47 +0200113 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200114{
115 const struct lysp_stmt *child;
116
117 if (*value) {
118 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
119 return LY_EVALID;
120 }
121
122 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
Radek Krejci011e4aa2020-09-04 15:22:31 +0200123 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, value));
Radek Krejci335332a2019-09-05 13:03:35 +0200124
125 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200126 struct ly_in *in;
127 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
128 enum ly_stmt kw = lysp_match_kw(NULL, in);
129 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200130
131 switch (kw) {
132 case LY_STMT_EXTENSION_INSTANCE:
133 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, substmt_index, exts));
134 break;
135 default:
136 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
137 return LY_EVALID;
138 }
139 }
140 return LY_SUCCESS;
141}
142
143/**
Michal Vasko7f45cf22020-10-01 12:49:44 +0200144 * @brief Parse a qname that can have more instances such as if-feature.
145 *
146 * @param[in] ctx yang parser context for logging.
147 * @param[in,out] data Data to read from, always moved to currently handled character.
148 * @param[in] substmt Type of this substatement.
149 * @param[in,out] qnames Parsed qnames to add to.
150 * @param[in] arg Type of the expected argument.
151 * @param[in,out] exts Extension instances to add to.
152 *
153 * @return LY_ERR values.
154 */
155static LY_ERR
156lysp_stmt_qnames(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt,
157 struct lysp_qname **qnames, enum yang_arg arg, struct lysp_ext_instance **exts)
158{
159 struct lysp_qname *item;
160 const struct lysp_stmt *child;
161
162 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
163
164 /* allocate new pointer */
165 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *qnames, item, LY_EMEM);
166 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &item->str));
167 item->mod = ctx->main_mod;
168
169 for (child = stmt->child; child; child = child->next) {
170 struct ly_in *in;
171 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
172 enum ly_stmt kw = lysp_match_kw(NULL, in);
173 ly_in_free(in, 0);
174
175 switch (kw) {
176 case LY_STMT_EXTENSION_INSTANCE:
177 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, LY_ARRAY_COUNT(*qnames) - 1, exts));
178 break;
179 default:
180 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
181 return LY_EVALID;
182 }
183 }
184 return LY_SUCCESS;
185}
186
187/**
Radek Krejci335332a2019-09-05 13:03:35 +0200188 * @brief Parse a generic text field that can have more instances such as base.
189 *
190 * @param[in] ctx yang parser context for logging.
191 * @param[in,out] data Data to read from, always moved to currently handled character.
192 * @param[in] substmt Type of this substatement.
193 * @param[in,out] texts Parsed values to add to.
194 * @param[in] arg Type of the expected argument.
195 * @param[in,out] exts Extension instances to add to.
196 *
197 * @return LY_ERR values.
198 */
199static LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200200lysp_stmt_text_fields(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt,
Radek Krejci0f969882020-08-21 16:56:47 +0200201 const char ***texts, enum yang_arg arg, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200202{
203 const char **item;
204 const struct lysp_stmt *child;
205
206 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
207
208 /* allocate new pointer */
Michal Vaskob36053d2020-03-26 15:49:30 +0100209 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200210 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, item));
Radek Krejci335332a2019-09-05 13:03:35 +0200211
212 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200213 struct ly_in *in;
214 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
215 enum ly_stmt kw = lysp_match_kw(NULL, in);
216 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200217
218 switch (kw) {
219 case LY_STMT_EXTENSION_INSTANCE:
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200220 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
Radek Krejci335332a2019-09-05 13:03:35 +0200221 break;
222 default:
223 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
224 return LY_EVALID;
225 }
226 }
227 return LY_SUCCESS;
228}
229
230/**
231 * @brief Parse the status statement.
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,out] flags Flags to add to.
236 * @param[in,out] exts Extension instances to add to.
237 *
238 * @return LY_ERR values.
239 */
240static LY_ERR
241lysp_stmt_status(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint16_t *flags, struct lysp_ext_instance **exts)
242{
243 size_t arg_len;
244 const struct lysp_stmt *child;
245
246 if (*flags & LYS_STATUS_MASK) {
247 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
248 return LY_EVALID;
249 }
250
251 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
252 arg_len = strlen(stmt->arg);
253 if ((arg_len == 7) && !strncmp(stmt->arg, "current", arg_len)) {
254 *flags |= LYS_STATUS_CURR;
255 } else if ((arg_len == 10) && !strncmp(stmt->arg, "deprecated", arg_len)) {
256 *flags |= LYS_STATUS_DEPRC;
257 } else if ((arg_len == 8) && !strncmp(stmt->arg, "obsolete", arg_len)) {
258 *flags |= LYS_STATUS_OBSLT;
259 } else {
260 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "status");
261 return LY_EVALID;
262 }
263
264 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200265 struct ly_in *in;
266 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
267 enum ly_stmt kw = lysp_match_kw(NULL, in);
268 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200269
270 switch (kw) {
271 case LY_STMT_EXTENSION_INSTANCE:
272 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_STATUS, 0, exts));
273 break;
274 default:
275 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
276 return LY_EVALID;
277 }
278 }
279 return LY_SUCCESS;
280}
281
282/**
283 * @brief Parse a restriction such as range or length.
284 *
285 * @param[in] ctx yang parser context for logging.
286 * @param[in,out] data Data to read from, always moved to currently handled character.
287 * @param[in] restr_kw Type of this particular restriction.
288 * @param[in,out] exts Extension instances to add to.
289 *
290 * @return LY_ERR values.
291 */
292static LY_ERR
293lysp_stmt_restr(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr *restr)
294{
295 const struct lysp_stmt *child;
296
297 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200298 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &restr->arg.str));
299 restr->arg.mod = ctx->main_mod;
Radek Krejci335332a2019-09-05 13:03:35 +0200300
301 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200302 struct ly_in *in;
303 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
304 enum ly_stmt kw = lysp_match_kw(NULL, in);
305 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200306
307 switch (kw) {
308 case LY_STMT_DESCRIPTION:
309 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
310 break;
311 case LY_STMT_REFERENCE:
312 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
313 break;
314 case LY_STMT_ERROR_APP_TAG:
315 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
316 break;
317 case LY_STMT_ERROR_MESSAGE:
318 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
319 break;
320 case LY_STMT_EXTENSION_INSTANCE:
321 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
322 break;
323 default:
324 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
325 return LY_EVALID;
326 }
327 }
328 return LY_SUCCESS;
329}
330
331/**
332 * @brief Parse a restriction that can have more instances such as must.
333 *
334 * @param[in] ctx yang parser context for logging.
335 * @param[in,out] data Data to read from, always moved to currently handled character.
336 * @param[in] restr_kw Type of this particular restriction.
337 * @param[in,out] restrs Restrictions to add to.
338 *
339 * @return LY_ERR values.
340 */
341static LY_ERR
342lysp_stmt_restrs(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr **restrs)
343{
344 struct lysp_restr *restr;
345
Michal Vaskob36053d2020-03-26 15:49:30 +0100346 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200347 return lysp_stmt_restr(ctx, stmt, restr_kw, restr);
348}
349
350/**
351 * @brief Parse the value or position statement. Substatement of type enum statement.
352 *
353 * @param[in] ctx yang parser context for logging.
354 * @param[in,out] data Data to read from, always moved to currently handled character.
355 * @param[in] val_kw Type of this particular keyword.
356 * @param[in,out] value Value to write to.
357 * @param[in,out] flags Flags to write to.
358 * @param[in,out] exts Extension instances to add to.
359 *
360 * @return LY_ERR values.
361 */
362static LY_ERR
363lysp_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,
Radek Krejci0f969882020-08-21 16:56:47 +0200364 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200365{
366 size_t arg_len;
367 char *ptr = NULL;
368 long int num = 0;
369 unsigned long int unum = 0;
370 struct lysp_stmt *child;
371
372 if (*flags & LYS_SET_VALUE) {
373 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
374 return LY_EVALID;
375 }
376 *flags |= LYS_SET_VALUE;
377
378 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
379
380 arg_len = strlen(stmt->arg);
381 if (!arg_len || (stmt->arg[0] == '+') || ((stmt->arg[0] == '0') && (arg_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(stmt->arg, "-0", 2))) {
382 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
383 goto error;
384 }
385
386 errno = 0;
387 if (val_kw == LY_STMT_VALUE) {
388 num = strtol(stmt->arg, &ptr, 10);
Michal Vasko69730152020-10-09 16:30:07 +0200389 if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
Radek Krejci335332a2019-09-05 13:03:35 +0200390 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
391 goto error;
392 }
393 } else {
394 unum = strtoul(stmt->arg, &ptr, 10);
395 if (unum > UINT64_C(4294967295)) {
396 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
397 goto error;
398 }
399 }
400 /* we have not parsed the whole argument */
401 if ((size_t)(ptr - stmt->arg) != arg_len) {
402 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
403 goto error;
404 }
405 if (errno == ERANGE) {
406 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, ly_stmt2str(val_kw));
407 goto error;
408 }
409 if (val_kw == LY_STMT_VALUE) {
410 *value = num;
411 } else {
412 *value = unum;
413 }
414
415 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200416 struct ly_in *in;
417 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
418 enum ly_stmt kw = lysp_match_kw(NULL, in);
419 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200420
421 switch (kw) {
422 case LY_STMT_EXTENSION_INSTANCE:
423 LY_CHECK_RET(lysp_stmt_ext(ctx, child, val_kw == LY_STMT_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
424 break;
425 default:
426 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
427 return LY_EVALID;
428 }
429 }
430 return LY_SUCCESS;
431
432error:
433 return LY_EVALID;
434}
435
436/**
437 * @brief Parse the enum or bit statement. Substatement of type statement.
438 *
439 * @param[in] ctx yang parser context for logging.
440 * @param[in,out] data Data to read from, always moved to currently handled character.
441 * @param[in] enum_kw Type of this particular keyword.
442 * @param[in,out] enums Enums or bits to add to.
443 *
444 * @return LY_ERR values.
445 */
446static LY_ERR
447lysp_stmt_type_enum(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
448{
449 struct lysp_type_enum *enm;
450 const struct lysp_stmt *child;
451
452 LY_CHECK_RET(lysp_stmt_validate_value(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, stmt->arg));
453
Michal Vaskob36053d2020-03-26 15:49:30 +0100454 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200455
456 if (enum_kw == LY_STMT_ENUM) {
457 LY_CHECK_RET(lysp_check_enum_name(ctx, stmt->arg, strlen(stmt->arg)));
458 } /* else nothing specific for YANG_BIT */
459
Radek Krejci011e4aa2020-09-04 15:22:31 +0200460 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &enm->name));
Radek Krejci335332a2019-09-05 13:03:35 +0200461 CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
462
463 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200464 struct ly_in *in;
465 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
466 enum ly_stmt kw = lysp_match_kw(NULL, in);
467 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200468
469 switch (kw) {
470 case LY_STMT_DESCRIPTION:
471 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
472 break;
473 case LY_STMT_IF_FEATURE:
474 PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200475 LY_CHECK_RET(lysp_stmt_qnames(ctx, child, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
Radek Krejci335332a2019-09-05 13:03:35 +0200476 break;
477 case LY_STMT_REFERENCE:
478 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
479 break;
480 case LY_STMT_STATUS:
481 LY_CHECK_RET(lysp_stmt_status(ctx, child, &enm->flags, &enm->exts));
482 break;
483 case LY_STMT_VALUE:
484 LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
Michal Vasko69730152020-10-09 16:30:07 +0200485 ly_stmt2str(enum_kw)), LY_EVALID);
Radek Krejci335332a2019-09-05 13:03:35 +0200486 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
487 break;
488 case LY_STMT_POSITION:
489 LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
Michal Vasko69730152020-10-09 16:30:07 +0200490 ly_stmt2str(enum_kw)), LY_EVALID);
Radek Krejci335332a2019-09-05 13:03:35 +0200491 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
492 break;
493 case LY_STMT_EXTENSION_INSTANCE:
494 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
495 break;
496 default:
497 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
498 return LY_EVALID;
499 }
500 }
501 return LY_SUCCESS;
502}
503
504/**
505 * @brief Parse the fraction-digits 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] fracdig Value 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_fracdigits(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *fracdig, struct lysp_ext_instance **exts)
516{
517 char *ptr;
518 size_t arg_len;
519 unsigned long int num;
520 const struct lysp_stmt *child;
521
522 if (*fracdig) {
523 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
524 return LY_EVALID;
525 }
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 || (stmt->arg[0] == '0') || !isdigit(stmt->arg[0])) {
530 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
531 return LY_EVALID;
532 }
533
534 errno = 0;
535 num = strtoul(stmt->arg, &ptr, 10);
536 /* we have not parsed the whole argument */
537 if ((size_t)(ptr - stmt->arg) != arg_len) {
538 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
539 return LY_EVALID;
540 }
541 if ((errno == ERANGE) || (num > 18)) {
542 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, "fraction-digits");
543 return LY_EVALID;
544 }
545 *fracdig = num;
546
547 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200548 struct ly_in *in;
549 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
550 enum ly_stmt kw = lysp_match_kw(NULL, in);
551 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200552
553 switch (kw) {
554 case LY_STMT_EXTENSION_INSTANCE:
555 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
556 break;
557 default:
558 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
559 return LY_EVALID;
560 }
561 }
562 return LY_SUCCESS;
563}
564
565/**
566 * @brief Parse the require-instance statement. Substatement of type statement.
567 *
568 * @param[in] ctx yang parser context for logging.
569 * @param[in,out] data Data to read from, always moved to currently handled character.
570 * @param[in,out] reqinst Value to write to.
571 * @param[in,out] flags Flags to write to.
572 * @param[in,out] exts Extension instances to add to.
573 *
574 * @return LY_ERR values.
575 */
576static LY_ERR
577lysp_stmt_type_reqinstance(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *reqinst, uint16_t *flags,
Radek Krejci0f969882020-08-21 16:56:47 +0200578 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200579{
580 size_t arg_len;
581 struct lysp_stmt *child;
582
583 if (*flags & LYS_SET_REQINST) {
584 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
585 return LY_EVALID;
586 }
587 *flags |= LYS_SET_REQINST;
588
589 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
590 arg_len = strlen(stmt->arg);
591 if ((arg_len == 4) && !strncmp(stmt->arg, "true", arg_len)) {
592 *reqinst = 1;
593 } else if ((arg_len != 5) || strncmp(stmt->arg, "false", arg_len)) {
594 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "require-instance");
595 return LY_EVALID;
596 }
597
598 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200599 struct ly_in *in;
600 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
601 enum ly_stmt kw = lysp_match_kw(NULL, in);
602 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200603
604 switch (kw) {
605 case LY_STMT_EXTENSION_INSTANCE:
606 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
607 break;
608 default:
609 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
610 return LY_EVALID;
611 }
612 }
613 return LY_SUCCESS;
614}
615
616/**
617 * @brief Parse the modifier statement. Substatement of type pattern statement.
618 *
619 * @param[in] ctx yang parser context for logging.
620 * @param[in,out] data Data to read from, always moved to currently handled character.
621 * @param[in,out] pat Value to write to.
622 * @param[in,out] exts Extension instances to add to.
623 *
624 * @return LY_ERR values.
625 */
626static LY_ERR
627lysp_stmt_type_pattern_modifier(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, const char **pat, struct lysp_ext_instance **exts)
628{
629 size_t arg_len;
630 char *buf;
631 const struct lysp_stmt *child;
632
633 if ((*pat)[0] == 0x15) {
634 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
635 return LY_EVALID;
636 }
637
638 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
639 arg_len = strlen(stmt->arg);
640 if ((arg_len != 12) || strncmp(stmt->arg, "invert-match", arg_len)) {
641 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "modifier");
642 return LY_EVALID;
643 }
644
645 /* replace the value in the dictionary */
646 buf = malloc(strlen(*pat) + 1);
Michal Vaskob36053d2020-03-26 15:49:30 +0100647 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200648 strcpy(buf, *pat);
Michal Vaskob36053d2020-03-26 15:49:30 +0100649 lydict_remove(PARSER_CTX(ctx), *pat);
Radek Krejci335332a2019-09-05 13:03:35 +0200650
651 assert(buf[0] == 0x06);
652 buf[0] = 0x15;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200653 LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, pat));
Radek Krejci335332a2019-09-05 13:03:35 +0200654
655 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200656 struct ly_in *in;
657 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
658 enum ly_stmt kw = lysp_match_kw(NULL, in);
659 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200660
661 switch (kw) {
662 case LY_STMT_EXTENSION_INSTANCE:
663 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_MODIFIER, 0, exts));
664 break;
665 default:
666 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
667 return LY_EVALID;
668 }
669 }
670 return LY_SUCCESS;
671}
672
673/**
674 * @brief Parse the pattern statement. Substatement of type statement.
675 *
676 * @param[in] ctx yang parser context for logging.
677 * @param[in,out] data Data to read from, always moved to currently handled character.
678 * @param[in,out] patterns Restrictions to add to.
679 *
680 * @return LY_ERR values.
681 */
682static LY_ERR
683lysp_stmt_type_pattern(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_restr **patterns)
684{
685 char *buf;
686 size_t arg_len;
687 const struct lysp_stmt *child;
688 struct lysp_restr *restr;
689
690 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100691 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200692 arg_len = strlen(stmt->arg);
693
694 /* add special meaning first byte */
695 buf = malloc(arg_len + 2);
Michal Vaskob36053d2020-03-26 15:49:30 +0100696 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200697 memmove(buf + 1, stmt->arg, arg_len);
698 buf[0] = 0x06; /* pattern's default regular-match flag */
699 buf[arg_len + 1] = '\0'; /* terminating NULL byte */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200700 LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str));
701 restr->arg.mod = ctx->main_mod;
Radek Krejci335332a2019-09-05 13:03:35 +0200702
703 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200704 struct ly_in *in;
705 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
706 enum ly_stmt kw = lysp_match_kw(NULL, in);
707 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200708
709 switch (kw) {
710 case LY_STMT_DESCRIPTION:
711 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
712 break;
713 case LY_STMT_REFERENCE:
714 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
715 break;
716 case LY_STMT_ERROR_APP_TAG:
717 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
718 break;
719 case LY_STMT_ERROR_MESSAGE:
720 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
721 break;
722 case LY_STMT_MODIFIER:
723 PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
Michal Vasko7f45cf22020-10-01 12:49:44 +0200724 LY_CHECK_RET(lysp_stmt_type_pattern_modifier(ctx, child, &restr->arg.str, &restr->exts));
Radek Krejci335332a2019-09-05 13:03:35 +0200725 break;
726 case LY_STMT_EXTENSION_INSTANCE:
727 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
728 break;
729 default:
730 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
731 return LY_EVALID;
732 }
733 }
734 return LY_SUCCESS;
735}
736
737/**
738 * @brief Parse the type statement.
739 *
740 * @param[in] ctx yang parser context for logging.
741 * @param[in,out] data Data to read from, always moved to currently handled character.
742 * @param[in,out] type Type to wrote to.
743 *
744 * @return LY_ERR values.
745 */
746static LY_ERR
747lysp_stmt_type(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_type *type)
748{
749 struct lysp_type *nest_type;
750 const struct lysp_stmt *child;
Radek Krejcib1247842020-07-02 16:22:38 +0200751 const char *str_path = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200752 LY_ERR ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200753
754 if (type->name) {
755 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
756 return LY_EVALID;
757 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200758 LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &type->name));
Michal Vaskoe9c050f2020-10-06 14:01:23 +0200759 type->mod = ctx->main_mod;
Radek Krejci335332a2019-09-05 13:03:35 +0200760
761 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200762 struct ly_in *in;
763 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
764 enum ly_stmt kw = lysp_match_kw(NULL, in);
765 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200766
767 switch (kw) {
768 case LY_STMT_BASE:
769 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
770 type->flags |= LYS_SET_BASE;
771 break;
772 case LY_STMT_BIT:
773 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->bits));
774 type->flags |= LYS_SET_BIT;
775 break;
776 case LY_STMT_ENUM:
777 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->enums));
778 type->flags |= LYS_SET_ENUM;
779 break;
780 case LY_STMT_FRACTION_DIGITS:
781 LY_CHECK_RET(lysp_stmt_type_fracdigits(ctx, child, &type->fraction_digits, &type->exts));
782 type->flags |= LYS_SET_FRDIGITS;
783 break;
784 case LY_STMT_LENGTH:
785 if (type->length) {
786 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
787 return LY_EVALID;
788 }
789 type->length = calloc(1, sizeof *type->length);
Michal Vaskob36053d2020-03-26 15:49:30 +0100790 LY_CHECK_ERR_RET(!type->length, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200791
792 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->length));
793 type->flags |= LYS_SET_LENGTH;
794 break;
795 case LY_STMT_PATH:
Michal Vasko004d3152020-06-11 19:59:22 +0200796 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_PATH, 0, &str_path, Y_STR_ARG, &type->exts));
Michal Vasko6b26e742020-07-17 15:02:10 +0200797 ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
Michal Vasko69730152020-10-09 16:30:07 +0200798 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
Michal Vasko004d3152020-06-11 19:59:22 +0200799 lydict_remove(PARSER_CTX(ctx), str_path);
800 LY_CHECK_RET(ret);
Radek Krejci335332a2019-09-05 13:03:35 +0200801 type->flags |= LYS_SET_PATH;
802 break;
803 case LY_STMT_PATTERN:
804 LY_CHECK_RET(lysp_stmt_type_pattern(ctx, child, &type->patterns));
805 type->flags |= LYS_SET_PATTERN;
806 break;
807 case LY_STMT_RANGE:
808 if (type->range) {
809 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
810 return LY_EVALID;
811 }
812 type->range = calloc(1, sizeof *type->range);
Michal Vaskob36053d2020-03-26 15:49:30 +0100813 LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200814
815 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->range));
816 type->flags |= LYS_SET_RANGE;
817 break;
818 case LY_STMT_REQUIRE_INSTANCE:
819 LY_CHECK_RET(lysp_stmt_type_reqinstance(ctx, child, &type->require_instance, &type->flags, &type->exts));
820 /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
821 break;
822 case LY_STMT_TYPE:
Michal Vaskob36053d2020-03-26 15:49:30 +0100823 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200824 LY_CHECK_RET(lysp_stmt_type(ctx, child, nest_type));
825 type->flags |= LYS_SET_TYPE;
826 break;
827 case LY_STMT_EXTENSION_INSTANCE:
828 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &type->exts));
829 break;
830 default:
831 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
832 return LY_EVALID;
833 }
834 }
835 return LY_SUCCESS;
836}
837
838LY_ERR
Radek Krejciad5963b2019-09-06 16:03:05 +0200839lysp_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 +0200840{
Radek Krejciad5963b2019-09-06 16:03:05 +0200841 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100842 struct lys_yang_parser_ctx pctx = {0};
Radek Krejci335332a2019-09-05 13:03:35 +0200843
Michal Vaskob36053d2020-03-26 15:49:30 +0100844 pctx.format = LYS_IN_YANG;
Radek Krejci335332a2019-09-05 13:03:35 +0200845 pctx.ctx = ctx->ctx;
846 pctx.mod_version = ctx->mod->version;
847 pctx.pos_type = LY_VLOG_STR;
848 pctx.path = ctx->path;
849
Michal Vaskod989ba02020-08-24 10:59:24 +0200850 switch (kw) {
Michal Vasko69730152020-10-09 16:30:07 +0200851 case LY_STMT_STATUS:
Michal Vasko22df3f02020-08-24 13:29:22 +0200852 ret = lysp_stmt_status((struct lys_parser_ctx *)&pctx, stmt, *(uint16_t **)result, exts);
Radek Krejciad5963b2019-09-06 16:03:05 +0200853 break;
Radek Krejci335332a2019-09-05 13:03:35 +0200854 case LY_STMT_TYPE: {
855 struct lysp_type *type;
856 type = calloc(1, sizeof *type);
857
Michal Vaskob36053d2020-03-26 15:49:30 +0100858 ret = lysp_stmt_type((struct lys_parser_ctx *)&pctx, stmt, type);
Radek Krejci335332a2019-09-05 13:03:35 +0200859 (*result) = type;
860 break;
Radek Krejci0f969882020-08-21 16:56:47 +0200861 }
Radek Krejci335332a2019-09-05 13:03:35 +0200862 default:
863 LOGINT(ctx->ctx);
864 return LY_EINT;
865 }
866
Radek Krejciad5963b2019-09-06 16:03:05 +0200867 return ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200868}