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