blob: 7f282a6d6cd1cc0b71d5a9ec0025e97d6070e6c9 [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"
Michal Vasko63f3d842020-07-08 10:10:14 +020026#include "parser.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020027#include "parser_schema.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{
35 int prefix = 0, first = 1;
36 unsigned int c;
37 size_t utf8_char_len;
38
39 while (*val) {
40 LY_CHECK_ERR_RET(ly_getutf8(&val, &c, &utf8_char_len),
41 LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
42
43 switch (val_type) {
44 case Y_IDENTIF_ARG:
45 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, NULL));
46 break;
47 case Y_PREF_IDENTIF_ARG:
48 LY_CHECK_RET(lysp_check_identifierchar(ctx, c, first, &prefix));
49 break;
50 case Y_STR_ARG:
51 case Y_MAYBE_STR_ARG:
52 LY_CHECK_RET(lysp_check_stringchar(ctx, c));
53 break;
54 }
55 first = 0;
56 }
57
58 return LY_SUCCESS;
59}
60
61/**
62 * @brief Parse extension instance.
63 *
64 * @param[in] ctx yang parser context for logging.
65 * @param[in,out] data Data to read from, always moved to currently handled character.
66 * @param[in] ext_name Extension instance substatement name (keyword).
67 * @param[in] ext_name_len Extension instance substatement name length.
68 * @param[in] insubstmt Type of the keyword this extension instance is a substatement of.
69 * @param[in] insubstmt_index Index of the keyword instance this extension instance is a substatement of.
70 * @param[in,out] exts Extension instances to add to.
71 *
72 * @return LY_ERR values.
73 */
74static LY_ERR
75lysp_stmt_ext(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT insubstmt,
Radek Krejci0f969882020-08-21 16:56:47 +020076 LY_ARRAY_COUNT_TYPE insubstmt_index, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +020077{
78 struct lysp_ext_instance *e;
79
Michal Vaskob36053d2020-03-26 15:49:30 +010080 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *exts, e, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +020081
82 /* store name and insubstmt info */
Michal Vaskob36053d2020-03-26 15:49:30 +010083 e->name = lydict_insert(PARSER_CTX(ctx), stmt->stmt, 0);
Radek Krejci335332a2019-09-05 13:03:35 +020084 e->insubstmt = insubstmt;
85 e->insubstmt_index = insubstmt_index;
86 /* TODO (duplicate) e->child = stmt->child; */
87
88 /* get optional argument */
89 if (stmt->arg) {
Michal Vaskob36053d2020-03-26 15:49:30 +010090 e->argument = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +020091 }
92
93 return LY_SUCCESS;
94}
95
96/**
97 * @brief Parse a generic text field without specific constraints. Those are contact, organization,
98 * description, etc...
99 *
100 * @param[in] ctx yang parser context for logging.
Michal Vasko63f3d842020-07-08 10:10:14 +0200101 * @param[in] stmt Statement structure.
Radek Krejci335332a2019-09-05 13:03:35 +0200102 * @param[in] substmt Type of this substatement.
103 * @param[in] substmt_index Index of this substatement.
104 * @param[in,out] value Place to store the parsed value.
105 * @param[in] arg Type of the YANG keyword argument (of the value).
106 * @param[in,out] exts Extension instances to add to.
107 *
108 * @return LY_ERR values.
109 */
110static LY_ERR
111lysp_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 +0200112 const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200113{
114 const struct lysp_stmt *child;
115
116 if (*value) {
117 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
118 return LY_EVALID;
119 }
120
121 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100122 *value = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200123
124 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200125 struct ly_in *in;
126 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
127 enum ly_stmt kw = lysp_match_kw(NULL, in);
128 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200129
130 switch (kw) {
131 case LY_STMT_EXTENSION_INSTANCE:
132 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, substmt_index, exts));
133 break;
134 default:
135 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
136 return LY_EVALID;
137 }
138 }
139 return LY_SUCCESS;
140}
141
142/**
143 * @brief Parse a generic text field that can have more instances such as base.
144 *
145 * @param[in] ctx yang parser context for logging.
146 * @param[in,out] data Data to read from, always moved to currently handled character.
147 * @param[in] substmt Type of this substatement.
148 * @param[in,out] texts Parsed values to add to.
149 * @param[in] arg Type of the expected argument.
150 * @param[in,out] exts Extension instances to add to.
151 *
152 * @return LY_ERR values.
153 */
154static LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200155lysp_stmt_text_fields(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt,
Radek Krejci0f969882020-08-21 16:56:47 +0200156 const char ***texts, enum yang_arg arg, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200157{
158 const char **item;
159 const struct lysp_stmt *child;
160
161 LY_CHECK_RET(lysp_stmt_validate_value(ctx, arg, stmt->arg));
162
163 /* allocate new pointer */
Michal Vaskob36053d2020-03-26 15:49:30 +0100164 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
165 *item = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200166
167 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200168 struct ly_in *in;
169 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
170 enum ly_stmt kw = lysp_match_kw(NULL, in);
171 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200172
173 switch (kw) {
174 case LY_STMT_EXTENSION_INSTANCE:
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200175 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
Radek Krejci335332a2019-09-05 13:03:35 +0200176 break;
177 default:
178 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
179 return LY_EVALID;
180 }
181 }
182 return LY_SUCCESS;
183}
184
185/**
186 * @brief Parse the status statement.
187 *
188 * @param[in] ctx yang parser context for logging.
189 * @param[in,out] data Data to read from, always moved to currently handled character.
190 * @param[in,out] flags Flags to add to.
191 * @param[in,out] exts Extension instances to add to.
192 *
193 * @return LY_ERR values.
194 */
195static LY_ERR
196lysp_stmt_status(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint16_t *flags, struct lysp_ext_instance **exts)
197{
198 size_t arg_len;
199 const struct lysp_stmt *child;
200
201 if (*flags & LYS_STATUS_MASK) {
202 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
203 return LY_EVALID;
204 }
205
206 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
207 arg_len = strlen(stmt->arg);
208 if ((arg_len == 7) && !strncmp(stmt->arg, "current", arg_len)) {
209 *flags |= LYS_STATUS_CURR;
210 } else if ((arg_len == 10) && !strncmp(stmt->arg, "deprecated", arg_len)) {
211 *flags |= LYS_STATUS_DEPRC;
212 } else if ((arg_len == 8) && !strncmp(stmt->arg, "obsolete", arg_len)) {
213 *flags |= LYS_STATUS_OBSLT;
214 } else {
215 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "status");
216 return LY_EVALID;
217 }
218
219 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200220 struct ly_in *in;
221 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
222 enum ly_stmt kw = lysp_match_kw(NULL, in);
223 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200224
225 switch (kw) {
226 case LY_STMT_EXTENSION_INSTANCE:
227 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_STATUS, 0, exts));
228 break;
229 default:
230 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
231 return LY_EVALID;
232 }
233 }
234 return LY_SUCCESS;
235}
236
237/**
238 * @brief Parse a restriction such as range or length.
239 *
240 * @param[in] ctx yang parser context for logging.
241 * @param[in,out] data Data to read from, always moved to currently handled character.
242 * @param[in] restr_kw Type of this particular restriction.
243 * @param[in,out] exts Extension instances to add to.
244 *
245 * @return LY_ERR values.
246 */
247static LY_ERR
248lysp_stmt_restr(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr *restr)
249{
250 const struct lysp_stmt *child;
251
252 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100253 restr->arg = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200254
255 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200256 struct ly_in *in;
257 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
258 enum ly_stmt kw = lysp_match_kw(NULL, in);
259 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200260
261 switch (kw) {
262 case LY_STMT_DESCRIPTION:
263 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
264 break;
265 case LY_STMT_REFERENCE:
266 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
267 break;
268 case LY_STMT_ERROR_APP_TAG:
269 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
270 break;
271 case LY_STMT_ERROR_MESSAGE:
272 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
273 break;
274 case LY_STMT_EXTENSION_INSTANCE:
275 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
276 break;
277 default:
278 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
279 return LY_EVALID;
280 }
281 }
282 return LY_SUCCESS;
283}
284
285/**
286 * @brief Parse a restriction that can have more instances such as must.
287 *
288 * @param[in] ctx yang parser context for logging.
289 * @param[in,out] data Data to read from, always moved to currently handled character.
290 * @param[in] restr_kw Type of this particular restriction.
291 * @param[in,out] restrs Restrictions to add to.
292 *
293 * @return LY_ERR values.
294 */
295static LY_ERR
296lysp_stmt_restrs(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr **restrs)
297{
298 struct lysp_restr *restr;
299
Michal Vaskob36053d2020-03-26 15:49:30 +0100300 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200301 return lysp_stmt_restr(ctx, stmt, restr_kw, restr);
302}
303
304/**
305 * @brief Parse the value or position statement. Substatement of type enum statement.
306 *
307 * @param[in] ctx yang parser context for logging.
308 * @param[in,out] data Data to read from, always moved to currently handled character.
309 * @param[in] val_kw Type of this particular keyword.
310 * @param[in,out] value Value to write to.
311 * @param[in,out] flags Flags to write to.
312 * @param[in,out] exts Extension instances to add to.
313 *
314 * @return LY_ERR values.
315 */
316static LY_ERR
317lysp_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 +0200318 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200319{
320 size_t arg_len;
321 char *ptr = NULL;
322 long int num = 0;
323 unsigned long int unum = 0;
324 struct lysp_stmt *child;
325
326 if (*flags & LYS_SET_VALUE) {
327 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
328 return LY_EVALID;
329 }
330 *flags |= LYS_SET_VALUE;
331
332 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
333
334 arg_len = strlen(stmt->arg);
335 if (!arg_len || (stmt->arg[0] == '+') || ((stmt->arg[0] == '0') && (arg_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(stmt->arg, "-0", 2))) {
336 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
337 goto error;
338 }
339
340 errno = 0;
341 if (val_kw == LY_STMT_VALUE) {
342 num = strtol(stmt->arg, &ptr, 10);
343 if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
344 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
345 goto error;
346 }
347 } else {
348 unum = strtoul(stmt->arg, &ptr, 10);
349 if (unum > UINT64_C(4294967295)) {
350 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
351 goto error;
352 }
353 }
354 /* we have not parsed the whole argument */
355 if ((size_t)(ptr - stmt->arg) != arg_len) {
356 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
357 goto error;
358 }
359 if (errno == ERANGE) {
360 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, ly_stmt2str(val_kw));
361 goto error;
362 }
363 if (val_kw == LY_STMT_VALUE) {
364 *value = num;
365 } else {
366 *value = unum;
367 }
368
369 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200370 struct ly_in *in;
371 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
372 enum ly_stmt kw = lysp_match_kw(NULL, in);
373 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200374
375 switch (kw) {
376 case LY_STMT_EXTENSION_INSTANCE:
377 LY_CHECK_RET(lysp_stmt_ext(ctx, child, val_kw == LY_STMT_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
378 break;
379 default:
380 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
381 return LY_EVALID;
382 }
383 }
384 return LY_SUCCESS;
385
386error:
387 return LY_EVALID;
388}
389
390/**
391 * @brief Parse the enum or bit statement. Substatement of type statement.
392 *
393 * @param[in] ctx yang parser context for logging.
394 * @param[in,out] data Data to read from, always moved to currently handled character.
395 * @param[in] enum_kw Type of this particular keyword.
396 * @param[in,out] enums Enums or bits to add to.
397 *
398 * @return LY_ERR values.
399 */
400static LY_ERR
401lysp_stmt_type_enum(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
402{
403 struct lysp_type_enum *enm;
404 const struct lysp_stmt *child;
405
406 LY_CHECK_RET(lysp_stmt_validate_value(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, stmt->arg));
407
Michal Vaskob36053d2020-03-26 15:49:30 +0100408 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200409
410 if (enum_kw == LY_STMT_ENUM) {
411 LY_CHECK_RET(lysp_check_enum_name(ctx, stmt->arg, strlen(stmt->arg)));
412 } /* else nothing specific for YANG_BIT */
413
Michal Vaskob36053d2020-03-26 15:49:30 +0100414 enm->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200415 CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
416
417 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200418 struct ly_in *in;
419 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
420 enum ly_stmt kw = lysp_match_kw(NULL, in);
421 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200422
423 switch (kw) {
424 case LY_STMT_DESCRIPTION:
425 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
426 break;
427 case LY_STMT_IF_FEATURE:
428 PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
429 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
430 break;
431 case LY_STMT_REFERENCE:
432 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
433 break;
434 case LY_STMT_STATUS:
435 LY_CHECK_RET(lysp_stmt_status(ctx, child, &enm->flags, &enm->exts));
436 break;
437 case LY_STMT_VALUE:
438 LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
439 ly_stmt2str(enum_kw)), LY_EVALID);
440 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
441 break;
442 case LY_STMT_POSITION:
443 LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
444 ly_stmt2str(enum_kw)), LY_EVALID);
445 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
446 break;
447 case LY_STMT_EXTENSION_INSTANCE:
448 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
449 break;
450 default:
451 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
452 return LY_EVALID;
453 }
454 }
455 return LY_SUCCESS;
456}
457
458/**
459 * @brief Parse the fraction-digits statement. Substatement of type statement.
460 *
461 * @param[in] ctx yang parser context for logging.
462 * @param[in,out] data Data to read from, always moved to currently handled character.
463 * @param[in,out] fracdig Value to write to.
464 * @param[in,out] exts Extension instances to add to.
465 *
466 * @return LY_ERR values.
467 */
468static LY_ERR
469lysp_stmt_type_fracdigits(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *fracdig, struct lysp_ext_instance **exts)
470{
471 char *ptr;
472 size_t arg_len;
473 unsigned long int num;
474 const struct lysp_stmt *child;
475
476 if (*fracdig) {
477 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
478 return LY_EVALID;
479 }
480
481 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
482 arg_len = strlen(stmt->arg);
483 if (!arg_len || (stmt->arg[0] == '0') || !isdigit(stmt->arg[0])) {
484 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
485 return LY_EVALID;
486 }
487
488 errno = 0;
489 num = strtoul(stmt->arg, &ptr, 10);
490 /* we have not parsed the whole argument */
491 if ((size_t)(ptr - stmt->arg) != arg_len) {
492 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
493 return LY_EVALID;
494 }
495 if ((errno == ERANGE) || (num > 18)) {
496 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, "fraction-digits");
497 return LY_EVALID;
498 }
499 *fracdig = num;
500
501 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200502 struct ly_in *in;
503 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
504 enum ly_stmt kw = lysp_match_kw(NULL, in);
505 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200506
507 switch (kw) {
508 case LY_STMT_EXTENSION_INSTANCE:
509 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
510 break;
511 default:
512 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
513 return LY_EVALID;
514 }
515 }
516 return LY_SUCCESS;
517}
518
519/**
520 * @brief Parse the require-instance statement. Substatement of type statement.
521 *
522 * @param[in] ctx yang parser context for logging.
523 * @param[in,out] data Data to read from, always moved to currently handled character.
524 * @param[in,out] reqinst Value to write to.
525 * @param[in,out] flags Flags to write to.
526 * @param[in,out] exts Extension instances to add to.
527 *
528 * @return LY_ERR values.
529 */
530static LY_ERR
531lysp_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 +0200532 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200533{
534 size_t arg_len;
535 struct lysp_stmt *child;
536
537 if (*flags & LYS_SET_REQINST) {
538 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
539 return LY_EVALID;
540 }
541 *flags |= LYS_SET_REQINST;
542
543 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
544 arg_len = strlen(stmt->arg);
545 if ((arg_len == 4) && !strncmp(stmt->arg, "true", arg_len)) {
546 *reqinst = 1;
547 } else if ((arg_len != 5) || strncmp(stmt->arg, "false", arg_len)) {
548 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "require-instance");
549 return LY_EVALID;
550 }
551
552 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200553 struct ly_in *in;
554 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
555 enum ly_stmt kw = lysp_match_kw(NULL, in);
556 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200557
558 switch (kw) {
559 case LY_STMT_EXTENSION_INSTANCE:
560 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
561 break;
562 default:
563 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
564 return LY_EVALID;
565 }
566 }
567 return LY_SUCCESS;
568}
569
570/**
571 * @brief Parse the modifier statement. Substatement of type pattern statement.
572 *
573 * @param[in] ctx yang parser context for logging.
574 * @param[in,out] data Data to read from, always moved to currently handled character.
575 * @param[in,out] pat Value to write to.
576 * @param[in,out] exts Extension instances to add to.
577 *
578 * @return LY_ERR values.
579 */
580static LY_ERR
581lysp_stmt_type_pattern_modifier(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, const char **pat, struct lysp_ext_instance **exts)
582{
583 size_t arg_len;
584 char *buf;
585 const struct lysp_stmt *child;
586
587 if ((*pat)[0] == 0x15) {
588 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
589 return LY_EVALID;
590 }
591
592 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
593 arg_len = strlen(stmt->arg);
594 if ((arg_len != 12) || strncmp(stmt->arg, "invert-match", arg_len)) {
595 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "modifier");
596 return LY_EVALID;
597 }
598
599 /* replace the value in the dictionary */
600 buf = malloc(strlen(*pat) + 1);
Michal Vaskob36053d2020-03-26 15:49:30 +0100601 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200602 strcpy(buf, *pat);
Michal Vaskob36053d2020-03-26 15:49:30 +0100603 lydict_remove(PARSER_CTX(ctx), *pat);
Radek Krejci335332a2019-09-05 13:03:35 +0200604
605 assert(buf[0] == 0x06);
606 buf[0] = 0x15;
Michal Vaskob36053d2020-03-26 15:49:30 +0100607 *pat = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200608
609 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200610 struct ly_in *in;
611 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
612 enum ly_stmt kw = lysp_match_kw(NULL, in);
613 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200614
615 switch (kw) {
616 case LY_STMT_EXTENSION_INSTANCE:
617 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_MODIFIER, 0, exts));
618 break;
619 default:
620 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
621 return LY_EVALID;
622 }
623 }
624 return LY_SUCCESS;
625}
626
627/**
628 * @brief Parse the pattern statement. Substatement of type statement.
629 *
630 * @param[in] ctx yang parser context for logging.
631 * @param[in,out] data Data to read from, always moved to currently handled character.
632 * @param[in,out] patterns Restrictions to add to.
633 *
634 * @return LY_ERR values.
635 */
636static LY_ERR
637lysp_stmt_type_pattern(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_restr **patterns)
638{
639 char *buf;
640 size_t arg_len;
641 const struct lysp_stmt *child;
642 struct lysp_restr *restr;
643
644 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100645 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200646 arg_len = strlen(stmt->arg);
647
648 /* add special meaning first byte */
649 buf = malloc(arg_len + 2);
Michal Vaskob36053d2020-03-26 15:49:30 +0100650 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200651 memmove(buf + 1, stmt->arg, arg_len);
652 buf[0] = 0x06; /* pattern's default regular-match flag */
653 buf[arg_len + 1] = '\0'; /* terminating NULL byte */
Michal Vaskob36053d2020-03-26 15:49:30 +0100654 restr->arg = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200655
656 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200657 struct ly_in *in;
658 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
659 enum ly_stmt kw = lysp_match_kw(NULL, in);
660 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200661
662 switch (kw) {
663 case LY_STMT_DESCRIPTION:
664 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
665 break;
666 case LY_STMT_REFERENCE:
667 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
668 break;
669 case LY_STMT_ERROR_APP_TAG:
670 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
671 break;
672 case LY_STMT_ERROR_MESSAGE:
673 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
674 break;
675 case LY_STMT_MODIFIER:
676 PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
677 LY_CHECK_RET(lysp_stmt_type_pattern_modifier(ctx, child, &restr->arg, &restr->exts));
678 break;
679 case LY_STMT_EXTENSION_INSTANCE:
680 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
681 break;
682 default:
683 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
684 return LY_EVALID;
685 }
686 }
687 return LY_SUCCESS;
688}
689
690/**
691 * @brief Parse the type statement.
692 *
693 * @param[in] ctx yang parser context for logging.
694 * @param[in,out] data Data to read from, always moved to currently handled character.
695 * @param[in,out] type Type to wrote to.
696 *
697 * @return LY_ERR values.
698 */
699static LY_ERR
700lysp_stmt_type(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_type *type)
701{
702 struct lysp_type *nest_type;
703 const struct lysp_stmt *child;
Radek Krejcib1247842020-07-02 16:22:38 +0200704 const char *str_path = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200705 LY_ERR ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200706
707 if (type->name) {
708 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
709 return LY_EVALID;
710 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100711 type->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200712
713 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200714 struct ly_in *in;
715 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
716 enum ly_stmt kw = lysp_match_kw(NULL, in);
717 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200718
719 switch (kw) {
720 case LY_STMT_BASE:
721 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
722 type->flags |= LYS_SET_BASE;
723 break;
724 case LY_STMT_BIT:
725 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->bits));
726 type->flags |= LYS_SET_BIT;
727 break;
728 case LY_STMT_ENUM:
729 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->enums));
730 type->flags |= LYS_SET_ENUM;
731 break;
732 case LY_STMT_FRACTION_DIGITS:
733 LY_CHECK_RET(lysp_stmt_type_fracdigits(ctx, child, &type->fraction_digits, &type->exts));
734 type->flags |= LYS_SET_FRDIGITS;
735 break;
736 case LY_STMT_LENGTH:
737 if (type->length) {
738 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
739 return LY_EVALID;
740 }
741 type->length = calloc(1, sizeof *type->length);
Michal Vaskob36053d2020-03-26 15:49:30 +0100742 LY_CHECK_ERR_RET(!type->length, 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->length));
745 type->flags |= LYS_SET_LENGTH;
746 break;
747 case LY_STMT_PATH:
Michal Vasko004d3152020-06-11 19:59:22 +0200748 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 +0200749 ret = ly_path_parse(PARSER_CTX(ctx), NULL, str_path, 0, LY_PATH_BEGIN_EITHER, LY_PATH_LREF_TRUE,
Michal Vasko004d3152020-06-11 19:59:22 +0200750 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
751 lydict_remove(PARSER_CTX(ctx), str_path);
752 LY_CHECK_RET(ret);
Radek Krejci335332a2019-09-05 13:03:35 +0200753 type->flags |= LYS_SET_PATH;
754 break;
755 case LY_STMT_PATTERN:
756 LY_CHECK_RET(lysp_stmt_type_pattern(ctx, child, &type->patterns));
757 type->flags |= LYS_SET_PATTERN;
758 break;
759 case LY_STMT_RANGE:
760 if (type->range) {
761 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
762 return LY_EVALID;
763 }
764 type->range = calloc(1, sizeof *type->range);
Michal Vaskob36053d2020-03-26 15:49:30 +0100765 LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200766
767 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->range));
768 type->flags |= LYS_SET_RANGE;
769 break;
770 case LY_STMT_REQUIRE_INSTANCE:
771 LY_CHECK_RET(lysp_stmt_type_reqinstance(ctx, child, &type->require_instance, &type->flags, &type->exts));
772 /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
773 break;
774 case LY_STMT_TYPE:
Michal Vaskob36053d2020-03-26 15:49:30 +0100775 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200776 LY_CHECK_RET(lysp_stmt_type(ctx, child, nest_type));
777 type->flags |= LYS_SET_TYPE;
778 break;
779 case LY_STMT_EXTENSION_INSTANCE:
780 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &type->exts));
781 break;
782 default:
783 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
784 return LY_EVALID;
785 }
786 }
787 return LY_SUCCESS;
788}
789
790LY_ERR
Radek Krejciad5963b2019-09-06 16:03:05 +0200791lysp_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 +0200792{
Radek Krejciad5963b2019-09-06 16:03:05 +0200793 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100794 struct lys_yang_parser_ctx pctx = {0};
Radek Krejci335332a2019-09-05 13:03:35 +0200795
Michal Vaskob36053d2020-03-26 15:49:30 +0100796 pctx.format = LYS_IN_YANG;
Radek Krejci335332a2019-09-05 13:03:35 +0200797 pctx.ctx = ctx->ctx;
798 pctx.mod_version = ctx->mod->version;
799 pctx.pos_type = LY_VLOG_STR;
800 pctx.path = ctx->path;
801
802 switch(kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200803 case LY_STMT_STATUS: {
Michal Vaskob36053d2020-03-26 15:49:30 +0100804 ret = lysp_stmt_status((struct lys_parser_ctx *)&pctx, stmt, *(uint16_t**)result, exts);
Radek Krejciad5963b2019-09-06 16:03:05 +0200805 break;
806 }
Radek Krejci335332a2019-09-05 13:03:35 +0200807 case LY_STMT_TYPE: {
808 struct lysp_type *type;
809 type = calloc(1, sizeof *type);
810
Michal Vaskob36053d2020-03-26 15:49:30 +0100811 ret = lysp_stmt_type((struct lys_parser_ctx *)&pctx, stmt, type);
Radek Krejci335332a2019-09-05 13:03:35 +0200812 (*result) = type;
813 break;
Radek Krejci0f969882020-08-21 16:56:47 +0200814 }
Radek Krejci335332a2019-09-05 13:03:35 +0200815 default:
816 LOGINT(ctx->ctx);
817 return LY_EINT;
818 }
819
Radek Krejciad5963b2019-09-06 16:03:05 +0200820 return ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200821}