blob: 3c36fbd4f7598b5196cd55771ab6500da416bc7e [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{
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),
42 LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
43
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 */
Michal Vaskob36053d2020-03-26 15:49:30 +010084 e->name = lydict_insert(PARSER_CTX(ctx), stmt->stmt, 0);
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) {
Michal Vaskob36053d2020-03-26 15:49:30 +010091 e->argument = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
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));
Michal Vaskob36053d2020-03-26 15:49:30 +0100123 *value = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
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/**
144 * @brief Parse a generic text field that can have more instances such as base.
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] texts Parsed values 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
Michal Vasko63f3d842020-07-08 10:10:14 +0200156lysp_stmt_text_fields(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, LYEXT_SUBSTMT substmt,
Radek Krejci0f969882020-08-21 16:56:47 +0200157 const char ***texts, enum yang_arg arg, struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200158{
159 const char **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 */
Michal Vaskob36053d2020-03-26 15:49:30 +0100165 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *texts, item, LY_EMEM);
166 *item = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200167
168 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200169 struct ly_in *in;
170 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
171 enum ly_stmt kw = lysp_match_kw(NULL, in);
172 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200173
174 switch (kw) {
175 case LY_STMT_EXTENSION_INSTANCE:
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200176 LY_CHECK_RET(lysp_stmt_ext(ctx, child, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
Radek Krejci335332a2019-09-05 13:03:35 +0200177 break;
178 default:
179 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
180 return LY_EVALID;
181 }
182 }
183 return LY_SUCCESS;
184}
185
186/**
187 * @brief Parse the status statement.
188 *
189 * @param[in] ctx yang parser context for logging.
190 * @param[in,out] data Data to read from, always moved to currently handled character.
191 * @param[in,out] flags Flags to add to.
192 * @param[in,out] exts Extension instances to add to.
193 *
194 * @return LY_ERR values.
195 */
196static LY_ERR
197lysp_stmt_status(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint16_t *flags, struct lysp_ext_instance **exts)
198{
199 size_t arg_len;
200 const struct lysp_stmt *child;
201
202 if (*flags & LYS_STATUS_MASK) {
203 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
204 return LY_EVALID;
205 }
206
207 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
208 arg_len = strlen(stmt->arg);
209 if ((arg_len == 7) && !strncmp(stmt->arg, "current", arg_len)) {
210 *flags |= LYS_STATUS_CURR;
211 } else if ((arg_len == 10) && !strncmp(stmt->arg, "deprecated", arg_len)) {
212 *flags |= LYS_STATUS_DEPRC;
213 } else if ((arg_len == 8) && !strncmp(stmt->arg, "obsolete", arg_len)) {
214 *flags |= LYS_STATUS_OBSLT;
215 } else {
216 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "status");
217 return LY_EVALID;
218 }
219
220 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200221 struct ly_in *in;
222 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
223 enum ly_stmt kw = lysp_match_kw(NULL, in);
224 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200225
226 switch (kw) {
227 case LY_STMT_EXTENSION_INSTANCE:
228 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_STATUS, 0, exts));
229 break;
230 default:
231 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
232 return LY_EVALID;
233 }
234 }
235 return LY_SUCCESS;
236}
237
238/**
239 * @brief Parse a restriction such as range or length.
240 *
241 * @param[in] ctx yang parser context for logging.
242 * @param[in,out] data Data to read from, always moved to currently handled character.
243 * @param[in] restr_kw Type of this particular restriction.
244 * @param[in,out] exts Extension instances to add to.
245 *
246 * @return LY_ERR values.
247 */
248static LY_ERR
249lysp_stmt_restr(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr *restr)
250{
251 const struct lysp_stmt *child;
252
253 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100254 restr->arg = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200255
256 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200257 struct ly_in *in;
258 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
259 enum ly_stmt kw = lysp_match_kw(NULL, in);
260 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200261
262 switch (kw) {
263 case LY_STMT_DESCRIPTION:
264 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
265 break;
266 case LY_STMT_REFERENCE:
267 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
268 break;
269 case LY_STMT_ERROR_APP_TAG:
270 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
271 break;
272 case LY_STMT_ERROR_MESSAGE:
273 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
274 break;
275 case LY_STMT_EXTENSION_INSTANCE:
276 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
277 break;
278 default:
279 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
280 return LY_EVALID;
281 }
282 }
283 return LY_SUCCESS;
284}
285
286/**
287 * @brief Parse a restriction that can have more instances such as must.
288 *
289 * @param[in] ctx yang parser context for logging.
290 * @param[in,out] data Data to read from, always moved to currently handled character.
291 * @param[in] restr_kw Type of this particular restriction.
292 * @param[in,out] restrs Restrictions to add to.
293 *
294 * @return LY_ERR values.
295 */
296static LY_ERR
297lysp_stmt_restrs(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt restr_kw, struct lysp_restr **restrs)
298{
299 struct lysp_restr *restr;
300
Michal Vaskob36053d2020-03-26 15:49:30 +0100301 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *restrs, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200302 return lysp_stmt_restr(ctx, stmt, restr_kw, restr);
303}
304
305/**
306 * @brief Parse the value or position statement. Substatement of type enum statement.
307 *
308 * @param[in] ctx yang parser context for logging.
309 * @param[in,out] data Data to read from, always moved to currently handled character.
310 * @param[in] val_kw Type of this particular keyword.
311 * @param[in,out] value Value to write to.
312 * @param[in,out] flags Flags to write to.
313 * @param[in,out] exts Extension instances to add to.
314 *
315 * @return LY_ERR values.
316 */
317static LY_ERR
318lysp_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 +0200319 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200320{
321 size_t arg_len;
322 char *ptr = NULL;
323 long int num = 0;
324 unsigned long int unum = 0;
325 struct lysp_stmt *child;
326
327 if (*flags & LYS_SET_VALUE) {
328 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
329 return LY_EVALID;
330 }
331 *flags |= LYS_SET_VALUE;
332
333 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
334
335 arg_len = strlen(stmt->arg);
336 if (!arg_len || (stmt->arg[0] == '+') || ((stmt->arg[0] == '0') && (arg_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(stmt->arg, "-0", 2))) {
337 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
338 goto error;
339 }
340
341 errno = 0;
342 if (val_kw == LY_STMT_VALUE) {
343 num = strtol(stmt->arg, &ptr, 10);
344 if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
345 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
346 goto error;
347 }
348 } else {
349 unum = strtoul(stmt->arg, &ptr, 10);
350 if (unum > UINT64_C(4294967295)) {
351 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
352 goto error;
353 }
354 }
355 /* we have not parsed the whole argument */
356 if ((size_t)(ptr - stmt->arg) != arg_len) {
357 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, ly_stmt2str(val_kw));
358 goto error;
359 }
360 if (errno == ERANGE) {
361 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, ly_stmt2str(val_kw));
362 goto error;
363 }
364 if (val_kw == LY_STMT_VALUE) {
365 *value = num;
366 } else {
367 *value = unum;
368 }
369
370 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200371 struct ly_in *in;
372 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
373 enum ly_stmt kw = lysp_match_kw(NULL, in);
374 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200375
376 switch (kw) {
377 case LY_STMT_EXTENSION_INSTANCE:
378 LY_CHECK_RET(lysp_stmt_ext(ctx, child, val_kw == LY_STMT_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
379 break;
380 default:
381 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
382 return LY_EVALID;
383 }
384 }
385 return LY_SUCCESS;
386
387error:
388 return LY_EVALID;
389}
390
391/**
392 * @brief Parse the enum or bit statement. Substatement of type statement.
393 *
394 * @param[in] ctx yang parser context for logging.
395 * @param[in,out] data Data to read from, always moved to currently handled character.
396 * @param[in] enum_kw Type of this particular keyword.
397 * @param[in,out] enums Enums or bits to add to.
398 *
399 * @return LY_ERR values.
400 */
401static LY_ERR
402lysp_stmt_type_enum(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, enum ly_stmt enum_kw, struct lysp_type_enum **enums)
403{
404 struct lysp_type_enum *enm;
405 const struct lysp_stmt *child;
406
407 LY_CHECK_RET(lysp_stmt_validate_value(ctx, enum_kw == LY_STMT_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, stmt->arg));
408
Michal Vaskob36053d2020-03-26 15:49:30 +0100409 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *enums, enm, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200410
411 if (enum_kw == LY_STMT_ENUM) {
412 LY_CHECK_RET(lysp_check_enum_name(ctx, stmt->arg, strlen(stmt->arg)));
413 } /* else nothing specific for YANG_BIT */
414
Michal Vaskob36053d2020-03-26 15:49:30 +0100415 enm->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200416 CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
417
418 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200419 struct ly_in *in;
420 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
421 enum ly_stmt kw = lysp_match_kw(NULL, in);
422 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200423
424 switch (kw) {
425 case LY_STMT_DESCRIPTION:
426 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
427 break;
428 case LY_STMT_IF_FEATURE:
429 PARSER_CHECK_STMTVER2_RET(ctx, "if-feature", ly_stmt2str(enum_kw));
430 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_IFFEATURE, &enm->iffeatures, Y_STR_ARG, &enm->exts));
431 break;
432 case LY_STMT_REFERENCE:
433 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &enm->ref, Y_STR_ARG, &enm->exts));
434 break;
435 case LY_STMT_STATUS:
436 LY_CHECK_RET(lysp_stmt_status(ctx, child, &enm->flags, &enm->exts));
437 break;
438 case LY_STMT_VALUE:
439 LY_CHECK_ERR_RET(enum_kw == LY_STMT_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
440 ly_stmt2str(enum_kw)), LY_EVALID);
441 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
442 break;
443 case LY_STMT_POSITION:
444 LY_CHECK_ERR_RET(enum_kw == LY_STMT_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
445 ly_stmt2str(enum_kw)), LY_EVALID);
446 LY_CHECK_RET(lysp_stmt_type_enum_value_pos(ctx, child, kw, &enm->value, &enm->flags, &enm->exts));
447 break;
448 case LY_STMT_EXTENSION_INSTANCE:
449 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
450 break;
451 default:
452 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
453 return LY_EVALID;
454 }
455 }
456 return LY_SUCCESS;
457}
458
459/**
460 * @brief Parse the fraction-digits statement. Substatement of type statement.
461 *
462 * @param[in] ctx yang parser context for logging.
463 * @param[in,out] data Data to read from, always moved to currently handled character.
464 * @param[in,out] fracdig Value to write to.
465 * @param[in,out] exts Extension instances to add to.
466 *
467 * @return LY_ERR values.
468 */
469static LY_ERR
470lysp_stmt_type_fracdigits(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, uint8_t *fracdig, struct lysp_ext_instance **exts)
471{
472 char *ptr;
473 size_t arg_len;
474 unsigned long int num;
475 const struct lysp_stmt *child;
476
477 if (*fracdig) {
478 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
479 return LY_EVALID;
480 }
481
482 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
483 arg_len = strlen(stmt->arg);
484 if (!arg_len || (stmt->arg[0] == '0') || !isdigit(stmt->arg[0])) {
485 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
486 return LY_EVALID;
487 }
488
489 errno = 0;
490 num = strtoul(stmt->arg, &ptr, 10);
491 /* we have not parsed the whole argument */
492 if ((size_t)(ptr - stmt->arg) != arg_len) {
493 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "fraction-digits");
494 return LY_EVALID;
495 }
496 if ((errno == ERANGE) || (num > 18)) {
497 LOGVAL_PARSER(ctx, LY_VCODE_OOB, arg_len, stmt->arg, "fraction-digits");
498 return LY_EVALID;
499 }
500 *fracdig = num;
501
502 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200503 struct ly_in *in;
504 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
505 enum ly_stmt kw = lysp_match_kw(NULL, in);
506 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200507
508 switch (kw) {
509 case LY_STMT_EXTENSION_INSTANCE:
510 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
511 break;
512 default:
513 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
514 return LY_EVALID;
515 }
516 }
517 return LY_SUCCESS;
518}
519
520/**
521 * @brief Parse the require-instance statement. Substatement of type statement.
522 *
523 * @param[in] ctx yang parser context for logging.
524 * @param[in,out] data Data to read from, always moved to currently handled character.
525 * @param[in,out] reqinst Value to write to.
526 * @param[in,out] flags Flags to write to.
527 * @param[in,out] exts Extension instances to add to.
528 *
529 * @return LY_ERR values.
530 */
531static LY_ERR
532lysp_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 +0200533 struct lysp_ext_instance **exts)
Radek Krejci335332a2019-09-05 13:03:35 +0200534{
535 size_t arg_len;
536 struct lysp_stmt *child;
537
538 if (*flags & LYS_SET_REQINST) {
539 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
540 return LY_EVALID;
541 }
542 *flags |= LYS_SET_REQINST;
543
544 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
545 arg_len = strlen(stmt->arg);
546 if ((arg_len == 4) && !strncmp(stmt->arg, "true", arg_len)) {
547 *reqinst = 1;
548 } else if ((arg_len != 5) || strncmp(stmt->arg, "false", arg_len)) {
549 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "require-instance");
550 return LY_EVALID;
551 }
552
553 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200554 struct ly_in *in;
555 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
556 enum ly_stmt kw = lysp_match_kw(NULL, in);
557 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200558
559 switch (kw) {
560 case LY_STMT_EXTENSION_INSTANCE:
561 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
562 break;
563 default:
564 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
565 return LY_EVALID;
566 }
567 }
568 return LY_SUCCESS;
569}
570
571/**
572 * @brief Parse the modifier statement. Substatement of type pattern statement.
573 *
574 * @param[in] ctx yang parser context for logging.
575 * @param[in,out] data Data to read from, always moved to currently handled character.
576 * @param[in,out] pat Value to write to.
577 * @param[in,out] exts Extension instances to add to.
578 *
579 * @return LY_ERR values.
580 */
581static LY_ERR
582lysp_stmt_type_pattern_modifier(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, const char **pat, struct lysp_ext_instance **exts)
583{
584 size_t arg_len;
585 char *buf;
586 const struct lysp_stmt *child;
587
588 if ((*pat)[0] == 0x15) {
589 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
590 return LY_EVALID;
591 }
592
593 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
594 arg_len = strlen(stmt->arg);
595 if ((arg_len != 12) || strncmp(stmt->arg, "invert-match", arg_len)) {
596 LOGVAL_PARSER(ctx, LY_VCODE_INVAL, arg_len, stmt->arg, "modifier");
597 return LY_EVALID;
598 }
599
600 /* replace the value in the dictionary */
601 buf = malloc(strlen(*pat) + 1);
Michal Vaskob36053d2020-03-26 15:49:30 +0100602 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200603 strcpy(buf, *pat);
Michal Vaskob36053d2020-03-26 15:49:30 +0100604 lydict_remove(PARSER_CTX(ctx), *pat);
Radek Krejci335332a2019-09-05 13:03:35 +0200605
606 assert(buf[0] == 0x06);
607 buf[0] = 0x15;
Michal Vaskob36053d2020-03-26 15:49:30 +0100608 *pat = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200609
610 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200611 struct ly_in *in;
612 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
613 enum ly_stmt kw = lysp_match_kw(NULL, in);
614 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200615
616 switch (kw) {
617 case LY_STMT_EXTENSION_INSTANCE:
618 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_MODIFIER, 0, exts));
619 break;
620 default:
621 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
622 return LY_EVALID;
623 }
624 }
625 return LY_SUCCESS;
626}
627
628/**
629 * @brief Parse the pattern statement. Substatement of type statement.
630 *
631 * @param[in] ctx yang parser context for logging.
632 * @param[in,out] data Data to read from, always moved to currently handled character.
633 * @param[in,out] patterns Restrictions to add to.
634 *
635 * @return LY_ERR values.
636 */
637static LY_ERR
638lysp_stmt_type_pattern(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_restr **patterns)
639{
640 char *buf;
641 size_t arg_len;
642 const struct lysp_stmt *child;
643 struct lysp_restr *restr;
644
645 LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
Michal Vaskob36053d2020-03-26 15:49:30 +0100646 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *patterns, restr, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200647 arg_len = strlen(stmt->arg);
648
649 /* add special meaning first byte */
650 buf = malloc(arg_len + 2);
Michal Vaskob36053d2020-03-26 15:49:30 +0100651 LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200652 memmove(buf + 1, stmt->arg, arg_len);
653 buf[0] = 0x06; /* pattern's default regular-match flag */
654 buf[arg_len + 1] = '\0'; /* terminating NULL byte */
Michal Vaskob36053d2020-03-26 15:49:30 +0100655 restr->arg = lydict_insert_zc(PARSER_CTX(ctx), buf);
Radek Krejci335332a2019-09-05 13:03:35 +0200656
657 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200658 struct ly_in *in;
659 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
660 enum ly_stmt kw = lysp_match_kw(NULL, in);
661 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200662
663 switch (kw) {
664 case LY_STMT_DESCRIPTION:
665 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
666 break;
667 case LY_STMT_REFERENCE:
668 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_REFERENCE, 0, &restr->ref, Y_STR_ARG, &restr->exts));
669 break;
670 case LY_STMT_ERROR_APP_TAG:
671 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRTAG, 0, &restr->eapptag, Y_STR_ARG, &restr->exts));
672 break;
673 case LY_STMT_ERROR_MESSAGE:
674 LY_CHECK_RET(lysp_stmt_text_field(ctx, child, LYEXT_SUBSTMT_ERRMSG, 0, &restr->emsg, Y_STR_ARG, &restr->exts));
675 break;
676 case LY_STMT_MODIFIER:
677 PARSER_CHECK_STMTVER2_RET(ctx, "modifier", "pattern");
678 LY_CHECK_RET(lysp_stmt_type_pattern_modifier(ctx, child, &restr->arg, &restr->exts));
679 break;
680 case LY_STMT_EXTENSION_INSTANCE:
681 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
682 break;
683 default:
684 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
685 return LY_EVALID;
686 }
687 }
688 return LY_SUCCESS;
689}
690
691/**
692 * @brief Parse the type statement.
693 *
694 * @param[in] ctx yang parser context for logging.
695 * @param[in,out] data Data to read from, always moved to currently handled character.
696 * @param[in,out] type Type to wrote to.
697 *
698 * @return LY_ERR values.
699 */
700static LY_ERR
701lysp_stmt_type(struct lys_parser_ctx *ctx, const struct lysp_stmt *stmt, struct lysp_type *type)
702{
703 struct lysp_type *nest_type;
704 const struct lysp_stmt *child;
Radek Krejcib1247842020-07-02 16:22:38 +0200705 const char *str_path = NULL;
Michal Vasko004d3152020-06-11 19:59:22 +0200706 LY_ERR ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200707
708 if (type->name) {
709 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
710 return LY_EVALID;
711 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100712 type->name = lydict_insert(PARSER_CTX(ctx), stmt->arg, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200713
714 for (child = stmt->child; child; child = child->next) {
Michal Vasko63f3d842020-07-08 10:10:14 +0200715 struct ly_in *in;
716 LY_CHECK_RET(ly_in_new_memory(child->stmt, &in));
717 enum ly_stmt kw = lysp_match_kw(NULL, in);
718 ly_in_free(in, 0);
Radek Krejci335332a2019-09-05 13:03:35 +0200719
720 switch (kw) {
721 case LY_STMT_BASE:
722 LY_CHECK_RET(lysp_stmt_text_fields(ctx, child, LYEXT_SUBSTMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
723 type->flags |= LYS_SET_BASE;
724 break;
725 case LY_STMT_BIT:
726 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->bits));
727 type->flags |= LYS_SET_BIT;
728 break;
729 case LY_STMT_ENUM:
730 LY_CHECK_RET(lysp_stmt_type_enum(ctx, child, kw, &type->enums));
731 type->flags |= LYS_SET_ENUM;
732 break;
733 case LY_STMT_FRACTION_DIGITS:
734 LY_CHECK_RET(lysp_stmt_type_fracdigits(ctx, child, &type->fraction_digits, &type->exts));
735 type->flags |= LYS_SET_FRDIGITS;
736 break;
737 case LY_STMT_LENGTH:
738 if (type->length) {
739 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
740 return LY_EVALID;
741 }
742 type->length = calloc(1, sizeof *type->length);
Michal Vaskob36053d2020-03-26 15:49:30 +0100743 LY_CHECK_ERR_RET(!type->length, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200744
745 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->length));
746 type->flags |= LYS_SET_LENGTH;
747 break;
748 case LY_STMT_PATH:
Michal Vasko004d3152020-06-11 19:59:22 +0200749 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 +0200750 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 +0200751 LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &type->path);
752 lydict_remove(PARSER_CTX(ctx), str_path);
753 LY_CHECK_RET(ret);
Radek Krejci335332a2019-09-05 13:03:35 +0200754 type->flags |= LYS_SET_PATH;
755 break;
756 case LY_STMT_PATTERN:
757 LY_CHECK_RET(lysp_stmt_type_pattern(ctx, child, &type->patterns));
758 type->flags |= LYS_SET_PATTERN;
759 break;
760 case LY_STMT_RANGE:
761 if (type->range) {
762 LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
763 return LY_EVALID;
764 }
765 type->range = calloc(1, sizeof *type->range);
Michal Vaskob36053d2020-03-26 15:49:30 +0100766 LY_CHECK_ERR_RET(!type->range, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200767
768 LY_CHECK_RET(lysp_stmt_restr(ctx, child, kw, type->range));
769 type->flags |= LYS_SET_RANGE;
770 break;
771 case LY_STMT_REQUIRE_INSTANCE:
772 LY_CHECK_RET(lysp_stmt_type_reqinstance(ctx, child, &type->require_instance, &type->flags, &type->exts));
773 /* LYS_SET_REQINST checked and set inside parse_type_reqinstance() */
774 break;
775 case LY_STMT_TYPE:
Michal Vaskob36053d2020-03-26 15:49:30 +0100776 LY_ARRAY_NEW_RET(PARSER_CTX(ctx), type->types, nest_type, LY_EMEM);
Radek Krejci335332a2019-09-05 13:03:35 +0200777 LY_CHECK_RET(lysp_stmt_type(ctx, child, nest_type));
778 type->flags |= LYS_SET_TYPE;
779 break;
780 case LY_STMT_EXTENSION_INSTANCE:
781 LY_CHECK_RET(lysp_stmt_ext(ctx, child, LYEXT_SUBSTMT_SELF, 0, &type->exts));
782 break;
783 default:
784 LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
785 return LY_EVALID;
786 }
787 }
788 return LY_SUCCESS;
789}
790
791LY_ERR
Radek Krejciad5963b2019-09-06 16:03:05 +0200792lysp_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 +0200793{
Radek Krejciad5963b2019-09-06 16:03:05 +0200794 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100795 struct lys_yang_parser_ctx pctx = {0};
Radek Krejci335332a2019-09-05 13:03:35 +0200796
Michal Vaskob36053d2020-03-26 15:49:30 +0100797 pctx.format = LYS_IN_YANG;
Radek Krejci335332a2019-09-05 13:03:35 +0200798 pctx.ctx = ctx->ctx;
799 pctx.mod_version = ctx->mod->version;
800 pctx.pos_type = LY_VLOG_STR;
801 pctx.path = ctx->path;
802
Michal Vaskod989ba02020-08-24 10:59:24 +0200803 switch (kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200804 case LY_STMT_STATUS: {
Michal Vasko22df3f02020-08-24 13:29:22 +0200805 ret = lysp_stmt_status((struct lys_parser_ctx *)&pctx, stmt, *(uint16_t **)result, exts);
Radek Krejciad5963b2019-09-06 16:03:05 +0200806 break;
807 }
Radek Krejci335332a2019-09-05 13:03:35 +0200808 case LY_STMT_TYPE: {
809 struct lysp_type *type;
810 type = calloc(1, sizeof *type);
811
Michal Vaskob36053d2020-03-26 15:49:30 +0100812 ret = lysp_stmt_type((struct lys_parser_ctx *)&pctx, stmt, type);
Radek Krejci335332a2019-09-05 13:03:35 +0200813 (*result) = type;
814 break;
Radek Krejci0f969882020-08-21 16:56:47 +0200815 }
Radek Krejci335332a2019-09-05 13:03:35 +0200816 default:
817 LOGINT(ctx->ctx);
818 return LY_EINT;
819 }
820
Radek Krejciad5963b2019-09-06 16:03:05 +0200821 return ret;
Radek Krejci335332a2019-09-05 13:03:35 +0200822}