1 /**
2 * @file yin.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief YIN parser for libyang
5 *
6 * Copyright (c) 2015 - 2018 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 <assert.h>
16 #include <ctype.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stddef.h>
23 #include <sys/types.h>
24
25 #include "libyang.h"
26 #include "common.h"
27 #include "context.h"
28 #include "hash_table.h"
29 #include "xpath.h"
30 #include "parser.h"
31 #include "resolve.h"
32 #include "tree_internal.h"
33 #include "xml_internal.h"
34
35 #define GETVAL(ctx, value, node, arg) \
36 value = lyxml_get_attr(node, arg, NULL); \
37 if (!value) { \
38 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, arg, node->name); \
39 goto error; \
40 }
41
42 #define YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, counter, storage, name, parent, code) \
43 if ((counter) == LY_ARRAY_MAX(storage)) { \
44 LOGERR(ctx, LY_EINT, "Reached limit (%"PRIu64") for storing %s in %s statement.", \
45 LY_ARRAY_MAX(storage), name, parent); \
46 code; \
47 }
48
49 #define YIN_CHECK_ARRAY_OVERFLOW_RETURN(ctx, counter, storage, name, parent, retval) \
50 YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, counter, storage, name, parent, return retval)
51
52 #define YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, counter, storage, name, parent, target) \
53 YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, counter, storage, name, parent, goto target)
54
55 #define OPT_IDENT 0x01
56 #define OPT_CFG_PARSE 0x02
57 #define OPT_CFG_INHERIT 0x04
58 #define OPT_CFG_IGNORE 0x08
59 #define OPT_MODULE 0x10
60 static int read_yin_common(struct lys_module *, struct lys_node *, void *, LYEXT_PAR, struct lyxml_elem *, int,
61 struct unres_schema *);
62
63 static struct lys_node *read_yin_choice(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
64 int options, struct unres_schema *unres);
65 static struct lys_node *read_yin_case(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
66 int options, struct unres_schema *unres);
67 static struct lys_node *read_yin_anydata(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
68 LYS_NODE type, int valid_config, struct unres_schema *unres);
69 static struct lys_node *read_yin_container(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
70 int options, struct unres_schema *unres);
71 static struct lys_node *read_yin_leaf(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
72 int valid_config, struct unres_schema *unres);
73 static struct lys_node *read_yin_leaflist(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
74 int valid_config, struct unres_schema *unres);
75 static struct lys_node *read_yin_list(struct lys_module *module,struct lys_node *parent, struct lyxml_elem *yin,
76 int options, struct unres_schema *unres);
77 static struct lys_node *read_yin_uses(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
78 int options, struct unres_schema *unres);
79 static struct lys_node *read_yin_grouping(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
80 int options, struct unres_schema *unres);
81 static struct lys_node *read_yin_rpc_action(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
82 int options, struct unres_schema *unres);
83 static struct lys_node *read_yin_notif(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
84 int options, struct unres_schema *unres);
85 static struct lys_when *read_yin_when(struct lys_module *module, struct lyxml_elem *yin, struct unres_schema *unres);
86
87 /*
88 * yin - the provided XML subtree is unlinked
89 * ext - pointer to the storage in the parent structure to be able to update its location after realloc
90 */
91 int
lyp_yin_fill_ext(void * parent,LYEXT_PAR parent_type,LYEXT_SUBSTMT substmt,uint8_t substmt_index,struct lys_module * module,struct lyxml_elem * yin,struct lys_ext_instance *** ext,uint8_t * ext_size,struct unres_schema * unres)92 lyp_yin_fill_ext(void *parent, LYEXT_PAR parent_type, LYEXT_SUBSTMT substmt, uint8_t substmt_index,
93 struct lys_module *module, struct lyxml_elem *yin, struct lys_ext_instance ***ext,
94 uint8_t *ext_size, struct unres_schema *unres)
95 {
96 struct unres_ext *info;
97 int rc;
98
99 info = malloc(sizeof *info);
100 LY_CHECK_ERR_RETURN(!info, LOGMEM(module->ctx), EXIT_FAILURE);
101 lyxml_unlink(module->ctx, yin);
102 info->data.yin = yin;
103 info->datatype = LYS_IN_YIN;
104 info->parent = parent;
105 info->mod = module;
106 info->parent_type = parent_type;
107 info->substmt = substmt;
108 info->substmt_index = substmt_index;
109 info->ext_index = *ext_size;
110
111 rc = unres_schema_add_node(module, unres, ext, UNRES_EXT, (struct lys_node *)info);
112 if (!rc && !(*ext)[*ext_size]) {
113 /* extension instance is skipped */
114 } else {
115 ++(*ext_size);
116 }
117
118 return rc == -1 ? EXIT_FAILURE : EXIT_SUCCESS;
119 }
120
121 /* logs directly */
122 static const char *
read_yin_subnode(struct ly_ctx * ctx,struct lyxml_elem * node,const char * name)123 read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
124 {
125 int len;
126
127 /* there should be <text> child */
128 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
129 LOGERR(ctx, LY_EVALID, "Expected \"%s\" element in \"%s\" element.", name, node->name);
130 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, name, node->name);
131 return NULL;
132 } else if (node->child->content) {
133 len = strlen(node->child->content);
134 return lydict_insert(ctx, node->child->content, len);
135 } else {
136 return lydict_insert(ctx, "", 0);
137 }
138 }
139
140 int
lyp_yin_parse_subnode_ext(struct lys_module * mod,void * elem,LYEXT_PAR elem_type,struct lyxml_elem * yin,LYEXT_SUBSTMT type,uint8_t i,struct unres_schema * unres)141 lyp_yin_parse_subnode_ext(struct lys_module *mod, void *elem, LYEXT_PAR elem_type,
142 struct lyxml_elem *yin, LYEXT_SUBSTMT type, uint8_t i, struct unres_schema *unres)
143 {
144 void *reallocated;
145 struct lyxml_elem *next, *child;
146 int r;
147 struct lys_ext_instance ***ext;
148 uint8_t *ext_size;
149 const char *statement;
150
151 r = lyp_get_ext_list(mod->ctx, elem, elem_type, &ext, &ext_size, &statement);
152 LY_CHECK_RETURN(r, EXIT_FAILURE);
153
154 if (type == LYEXT_SUBSTMT_SELF) {
155 /* parse for the statement self, not for the substatement */
156 child = yin;
157 next = NULL;
158 goto parseext;
159 }
160
161 LY_TREE_FOR_SAFE(yin->child, next, child) {
162 if (!child->ns) {
163 LOGVAL(mod->ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Extension instance \"%s\" is missing namespace.", child->name);
164 return EXIT_FAILURE;
165 }
166 if (!strcmp(child->ns->value, LY_NSYIN)) {
167 /* skip the regular YIN nodes */
168 continue;
169 }
170
171 /* parse it as extension */
172 parseext:
173
174 YIN_CHECK_ARRAY_OVERFLOW_RETURN(mod->ctx, *ext_size, *ext_size, "extension", statement, EXIT_FAILURE);
175 /* first, allocate a space for the extension instance in the parent elem */
176 reallocated = realloc(*ext, (1 + (*ext_size)) * sizeof **ext);
177 LY_CHECK_ERR_RETURN(!reallocated, LOGMEM(mod->ctx), EXIT_FAILURE);
178 (*ext) = reallocated;
179
180 /* init memory */
181 (*ext)[(*ext_size)] = NULL;
182
183 /* parse YIN data */
184 r = lyp_yin_fill_ext(elem, elem_type, type, i, mod, child, ext, ext_size, unres);
185 if (r) {
186 return EXIT_FAILURE;
187 }
188
189 lyp_reduce_ext_list(ext, *ext_size, 1 + (*ext_size));
190
191 /* done - do not free the child, it is unlinked in lyp_yin_fill_ext */
192 }
193
194 return EXIT_SUCCESS;
195 }
196
197 /* logs directly */
198 static int
fill_yin_iffeature(struct lys_node * parent,int parent_is_feature,struct lyxml_elem * yin,struct lys_iffeature * iffeat,struct unres_schema * unres)199 fill_yin_iffeature(struct lys_node *parent, int parent_is_feature, struct lyxml_elem *yin, struct lys_iffeature *iffeat,
200 struct unres_schema *unres)
201 {
202 int r, c_ext = 0;
203 const char *value;
204 struct lyxml_elem *node, *next;
205 struct ly_ctx *ctx = parent->module->ctx;
206
207 GETVAL(ctx, value, yin, "name");
208
209 if ((lys_node_module(parent)->version != 2) && ((value[0] == '(') || strchr(value, ' '))) {
210 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
211 error:
212 return EXIT_FAILURE;
213 }
214
215 if (!(value = transform_iffeat_schema2json(parent->module, value))) {
216 return EXIT_FAILURE;
217 }
218
219 r = resolve_iffeature_compile(iffeat, value, parent, parent_is_feature, unres);
220 lydict_remove(ctx, value);
221 if (r) {
222 return EXIT_FAILURE;
223 }
224
225 LY_TREE_FOR_SAFE(yin->child, next, node) {
226 if (!node->ns) {
227 /* garbage */
228 lyxml_free(ctx, node);
229 } else if (strcmp(node->ns->value, LY_NSYIN)) {
230 /* extension */
231 YIN_CHECK_ARRAY_OVERFLOW_RETURN(ctx, c_ext, iffeat->ext_size, "extensions", "if-feature", EXIT_FAILURE);
232 c_ext++;
233 } else {
234 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name, "if-feature");
235 return EXIT_FAILURE;
236 }
237 }
238 if (c_ext) {
239 iffeat->ext = calloc(c_ext, sizeof *iffeat->ext);
240 LY_CHECK_ERR_RETURN(!iffeat->ext, LOGMEM(ctx), EXIT_FAILURE);
241 LY_TREE_FOR_SAFE(yin->child, next, node) {
242 /* extensions */
243 r = lyp_yin_fill_ext(iffeat, LYEXT_PAR_IDENT, 0, 0, parent->module, node,
244 &iffeat->ext, &iffeat->ext_size, unres);
245 if (r) {
246 return EXIT_FAILURE;
247 }
248 }
249
250 lyp_reduce_ext_list(&iffeat->ext, iffeat->ext_size, c_ext + iffeat->ext_size);
251 }
252
253 return EXIT_SUCCESS;
254 }
255
256 /* logs directly */
257 static int
fill_yin_identity(struct lys_module * module,struct lyxml_elem * yin,struct lys_ident * ident,struct unres_schema * unres)258 fill_yin_identity(struct lys_module *module, struct lyxml_elem *yin, struct lys_ident *ident, struct unres_schema *unres)
259 {
260 struct lyxml_elem *node, *next;
261 struct ly_ctx *ctx = module->ctx;
262 const char *value;
263 int rc;
264 int c_ftrs = 0, c_base = 0, c_ext = 0;
265 void *reallocated;
266
267 GETVAL(ctx, value, yin, "name");
268 ident->name = value;
269
270 if (read_yin_common(module, NULL, ident, LYEXT_PAR_IDENT, yin, OPT_IDENT | OPT_MODULE, unres)) {
271 goto error;
272 }
273
274 if (dup_identities_check(ident->name, module)) {
275 goto error;
276 }
277
278 LY_TREE_FOR(yin->child, node) {
279 if (strcmp(node->ns->value, LY_NSYIN)) {
280 /* extension */
281 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, ident->ext_size, "extensions", "identity", error);
282 c_ext++;
283 } else if (!strcmp(node->name, "base")) {
284 if (c_base && (module->version < 2)) {
285 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "base", "identity");
286 goto error;
287 }
288 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_base, ident->base_size, "bases", "identity", error);
289 if (lyp_yin_parse_subnode_ext(module, ident, LYEXT_PAR_IDENT, node, LYEXT_SUBSTMT_BASE, c_base, unres)) {
290 goto error;
291 }
292 c_base++;
293
294 } else if ((module->version >= 2) && !strcmp(node->name, "if-feature")) {
295 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, ident->iffeature_size, "if-features", "identity", error);
296 c_ftrs++;
297
298 } else {
299 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name, "identity");
300 goto error;
301 }
302 }
303
304 if (c_base) {
305 ident->base_size = 0;
306 ident->base = calloc(c_base, sizeof *ident->base);
307 LY_CHECK_ERR_GOTO(!ident->base, LOGMEM(ctx), error);
308 }
309 if (c_ftrs) {
310 ident->iffeature = calloc(c_ftrs, sizeof *ident->iffeature);
311 LY_CHECK_ERR_GOTO(!ident->iffeature, LOGMEM(ctx), error);
312 }
313 if (c_ext) {
314 /* some extensions may be already present from the substatements */
315 reallocated = realloc(ident->ext, (c_ext + ident->ext_size) * sizeof *ident->ext);
316 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
317 ident->ext = reallocated;
318
319 /* init memory */
320 memset(&ident->ext[ident->ext_size], 0, c_ext * sizeof *ident->ext);
321 }
322
323 LY_TREE_FOR_SAFE(yin->child, next, node) {
324 if (strcmp(node->ns->value, LY_NSYIN)) {
325 /* extension */
326 rc = lyp_yin_fill_ext(ident, LYEXT_PAR_IDENT, 0, 0, module, node, &ident->ext, &ident->ext_size, unres);
327 if (rc) {
328 goto error;
329 }
330 } else if (!strcmp(node->name, "base")) {
331 GETVAL(ctx, value, node, "name");
332 value = transform_schema2json(module, value);
333 if (!value) {
334 goto error;
335 }
336
337 if (unres_schema_add_str(module, unres, ident, UNRES_IDENT, value) == -1) {
338 lydict_remove(ctx, value);
339 goto error;
340 }
341 lydict_remove(ctx, value);
342 } else if (!strcmp(node->name, "if-feature")) {
343 rc = fill_yin_iffeature((struct lys_node *)ident, 0, node, &ident->iffeature[ident->iffeature_size], unres);
344 ident->iffeature_size++;
345 if (rc) {
346 goto error;
347 }
348 }
349 }
350
351 lyp_reduce_ext_list(&ident->ext, ident->ext_size, c_ext + ident->ext_size);
352
353 return EXIT_SUCCESS;
354
355 error:
356 return EXIT_FAILURE;
357 }
358
359 /* logs directly */
360 static int
read_restr_substmt(struct lys_module * module,struct lys_restr * restr,struct lyxml_elem * yin,struct unres_schema * unres)361 read_restr_substmt(struct lys_module *module, struct lys_restr *restr, struct lyxml_elem *yin,
362 struct unres_schema *unres)
363 {
364 struct lyxml_elem *child, *next;
365 const char *value;
366 struct ly_ctx *ctx = module->ctx;
367
368 LY_TREE_FOR_SAFE(yin->child, next, child) {
369 if (!child->ns) {
370 /* garbage */
371 continue;
372 } else if (strcmp(child->ns->value, LY_NSYIN)) {
373 /* extension */
374 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_SELF, 0, unres)) {
375 return EXIT_FAILURE;
376 }
377 } else if (!strcmp(child->name, "description")) {
378 if (restr->dsc) {
379 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
380 return EXIT_FAILURE;
381 }
382 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
383 return EXIT_FAILURE;
384 }
385 restr->dsc = read_yin_subnode(ctx, child, "text");
386 if (!restr->dsc) {
387 return EXIT_FAILURE;
388 }
389 } else if (!strcmp(child->name, "reference")) {
390 if (restr->ref) {
391 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
392 return EXIT_FAILURE;
393 }
394 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
395 return EXIT_FAILURE;
396 }
397 restr->ref = read_yin_subnode(ctx, child, "text");
398 if (!restr->ref) {
399 return EXIT_FAILURE;
400 }
401 } else if (!strcmp(child->name, "error-app-tag")) {
402 if (restr->eapptag) {
403 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
404 return EXIT_FAILURE;
405 }
406 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_ERRTAG, 0, unres)) {
407 return EXIT_FAILURE;
408 }
409 GETVAL(ctx, value, child, "value");
410 restr->eapptag = lydict_insert(ctx, value, 0);
411 } else if (!strcmp(child->name, "error-message")) {
412 if (restr->emsg) {
413 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
414 return EXIT_FAILURE;
415 }
416 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_ERRMSG, 0, unres)) {
417 return EXIT_FAILURE;
418 }
419 restr->emsg = read_yin_subnode(ctx, child, "value");
420 if (!restr->emsg) {
421 return EXIT_FAILURE;
422 }
423 } else {
424 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
425 return EXIT_FAILURE;
426 }
427 }
428
429 return EXIT_SUCCESS;
430
431 error:
432 return EXIT_FAILURE;
433 }
434
435 /* logs directly, returns EXIT_SUCCESS, EXIT_FAILURE, -1 */
436 int
fill_yin_type(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,struct lys_type * type,int parenttype,struct unres_schema * unres)437 fill_yin_type(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_type *type,
438 int parenttype, struct unres_schema *unres)
439 {
440 const char *value, *name, *module_name = NULL;
441 struct lys_node *siter;
442 struct lyxml_elem *next, *next2, *node, *child, exts;
443 struct lys_restr **restrs, *restr;
444 struct lys_type_bit bit, *bits_sc = NULL;
445 struct lys_type_enum *enms_sc = NULL; /* shortcut */
446 struct lys_type *dertype;
447 struct ly_ctx *ctx = module->ctx;
448 int rc, val_set, c_ftrs, c_ext = 0;
449 unsigned int i, j;
450 int ret = -1;
451 int64_t v, v_ = 0;
452 int64_t p, p_;
453 size_t len;
454 int in_grp = 0;
455 char *buf, modifier;
456
457 /* init */
458 memset(&exts, 0, sizeof exts);
459
460 GETVAL(ctx, value, yin, "name");
461 value = transform_schema2json(module, value);
462 if (!value) {
463 goto error;
464 }
465
466 i = parse_identifier(value);
467 if (i < 1) {
468 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, value[-i], &value[-i]);
469 lydict_remove(ctx, value);
470 goto error;
471 }
472 /* module name */
473 name = value;
474 if (value[i]) {
475 module_name = lydict_insert(ctx, value, i);
476 name += i;
477 if ((name[0] != ':') || (parse_identifier(name + 1) < 1)) {
478 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, name[0], name);
479 lydict_remove(ctx, module_name);
480 lydict_remove(ctx, value);
481 goto error;
482 }
483 /* name is in dictionary, but moved */
484 ++name;
485 }
486
487 rc = resolve_superior_type(name, module_name, module, parent, &type->der);
488 if (rc == -1) {
489 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, module_name);
490 lydict_remove(ctx, module_name);
491 lydict_remove(ctx, value);
492 goto error;
493
494 /* the type could not be resolved or it was resolved to an unresolved typedef */
495 } else if (rc == EXIT_FAILURE) {
496 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_NONE, NULL, "type", name);
497 lydict_remove(ctx, module_name);
498 lydict_remove(ctx, value);
499 ret = EXIT_FAILURE;
500 goto error;
501 }
502 lydict_remove(ctx, module_name);
503 lydict_remove(ctx, value);
504
505 if (type->value_flags & LY_VALUE_UNRESGRP) {
506 /* resolved type in grouping, decrease the grouping's nacm number to indicate that one less
507 * unresolved item left inside the grouping, LYTYPE_GRP used as a flag for types inside a grouping. */
508 for (siter = parent; siter && (siter->nodetype != LYS_GROUPING); siter = lys_parent(siter));
509 if (siter) {
510 assert(((struct lys_node_grp *)siter)->unres_count);
511 ((struct lys_node_grp *)siter)->unres_count--;
512 } else {
513 LOGINT(ctx);
514 goto error;
515 }
516 type->value_flags &= ~LY_VALUE_UNRESGRP;
517 }
518 type->base = type->der->type.base;
519
520 /* check status */
521 if (lyp_check_status(type->parent->flags, type->parent->module, type->parent->name,
522 type->der->flags, type->der->module, type->der->name, parent)) {
523 return -1;
524 }
525
526 /* parse extension instances */
527 LY_TREE_FOR_SAFE(yin->child, next, node) {
528 if (!node->ns) {
529 /* garbage */
530 lyxml_free(ctx, node);
531 continue;
532 } else if (!strcmp(node->ns->value, LY_NSYIN)) {
533 /* YANG (YIN) statements - process later */
534 continue;
535 }
536
537 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, type->ext_size, "extensions", "type", error);
538
539 lyxml_unlink_elem(ctx, node, 2);
540 lyxml_add_child(ctx, &exts, node);
541 c_ext++;
542 }
543 if (c_ext) {
544 type->ext = calloc(c_ext, sizeof *type->ext);
545 LY_CHECK_ERR_GOTO(!type->ext, LOGMEM(ctx), error);
546
547 LY_TREE_FOR_SAFE(exts.child, next, node) {
548 rc = lyp_yin_fill_ext(type, LYEXT_PAR_TYPE, 0, 0, module, node, &type->ext, &type->ext_size, unres);
549 if (rc) {
550 goto error;
551 }
552 }
553
554 lyp_reduce_ext_list(&type->ext, type->ext_size, c_ext + type->ext_size);
555 }
556
557 switch (type->base) {
558 case LY_TYPE_BITS:
559 /* RFC 6020 9.7.4 - bit */
560
561 /* get bit specifications, at least one must be present */
562 LY_TREE_FOR_SAFE(yin->child, next, node) {
563 if (!strcmp(node->name, "bit")) {
564 YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, type->info.bits.count, type->info.bits.count, "bits", "type",
565 type->info.bits.count = 0; goto error);
566 type->info.bits.count++;
567 } else {
568 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
569 type->info.bits.count = 0;
570 goto error;
571 }
572 }
573 dertype = &type->der->type;
574 if (!dertype->der) {
575 if (!type->info.bits.count) {
576 /* type is derived directly from buit-in bits type and bit statement is required */
577 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "bit", "type");
578 goto error;
579 }
580 } else {
581 for (; !dertype->info.enums.count; dertype = &dertype->der->type);
582 if (module->version < 2 && type->info.bits.count) {
583 /* type is not directly derived from buit-in bits type and bit statement is prohibited,
584 * since YANG 1.1 the bit statements can be used to restrict the base bits type */
585 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
586 type->info.bits.count = 0;
587 goto error;
588 }
589 }
590
591 if (type->info.bits.count) {
592 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
593 LY_CHECK_ERR_GOTO(!type->info.bits.bit, LOGMEM(ctx), error);
594 }
595
596 p = 0;
597 i = 0;
598 LY_TREE_FOR(yin->child, next) {
599 c_ftrs = 0;
600
601 GETVAL(ctx, value, next, "name");
602 if (lyp_check_identifier(ctx, value, LY_IDENT_SIMPLE, NULL, NULL)) {
603 goto error;
604 }
605
606 type->info.bits.bit[i].name = lydict_insert(ctx, value, strlen(value));
607 if (read_yin_common(module, NULL, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, next, 0, unres)) {
608 type->info.bits.count = i + 1;
609 goto error;
610 }
611
612 if (!dertype->der) { /* directly derived type from bits built-in type */
613 /* check the name uniqueness */
614 for (j = 0; j < i; j++) {
615 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
616 LOGVAL(ctx, LYE_BITS_DUPNAME, LY_VLOG_NONE, NULL, type->info.bits.bit[i].name);
617 type->info.bits.count = i + 1;
618 goto error;
619 }
620 }
621 } else {
622 /* restricted bits type - the name MUST be used in the base type */
623 bits_sc = dertype->info.bits.bit;
624 for (j = 0; j < dertype->info.bits.count; j++) {
625 if (ly_strequal(bits_sc[j].name, value, 1)) {
626 break;
627 }
628 }
629 if (j == dertype->info.bits.count) {
630 LOGVAL(ctx, LYE_BITS_INNAME, LY_VLOG_NONE, NULL, value);
631 type->info.bits.count = i + 1;
632 goto error;
633 }
634 }
635
636
637 p_ = -1;
638 LY_TREE_FOR_SAFE(next->child, next2, node) {
639 if (!node->ns) {
640 /* garbage */
641 continue;
642 } else if (strcmp(node->ns->value, LY_NSYIN)) {
643 /* extension */
644 if (lyp_yin_parse_subnode_ext(module, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, node,
645 LYEXT_SUBSTMT_SELF, 0, unres)) {
646 goto error;
647 }
648 } else if (!strcmp(node->name, "position")) {
649 if (p_ != -1) {
650 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
651 type->info.bits.count = i + 1;
652 goto error;
653 }
654
655 GETVAL(ctx, value, node, "value");
656 p_ = strtoll(value, NULL, 10);
657
658 /* range check */
659 if (p_ < 0 || p_ > UINT32_MAX) {
660 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "bit/position");
661 type->info.bits.count = i + 1;
662 goto error;
663 }
664 type->info.bits.bit[i].pos = (uint32_t)p_;
665
666 if (!dertype->der) { /* directly derived type from bits built-in type */
667 /* keep the highest enum value for automatic increment */
668 if (type->info.bits.bit[i].pos >= p) {
669 p = type->info.bits.bit[i].pos;
670 p++;
671 } else {
672 /* check that the value is unique */
673 for (j = 0; j < i; j++) {
674 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
675 LOGVAL(ctx, LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL,
676 type->info.bits.bit[i].pos, type->info.bits.bit[i].name,
677 type->info.bits.bit[j].name);
678 type->info.bits.count = i + 1;
679 goto error;
680 }
681 }
682 }
683 }
684
685 if (lyp_yin_parse_subnode_ext(module, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, node,
686 LYEXT_SUBSTMT_POSITION, 0, unres)) {
687 goto error;
688 }
689
690 for (j = 0; j < type->info.bits.bit[i].ext_size; ++j) {
691 /* set flag, which represent LYEXT_OPT_VALID */
692 if (type->info.bits.bit[i].ext[j]->flags & LYEXT_OPT_VALID) {
693 type->parent->flags |= LYS_VALID_EXT;
694 break;
695 }
696 }
697
698 } else if ((module->version >= 2) && !strcmp(node->name, "if-feature")) {
699 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, type->info.bits.bit[i].iffeature_size, "if-features", "bit", error);
700 c_ftrs++;
701 } else {
702 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
703 goto error;
704 }
705 }
706
707 if (!dertype->der) { /* directly derived type from bits built-in type */
708 if (p_ == -1) {
709 /* assign value automatically */
710 if (p > UINT32_MAX) {
711 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "4294967295", "bit/position");
712 type->info.bits.count = i + 1;
713 goto error;
714 }
715 type->info.bits.bit[i].pos = (uint32_t)p;
716 type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
717 p++;
718 }
719 } else { /* restricted bits type */
720 if (p_ == -1) {
721 /* automatically assign position from base type */
722 type->info.bits.bit[i].pos = bits_sc[j].pos;
723 type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
724 } else {
725 /* check that the assigned position corresponds to the original
726 * position of the bit in the base type */
727 if (p_ != bits_sc[j].pos) {
728 /* p_ - assigned position in restricted bits
729 * bits_sc[j].pos - position assigned to the corresponding bit (detected above) in base type */
730 LOGVAL(ctx, LYE_BITS_INVAL, LY_VLOG_NONE, NULL, type->info.bits.bit[i].pos,
731 type->info.bits.bit[i].name, bits_sc[j].pos);
732 type->info.bits.count = i + 1;
733 goto error;
734 }
735 }
736 }
737
738 /* if-features */
739 if (c_ftrs) {
740 bits_sc = &type->info.bits.bit[i];
741 bits_sc->iffeature = calloc(c_ftrs, sizeof *bits_sc->iffeature);
742 if (!bits_sc->iffeature) {
743 LOGMEM(ctx);
744 type->info.bits.count = i + 1;
745 goto error;
746 }
747
748 LY_TREE_FOR(next->child, node) {
749 if (!strcmp(node->name, "if-feature")) {
750 rc = fill_yin_iffeature((struct lys_node *)type->parent, 0, node,
751 &bits_sc->iffeature[bits_sc->iffeature_size], unres);
752 bits_sc->iffeature_size++;
753 if (rc) {
754 type->info.bits.count = i + 1;
755 goto error;
756 }
757 }
758 }
759 }
760
761 /* keep them ordered by position */
762 j = i;
763 while (j && type->info.bits.bit[j - 1].pos > type->info.bits.bit[j].pos) {
764 /* switch them */
765 memcpy(&bit, &type->info.bits.bit[j], sizeof bit);
766 memcpy(&type->info.bits.bit[j], &type->info.bits.bit[j - 1], sizeof bit);
767 memcpy(&type->info.bits.bit[j - 1], &bit, sizeof bit);
768 j--;
769 }
770
771 ++i;
772 }
773 break;
774
775 case LY_TYPE_DEC64:
776 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
777 LY_TREE_FOR(yin->child, node) {
778
779 if (!strcmp(node->name, "range")) {
780 if (type->info.dec64.range) {
781 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
782 goto error;
783 }
784
785 GETVAL(ctx, value, node, "value");
786 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
787 LY_CHECK_ERR_GOTO(!type->info.dec64.range, LOGMEM(ctx), error);
788 type->info.dec64.range->expr = lydict_insert(ctx, value, 0);
789
790 /* get possible substatements */
791 if (read_restr_substmt(module, type->info.dec64.range, node, unres)) {
792 goto error;
793 }
794 for (j = 0; j < type->info.dec64.range->ext_size; ++j) {
795 /* set flag, which represent LYEXT_OPT_VALID */
796 if (type->info.dec64.range->ext[j]->flags & LYEXT_OPT_VALID) {
797 type->parent->flags |= LYS_VALID_EXT;
798 break;
799 }
800 }
801 } else if (!strcmp(node->name, "fraction-digits")) {
802 if (type->info.dec64.dig) {
803 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
804 goto error;
805 }
806 GETVAL(ctx, value, node, "value");
807 v = strtol(value, NULL, 10);
808
809 /* range check */
810 if (v < 1 || v > 18) {
811 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
812 goto error;
813 }
814 type->info.dec64.dig = (uint8_t)v;
815 type->info.dec64.div = 10;
816 for (i = 1; i < v; i++) {
817 type->info.dec64.div *= 10;
818 }
819
820 /* extensions */
821 if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_DIGITS, 0, unres)) {
822 goto error;
823 }
824 } else {
825 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
826 goto error;
827 }
828 }
829
830 /* mandatory sub-statement(s) check */
831 if (!type->info.dec64.dig && !type->der->type.der) {
832 /* decimal64 type directly derived from built-in type requires fraction-digits */
833 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "fraction-digits", "type");
834 goto error;
835 }
836 if (type->info.dec64.dig && type->der->type.der) {
837 /* type is not directly derived from buit-in type and fraction-digits statement is prohibited */
838 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "fraction-digits");
839 goto error;
840 }
841
842 /* copy fraction-digits specification from parent type for easier internal use */
843 if (type->der->type.der) {
844 type->info.dec64.dig = type->der->type.info.dec64.dig;
845 type->info.dec64.div = type->der->type.info.dec64.div;
846 }
847
848 if (type->info.dec64.range && lyp_check_length_range(ctx, type->info.dec64.range->expr, type)) {
849 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "range");
850 goto error;
851 }
852 break;
853
854 case LY_TYPE_ENUM:
855 /* RFC 6020 9.6 - enum */
856
857 /* get enum specifications, at least one must be present */
858 LY_TREE_FOR_SAFE(yin->child, next, node) {
859
860 if (!strcmp(node->name, "enum")) {
861 YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, type->info.enums.count, type->info.enums.count, "enums", "type",
862 type->info.enums.count = 0; goto error);
863 type->info.enums.count++;
864 } else {
865 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
866 type->info.enums.count = 0;
867 goto error;
868 }
869 }
870 dertype = &type->der->type;
871 if (!dertype->der) {
872 if (!type->info.enums.count) {
873 /* type is derived directly from buit-in enumeartion type and enum statement is required */
874 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "enum", "type");
875 goto error;
876 }
877 } else {
878 for (; !dertype->info.enums.count; dertype = &dertype->der->type);
879 if (module->version < 2 && type->info.enums.count) {
880 /* type is not directly derived from built-in enumeration type and enum statement is prohibited
881 * in YANG 1.0, since YANG 1.1 enum statements can be used to restrict the base enumeration type */
882 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
883 type->info.enums.count = 0;
884 goto error;
885 }
886 }
887
888 if (type->info.enums.count) {
889 type->info.enums.enm = calloc(type->info.enums.count, sizeof *type->info.enums.enm);
890 LY_CHECK_ERR_GOTO(!type->info.enums.enm, LOGMEM(ctx), error);
891 }
892
893 v = 0;
894 i = 0;
895 LY_TREE_FOR(yin->child, next) {
896 c_ftrs = 0;
897
898 GETVAL(ctx, value, next, "name");
899 if (!value[0]) {
900 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "enum name");
901 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Enum name must not be empty.");
902 goto error;
903 }
904 type->info.enums.enm[i].name = lydict_insert(ctx, value, strlen(value));
905 if (read_yin_common(module, NULL, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, next, 0, unres)) {
906 type->info.enums.count = i + 1;
907 goto error;
908 }
909
910 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
911 value = type->info.enums.enm[i].name;
912 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
913 LOGVAL(ctx, LYE_ENUM_WS, LY_VLOG_NONE, NULL, value);
914 type->info.enums.count = i + 1;
915 goto error;
916 }
917
918 if (!dertype->der) { /* directly derived type from enumeration built-in type */
919 /* check the name uniqueness */
920 for (j = 0; j < i; j++) {
921 if (ly_strequal(type->info.enums.enm[j].name, value, 1)) {
922 LOGVAL(ctx, LYE_ENUM_DUPNAME, LY_VLOG_NONE, NULL, value);
923 type->info.enums.count = i + 1;
924 goto error;
925 }
926 }
927 } else {
928 /* restricted enumeration type - the name MUST be used in the base type */
929 enms_sc = dertype->info.enums.enm;
930 for (j = 0; j < dertype->info.enums.count; j++) {
931 if (ly_strequal(enms_sc[j].name, value, 1)) {
932 break;
933 }
934 }
935 if (j == dertype->info.enums.count) {
936 LOGVAL(ctx, LYE_ENUM_INNAME, LY_VLOG_NONE, NULL, value);
937 type->info.enums.count = i + 1;
938 goto error;
939 }
940 }
941
942 val_set = 0;
943 LY_TREE_FOR_SAFE(next->child, next2, node) {
944 if (!node->ns) {
945 /* garbage */
946 continue;
947 } else if (strcmp(node->ns->value, LY_NSYIN)) {
948 /* extensions */
949 if (lyp_yin_parse_subnode_ext(module, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, node,
950 LYEXT_SUBSTMT_SELF, 0, unres)) {
951 goto error;
952 }
953 } else if (!strcmp(node->name, "value")) {
954 if (val_set) {
955 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
956 type->info.enums.count = i + 1;
957 goto error;
958 }
959
960 GETVAL(ctx, value, node, "value");
961 v_ = strtoll(value, NULL, 10);
962
963 /* range check */
964 if (v_ < INT32_MIN || v_ > INT32_MAX) {
965 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "enum/value");
966 type->info.enums.count = i + 1;
967 goto error;
968 }
969 type->info.enums.enm[i].value = v_;
970
971 if (!dertype->der) { /* directly derived type from enumeration built-in type */
972 if (!i) {
973 /* change value, which is assigned automatically, if first enum has value. */
974 v = type->info.enums.enm[i].value;
975 v++;
976 } else {
977 /* keep the highest enum value for automatic increment */
978 if (type->info.enums.enm[i].value >= v) {
979 v = type->info.enums.enm[i].value;
980 v++;
981 } else {
982 /* check that the value is unique */
983 for (j = 0; j < i; j++) {
984 if (type->info.enums.enm[j].value == type->info.enums.enm[i].value) {
985 LOGVAL(ctx, LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
986 type->info.enums.enm[i].value, type->info.enums.enm[i].name,
987 type->info.enums.enm[j].name);
988 type->info.enums.count = i + 1;
989 goto error;
990 }
991 }
992 }
993 }
994 }
995 val_set = 1;
996
997 if (lyp_yin_parse_subnode_ext(module, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, node,
998 LYEXT_SUBSTMT_VALUE, 0, unres)) {
999 goto error;
1000 }
1001
1002 for (j = 0; j < type->info.enums.enm[i].ext_size; ++j) {
1003 /* set flag, which represent LYEXT_OPT_VALID */
1004 if (type->info.enums.enm[i].ext[j]->flags & LYEXT_OPT_VALID) {
1005 type->parent->flags |= LYS_VALID_EXT;
1006 break;
1007 }
1008 }
1009 } else if ((module->version >= 2) && !strcmp(node->name, "if-feature")) {
1010 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, type->info.enums.enm[i].iffeature_size, "if-features", "enum", error);
1011 c_ftrs++;
1012
1013 } else {
1014 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1015 goto error;
1016 }
1017 }
1018
1019 if (!dertype->der) { /* directly derived type from enumeration */
1020 if (!val_set) {
1021 /* assign value automatically */
1022 if (v > INT32_MAX) {
1023 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "2147483648", "enum/value");
1024 type->info.enums.count = i + 1;
1025 goto error;
1026 }
1027 type->info.enums.enm[i].value = v;
1028 type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
1029 v++;
1030 }
1031 } else { /* restricted enum type */
1032 if (!val_set) {
1033 /* automatically assign value from base type */
1034 type->info.enums.enm[i].value = enms_sc[j].value;
1035 type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
1036 } else {
1037 /* check that the assigned value corresponds to the original
1038 * value of the enum in the base type */
1039 if (v_ != enms_sc[j].value) {
1040 /* v_ - assigned value in restricted enum
1041 * enms_sc[j].value - value assigned to the corresponding enum (detected above) in base type */
1042 LOGVAL(ctx, LYE_ENUM_INVAL, LY_VLOG_NONE, NULL,
1043 type->info.enums.enm[i].value, type->info.enums.enm[i].name, enms_sc[j].value);
1044 type->info.enums.count = i + 1;
1045 goto error;
1046 }
1047 }
1048 }
1049
1050 /* if-features */
1051 if (c_ftrs) {
1052 enms_sc = &type->info.enums.enm[i];
1053 enms_sc->iffeature = calloc(c_ftrs, sizeof *enms_sc->iffeature);
1054 if (!enms_sc->iffeature) {
1055 LOGMEM(ctx);
1056 type->info.enums.count = i + 1;
1057 goto error;
1058 }
1059
1060 LY_TREE_FOR(next->child, node) {
1061 if (!strcmp(node->name, "if-feature")) {
1062 rc = fill_yin_iffeature((struct lys_node *)type->parent, 0, node,
1063 &enms_sc->iffeature[enms_sc->iffeature_size], unres);
1064 enms_sc->iffeature_size++;
1065 if (rc) {
1066 type->info.enums.count = i + 1;
1067 goto error;
1068 }
1069 }
1070 }
1071 }
1072
1073 ++i;
1074 }
1075 break;
1076
1077 case LY_TYPE_IDENT:
1078 /* RFC 6020 9.10 - base */
1079
1080 /* get base specification, at least one must be present */
1081 LY_TREE_FOR_SAFE(yin->child, next, node) {
1082
1083 if (strcmp(node->name, "base")) {
1084 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1085 goto error;
1086 }
1087
1088 GETVAL(ctx, value, yin->child, "name");
1089 /* store in the JSON format */
1090 value = transform_schema2json(module, value);
1091 if (!value) {
1092 goto error;
1093 }
1094 rc = unres_schema_add_str(module, unres, type, UNRES_TYPE_IDENTREF, value);
1095 lydict_remove(ctx, value);
1096 if (rc == -1) {
1097 goto error;
1098 }
1099
1100 if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_BASE, 0, unres)) {
1101 goto error;
1102 }
1103 }
1104
1105 if (!yin->child) {
1106 if (type->der->type.der) {
1107 /* this is just a derived type with no base required */
1108 break;
1109 }
1110 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "base", "type");
1111 goto error;
1112 } else {
1113 if (type->der->type.der) {
1114 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "base");
1115 goto error;
1116 }
1117 }
1118 if (yin->child->next) {
1119 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, yin->child->next->name, yin->name);
1120 goto error;
1121 }
1122 break;
1123
1124 case LY_TYPE_INST:
1125 /* RFC 6020 9.13.2 - require-instance */
1126 LY_TREE_FOR(yin->child, node) {
1127 if (!strcmp(node->name, "require-instance")) {
1128 if (type->info.inst.req) {
1129 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1130 goto error;
1131 }
1132 GETVAL(ctx, value, node, "value");
1133 if (!strcmp(value, "true")) {
1134 type->info.inst.req = 1;
1135 } else if (!strcmp(value, "false")) {
1136 type->info.inst.req = -1;
1137 } else {
1138 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
1139 goto error;
1140 }
1141
1142 /* extensions */
1143 if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_REQINSTANCE, 0, unres)) {
1144 goto error;
1145 }
1146 } else {
1147 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1148 goto error;
1149 }
1150 }
1151
1152 if (type->der->type.der && !type->info.inst.req) {
1153 /* inherit require-instance property */
1154 type->info.inst.req = type->der->type.info.inst.req;
1155 }
1156
1157 break;
1158
1159 case LY_TYPE_BINARY:
1160 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
1161 case LY_TYPE_INT8:
1162 case LY_TYPE_INT16:
1163 case LY_TYPE_INT32:
1164 case LY_TYPE_INT64:
1165 case LY_TYPE_UINT8:
1166 case LY_TYPE_UINT16:
1167 case LY_TYPE_UINT32:
1168 case LY_TYPE_UINT64:
1169 /* RFC 6020 9.2.4 - range */
1170
1171 /* length and range are actually the same restriction, so process
1172 * them by this common code, we just need to differ the name and
1173 * structure where the information will be stored
1174 */
1175 if (type->base == LY_TYPE_BINARY) {
1176 restrs = &type->info.binary.length;
1177 name = "length";
1178 } else {
1179 restrs = &type->info.num.range;
1180 name = "range";
1181 }
1182
1183 LY_TREE_FOR(yin->child, node) {
1184
1185 if (!strcmp(node->name, name)) {
1186 if (*restrs) {
1187 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1188 goto error;
1189 }
1190
1191 GETVAL(ctx, value, node, "value");
1192 if (lyp_check_length_range(ctx, value, type)) {
1193 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, name);
1194 goto error;
1195 }
1196 *restrs = calloc(1, sizeof **restrs);
1197 LY_CHECK_ERR_GOTO(!(*restrs), LOGMEM(ctx), error);
1198 (*restrs)->expr = lydict_insert(ctx, value, 0);
1199
1200 /* get possible substatements */
1201 if (read_restr_substmt(module, *restrs, node, unres)) {
1202 goto error;
1203 }
1204
1205 for (j = 0; j < (*restrs)->ext_size; ++j) {
1206 /* set flag, which represent LYEXT_OPT_VALID */
1207 if ((*restrs)->ext[j]->flags & LYEXT_OPT_VALID) {
1208 type->parent->flags |= LYS_VALID_EXT;
1209 break;
1210 }
1211 }
1212 } else {
1213 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1214 goto error;
1215 }
1216 }
1217 break;
1218
1219 case LY_TYPE_LEAFREF:
1220 /* flag resolving for later use */
1221 if (!parenttype && lys_ingrouping(parent)) {
1222 /* just a flag - do not resolve */
1223 parenttype = 1;
1224 }
1225
1226 /* RFC 6020 9.9.2 - path */
1227 LY_TREE_FOR(yin->child, node) {
1228 if (!strcmp(node->name, "path") && !type->der->type.der) {
1229 /* keep path for later */
1230 } else if (module->version >= 2 && !strcmp(node->name, "require-instance")) {
1231 if (type->info.lref.req) {
1232 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1233 goto error;
1234 }
1235 GETVAL(ctx, value, node, "value");
1236 if (!strcmp(value, "true")) {
1237 type->info.lref.req = 1;
1238 } else if (!strcmp(value, "false")) {
1239 type->info.lref.req = -1;
1240 } else {
1241 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
1242 goto error;
1243 }
1244
1245 /* extensions */
1246 if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_REQINSTANCE, 0, unres)) {
1247 goto error;
1248 }
1249 } else {
1250 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1251 goto error;
1252 }
1253 }
1254
1255 /* now that require-instance is properly set, try to find and resolve path */
1256 LY_TREE_FOR(yin->child, node) {
1257 if (!strcmp(node->name, "path") && !type->der->type.der) {
1258 if (type->info.lref.path) {
1259 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1260 goto error;
1261 }
1262
1263 GETVAL(ctx, value, node, "value");
1264 /* store in the JSON format */
1265 type->info.lref.path = transform_schema2json(module, value);
1266 if (!type->info.lref.path) {
1267 goto error;
1268 }
1269
1270 /* try to resolve leafref path only when this is instantiated
1271 * leaf, so it is not:
1272 * - typedef's type,
1273 * - in grouping definition,
1274 * - just instantiated in a grouping definition,
1275 * because in those cases the nodes referenced in path might not be present
1276 * and it is not a bug. */
1277 if (!parenttype && unres_schema_add_node(module, unres, type, UNRES_TYPE_LEAFREF, parent) == -1) {
1278 goto error;
1279 }
1280
1281 /* extensions */
1282 if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_PATH, 0, unres)) {
1283 goto error;
1284 }
1285
1286 break;
1287 }
1288 }
1289
1290 if (!type->info.lref.path) {
1291 if (!type->der->type.der) {
1292 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "path", "type");
1293 goto error;
1294 } else {
1295 /* copy leafref definition into the derived type */
1296 type->info.lref.path = lydict_insert(ctx, type->der->type.info.lref.path, 0);
1297 if (!type->info.lref.req) {
1298 type->info.lref.req = type->der->type.info.lref.req;
1299 }
1300 /* and resolve the path at the place we are (if not in grouping/typedef) */
1301 if (!parenttype && unres_schema_add_node(module, unres, type, UNRES_TYPE_LEAFREF, parent) == -1) {
1302 goto error;
1303 }
1304 }
1305 }
1306
1307 break;
1308
1309 case LY_TYPE_STRING:
1310 /* RFC 6020 9.4.4 - length */
1311 /* RFC 6020 9.4.6 - pattern */
1312 i = 0;
1313 LY_TREE_FOR_SAFE(yin->child, next, node) {
1314
1315 if (!strcmp(node->name, "length")) {
1316 if (type->info.str.length) {
1317 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1318 goto error;
1319 }
1320
1321 GETVAL(ctx, value, node, "value");
1322 if (lyp_check_length_range(ctx, value, type)) {
1323 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "length");
1324 goto error;
1325 }
1326 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1327 LY_CHECK_ERR_GOTO(!type->info.str.length, LOGMEM(ctx), error);
1328 type->info.str.length->expr = lydict_insert(ctx, value, 0);
1329
1330 /* get possible sub-statements */
1331 if (read_restr_substmt(module, type->info.str.length, node, unres)) {
1332 goto error;
1333 }
1334
1335 for (j = 0; j < type->info.str.length->ext_size; ++j) {
1336 /* set flag, which represent LYEXT_OPT_VALID */
1337 if (type->info.str.length->ext[j]->flags & LYEXT_OPT_VALID) {
1338 type->parent->flags |= LYS_VALID_EXT;
1339 break;
1340 }
1341 }
1342 lyxml_free(ctx, node);
1343 } else if (!strcmp(node->name, "pattern")) {
1344 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, i, type->info.str.pat_count, "patterns", "type", error);
1345 i++;
1346 } else {
1347 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1348 goto error;
1349 }
1350 }
1351 /* store patterns in array */
1352 if (i) {
1353 if (!parenttype && parent && lys_ingrouping(parent)) {
1354 in_grp = 1;
1355 }
1356 type->info.str.patterns = calloc(i, sizeof *type->info.str.patterns);
1357 LY_CHECK_ERR_GOTO(!type->info.str.patterns, LOGMEM(ctx), error);
1358 #ifdef LY_ENABLED_CACHE
1359 if (!in_grp) {
1360 /* do not compile patterns in groupings */
1361 type->info.str.patterns_pcre = calloc(2 * i, sizeof *type->info.str.patterns_pcre);
1362 LY_CHECK_ERR_GOTO(!type->info.str.patterns_pcre, LOGMEM(ctx), error);
1363 }
1364 #endif
1365 LY_TREE_FOR(yin->child, node) {
1366 GETVAL(ctx, value, node, "value");
1367
1368 if (in_grp) {
1369 /* in grouping, just check the pattern syntax */
1370 if (!(ctx->models.flags & LY_CTX_TRUSTED) && lyp_check_pattern(ctx, value, NULL)) {
1371 goto error;
1372 }
1373 }
1374 #ifdef LY_ENABLED_CACHE
1375 else {
1376 /* outside grouping, check syntax and precompile pattern for later use by libpcre */
1377 if (lyp_precompile_pattern(ctx, value,
1378 (pcre **)&type->info.str.patterns_pcre[type->info.str.pat_count * 2],
1379 (pcre_extra **)&type->info.str.patterns_pcre[type->info.str.pat_count * 2 + 1])) {
1380 goto error;
1381 }
1382 }
1383 #endif
1384 restr = &type->info.str.patterns[type->info.str.pat_count]; /* shortcut */
1385 type->info.str.pat_count++;
1386
1387 modifier = 0x06; /* ACK */
1388 name = NULL;
1389 if (module->version >= 2) {
1390 LY_TREE_FOR_SAFE(node->child, next2, child) {
1391 if (child->ns && !strcmp(child->ns->value, LY_NSYIN) && !strcmp(child->name, "modifier")) {
1392 if (name) {
1393 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "modifier", node->name);
1394 goto error;
1395 }
1396
1397 GETVAL(ctx, name, child, "value");
1398 if (!strcmp(name, "invert-match")) {
1399 modifier = 0x15; /* NACK */
1400 } else {
1401 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, name, "modifier");
1402 goto error;
1403 }
1404 /* get extensions of the modifier */
1405 if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child,
1406 LYEXT_SUBSTMT_MODIFIER, 0, unres)) {
1407 goto error;
1408 }
1409
1410 lyxml_free(ctx, child);
1411 }
1412 }
1413 }
1414
1415 len = strlen(value);
1416 buf = malloc((len + 2) * sizeof *buf); /* modifier byte + value + terminating NULL byte */
1417 LY_CHECK_ERR_GOTO(!buf, LOGMEM(ctx), error);
1418 buf[0] = modifier;
1419 strcpy(&buf[1], value);
1420
1421 restr->expr = lydict_insert_zc(ctx, buf);
1422
1423 /* get possible sub-statements */
1424 if (read_restr_substmt(module, restr, node, unres)) {
1425 goto error;
1426 }
1427
1428 for (j = 0; j < restr->ext_size; ++j) {
1429 /* set flag, which represent LYEXT_OPT_VALID */
1430 if (restr->ext[j]->flags & LYEXT_OPT_VALID) {
1431 type->parent->flags |= LYS_VALID_EXT;
1432 break;
1433 }
1434 }
1435 }
1436 }
1437 break;
1438
1439 case LY_TYPE_UNION:
1440 /* RFC 6020 7.4 - type */
1441 /* count number of types in union */
1442 i = 0;
1443 LY_TREE_FOR_SAFE(yin->child, next, node) {
1444
1445 if (!strcmp(node->name, "type")) {
1446 if (type->der->type.der) {
1447 /* type can be a substatement only in "union" type, not in derived types */
1448 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "type", "derived type");
1449 goto error;
1450 }
1451 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, i, type->info.uni.count, "types", "type", error);
1452 i++;
1453 } else {
1454 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
1455 goto error;
1456 }
1457 }
1458
1459 if (!i && !type->der->type.der) {
1460 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "type", "(union) type");
1461 goto error;
1462 }
1463
1464 /* inherit instid presence information */
1465 if ((type->der->type.base == LY_TYPE_UNION) && type->der->type.info.uni.has_ptr_type) {
1466 type->info.uni.has_ptr_type = 1;
1467 }
1468
1469 /* allocate array for union's types ... */
1470 if (i) {
1471 type->info.uni.types = calloc(i, sizeof *type->info.uni.types);
1472 LY_CHECK_ERR_GOTO(!type->info.uni.types, LOGMEM(ctx), error);
1473 }
1474
1475 /* ... and fill the structures */
1476 LY_TREE_FOR(yin->child, node) {
1477 type->info.uni.types[type->info.uni.count].parent = type->parent;
1478 rc = fill_yin_type(module, parent, node, &type->info.uni.types[type->info.uni.count], parenttype, unres);
1479 if (!rc) {
1480 type->info.uni.count++;
1481
1482 if (module->version < 2) {
1483 /* union's type cannot be empty or leafref */
1484 if (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_EMPTY) {
1485 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "empty", node->name);
1486 rc = -1;
1487 } else if (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_LEAFREF) {
1488 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "leafref", node->name);
1489 rc = -1;
1490 }
1491 }
1492
1493 if ((type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_INST)
1494 || (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_LEAFREF)
1495 || ((type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_UNION)
1496 && type->info.uni.types[type->info.uni.count - 1].info.uni.has_ptr_type)) {
1497 type->info.uni.has_ptr_type = 1;
1498 }
1499 }
1500 if (rc) {
1501 /* even if we got EXIT_FAILURE, throw it all away, too much trouble doing something else */
1502 for (i = 0; i < type->info.uni.count; ++i) {
1503 lys_type_free(ctx, &type->info.uni.types[i], NULL);
1504 }
1505 free(type->info.uni.types);
1506 type->info.uni.types = NULL;
1507 type->info.uni.count = 0;
1508 type->info.uni.has_ptr_type = 0;
1509 type->der = NULL;
1510 type->base = LY_TYPE_DER;
1511
1512 if (rc == EXIT_FAILURE) {
1513 ret = EXIT_FAILURE;
1514 }
1515 goto error;
1516 }
1517 }
1518 break;
1519
1520 case LY_TYPE_BOOL:
1521 case LY_TYPE_EMPTY:
1522 /* no sub-statement allowed */
1523 if (yin->child) {
1524 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, yin->child->name);
1525 goto error;
1526 }
1527 break;
1528
1529 default:
1530 LOGINT(ctx);
1531 goto error;
1532 }
1533
1534 for(j = 0; j < type->ext_size; ++j) {
1535 /* set flag, which represent LYEXT_OPT_VALID */
1536 if (type->ext[j]->flags & LYEXT_OPT_VALID) {
1537 type->parent->flags |= LYS_VALID_EXT;
1538 break;
1539 }
1540 }
1541
1542 /* if derived type has extension, which need validate data */
1543 dertype = &type->der->type;
1544 while (dertype->der) {
1545 if (dertype->parent->flags & LYS_VALID_EXT) {
1546 type->parent->flags |= LYS_VALID_EXT;
1547 }
1548 dertype = &dertype->der->type;
1549 }
1550
1551 return EXIT_SUCCESS;
1552
1553 error:
1554 lyxml_free_withsiblings(ctx, exts.child);
1555 return ret;
1556 }
1557
1558 /* logs directly */
1559 static int
fill_yin_typedef(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,struct lys_tpdf * tpdf,struct unres_schema * unres)1560 fill_yin_typedef(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_tpdf *tpdf,
1561 struct unres_schema *unres)
1562 {
1563 const char *value;
1564 struct lyxml_elem *node, *next;
1565 struct ly_ctx *ctx = module->ctx;
1566 int rc, has_type = 0, c_ext = 0, i;
1567 void *reallocated;
1568
1569 GETVAL(ctx, value, yin, "name");
1570 if (lyp_check_identifier(ctx, value, LY_IDENT_TYPE, module, parent)) {
1571 goto error;
1572 }
1573 tpdf->name = lydict_insert(ctx, value, strlen(value));
1574
1575 /* generic part - status, description, reference */
1576 if (read_yin_common(module, NULL, tpdf, LYEXT_PAR_TPDF, yin, OPT_MODULE, unres)) {
1577 goto error;
1578 }
1579
1580 LY_TREE_FOR_SAFE(yin->child, next, node) {
1581 if (strcmp(node->ns->value, LY_NSYIN)) {
1582 /* extension */
1583 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, tpdf->ext_size, "extensions", "typedef", error);
1584 c_ext++;
1585 continue;
1586 } else if (!strcmp(node->name, "type")) {
1587 if (has_type) {
1588 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1589 goto error;
1590 }
1591 /* HACK for unres */
1592 tpdf->type.der = (struct lys_tpdf *)node;
1593 tpdf->type.parent = tpdf;
1594 if (unres_schema_add_node(module, unres, &tpdf->type, UNRES_TYPE_DER_TPDF, parent) == -1) {
1595 goto error;
1596 }
1597 has_type = 1;
1598
1599 /* skip lyxml_free() at the end of the loop, node was freed or at least unlinked in unres processing */
1600 continue;
1601 } else if (!strcmp(node->name, "default")) {
1602 if (tpdf->dflt) {
1603 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1604 goto error;
1605 }
1606 GETVAL(ctx, value, node, "value");
1607 tpdf->dflt = lydict_insert(ctx, value, strlen(value));
1608
1609 if (lyp_yin_parse_subnode_ext(module, tpdf, LYEXT_PAR_TPDF, node, LYEXT_SUBSTMT_DEFAULT, 0, unres)) {
1610 goto error;
1611 }
1612 } else if (!strcmp(node->name, "units")) {
1613 if (tpdf->units) {
1614 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
1615 goto error;
1616 }
1617 GETVAL(ctx, value, node, "name");
1618 tpdf->units = lydict_insert(ctx, value, strlen(value));
1619
1620 if (lyp_yin_parse_subnode_ext(module, tpdf, LYEXT_PAR_TPDF, node, LYEXT_SUBSTMT_UNITS, 0, unres)) {
1621 goto error;
1622 }
1623 } else {
1624 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, value);
1625 goto error;
1626 }
1627
1628 lyxml_free(ctx, node);
1629 }
1630
1631 /* check mandatory value */
1632 if (!has_type) {
1633 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "type", yin->name);
1634 goto error;
1635 }
1636
1637 /* check default value (if not defined, there still could be some restrictions
1638 * that need to be checked against a default value from a derived type) */
1639 if (!(ctx->models.flags & LY_CTX_TRUSTED) &&
1640 unres_schema_add_node(module, unres, &tpdf->type, UNRES_TYPEDEF_DFLT, (struct lys_node *)(&tpdf->dflt)) == -1) {
1641 goto error;
1642 }
1643
1644 /* finish extensions parsing */
1645 if (c_ext) {
1646 /* some extensions may be already present from the substatements */
1647 reallocated = realloc(tpdf->ext, (c_ext + tpdf->ext_size) * sizeof *tpdf->ext);
1648 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
1649 tpdf->ext = reallocated;
1650
1651 /* init memory */
1652 memset(&tpdf->ext[tpdf->ext_size], 0, c_ext * sizeof *tpdf->ext);
1653
1654 LY_TREE_FOR_SAFE(yin->child, next, node) {
1655 rc = lyp_yin_fill_ext(tpdf, LYEXT_PAR_TYPE, 0, 0, module, node, &tpdf->ext, &tpdf->ext_size, unres);
1656 if (rc) {
1657 goto error;
1658 }
1659 }
1660
1661 lyp_reduce_ext_list(&tpdf->ext, tpdf->ext_size, c_ext + tpdf->ext_size);
1662 }
1663
1664 for (i = 0; i < tpdf->ext_size; ++i) {
1665 /* set flag, which represent LYEXT_OPT_VALID */
1666 if (tpdf->ext[i]->flags & LYEXT_OPT_VALID) {
1667 tpdf->flags |= LYS_VALID_EXT;
1668 break;
1669 }
1670 }
1671
1672 return EXIT_SUCCESS;
1673
1674 error:
1675 return EXIT_FAILURE;
1676 }
1677
1678 static int
fill_yin_extension(struct lys_module * module,struct lyxml_elem * yin,struct lys_ext * ext,struct unres_schema * unres)1679 fill_yin_extension(struct lys_module *module, struct lyxml_elem *yin, struct lys_ext *ext, struct unres_schema *unres)
1680 {
1681 struct ly_ctx *ctx = module->ctx;
1682 const char *value;
1683 struct lyxml_elem *child, *node, *next, *next2;
1684 int c_ext = 0, rc;
1685 void *reallocated;
1686
1687 GETVAL(ctx, value, yin, "name");
1688
1689 if (lyp_check_identifier(ctx, value, LY_IDENT_EXTENSION, module, NULL)) {
1690 goto error;
1691 }
1692 ext->name = lydict_insert(ctx, value, strlen(value));
1693
1694 if (read_yin_common(module, NULL, ext, LYEXT_PAR_EXT, yin, OPT_MODULE, unres)) {
1695 goto error;
1696 }
1697
1698 LY_TREE_FOR_SAFE(yin->child, next, node) {
1699 if (strcmp(node->ns->value, LY_NSYIN)) {
1700 /* possible extension instance */
1701 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, ext->ext_size, "extensions", "extension", error);
1702 c_ext++;
1703 } else if (!strcmp(node->name, "argument")) {
1704 /* argument */
1705 GETVAL(ctx, value, node, "name");
1706 ext->argument = lydict_insert(ctx, value, strlen(value));
1707 if (lyp_yin_parse_subnode_ext(module, ext, LYEXT_PAR_EXT, node, LYEXT_SUBSTMT_ARGUMENT, 0, unres)) {
1708 goto error;
1709 }
1710
1711 /* yin-element */
1712 LY_TREE_FOR_SAFE(node->child, next2, child) {
1713 if (child->ns == node->ns && !strcmp(child->name, "yin-element")) {
1714 GETVAL(ctx, value, child, "value");
1715 if (ly_strequal(value, "true", 0)) {
1716 ext->flags |= LYS_YINELEM;
1717 }
1718
1719 if (lyp_yin_parse_subnode_ext(module, ext, LYEXT_PAR_EXT, child, LYEXT_SUBSTMT_YINELEM, 0, unres)) {
1720 goto error;
1721 }
1722 } else if (child->ns) {
1723 /* unexpected YANG statement */
1724 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, child->name, child->name);
1725 goto error;
1726 } /* else garbage, but save resource needed for unlinking */
1727 }
1728
1729 lyxml_free(ctx, node);
1730 } else {
1731 /* unexpected YANG statement */
1732 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->name);
1733 goto error;
1734 }
1735 }
1736
1737 if (c_ext) {
1738 /* some extensions may be already present from the substatements */
1739 reallocated = realloc(ext->ext, (c_ext + ext->ext_size) * sizeof *ext->ext);
1740 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
1741 ext->ext = reallocated;
1742
1743 /* init memory */
1744 memset(&ext->ext[ext->ext_size], 0, c_ext * sizeof *ext->ext);
1745
1746 /* process the extension instances of the extension itself */
1747 LY_TREE_FOR_SAFE(yin->child, next, node) {
1748 rc = lyp_yin_fill_ext(ext, LYEXT_PAR_EXT, 0, 0, module, node, &ext->ext, &ext->ext_size, unres);
1749 if (rc) {
1750 goto error;
1751 }
1752 }
1753
1754 lyp_reduce_ext_list(&ext->ext, ext->ext_size, c_ext + ext->ext_size);
1755 }
1756
1757 /* search for plugin */
1758 ext->plugin = ext_get_plugin(ext->name, ext->module->name, ext->module->rev ? ext->module->rev[0].date : NULL);
1759
1760 return EXIT_SUCCESS;
1761
1762 error:
1763 return EXIT_FAILURE;
1764 }
1765
1766 /* logs directly */
1767 static int
fill_yin_feature(struct lys_module * module,struct lyxml_elem * yin,struct lys_feature * f,struct unres_schema * unres)1768 fill_yin_feature(struct lys_module *module, struct lyxml_elem *yin, struct lys_feature *f, struct unres_schema *unres)
1769 {
1770 struct ly_ctx *ctx = module->ctx;
1771 const char *value;
1772 struct lyxml_elem *child, *next;
1773 int c_ftrs = 0, c_ext = 0, ret;
1774 void *reallocated;
1775
1776 GETVAL(ctx, value, yin, "name");
1777 if (lyp_check_identifier(ctx, value, LY_IDENT_FEATURE, module, NULL)) {
1778 goto error;
1779 }
1780 f->name = lydict_insert(ctx, value, strlen(value));
1781 f->module = module;
1782
1783 if (read_yin_common(module, NULL, f, LYEXT_PAR_FEATURE, yin, 0, unres)) {
1784 goto error;
1785 }
1786
1787 LY_TREE_FOR(yin->child, child) {
1788 if (strcmp(child->ns->value, LY_NSYIN)) {
1789 /* extension */
1790 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, f->ext_size, "extensions", "feature", error);
1791 c_ext++;
1792 } else if (!strcmp(child->name, "if-feature")) {
1793 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, f->iffeature_size, "if-feature", "feature", error);
1794 c_ftrs++;
1795 } else {
1796 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
1797 goto error;
1798 }
1799 }
1800
1801 if (c_ftrs) {
1802 f->iffeature = calloc(c_ftrs, sizeof *f->iffeature);
1803 LY_CHECK_ERR_GOTO(!f->iffeature, LOGMEM(ctx), error);
1804 }
1805 if (c_ext) {
1806 /* some extensions may be already present from the substatements */
1807 reallocated = realloc(f->ext, (c_ext + f->ext_size) * sizeof *f->ext);
1808 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
1809 f->ext = reallocated;
1810
1811 /* init memory */
1812 memset(&f->ext[f->ext_size], 0, c_ext * sizeof *f->ext);
1813 }
1814
1815 LY_TREE_FOR_SAFE(yin->child, next, child) {
1816 if (strcmp(child->ns->value, LY_NSYIN)) {
1817 /* extension */
1818 ret = lyp_yin_fill_ext(f, LYEXT_PAR_FEATURE, 0, 0, module, child, &f->ext, &f->ext_size, unres);
1819 if (ret) {
1820 goto error;
1821 }
1822 } else { /* if-feature */
1823 ret = fill_yin_iffeature((struct lys_node *)f, 1, child, &f->iffeature[f->iffeature_size], unres);
1824 f->iffeature_size++;
1825 if (ret) {
1826 goto error;
1827 }
1828 }
1829 }
1830
1831 lyp_reduce_ext_list(&f->ext, f->ext_size, c_ext + f->ext_size);
1832
1833 /* check for circular dependencies */
1834 if (f->iffeature_size) {
1835 if (unres_schema_add_node(module, unres, f, UNRES_FEATURE, NULL) == -1) {
1836 goto error;
1837 }
1838 }
1839
1840 return EXIT_SUCCESS;
1841
1842 error:
1843 return EXIT_FAILURE;
1844 }
1845
1846 /* logs directly */
1847 static int
fill_yin_must(struct lys_module * module,struct lyxml_elem * yin,struct lys_restr * must,struct unres_schema * unres)1848 fill_yin_must(struct lys_module *module, struct lyxml_elem *yin, struct lys_restr *must, struct unres_schema *unres)
1849 {
1850 int ret = EXIT_FAILURE;
1851 const char *value;
1852
1853 must->expr = NULL;
1854 GETVAL(module->ctx, value, yin, "condition");
1855 must->expr = transform_schema2json(module, value);
1856 if (!must->expr) {
1857 goto error;
1858 }
1859
1860 ret = read_restr_substmt(module, must, yin, unres);
1861
1862 error:
1863 if (ret) {
1864 lydict_remove(module->ctx, must->expr);
1865 must->expr = NULL;
1866 }
1867 return ret;
1868 }
1869
1870 static int
fill_yin_revision(struct lys_module * module,struct lyxml_elem * yin,struct lys_revision * rev,struct unres_schema * unres)1871 fill_yin_revision(struct lys_module *module, struct lyxml_elem *yin, struct lys_revision *rev,
1872 struct unres_schema *unres)
1873 {
1874 struct ly_ctx *ctx = module->ctx;
1875 struct lyxml_elem *next, *child;
1876 const char *value;
1877
1878 GETVAL(ctx, value, yin, "date");
1879 if (lyp_check_date(ctx, value)) {
1880 goto error;
1881 }
1882 memcpy(rev->date, value, LY_REV_SIZE - 1);
1883
1884 LY_TREE_FOR_SAFE(yin->child, next, child) {
1885 if (!child->ns) {
1886 /* garbage */
1887 continue;
1888 } else if (strcmp(child->ns->value, LY_NSYIN)) {
1889 /* possible extension instance */
1890 if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
1891 child, LYEXT_SUBSTMT_SELF, 0, unres)) {
1892 goto error;
1893 }
1894 } else if (!strcmp(child->name, "description")) {
1895 if (rev->dsc) {
1896 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
1897 goto error;
1898 }
1899 if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
1900 child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
1901 goto error;
1902 }
1903 rev->dsc = read_yin_subnode(ctx, child, "text");
1904 if (!rev->dsc) {
1905 goto error;
1906 }
1907 } else if (!strcmp(child->name, "reference")) {
1908 if (rev->ref) {
1909 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
1910 goto error;
1911 }
1912 if (lyp_yin_parse_subnode_ext(module, rev, LYEXT_PAR_REVISION,
1913 child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
1914 goto error;
1915 }
1916 rev->ref = read_yin_subnode(ctx, child, "text");
1917 if (!rev->ref) {
1918 goto error;
1919 }
1920 } else {
1921 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
1922 goto error;
1923 }
1924 }
1925
1926 return EXIT_SUCCESS;
1927
1928 error:
1929 return EXIT_FAILURE;
1930 }
1931
1932 static int
fill_yin_unique(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,struct lys_unique * unique,struct unres_schema * unres)1933 fill_yin_unique(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_unique *unique,
1934 struct unres_schema *unres)
1935 {
1936 struct ly_ctx *ctx = module->ctx;
1937 int i, j, ret = EXIT_FAILURE;
1938 const char *orig;
1939 char *value, *vaux, *start = NULL, c = 0;
1940 struct unres_list_uniq *unique_info;
1941
1942 /* get unique value (list of leafs supposed to be unique */
1943 GETVAL(ctx, orig, yin, "tag");
1944
1945 /* count the number of unique leafs in the value */
1946 start = value = vaux = strdup(orig);
1947 LY_CHECK_ERR_GOTO(!vaux, LOGMEM(ctx), error);
1948 while ((vaux = strpbrk(vaux, " \t\n"))) {
1949 YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, unique->expr_size, unique->expr_size, "referenced items", "unique",
1950 unique->expr_size = 0; goto error);
1951 unique->expr_size++;
1952 while (isspace(*vaux)) {
1953 vaux++;
1954 }
1955 }
1956 unique->expr_size++;
1957 unique->expr = calloc(unique->expr_size, sizeof *unique->expr);
1958 LY_CHECK_ERR_GOTO(!unique->expr, LOGMEM(ctx), error);
1959
1960 for (i = 0; i < unique->expr_size; i++) {
1961 vaux = strpbrk(value, " \t\n");
1962 if (vaux) {
1963 c = *vaux;
1964 *vaux = '\0';
1965 }
1966
1967 /* store token into unique structure */
1968 unique->expr[i] = transform_schema2json(module, value);
1969 if (vaux) {
1970 *vaux = c;
1971 }
1972
1973 /* check that the expression does not repeat */
1974 for (j = 0; j < i; j++) {
1975 if (ly_strequal(unique->expr[j], unique->expr[i], 1)) {
1976 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, unique->expr[i], "unique");
1977 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The identifier is not unique");
1978 goto error;
1979 }
1980 }
1981
1982 /* try to resolve leaf */
1983 if (unres) {
1984 unique_info = malloc(sizeof *unique_info);
1985 LY_CHECK_ERR_GOTO(!unique_info, LOGMEM(ctx), error);
1986 unique_info->list = parent;
1987 unique_info->expr = unique->expr[i];
1988 unique_info->trg_type = &unique->trg_type;
1989 if (unres_schema_add_node(module, unres, unique_info, UNRES_LIST_UNIQ, NULL) == -1){
1990 goto error;
1991 }
1992 } else {
1993 if (resolve_unique(parent, unique->expr[i], &unique->trg_type)) {
1994 goto error;
1995 }
1996 }
1997
1998 /* move to next token */
1999 value = vaux;
2000 while (value && isspace(*value)) {
2001 value++;
2002 }
2003 }
2004
2005 ret = EXIT_SUCCESS;
2006
2007 error:
2008 free(start);
2009 return ret;
2010 }
2011
2012 /* logs directly
2013 *
2014 * type: 0 - min, 1 - max
2015 */
2016 static int
deviate_minmax(struct lys_node * target,struct lyxml_elem * node,struct lys_deviate * d,int type)2017 deviate_minmax(struct lys_node *target, struct lyxml_elem *node, struct lys_deviate *d, int type)
2018 {
2019 const char *value;
2020 char *endptr;
2021 unsigned long val;
2022 uint32_t *ui32val, *min, *max;
2023 struct ly_ctx *ctx = target->module->ctx;
2024
2025 /* del min/max is forbidden */
2026 if (d->mod == LY_DEVIATE_DEL) {
2027 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, (type ? "max-elements" : "min-elements"), "deviate delete");
2028 goto error;
2029 }
2030
2031 /* check target node type */
2032 if (target->nodetype == LYS_LEAFLIST) {
2033 max = &((struct lys_node_leaflist *)target)->max;
2034 min = &((struct lys_node_leaflist *)target)->min;
2035 } else if (target->nodetype == LYS_LIST) {
2036 max = &((struct lys_node_list *)target)->max;
2037 min = &((struct lys_node_list *)target)->min;
2038 } else {
2039 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
2040 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"%s\" property.", node->name);
2041 goto error;
2042 }
2043
2044 GETVAL(ctx, value, node, "value");
2045 while (isspace(value[0])) {
2046 value++;
2047 }
2048
2049 if (type && !strcmp(value, "unbounded")) {
2050 d->max = val = 0;
2051 d->max_set = 1;
2052 ui32val = max;
2053 } else {
2054 /* convert it to uint32_t */
2055 errno = 0;
2056 endptr = NULL;
2057 val = strtoul(value, &endptr, 10);
2058 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2059 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
2060 goto error;
2061 }
2062 if (type) {
2063 d->max = (uint32_t)val;
2064 d->max_set = 1;
2065 ui32val = max;
2066 } else {
2067 d->min = (uint32_t)val;
2068 d->min_set = 1;
2069 ui32val = min;
2070 }
2071 }
2072
2073 if (d->mod == LY_DEVIATE_ADD) {
2074 /* check that there is no current value */
2075 if (*ui32val) {
2076 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
2077 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Adding property that already exists.");
2078 goto error;
2079 }
2080 } else if (d->mod == LY_DEVIATE_RPL) {
2081 /* unfortunately, there is no way to check reliably that there
2082 * was a value before, it could have been the default */
2083 }
2084
2085 /* add (already checked) and replace */
2086 /* set new value specified in deviation */
2087 *ui32val = (uint32_t)val;
2088
2089 /* check min-elements is smaller than max-elements */
2090 if (*max && *min > *max) {
2091 if (type) {
2092 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "max-elements");
2093 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "\"max-elements\" is smaller than \"min-elements\".");
2094 } else {
2095 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "min-elements");
2096 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
2097 }
2098 goto error;
2099 }
2100
2101 return EXIT_SUCCESS;
2102
2103 error:
2104 return EXIT_FAILURE;
2105 }
2106
2107 /* logs directly */
2108 static int
fill_yin_deviation(struct lys_module * module,struct lyxml_elem * yin,struct lys_deviation * dev,struct unres_schema * unres)2109 fill_yin_deviation(struct lys_module *module, struct lyxml_elem *yin, struct lys_deviation *dev,
2110 struct unres_schema *unres)
2111 {
2112 const char *value, *dflt, *ptr, **stritem;
2113 struct lyxml_elem *next, *next2, *child, *develem;
2114 int c_dev = 0, c_must, c_uniq, c_dflt, c_ext = 0, c_ext2;
2115 int f_min = 0, f_max = 0; /* flags */
2116 int i, j, k = 0, rc;
2117 unsigned int u;
2118 struct ly_ctx *ctx = module->ctx;
2119 struct lys_deviate *d = NULL;
2120 struct lys_node *node, *parent, *dev_target = NULL;
2121 struct lys_node_choice *choice = NULL;
2122 struct lys_node_leaf *leaf = NULL;
2123 struct ly_set *dflt_check = ly_set_new(), *set;
2124 struct lys_node_list *list = NULL;
2125 struct lys_node_leaflist *llist = NULL;
2126 struct lys_node_inout *inout;
2127 struct lys_type *t = NULL;
2128 uint8_t *trg_must_size = NULL;
2129 struct lys_restr **trg_must = NULL;
2130 struct unres_schema *tmp_unres;
2131 struct lys_module *mod;
2132 void *reallocated;
2133 size_t deviate_must_index;
2134
2135 GETVAL(ctx, value, yin, "target-node");
2136 dev->target_name = transform_schema2json(module, value);
2137 if (!dev->target_name) {
2138 goto error;
2139 }
2140
2141 /* resolve target node */
2142 rc = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
2143 if (rc == -1) {
2144 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, yin->name);
2145 ly_set_free(set);
2146 goto error;
2147 }
2148 dev_target = set->set.s[0];
2149 ly_set_free(set);
2150
2151 if (dev_target->module == lys_main_module(module)) {
2152 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, yin->name);
2153 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Deviating own module is not allowed.");
2154 goto error;
2155 }
2156
2157 LY_TREE_FOR_SAFE(yin->child, next, child) {
2158 if (!child->ns ) {
2159 /* garbage */
2160 lyxml_free(ctx, child);
2161 continue;
2162 } else if (strcmp(child->ns->value, LY_NSYIN)) {
2163 /* extension */
2164 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, dev->ext_size, "extensions", "deviation", error);
2165 c_ext++;
2166 continue;
2167 } else if (!strcmp(child->name, "description")) {
2168 if (dev->dsc) {
2169 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2170 goto error;
2171 }
2172 if (lyp_yin_parse_subnode_ext(module, dev, LYEXT_PAR_DEVIATION, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
2173 goto error;
2174 }
2175 dev->dsc = read_yin_subnode(ctx, child, "text");
2176 if (!dev->dsc) {
2177 goto error;
2178 }
2179 } else if (!strcmp(child->name, "reference")) {
2180 if (dev->ref) {
2181 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2182 goto error;
2183 }
2184 if (lyp_yin_parse_subnode_ext(module, dev, LYEXT_PAR_DEVIATION, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
2185 goto error;
2186 }
2187 dev->ref = read_yin_subnode(ctx, child, "text");
2188 if (!dev->ref) {
2189 goto error;
2190 }
2191 } else if (!strcmp(child->name, "deviate")) {
2192 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dev, dev->deviate_size, "deviates", "deviation", error);
2193 c_dev++;
2194
2195 /* skip lyxml_free() at the end of the loop, node will be
2196 * further processed later
2197 */
2198 continue;
2199
2200 } else {
2201 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2202 goto error;
2203 }
2204
2205 lyxml_free(ctx, child);
2206 }
2207
2208 if (c_dev) {
2209 dev->deviate = calloc(c_dev, sizeof *dev->deviate);
2210 LY_CHECK_ERR_GOTO(!dev->deviate, LOGMEM(ctx), error);
2211 } else {
2212 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "deviate", "deviation");
2213 goto error;
2214 }
2215 if (c_ext) {
2216 /* some extensions may be already present from the substatements */
2217 reallocated = realloc(dev->ext, (c_ext + dev->ext_size) * sizeof *dev->ext);
2218 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
2219 dev->ext = reallocated;
2220
2221 /* init memory */
2222 memset(&dev->ext[dev->ext_size], 0, c_ext * sizeof *dev->ext);
2223 }
2224
2225 LY_TREE_FOR_SAFE(yin->child, next, develem) {
2226 if (strcmp(develem->ns->value, LY_NSYIN)) {
2227 /* deviation's extension */
2228 rc = lyp_yin_fill_ext(dev, LYEXT_PAR_DEVIATION, 0, 0, module, develem, &dev->ext, &dev->ext_size, unres);
2229 if (rc) {
2230 goto error;
2231 }
2232 continue;
2233 }
2234
2235 /* deviate */
2236 /* init */
2237 f_min = 0;
2238 f_max = 0;
2239 c_must = 0;
2240 c_uniq = 0;
2241 c_dflt = 0;
2242 c_ext2 = 0;
2243
2244 /* get deviation type */
2245 GETVAL(ctx, value, develem, "value");
2246 if (!strcmp(value, "not-supported")) {
2247 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_NO;
2248 /* no other deviate statement is expected,
2249 * not-supported deviation must be the only deviation of the target
2250 */
2251 if (dev->deviate_size || develem->next) {
2252 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, develem->name);
2253 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "\"not-supported\" deviation cannot be combined with any other deviation.");
2254 goto error;
2255 }
2256
2257 /* you cannot remove a key leaf */
2258 if ((dev_target->nodetype == LYS_LEAF) && lys_parent(dev_target) && (lys_parent(dev_target)->nodetype == LYS_LIST)) {
2259 for (i = 0; i < ((struct lys_node_list *)lys_parent(dev_target))->keys_size; ++i) {
2260 if (((struct lys_node_list *)lys_parent(dev_target))->keys[i] == (struct lys_node_leaf *)dev_target) {
2261 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, develem->name);
2262 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "\"not-supported\" deviation cannot remove a list key.");
2263 goto error;
2264 }
2265 }
2266 }
2267
2268 /* unlink and store the original node */
2269 parent = dev_target->parent;
2270 lys_node_unlink(dev_target);
2271 if (parent) {
2272 if (parent->nodetype & (LYS_AUGMENT | LYS_USES)) {
2273 /* hack for augment, because when the original will be sometime reconnected back, we actually need
2274 * to reconnect it to both - the augment and its target (which is deduced from the deviations target
2275 * path), so we need to remember the augment as an addition */
2276 /* remember uses parent so we can reconnect to it */
2277 dev_target->parent = parent;
2278 } else if (parent->nodetype & (LYS_RPC | LYS_ACTION)) {
2279 /* re-create implicit node */
2280 inout = calloc(1, sizeof *inout);
2281 LY_CHECK_ERR_GOTO(!inout, LOGMEM(ctx), error);
2282
2283 inout->nodetype = dev_target->nodetype;
2284 inout->name = lydict_insert(ctx, (inout->nodetype == LYS_INPUT) ? "input" : "output", 0);
2285 inout->module = dev_target->module;
2286 inout->flags = LYS_IMPLICIT;
2287
2288 /* insert it manually */
2289 assert(parent->child && !parent->child->next
2290 && (parent->child->nodetype == (inout->nodetype == LYS_INPUT ? LYS_OUTPUT : LYS_INPUT)));
2291 parent->child->next = (struct lys_node *)inout;
2292 inout->prev = parent->child;
2293 parent->child->prev = (struct lys_node *)inout;
2294 inout->parent = parent;
2295 }
2296 }
2297 dev->orig_node = dev_target;
2298
2299 } else if (!strcmp(value, "add")) {
2300 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_ADD;
2301 } else if (!strcmp(value, "replace")) {
2302 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_RPL;
2303 } else if (!strcmp(value, "delete")) {
2304 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_DEL;
2305 } else {
2306 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, develem->name);
2307 goto error;
2308 }
2309 d = &dev->deviate[dev->deviate_size];
2310 dev->deviate_size++;
2311
2312 /* store a shallow copy of the original node */
2313 if (!dev->orig_node) {
2314 tmp_unres = calloc(1, sizeof *tmp_unres);
2315 dev->orig_node = lys_node_dup(dev_target->module, NULL, dev_target, tmp_unres, 1);
2316 /* such a case is not really supported but whatever */
2317 unres_schema_free(dev_target->module, &tmp_unres, 1);
2318 }
2319
2320 /* process deviation properties */
2321 LY_TREE_FOR_SAFE(develem->child, next2, child) {
2322 if (!child->ns) {
2323 /* garbage */
2324 lyxml_free(ctx, child);
2325 continue;
2326 } else if (strcmp(child->ns->value, LY_NSYIN)) {
2327 /* extensions */
2328 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext2, d->ext_size, "extensions", "deviate", error);
2329 c_ext2++;
2330 } else if (d->mod == LY_DEVIATE_NO) {
2331 /* no YIN substatement expected in this case */
2332 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2333 goto error;
2334 } else if (!strcmp(child->name, "config")) {
2335 if (d->flags & LYS_CONFIG_MASK) {
2336 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2337 goto error;
2338 }
2339
2340 /* for we deviate from RFC 6020 and allow config property even it is/is not
2341 * specified in the target explicitly since config property inherits. So we expect
2342 * that config is specified in every node. But for delete, we check that the value
2343 * is the same as here in deviation
2344 */
2345 GETVAL(ctx, value, child, "value");
2346 if (!strcmp(value, "false")) {
2347 d->flags |= LYS_CONFIG_R;
2348 } else if (!strcmp(value, "true")) {
2349 d->flags |= LYS_CONFIG_W;
2350 } else {
2351 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, child->name);
2352 goto error;
2353 }
2354
2355 if (d->mod == LY_DEVIATE_DEL) {
2356 /* del config is forbidden */
2357 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "config", "deviate delete");
2358 goto error;
2359 } else if ((d->mod == LY_DEVIATE_ADD) && (dev_target->flags & LYS_CONFIG_SET)) {
2360 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "config");
2361 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Adding property that already exists.");
2362 goto error;
2363 } else if ((d->mod == LY_DEVIATE_RPL) && !(dev_target->flags & LYS_CONFIG_SET)) {
2364 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "config");
2365 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Replacing a property that does not exist.");
2366 goto error;
2367 } else { /* add and replace are the same in this case */
2368 /* remove current config value of the target ... */
2369 dev_target->flags &= ~LYS_CONFIG_MASK;
2370
2371 /* ... and replace it with the value specified in deviation */
2372 dev_target->flags |= d->flags & LYS_CONFIG_MASK;
2373
2374 /* "config" is explicitely set in the node */
2375 dev_target->flags |= LYS_CONFIG_SET;
2376
2377 /* "config" must be set to either "yes" or "no" */
2378 assert(dev_target->flags ^ LYS_CONFIG_MASK);
2379
2380 /* check and inherit new config to all the children */
2381 if (lyp_deviate_inherit_config_r(dev_target)) {
2382 goto error;
2383 }
2384 }
2385
2386 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_CONFIG, 0, unres)) {
2387 goto error;
2388 }
2389 } else if (!strcmp(child->name, "default")) {
2390 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_DEFAULT, c_dflt, unres)) {
2391 goto error;
2392 }
2393 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dflt, d->dflt_size, "defaults", "deviate", error);
2394 c_dflt++;
2395
2396 /* check target node type */
2397 if (module->version < 2 && dev_target->nodetype == LYS_LEAFLIST) {
2398 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "default");
2399 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"default\" property.");
2400 goto error;
2401 } else if (c_dflt > 1 && dev_target->nodetype != LYS_LEAFLIST) { /* from YANG 1.1 */
2402 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "default");
2403 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow multiple \"default\" properties.");
2404 goto error;
2405 } else if (c_dflt == 1 && (!(dev_target->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE)))) {
2406 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "default");
2407 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"default\" property.");
2408 goto error;
2409 }
2410
2411 /* skip lyxml_free() at the end of the loop, this node will be processed later */
2412 continue;
2413
2414 } else if (!strcmp(child->name, "mandatory")) {
2415 if (d->flags & LYS_MAND_MASK) {
2416 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2417 goto error;
2418 }
2419
2420 /* check target node type */
2421 if (!(dev_target->nodetype & (LYS_LEAF | LYS_CHOICE | LYS_ANYDATA))) {
2422 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2423 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"%s\" property.", child->name);
2424 goto error;
2425 }
2426
2427 GETVAL(ctx, value, child, "value");
2428 if (!strcmp(value, "false")) {
2429 d->flags |= LYS_MAND_FALSE;
2430 } else if (!strcmp(value, "true")) {
2431 d->flags |= LYS_MAND_TRUE;
2432 } else {
2433 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, child->name);
2434 goto error;
2435 }
2436
2437 if (d->mod == LY_DEVIATE_ADD) {
2438 /* check that there is no current value */
2439 if (dev_target->flags & LYS_MAND_MASK) {
2440 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2441 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Adding property that already exists.");
2442 goto error;
2443 }
2444
2445 /* check collision with default-stmt */
2446 if (d->flags & LYS_MAND_TRUE) {
2447 if (dev_target->nodetype == LYS_CHOICE) {
2448 if (((struct lys_node_choice *)(dev_target))->dflt) {
2449 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, child->name, child->parent->name);
2450 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
2451 "Adding the \"mandatory\" statement is forbidden on choice with the \"default\" statement.");
2452 goto error;
2453 }
2454 } else if (dev_target->nodetype == LYS_LEAF) {
2455 if (((struct lys_node_leaf *)(dev_target))->dflt) {
2456 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, child->name, child->parent->name);
2457 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
2458 "Adding the \"mandatory\" statement is forbidden on leaf with the \"default\" statement.");
2459 goto error;
2460 }
2461 }
2462 }
2463
2464 dev_target->flags |= d->flags & LYS_MAND_MASK;
2465 } else if (d->mod == LY_DEVIATE_RPL) {
2466 /* check that there was a value before */
2467 if (!(dev_target->flags & LYS_MAND_MASK)) {
2468 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2469 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Replacing a property that does not exist.");
2470 goto error;
2471 }
2472
2473 dev_target->flags &= ~LYS_MAND_MASK;
2474 dev_target->flags |= d->flags & LYS_MAND_MASK;
2475 } else if (d->mod == LY_DEVIATE_DEL) {
2476 /* del mandatory is forbidden */
2477 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "mandatory", "deviate delete");
2478 goto error;
2479 }
2480
2481 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
2482 for (parent = dev_target->parent;
2483 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION));
2484 parent = parent->parent) {
2485 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
2486 /* stop also on presence containers */
2487 break;
2488 }
2489 }
2490 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
2491 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
2492 if (lyp_check_mandatory_choice(parent)) {
2493 goto error;
2494 }
2495 }
2496
2497 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
2498 goto error;
2499 }
2500 } else if (!strcmp(child->name, "min-elements")) {
2501 if (f_min) {
2502 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2503 goto error;
2504 }
2505 f_min = 1;
2506
2507 if (deviate_minmax(dev_target, child, d, 0)) {
2508 goto error;
2509 }
2510 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_MIN, 0, unres)) {
2511 goto error;
2512 }
2513 } else if (!strcmp(child->name, "max-elements")) {
2514 if (f_max) {
2515 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2516 goto error;
2517 }
2518 f_max = 1;
2519
2520 if (deviate_minmax(dev_target, child, d, 1)) {
2521 goto error;
2522 }
2523 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_MAX, 0, unres)) {
2524 goto error;
2525 }
2526 } else if (!strcmp(child->name, "must")) {
2527 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, d->must_size, "musts", "deviate", error);
2528 c_must++;
2529 /* skip lyxml_free() at the end of the loop, this node will be processed later */
2530 continue;
2531 } else if (!strcmp(child->name, "type")) {
2532 if (d->type) {
2533 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2534 goto error;
2535 }
2536
2537 /* add, del type is forbidden */
2538 if (d->mod == LY_DEVIATE_ADD) {
2539 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "type", "deviate add");
2540 goto error;
2541 } else if (d->mod == LY_DEVIATE_DEL) {
2542 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "type", "deviate delete");
2543 goto error;
2544 }
2545
2546 /* check target node type */
2547 if (dev_target->nodetype == LYS_LEAF) {
2548 t = &((struct lys_node_leaf *)dev_target)->type;
2549 if (((struct lys_node_leaf *)dev_target)->dflt) {
2550 ly_set_add(dflt_check, dev_target, 0);
2551 }
2552 } else if (dev_target->nodetype == LYS_LEAFLIST) {
2553 t = &((struct lys_node_leaflist *)dev_target)->type;
2554 if (((struct lys_node_leaflist *)dev_target)->dflt) {
2555 ly_set_add(dflt_check, dev_target, 0);
2556 }
2557 } else {
2558 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2559 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"%s\" property.", child->name);
2560 goto error;
2561 }
2562
2563 /* replace */
2564 lys_type_free(ctx, t, NULL);
2565 memset(t, 0, sizeof (struct lys_type));
2566 /* HACK for unres */
2567 t->der = (struct lys_tpdf *)child;
2568 t->parent = (struct lys_tpdf *)dev_target;
2569 if (unres_schema_add_node(module, unres, t, UNRES_TYPE_DER, dev_target) == -1) {
2570 goto error;
2571 }
2572 d->type = t;
2573 } else if (!strcmp(child->name, "unique")) {
2574 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_UNIQUE, c_uniq, unres)) {
2575 goto error;
2576 }
2577 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_uniq, d->unique_size, "uniques", "deviate", error);
2578 c_uniq++;
2579 /* skip lyxml_free() at the end of the loop, this node will be processed later */
2580 continue;
2581 } else if (!strcmp(child->name, "units")) {
2582 if (d->units) {
2583 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
2584 goto error;
2585 }
2586
2587 /* check target node type */
2588 if (dev_target->nodetype == LYS_LEAFLIST) {
2589 stritem = &((struct lys_node_leaflist *)dev_target)->units;
2590 } else if (dev_target->nodetype == LYS_LEAF) {
2591 stritem = &((struct lys_node_leaf *)dev_target)->units;
2592 } else {
2593 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2594 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"%s\" property.", child->name);
2595 goto error;
2596 }
2597
2598 /* get units value */
2599 GETVAL(ctx, value, child, "name");
2600 d->units = lydict_insert(ctx, value, 0);
2601
2602 /* apply to target */
2603 if (d->mod == LY_DEVIATE_ADD) {
2604 /* check that there is no current value */
2605 if (*stritem) {
2606 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2607 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Adding property that already exists.");
2608 goto error;
2609 }
2610
2611 *stritem = lydict_insert(ctx, value, 0);
2612 } else if (d->mod == LY_DEVIATE_RPL) {
2613 /* check that there was a value before */
2614 if (!*stritem) {
2615 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2616 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Replacing a property that does not exist.");
2617 goto error;
2618 }
2619
2620 lydict_remove(ctx, *stritem);
2621 *stritem = lydict_insert(ctx, value, 0);
2622 } else if (d->mod == LY_DEVIATE_DEL) {
2623 /* check values */
2624 if (!ly_strequal(*stritem, d->units, 1)) {
2625 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, child->name);
2626 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Value differs from the target being deleted.");
2627 goto error;
2628 }
2629 /* remove current units value of the target */
2630 lydict_remove(ctx, *stritem);
2631 (*stritem) = NULL;
2632
2633 /* remove its extensions */
2634 j = -1;
2635 while ((j = lys_ext_iter(dev_target->ext, dev_target->ext_size, j + 1, LYEXT_SUBSTMT_UNITS)) != -1) {
2636 lyp_ext_instance_rm(ctx, &dev_target->ext, &dev_target->ext_size, j);
2637 --j;
2638 }
2639 }
2640
2641 if (lyp_yin_parse_subnode_ext(module, d, LYEXT_PAR_DEVIATE, child, LYEXT_SUBSTMT_UNITS, 0, unres)) {
2642 goto error;
2643 }
2644 } else {
2645 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
2646 goto error;
2647 }
2648
2649 /* do not free sub, it could have been unlinked and stored in unres */
2650 }
2651
2652 if (c_must) {
2653 /* check target node type */
2654 switch (dev_target->nodetype) {
2655 case LYS_LEAF:
2656 trg_must = &((struct lys_node_leaf *)dev_target)->must;
2657 trg_must_size = &((struct lys_node_leaf *)dev_target)->must_size;
2658 break;
2659 case LYS_CONTAINER:
2660 trg_must = &((struct lys_node_container *)dev_target)->must;
2661 trg_must_size = &((struct lys_node_container *)dev_target)->must_size;
2662 break;
2663 case LYS_LEAFLIST:
2664 trg_must = &((struct lys_node_leaflist *)dev_target)->must;
2665 trg_must_size = &((struct lys_node_leaflist *)dev_target)->must_size;
2666 break;
2667 case LYS_LIST:
2668 trg_must = &((struct lys_node_list *)dev_target)->must;
2669 trg_must_size = &((struct lys_node_list *)dev_target)->must_size;
2670 break;
2671 case LYS_ANYXML:
2672 case LYS_ANYDATA:
2673 trg_must = &((struct lys_node_anydata *)dev_target)->must;
2674 trg_must_size = &((struct lys_node_anydata *)dev_target)->must_size;
2675 break;
2676 default:
2677 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "must");
2678 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"must\" property.");
2679 goto error;
2680 }
2681
2682 dev_target->flags &= ~(LYS_XPCONF_DEP | LYS_XPSTATE_DEP);
2683
2684 if (d->mod == LY_DEVIATE_RPL) {
2685 /* replace must is forbidden */
2686 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "must", "deviate replace");
2687 goto error;
2688 } else if (d->mod == LY_DEVIATE_ADD) {
2689 /* reallocate the must array of the target */
2690 struct lys_restr *must = ly_realloc(*trg_must, (c_must + *trg_must_size) * sizeof *d->must);
2691 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), error);
2692 *trg_must = must;
2693 d->must = calloc(c_must, sizeof *d->must);
2694 d->must_size = c_must;
2695 } else { /* LY_DEVIATE_DEL */
2696 d->must = calloc(c_must, sizeof *d->must);
2697 }
2698 LY_CHECK_ERR_GOTO(!d->must, LOGMEM(ctx), error);
2699 }
2700 if (c_uniq) {
2701 /* replace unique is forbidden */
2702 if (d->mod == LY_DEVIATE_RPL) {
2703 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "unique", "deviate replace");
2704 goto error;
2705 }
2706
2707 /* check target node type */
2708 if (dev_target->nodetype != LYS_LIST) {
2709 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "unique");
2710 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Target node does not allow \"unique\" property.");
2711 goto error;
2712 }
2713
2714 list = (struct lys_node_list *)dev_target;
2715 if (d->mod == LY_DEVIATE_ADD) {
2716 /* reallocate the unique array of the target */
2717 d->unique = ly_realloc(list->unique, (c_uniq + list->unique_size) * sizeof *d->unique);
2718 LY_CHECK_ERR_GOTO(!d->unique, LOGMEM(ctx), error);
2719 list->unique = d->unique;
2720 d->unique = &list->unique[list->unique_size];
2721 d->unique_size = c_uniq;
2722 } else { /* LY_DEVIATE_DEL */
2723 d->unique = calloc(c_uniq, sizeof *d->unique);
2724 LY_CHECK_ERR_GOTO(!d->unique, LOGMEM(ctx), error);
2725 }
2726 }
2727 if (c_dflt) {
2728 if (d->mod == LY_DEVIATE_ADD) {
2729 /* check that there is no current value */
2730 if ((dev_target->nodetype == LYS_LEAF && ((struct lys_node_leaf *)dev_target)->dflt) ||
2731 (dev_target->nodetype == LYS_CHOICE && ((struct lys_node_choice *)dev_target)->dflt)) {
2732 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "default");
2733 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Adding property that already exists.");
2734 goto error;
2735 }
2736
2737 /* check collision with mandatory/min-elements */
2738 if ((dev_target->flags & LYS_MAND_TRUE) ||
2739 (dev_target->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)dev_target)->min)) {
2740 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", "deviation");
2741 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
2742 "Adding the \"default\" statement is forbidden on %s statement.",
2743 (dev_target->flags & LYS_MAND_TRUE) ? "nodes with the \"mandatory\"" : "leaflists with non-zero \"min-elements\"");
2744 goto error;
2745 }
2746 } else if (d->mod == LY_DEVIATE_RPL) {
2747 /* check that there was a value before */
2748 if (((dev_target->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && !((struct lys_node_leaf *)dev_target)->dflt) ||
2749 (dev_target->nodetype == LYS_CHOICE && !((struct lys_node_choice *)dev_target)->dflt)) {
2750 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "default");
2751 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Replacing a property that does not exist.");
2752 goto error;
2753 }
2754 }
2755
2756 if (dev_target->nodetype == LYS_LEAFLIST) {
2757 /* reallocate default list in the target */
2758 llist = (struct lys_node_leaflist *)dev_target;
2759 if (d->mod == LY_DEVIATE_ADD) {
2760 /* reallocate (enlarge) the unique array of the target */
2761 llist->dflt = ly_realloc(llist->dflt, (c_dflt + llist->dflt_size) * sizeof *d->dflt);
2762 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), error);
2763 } else if (d->mod == LY_DEVIATE_RPL) {
2764 /* reallocate (replace) the unique array of the target */
2765 for (i = 0; i < llist->dflt_size; i++) {
2766 lydict_remove(ctx, llist->dflt[i]);
2767 }
2768 llist->dflt = ly_realloc(llist->dflt, c_dflt * sizeof *d->dflt);
2769 llist->dflt_size = 0;
2770 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), error);
2771 }
2772 }
2773 d->dflt = calloc(c_dflt, sizeof *d->dflt);
2774 LY_CHECK_ERR_GOTO(!d->dflt, LOGMEM(ctx), error);
2775 }
2776 if (c_ext2) {
2777 /* some extensions may be already present from the substatements */
2778 reallocated = realloc(d->ext, (c_ext2 + d->ext_size) * sizeof *d->ext);
2779 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
2780 d->ext = reallocated;
2781
2782 /* init memory */
2783 memset(&d->ext[d->ext_size], 0, c_ext2 * sizeof *d->ext);
2784 }
2785
2786 /* process deviation properties with 0..n cardinality */
2787 deviate_must_index = 0;
2788 LY_TREE_FOR_SAFE(develem->child, next2, child) {
2789 if (strcmp(child->ns->value, LY_NSYIN)) {
2790 /* extension */
2791 if (lyp_yin_fill_ext(d, LYEXT_PAR_DEVIATE, 0, 0, module, child, &d->ext, &d->ext_size, unres)) {
2792 goto error;
2793 }
2794 } else if (!strcmp(child->name, "must")) {
2795 if (d->mod == LY_DEVIATE_DEL) {
2796 if (fill_yin_must(module, child, &d->must[d->must_size], unres)) {
2797 goto error;
2798 }
2799
2800 /* find must to delete, we are ok with just matching conditions */
2801 for (i = 0; i < *trg_must_size; i++) {
2802 if (ly_strequal(d->must[d->must_size].expr, (*trg_must)[i].expr, 1)) {
2803 /* we have a match, free the must structure ... */
2804 lys_restr_free(ctx, &((*trg_must)[i]), NULL);
2805 /* ... and maintain the array */
2806 (*trg_must_size)--;
2807 if (i != *trg_must_size) {
2808 (*trg_must)[i].expr = (*trg_must)[*trg_must_size].expr;
2809 (*trg_must)[i].dsc = (*trg_must)[*trg_must_size].dsc;
2810 (*trg_must)[i].ref = (*trg_must)[*trg_must_size].ref;
2811 (*trg_must)[i].eapptag = (*trg_must)[*trg_must_size].eapptag;
2812 (*trg_must)[i].emsg = (*trg_must)[*trg_must_size].emsg;
2813 }
2814 if (!(*trg_must_size)) {
2815 free(*trg_must);
2816 *trg_must = NULL;
2817 } else {
2818 (*trg_must)[*trg_must_size].expr = NULL;
2819 (*trg_must)[*trg_must_size].dsc = NULL;
2820 (*trg_must)[*trg_must_size].ref = NULL;
2821 (*trg_must)[*trg_must_size].eapptag = NULL;
2822 (*trg_must)[*trg_must_size].emsg = NULL;
2823 }
2824
2825 i = -1; /* set match flag */
2826 break;
2827 }
2828 }
2829 d->must_size++;
2830 if (i != -1) {
2831 /* no match found */
2832 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL,
2833 d->must[d->must_size - 1].expr, child->name);
2834 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Value does not match any must from the target.");
2835 goto error;
2836 }
2837 } else { /* replace or add */
2838 memset(&((*trg_must)[*trg_must_size]), 0, sizeof **trg_must);
2839 if (fill_yin_must(module, child, &((*trg_must)[*trg_must_size]), unres)) {
2840 goto error;
2841 }
2842 memcpy(d->must + deviate_must_index, &((*trg_must)[*trg_must_size]), sizeof *d->must);
2843 ++deviate_must_index;
2844 (*trg_must_size)++;
2845 }
2846
2847 /* check XPath dependencies again */
2848 if (*trg_must_size && !(ctx->models.flags & LY_CTX_TRUSTED) &&
2849 (unres_schema_add_node(module, unres, dev_target, UNRES_XPATH, NULL) == -1)) {
2850 goto error;
2851 }
2852 } else if (!strcmp(child->name, "unique")) {
2853 if (d->mod == LY_DEVIATE_DEL) {
2854 memset(&d->unique[d->unique_size], 0, sizeof *d->unique);
2855 if (fill_yin_unique(module, dev_target, child, &d->unique[d->unique_size], NULL)) {
2856 d->unique_size++;
2857 goto error;
2858 }
2859
2860 /* find unique structures to delete */
2861 for (i = 0; i < list->unique_size; i++) {
2862 if (list->unique[i].expr_size != d->unique[d->unique_size].expr_size) {
2863 continue;
2864 }
2865
2866 for (j = 0; j < d->unique[d->unique_size].expr_size; j++) {
2867 if (!ly_strequal(list->unique[i].expr[j], d->unique[d->unique_size].expr[j], 1)) {
2868 break;
2869 }
2870 }
2871
2872 if (j == d->unique[d->unique_size].expr_size) {
2873 /* we have a match, free the unique structure ... */
2874 for (j = 0; j < list->unique[i].expr_size; j++) {
2875 lydict_remove(ctx, list->unique[i].expr[j]);
2876 }
2877 free(list->unique[i].expr);
2878 /* ... and maintain the array */
2879 list->unique_size--;
2880 if (i != list->unique_size) {
2881 list->unique[i].expr_size = list->unique[list->unique_size].expr_size;
2882 list->unique[i].expr = list->unique[list->unique_size].expr;
2883 }
2884
2885 if (!list->unique_size) {
2886 free(list->unique);
2887 list->unique = NULL;
2888 } else {
2889 list->unique[list->unique_size].expr_size = 0;
2890 list->unique[list->unique_size].expr = NULL;
2891 }
2892
2893 k = i; /* remember index for removing extensions */
2894 i = -1; /* set match flag */
2895 break;
2896 }
2897 }
2898
2899 d->unique_size++;
2900 if (i != -1) {
2901 /* no match found */
2902 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, lyxml_get_attr(child, "tag", NULL), child->name);
2903 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Value differs from the target being deleted.");
2904 goto error;
2905 }
2906
2907 /* remove extensions of this unique instance from the target node */
2908 j = -1;
2909 while ((j = lys_ext_iter(dev_target->ext, dev_target->ext_size, j + 1, LYEXT_SUBSTMT_UNIQUE)) != -1) {
2910 if (dev_target->ext[j]->insubstmt_index == k) {
2911 lyp_ext_instance_rm(ctx, &dev_target->ext, &dev_target->ext_size, j);
2912 --j;
2913 } else if (dev_target->ext[j]->insubstmt_index > k) {
2914 /* decrease the substatement index of the extension because of the changed array of uniques */
2915 dev_target->ext[j]->insubstmt_index--;
2916 }
2917 }
2918 } else { /* replace or add */
2919 memset(&list->unique[list->unique_size], 0, sizeof *list->unique);
2920 i = fill_yin_unique(module, dev_target, child, &list->unique[list->unique_size], NULL);
2921 list->unique_size++;
2922 if (i) {
2923 goto error;
2924 }
2925 }
2926 } else if (!strcmp(child->name, "default")) {
2927 GETVAL(ctx, value, child, "value");
2928 u = strlen(value);
2929 d->dflt[d->dflt_size++] = lydict_insert(ctx, value, u);
2930
2931 if (dev_target->nodetype == LYS_CHOICE) {
2932 choice = (struct lys_node_choice *)dev_target;
2933 rc = resolve_choice_default_schema_nodeid(value, choice->child, (const struct lys_node **)&node);
2934 if (rc || !node) {
2935 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
2936 goto error;
2937 }
2938 if (d->mod == LY_DEVIATE_DEL) {
2939 if (!choice->dflt || (choice->dflt != node)) {
2940 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
2941 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Value differs from the target being deleted.");
2942 goto error;
2943 }
2944 choice->dflt = NULL;
2945 /* remove extensions of this default instance from the target node */
2946 j = -1;
2947 while ((j = lys_ext_iter(dev_target->ext, dev_target->ext_size, j + 1, LYEXT_SUBSTMT_DEFAULT)) != -1) {
2948 lyp_ext_instance_rm(ctx, &dev_target->ext, &dev_target->ext_size, j);
2949 --j;
2950 }
2951 } else { /* add or replace */
2952 choice->dflt = node;
2953 if (!choice->dflt) {
2954 /* default branch not found */
2955 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
2956 goto error;
2957 }
2958 }
2959 } else if (dev_target->nodetype == LYS_LEAF) {
2960 leaf = (struct lys_node_leaf *)dev_target;
2961 if (d->mod == LY_DEVIATE_DEL) {
2962 dflt = NULL;
2963 if (leaf->dflt) {
2964 if (leaf->type.base == LY_TYPE_IDENT) {
2965 /* skip prefixes, cannot be compared reliably */
2966 if ((ptr = strchr(leaf->dflt, ':'))) {
2967 dflt = ptr + 1;
2968 } else {
2969 dflt = leaf->dflt;
2970 }
2971 if ((ptr = strchr(value, ':'))) {
2972 value = ptr + 1;
2973 }
2974 } else {
2975 dflt = leaf->dflt;
2976 }
2977 }
2978 if (!dflt || !ly_strequal(dflt, value, 0)) {
2979 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
2980 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Value differs from the target being deleted.");
2981 goto error;
2982 }
2983 /* remove value */
2984 lydict_remove(ctx, leaf->dflt);
2985 leaf->dflt = NULL;
2986 leaf->flags &= ~LYS_DFLTJSON;
2987
2988 /* remove extensions of this default instance from the target node */
2989 j = -1;
2990 while ((j = lys_ext_iter(dev_target->ext, dev_target->ext_size, j + 1, LYEXT_SUBSTMT_DEFAULT)) != -1) {
2991 lyp_ext_instance_rm(ctx, &dev_target->ext, &dev_target->ext_size, j);
2992 --j;
2993 }
2994 } else { /* add (already checked) and replace */
2995 /* remove value */
2996 lydict_remove(ctx, leaf->dflt);
2997 leaf->flags &= ~LYS_DFLTJSON;
2998
2999 /* set new value */
3000 leaf->dflt = lydict_insert(ctx, value, u);
3001
3002 /* remember to check it later (it may not fit now, because the type can be deviated too) */
3003 ly_set_add(dflt_check, dev_target, 0);
3004 }
3005 } else { /* LYS_LEAFLIST */
3006 llist = (struct lys_node_leaflist *)dev_target;
3007 if (d->mod == LY_DEVIATE_DEL) {
3008 /* find and remove the value in target list */
3009 for (i = 0; i < llist->dflt_size; i++) {
3010 if (llist->dflt[i] && ly_strequal(llist->dflt[i], value, 1)) {
3011 /* match, remove the value */
3012 lydict_remove(ctx, llist->dflt[i]);
3013 llist->dflt[i] = NULL;
3014
3015 /* remove extensions of this default instance from the target node */
3016 j = -1;
3017 while ((j = lys_ext_iter(dev_target->ext, dev_target->ext_size, j + 1, LYEXT_SUBSTMT_DEFAULT)) != -1) {
3018 if (dev_target->ext[j]->insubstmt_index == i) {
3019 lyp_ext_instance_rm(ctx, &dev_target->ext, &dev_target->ext_size, j);
3020 --j;
3021 } else if (dev_target->ext[j]->insubstmt_index > i) {
3022 /* decrease the substatement index of the extension because of the changed array of defaults */
3023 dev_target->ext[j]->insubstmt_index--;
3024 }
3025 }
3026 break;
3027 }
3028 }
3029 if (i == llist->dflt_size) {
3030 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
3031 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The default value to delete not found in the target node.");
3032 goto error;
3033 }
3034 } else {
3035 /* add or replace, anyway we place items into the deviate's list
3036 which propagates to the target */
3037 /* we just want to check that the value isn't already in the list */
3038 for (i = 0; i < llist->dflt_size; i++) {
3039 if (ly_strequal(llist->dflt[i], value, 1)) {
3040 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
3041 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Duplicated default value \"%s\".", value);
3042 goto error;
3043 }
3044 }
3045 /* store it in target node */
3046 llist->dflt[llist->dflt_size++] = lydict_insert(ctx, value, u);
3047
3048 /* remember to check it later (it may not fit now, but the type can be deviated too) */
3049 ly_set_add(dflt_check, dev_target, 0);
3050 llist->flags &= ~LYS_DFLTJSON;
3051 }
3052 }
3053 }
3054 }
3055
3056 lyp_reduce_ext_list(&d->ext, d->ext_size, c_ext2 + d->ext_size);
3057
3058 if (c_dflt && dev_target->nodetype == LYS_LEAFLIST && d->mod == LY_DEVIATE_DEL) {
3059 /* consolidate the final list in the target after removing items from it */
3060 llist = (struct lys_node_leaflist *)dev_target;
3061 for (i = j = 0; j < llist->dflt_size; j++) {
3062 llist->dflt[i] = llist->dflt[j];
3063 if (llist->dflt[i]) {
3064 i++;
3065 }
3066 }
3067 llist->dflt_size = i + 1;
3068 }
3069 }
3070
3071 lyp_reduce_ext_list(&dev->ext, dev->ext_size, c_ext + dev->ext_size);
3072
3073 /* now check whether default value, if any, matches the type */
3074 if (!(ctx->models.flags & LY_CTX_TRUSTED)) {
3075 for (u = 0; u < dflt_check->number; ++u) {
3076 value = NULL;
3077 rc = EXIT_SUCCESS;
3078 if (dflt_check->set.s[u]->nodetype == LYS_LEAF) {
3079 leaf = (struct lys_node_leaf *)dflt_check->set.s[u];
3080 value = leaf->dflt;
3081 rc = unres_schema_add_node(module, unres, &leaf->type, UNRES_TYPE_DFLT, (struct lys_node *)(&leaf->dflt));
3082 } else { /* LYS_LEAFLIST */
3083 llist = (struct lys_node_leaflist *)dflt_check->set.s[u];
3084 for (j = 0; j < llist->dflt_size; j++) {
3085 rc = unres_schema_add_node(module, unres, &llist->type, UNRES_TYPE_DFLT,
3086 (struct lys_node *)(&llist->dflt[j]));
3087 if (rc == -1) {
3088 value = llist->dflt[j];
3089 break;
3090 }
3091 }
3092
3093 }
3094 if (rc == -1) {
3095 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
3096 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
3097 "The default value \"%s\" of the deviated node \"%s\" no longer matches its type.",
3098 dev->target_name);
3099 goto error;
3100 }
3101 }
3102 }
3103
3104 /* mark all the affected modules as deviated and implemented */
3105 for(parent = dev_target; parent; parent = lys_parent(parent)) {
3106 mod = lys_node_module(parent);
3107 if (module != mod) {
3108 mod->deviated = 1; /* main module */
3109 parent->module->deviated = 1; /* possible submodule */
3110 if (!mod->implemented) {
3111 mod->implemented = 1;
3112 if (unres_schema_add_node(mod, unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
3113 goto error;
3114 }
3115 }
3116 }
3117 }
3118
3119 ly_set_free(dflt_check);
3120 return EXIT_SUCCESS;
3121
3122 error:
3123 ly_set_free(dflt_check);
3124 return EXIT_FAILURE;
3125 }
3126
3127 /* logs directly */
3128 static int
fill_yin_augment(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,struct lys_node_augment * aug,int options,struct unres_schema * unres)3129 fill_yin_augment(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_node_augment *aug,
3130 int options, struct unres_schema *unres)
3131 {
3132 struct ly_ctx *ctx = module->ctx;
3133 const char *value;
3134 struct lyxml_elem *sub, *next;
3135 struct lys_node *node;
3136 int ret, c_ftrs = 0, c_ext = 0;
3137 void *reallocated;
3138
3139 aug->nodetype = LYS_AUGMENT;
3140 GETVAL(ctx, value, yin, "target-node");
3141 aug->target_name = transform_schema2json(module, value);
3142 if (!aug->target_name) {
3143 goto error;
3144 }
3145 aug->parent = parent;
3146
3147 if (read_yin_common(module, NULL, aug, LYEXT_PAR_NODE, yin, OPT_MODULE, unres)) {
3148 goto error;
3149 }
3150
3151 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3152 if (strcmp(sub->ns->value, LY_NSYIN)) {
3153 /* extension */
3154 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, aug->ext_size, "extensions", "augment", error);
3155 c_ext++;
3156 continue;
3157 } else if (!strcmp(sub->name, "if-feature")) {
3158 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, aug->iffeature_size, "if-features", "augment", error);
3159 c_ftrs++;
3160 continue;
3161 } else if (!strcmp(sub->name, "when")) {
3162 if (aug->when) {
3163 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3164 goto error;
3165 }
3166
3167 aug->when = read_yin_when(module, sub, unres);
3168 if (!aug->when) {
3169 lyxml_free(ctx, sub);
3170 goto error;
3171 }
3172 lyxml_free(ctx, sub);
3173 continue;
3174
3175 /* check allowed data sub-statements */
3176 } else if (!strcmp(sub->name, "container")) {
3177 node = read_yin_container(module, (struct lys_node *)aug, sub, options, unres);
3178 } else if (!strcmp(sub->name, "leaf-list")) {
3179 node = read_yin_leaflist(module, (struct lys_node *)aug, sub, options, unres);
3180 } else if (!strcmp(sub->name, "leaf")) {
3181 node = read_yin_leaf(module, (struct lys_node *)aug, sub, options, unres);
3182 } else if (!strcmp(sub->name, "list")) {
3183 node = read_yin_list(module, (struct lys_node *)aug, sub, options, unres);
3184 } else if (!strcmp(sub->name, "uses")) {
3185 node = read_yin_uses(module, (struct lys_node *)aug, sub, options, unres);
3186 } else if (!strcmp(sub->name, "choice")) {
3187 node = read_yin_choice(module, (struct lys_node *)aug, sub, options, unres);
3188 } else if (!strcmp(sub->name, "case")) {
3189 node = read_yin_case(module, (struct lys_node *)aug, sub, options, unres);
3190 } else if (!strcmp(sub->name, "anyxml")) {
3191 node = read_yin_anydata(module, (struct lys_node *)aug, sub, LYS_ANYXML, options, unres);
3192 } else if (!strcmp(sub->name, "anydata")) {
3193 node = read_yin_anydata(module, (struct lys_node *)aug, sub, LYS_ANYDATA, options, unres);
3194 } else if (!strcmp(sub->name, "action")) {
3195 node = read_yin_rpc_action(module, (struct lys_node *)aug, sub, options, unres);
3196 } else if (!strcmp(sub->name, "notification")) {
3197 node = read_yin_notif(module, (struct lys_node *)aug, sub, options, unres);
3198 } else {
3199 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, sub->name);
3200 goto error;
3201 }
3202
3203 if (!node) {
3204 goto error;
3205 }
3206
3207 node = NULL;
3208 lyxml_free(ctx, sub);
3209 }
3210
3211 if (c_ftrs) {
3212 aug->iffeature = calloc(c_ftrs, sizeof *aug->iffeature);
3213 LY_CHECK_ERR_GOTO(!aug->iffeature, LOGMEM(ctx), error);
3214 }
3215 if (c_ext) {
3216 /* some extensions may be already present from the substatements */
3217 reallocated = realloc(aug->ext, (c_ext + aug->ext_size) * sizeof *aug->ext);
3218 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
3219 aug->ext = reallocated;
3220
3221 /* init memory */
3222 memset(&aug->ext[aug->ext_size], 0, c_ext * sizeof *aug->ext);
3223 }
3224
3225 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3226 if (strcmp(sub->ns->value, LY_NSYIN)) {
3227 /* extension */
3228 ret = lyp_yin_fill_ext(aug, LYEXT_PAR_NODE, 0, 0, module, sub, &aug->ext, &aug->ext_size, unres);
3229 if (ret) {
3230 goto error;
3231 }
3232 } else if (!strcmp(sub->name, "if-feature")) {
3233 ret = fill_yin_iffeature((struct lys_node *)aug, 0, sub, &aug->iffeature[aug->iffeature_size], unres);
3234 aug->iffeature_size++;
3235 if (ret) {
3236 goto error;
3237 }
3238 lyxml_free(ctx, sub);
3239 }
3240 }
3241
3242 lyp_reduce_ext_list(&aug->ext, aug->ext_size, c_ext + aug->ext_size);
3243
3244 /* aug->child points to the parsed nodes, they must now be
3245 * connected to the tree and adjusted (if possible right now).
3246 * However, if this is augment in a uses (parent is NULL), it gets resolved
3247 * when the uses does and cannot be resolved now for sure
3248 * (the grouping was not yet copied into uses).
3249 */
3250 if (!parent) {
3251 if (unres_schema_add_node(module, unres, aug, UNRES_AUGMENT, NULL) == -1) {
3252 goto error;
3253 }
3254 }
3255
3256 /* check XPath dependencies */
3257 if (!(ctx->models.flags & LY_CTX_TRUSTED) && aug->when) {
3258 if (options & LYS_PARSE_OPT_INGRP) {
3259 if (lyxp_node_check_syntax((struct lys_node *)aug)) {
3260 goto error;
3261 }
3262 } else {
3263 if (unres_schema_add_node(module, unres, (struct lys_node *)aug, UNRES_XPATH, NULL) == -1) {
3264 goto error;
3265 }
3266 }
3267 }
3268
3269 return EXIT_SUCCESS;
3270
3271 error:
3272 return EXIT_FAILURE;
3273 }
3274
3275 /* logs directly */
3276 static int
fill_yin_refine(struct lys_node * uses,struct lyxml_elem * yin,struct lys_refine * rfn,struct unres_schema * unres)3277 fill_yin_refine(struct lys_node *uses, struct lyxml_elem *yin, struct lys_refine *rfn, struct unres_schema *unres)
3278 {
3279 struct ly_ctx *ctx = uses->module->ctx;
3280 struct lys_module *module;
3281 struct lyxml_elem *sub, *next;
3282 const char *value;
3283 char *endptr;
3284 int f_mand = 0, f_min = 0, f_max = 0;
3285 int c_must = 0, c_ftrs = 0, c_dflt = 0, c_ext = 0;
3286 int r;
3287 unsigned long int val;
3288 void *reallocated;
3289
3290 assert(uses);
3291 module = uses->module; /* shorthand */
3292
3293 GETVAL(ctx, value, yin, "target-node");
3294 rfn->target_name = transform_schema2json(module, value);
3295 if (!rfn->target_name) {
3296 goto error;
3297 }
3298
3299 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3300 if (!sub->ns) {
3301 /* garbage */
3302 } else if (strcmp(sub->ns->value, LY_NSYIN)) {
3303 /* extension */
3304 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, rfn->ext_size, "extensions", "refine", error);
3305 c_ext++;
3306 continue;
3307
3308 } else if (!strcmp(sub->name, "description")) {
3309 if (rfn->dsc) {
3310 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3311 goto error;
3312 }
3313
3314 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
3315 goto error;
3316 }
3317
3318 rfn->dsc = read_yin_subnode(ctx, sub, "text");
3319 if (!rfn->dsc) {
3320 goto error;
3321 }
3322 } else if (!strcmp(sub->name, "reference")) {
3323 if (rfn->ref) {
3324 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3325 goto error;
3326 }
3327
3328 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
3329 goto error;
3330 }
3331
3332 rfn->ref = read_yin_subnode(ctx, sub, "text");
3333 if (!rfn->ref) {
3334 goto error;
3335 }
3336 } else if (!strcmp(sub->name, "config")) {
3337 if (rfn->flags & LYS_CONFIG_MASK) {
3338 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3339 goto error;
3340 }
3341 GETVAL(ctx, value, sub, "value");
3342 if (!strcmp(value, "false")) {
3343 rfn->flags |= LYS_CONFIG_R;
3344 } else if (!strcmp(value, "true")) {
3345 rfn->flags |= LYS_CONFIG_W;
3346 } else {
3347 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3348 goto error;
3349 }
3350 rfn->flags |= LYS_CONFIG_SET;
3351
3352 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_CONFIG, 0, unres)) {
3353 goto error;
3354 }
3355 } else if (!strcmp(sub->name, "default")) {
3356 /* leaf, leaf-list or choice */
3357
3358 /* check possibility of statements combination */
3359 if (rfn->target_type) {
3360 if (c_dflt) {
3361 /* multiple defaults are allowed only in leaf-list */
3362 if (module->version < 2) {
3363 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3364 goto error;
3365 }
3366 rfn->target_type &= LYS_LEAFLIST;
3367 } else {
3368 if (module->version < 2) {
3369 rfn->target_type &= (LYS_LEAF | LYS_CHOICE);
3370 } else {
3371 /* YANG 1.1 */
3372 rfn->target_type &= (LYS_LEAFLIST | LYS_LEAF | LYS_CHOICE);
3373 }
3374 }
3375 if (!rfn->target_type) {
3376 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3377 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3378 goto error;
3379 }
3380 } else {
3381 if (module->version < 2) {
3382 rfn->target_type = LYS_LEAF | LYS_CHOICE;
3383 } else {
3384 /* YANG 1.1 */
3385 rfn->target_type = LYS_LEAFLIST | LYS_LEAF | LYS_CHOICE;
3386 }
3387 }
3388
3389 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dflt, rfn->dflt_size, "defaults", "refine", error);
3390 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_DEFAULT, c_dflt, unres)) {
3391 goto error;
3392 }
3393 c_dflt++;
3394 continue;
3395 } else if (!strcmp(sub->name, "mandatory")) {
3396 /* leaf, choice or anyxml */
3397 if (f_mand) {
3398 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3399 goto error;
3400 }
3401 /* just checking the flags in leaf is not sufficient, we would allow
3402 * multiple mandatory statements with the "false" value
3403 */
3404 f_mand = 1;
3405
3406 /* check possibility of statements combination */
3407 if (rfn->target_type) {
3408 rfn->target_type &= (LYS_LEAF | LYS_CHOICE | LYS_ANYDATA);
3409 if (!rfn->target_type) {
3410 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3411 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3412 goto error;
3413 }
3414 } else {
3415 rfn->target_type = LYS_LEAF | LYS_CHOICE | LYS_ANYDATA;
3416 }
3417
3418 GETVAL(ctx, value, sub, "value");
3419 if (!strcmp(value, "true")) {
3420 rfn->flags |= LYS_MAND_TRUE;
3421 } else if (!strcmp(value, "false")) {
3422 rfn->flags |= LYS_MAND_FALSE;
3423 } else {
3424 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3425 goto error;
3426 }
3427 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
3428 goto error;
3429 }
3430 } else if (!strcmp(sub->name, "min-elements")) {
3431 /* list or leaf-list */
3432 if (f_min) {
3433 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3434 goto error;
3435 }
3436 f_min = 1;
3437
3438 /* check possibility of statements combination */
3439 if (rfn->target_type) {
3440 rfn->target_type &= (LYS_LIST | LYS_LEAFLIST);
3441 if (!rfn->target_type) {
3442 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3443 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3444 goto error;
3445 }
3446 } else {
3447 rfn->target_type = LYS_LIST | LYS_LEAFLIST;
3448 }
3449
3450 GETVAL(ctx, value, sub, "value");
3451 while (isspace(value[0])) {
3452 value++;
3453 }
3454
3455 /* convert it to uint32_t */
3456 errno = 0;
3457 endptr = NULL;
3458 val = strtoul(value, &endptr, 10);
3459 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
3460 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3461 goto error;
3462 }
3463 rfn->mod.list.min = (uint32_t) val;
3464 rfn->flags |= LYS_RFN_MINSET;
3465
3466 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MIN, 0, unres)) {
3467 goto error;
3468 }
3469 } else if (!strcmp(sub->name, "max-elements")) {
3470 /* list or leaf-list */
3471 if (f_max) {
3472 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3473 goto error;
3474 }
3475 f_max = 1;
3476
3477 /* check possibility of statements combination */
3478 if (rfn->target_type) {
3479 rfn->target_type &= (LYS_LIST | LYS_LEAFLIST);
3480 if (!rfn->target_type) {
3481 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3482 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3483 goto error;
3484 }
3485 } else {
3486 rfn->target_type = LYS_LIST | LYS_LEAFLIST;
3487 }
3488
3489 GETVAL(ctx, value, sub, "value");
3490 while (isspace(value[0])) {
3491 value++;
3492 }
3493
3494 if (!strcmp(value, "unbounded")) {
3495 rfn->mod.list.max = 0;
3496 } else {
3497 /* convert it to uint32_t */
3498 errno = 0;
3499 endptr = NULL;
3500 val = strtoul(value, &endptr, 10);
3501 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3502 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3503 goto error;
3504 }
3505 rfn->mod.list.max = (uint32_t) val;
3506 }
3507 rfn->flags |= LYS_RFN_MAXSET;
3508
3509 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MAX, 0, unres)) {
3510 goto error;
3511 }
3512 } else if (!strcmp(sub->name, "presence")) {
3513 /* container */
3514 if (rfn->mod.presence) {
3515 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
3516 goto error;
3517 }
3518
3519 /* check possibility of statements combination */
3520 if (rfn->target_type) {
3521 rfn->target_type &= LYS_CONTAINER;
3522 if (!rfn->target_type) {
3523 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3524 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3525 goto error;
3526 }
3527 } else {
3528 rfn->target_type = LYS_CONTAINER;
3529 }
3530
3531 GETVAL(ctx, value, sub, "value");
3532 rfn->mod.presence = lydict_insert(ctx, value, strlen(value));
3533
3534 if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_PRESENCE, 0, unres)) {
3535 goto error;
3536 }
3537 } else if (!strcmp(sub->name, "must")) {
3538 /* leaf leaf-list, list, container or anyxml */
3539 /* check possibility of statements combination */
3540 if (rfn->target_type) {
3541 rfn->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA);
3542 if (!rfn->target_type) {
3543 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3544 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3545 goto error;
3546 }
3547 } else {
3548 rfn->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA;
3549 }
3550
3551 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, rfn->must_size, "musts", "refine", error);
3552 c_must++;
3553 continue;
3554
3555 } else if ((module->version >= 2) && !strcmp(sub->name, "if-feature")) {
3556 /* leaf, leaf-list, list, container, choice, case, anydata or anyxml */
3557 /* check possibility of statements combination */
3558 if (rfn->target_type) {
3559 rfn->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_ANYDATA);
3560 if (!rfn->target_type) {
3561 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
3562 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
3563 goto error;
3564 }
3565 } else {
3566 rfn->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_ANYDATA;
3567 }
3568
3569 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, rfn->iffeature_size, "if-feature", "refine", error);
3570 c_ftrs++;
3571 continue;
3572 } else {
3573 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, sub->name);
3574 goto error;
3575 }
3576
3577 lyxml_free(ctx, sub);
3578 }
3579
3580 /* process nodes with cardinality of 0..n */
3581 if (c_must) {
3582 rfn->must = calloc(c_must, sizeof *rfn->must);
3583 LY_CHECK_ERR_GOTO(!rfn->must, LOGMEM(ctx), error);
3584 }
3585 if (c_ftrs) {
3586 rfn->iffeature = calloc(c_ftrs, sizeof *rfn->iffeature);
3587 LY_CHECK_ERR_GOTO(!rfn->iffeature, LOGMEM(ctx), error);
3588 }
3589 if (c_dflt) {
3590 rfn->dflt = calloc(c_dflt, sizeof *rfn->dflt);
3591 LY_CHECK_ERR_GOTO(!rfn->dflt, LOGMEM(ctx), error);
3592 }
3593 if (c_ext) {
3594 /* some extensions may be already present from the substatements */
3595 reallocated = realloc(rfn->ext, (c_ext + rfn->ext_size) * sizeof *rfn->ext);
3596 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
3597 rfn->ext = reallocated;
3598
3599 /* init memory */
3600 memset(&rfn->ext[rfn->ext_size], 0, c_ext * sizeof *rfn->ext);
3601 }
3602
3603 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3604 if (strcmp(sub->ns->value, LY_NSYIN)) {
3605 /* extension */
3606 r = lyp_yin_fill_ext(rfn, LYEXT_PAR_REFINE, 0, 0, module, sub, &rfn->ext, &rfn->ext_size, unres);
3607 if (r) {
3608 goto error;
3609 }
3610 } else if (!strcmp(sub->name, "if-feature")) {
3611 r = fill_yin_iffeature(uses, 0, sub, &rfn->iffeature[rfn->iffeature_size], unres);
3612 rfn->iffeature_size++;
3613 if (r) {
3614 goto error;
3615 }
3616 } else if (!strcmp(sub->name, "must")) {
3617 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size], unres);
3618 rfn->must_size++;
3619 if (r) {
3620 goto error;
3621 }
3622 } else { /* default */
3623 GETVAL(ctx, value, sub, "value");
3624
3625 /* check for duplicity */
3626 for (r = 0; r < rfn->dflt_size; r++) {
3627 if (ly_strequal(rfn->dflt[r], value, 1)) {
3628 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
3629 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Duplicated default value \"%s\".", value);
3630 goto error;
3631 }
3632 }
3633 rfn->dflt[rfn->dflt_size++] = lydict_insert(ctx, value, strlen(value));
3634 }
3635 }
3636
3637 lyp_reduce_ext_list(&rfn->ext, rfn->ext_size, c_ext + rfn->ext_size);
3638
3639 return EXIT_SUCCESS;
3640
3641 error:
3642 return EXIT_FAILURE;
3643 }
3644
3645 /* logs directly */
3646 static int
fill_yin_import(struct lys_module * module,struct lyxml_elem * yin,struct lys_import * imp,struct unres_schema * unres)3647 fill_yin_import(struct lys_module *module, struct lyxml_elem *yin, struct lys_import *imp, struct unres_schema *unres)
3648 {
3649 struct ly_ctx *ctx = module->ctx;
3650 struct lyxml_elem *child, *next, exts;
3651 const char *value;
3652 int r, c_ext = 0;
3653 void *reallocated;
3654
3655 /* init */
3656 memset(&exts, 0, sizeof exts);
3657
3658 LY_TREE_FOR_SAFE(yin->child, next, child) {
3659 if (!child->ns) {
3660 /* garbage */
3661 continue;
3662 } else if (strcmp(child->ns->value, LY_NSYIN)) {
3663 /* extension */
3664 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, imp->ext_size, "extensions", "import", error);
3665 c_ext++;
3666 lyxml_unlink_elem(ctx, child, 2);
3667 lyxml_add_child(ctx, &exts, child);
3668 } else if (!strcmp(child->name, "prefix")) {
3669 GETVAL(ctx, value, child, "value");
3670 if (lyp_check_identifier(ctx, value, LY_IDENT_PREFIX, module, NULL)) {
3671 goto error;
3672 }
3673 imp->prefix = lydict_insert(ctx, value, strlen(value));
3674
3675 if (lyp_yin_parse_subnode_ext(module, imp, LYEXT_PAR_IMPORT, child, LYEXT_SUBSTMT_PREFIX, 0, unres)) {
3676 goto error;
3677 }
3678 } else if (!strcmp(child->name, "revision-date")) {
3679 if (imp->rev[0]) {
3680 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
3681 goto error;
3682 }
3683 GETVAL(ctx, value, child, "date");
3684 if (lyp_check_date(ctx, value)) {
3685 goto error;
3686 }
3687 memcpy(imp->rev, value, LY_REV_SIZE - 1);
3688
3689 if (lyp_yin_parse_subnode_ext(module, imp, LYEXT_PAR_IMPORT, child, LYEXT_SUBSTMT_REVISIONDATE, 0, unres)) {
3690 goto error;
3691 }
3692 } else if ((module->version >= 2) && !strcmp(child->name, "description")) {
3693 if (imp->dsc) {
3694 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
3695 goto error;
3696 }
3697 if (lyp_yin_parse_subnode_ext(module, imp, LYEXT_PAR_IMPORT, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
3698 goto error;
3699 }
3700 imp->dsc = read_yin_subnode(ctx, child, "text");
3701 if (!imp->dsc) {
3702 goto error;
3703 }
3704 } else if ((module->version >= 2) && !strcmp(child->name, "reference")) {
3705 if (imp->ref) {
3706 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
3707 goto error;
3708 }
3709 if (lyp_yin_parse_subnode_ext(module, imp, LYEXT_PAR_IMPORT, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
3710 goto error;
3711 }
3712 imp->ref = read_yin_subnode(ctx, child, "text");
3713 if (!imp->ref) {
3714 goto error;
3715 }
3716 } else {
3717 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
3718 goto error;
3719 }
3720 }
3721
3722 /* check mandatory information */
3723 if (!imp->prefix) {
3724 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", yin->name);
3725 goto error;
3726 }
3727
3728 /* process extensions */
3729 if (c_ext) {
3730 /* some extensions may be already present from the substatements */
3731 reallocated = realloc(imp->ext, (c_ext + imp->ext_size) * sizeof *imp->ext);
3732 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
3733 imp->ext = reallocated;
3734
3735 /* init memory */
3736 memset(&imp->ext[imp->ext_size], 0, c_ext * sizeof *imp->ext);
3737
3738 LY_TREE_FOR_SAFE(exts.child, next, child) {
3739 /* extension */
3740 r = lyp_yin_fill_ext(imp, LYEXT_PAR_IMPORT, 0, 0, module, child, &imp->ext, &imp->ext_size, unres);
3741 if (r) {
3742 goto error;
3743 }
3744 }
3745
3746 lyp_reduce_ext_list(&imp->ext, imp->ext_size, c_ext + imp->ext_size);
3747 }
3748
3749 GETVAL(ctx, value, yin, "module");
3750 return lyp_check_import(module, value, imp);
3751
3752 error:
3753 while (exts.child) {
3754 lyxml_free(ctx, exts.child);
3755 }
3756 return EXIT_FAILURE;
3757 }
3758
3759 /* logs directly
3760 * returns:
3761 * 0 - inc successfully filled
3762 * -1 - error
3763 */
3764 static int
fill_yin_include(struct lys_module * module,struct lys_submodule * submodule,struct lyxml_elem * yin,struct lys_include * inc,struct unres_schema * unres)3765 fill_yin_include(struct lys_module *module, struct lys_submodule *submodule, struct lyxml_elem *yin,
3766 struct lys_include *inc, struct unres_schema *unres)
3767 {
3768 struct ly_ctx *ctx = module->ctx;
3769 struct lyxml_elem *child, *next, exts;
3770 const char *value;
3771 int r, c_ext = 0;
3772 void *reallocated;
3773
3774 /* init */
3775 memset(&exts, 0, sizeof exts);
3776
3777 LY_TREE_FOR_SAFE(yin->child, next, child) {
3778 if (!child->ns) {
3779 /* garbage */
3780 continue;
3781 } else if (strcmp(child->ns->value, LY_NSYIN)) {
3782 /* extension */
3783 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, inc->ext_size, "extensions", "include", error);
3784 c_ext++;
3785 lyxml_unlink_elem(ctx, child, 2);
3786 lyxml_add_child(ctx, &exts, child);
3787 } else if (!strcmp(child->name, "revision-date")) {
3788 if (inc->rev[0]) {
3789 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "revision-date", yin->name);
3790 goto error;
3791 }
3792 GETVAL(ctx, value, child, "date");
3793 if (lyp_check_date(ctx, value)) {
3794 goto error;
3795 }
3796 memcpy(inc->rev, value, LY_REV_SIZE - 1);
3797
3798 if (lyp_yin_parse_subnode_ext(module, inc, LYEXT_PAR_INCLUDE, child, LYEXT_SUBSTMT_REVISIONDATE, 0, unres)) {
3799 goto error;
3800 }
3801 } else if ((module->version >= 2) && !strcmp(child->name, "description")) {
3802 if (inc->dsc) {
3803 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
3804 goto error;
3805 }
3806 if (lyp_yin_parse_subnode_ext(module, inc, LYEXT_PAR_INCLUDE, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
3807 goto error;
3808 }
3809 inc->dsc = read_yin_subnode(ctx, child, "text");
3810 if (!inc->dsc) {
3811 goto error;
3812 }
3813 } else if ((module->version >= 2) && !strcmp(child->name, "reference")) {
3814 if (inc->ref) {
3815 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
3816 goto error;
3817 }
3818 if (lyp_yin_parse_subnode_ext(module, inc, LYEXT_PAR_INCLUDE, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
3819 goto error;
3820 }
3821 inc->ref = read_yin_subnode(ctx, child, "text");
3822 if (!inc->ref) {
3823 goto error;
3824 }
3825 } else {
3826 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
3827 goto error;
3828 }
3829 }
3830
3831 /* process extensions */
3832 if (c_ext) {
3833 /* some extensions may be already present from the substatements */
3834 reallocated = realloc(inc->ext, (c_ext + inc->ext_size) * sizeof *inc->ext);
3835 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
3836 inc->ext = reallocated;
3837
3838 /* init memory */
3839 memset(&inc->ext[inc->ext_size], 0, c_ext * sizeof *inc->ext);
3840
3841 LY_TREE_FOR_SAFE(exts.child, next, child) {
3842 /* extension */
3843 r = lyp_yin_fill_ext(inc, LYEXT_PAR_INCLUDE, 0, 0, module, child, &inc->ext, &inc->ext_size, unres);
3844 if (r) {
3845 goto error;
3846 }
3847 }
3848
3849 lyp_reduce_ext_list(&inc->ext, inc->ext_size, c_ext + inc->ext_size);
3850 }
3851
3852 GETVAL(ctx, value, yin, "module");
3853 return lyp_check_include(submodule ? (struct lys_module *)submodule : module, value, inc, unres);
3854
3855 error:
3856 return -1;
3857 }
3858
3859 /* logs directly
3860 *
3861 * Covers:
3862 * description, reference, status, optionaly config
3863 *
3864 */
3865 static int
read_yin_common(struct lys_module * module,struct lys_node * parent,void * stmt,LYEXT_PAR stmt_type,struct lyxml_elem * xmlnode,int opt,struct unres_schema * unres)3866 read_yin_common(struct lys_module *module, struct lys_node *parent, void *stmt, LYEXT_PAR stmt_type,
3867 struct lyxml_elem *xmlnode, int opt, struct unres_schema *unres)
3868 {
3869 struct lys_node *node = stmt, *p;
3870 const char *value;
3871 struct lyxml_elem *sub, *next;
3872 struct ly_ctx *const ctx = module->ctx;
3873 char *str;
3874
3875 if (opt & OPT_MODULE) {
3876 node->module = module;
3877 }
3878
3879 if (opt & OPT_IDENT) {
3880 GETVAL(ctx, value, xmlnode, "name");
3881 if (lyp_check_identifier(ctx, value, LY_IDENT_NAME, NULL, NULL)) {
3882 goto error;
3883 }
3884 node->name = lydict_insert(ctx, value, strlen(value));
3885 }
3886
3887 /* process local parameters */
3888 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
3889 if (!sub->ns) {
3890 /* garbage */
3891 lyxml_free(ctx, sub);
3892 continue;
3893 }
3894 if (strcmp(sub->ns->value, LY_NSYIN)) {
3895 /* possibly an extension, keep the node for later processing, so skipping lyxml_free() */
3896 continue;
3897 }
3898
3899 if (!strcmp(sub->name, "description")) {
3900 if (node->dsc) {
3901 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, xmlnode->name);
3902 goto error;
3903 }
3904
3905 if (lyp_yin_parse_subnode_ext(module, stmt, stmt_type, sub, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
3906 goto error;
3907 }
3908
3909 node->dsc = read_yin_subnode(ctx, sub, "text");
3910 if (!node->dsc) {
3911 goto error;
3912 }
3913 } else if (!strcmp(sub->name, "reference")) {
3914 if (node->ref) {
3915 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, xmlnode->name);
3916 goto error;
3917 }
3918
3919 if (lyp_yin_parse_subnode_ext(module, stmt, stmt_type, sub, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
3920 goto error;
3921 }
3922
3923 node->ref = read_yin_subnode(ctx, sub, "text");
3924 if (!node->ref) {
3925 goto error;
3926 }
3927 } else if (!strcmp(sub->name, "status")) {
3928 if (node->flags & LYS_STATUS_MASK) {
3929 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, xmlnode->name);
3930 goto error;
3931 }
3932 GETVAL(ctx, value, sub, "value");
3933 if (!strcmp(value, "current")) {
3934 node->flags |= LYS_STATUS_CURR;
3935 } else if (!strcmp(value, "deprecated")) {
3936 node->flags |= LYS_STATUS_DEPRC;
3937 } else if (!strcmp(value, "obsolete")) {
3938 node->flags |= LYS_STATUS_OBSLT;
3939 } else {
3940 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3941 goto error;
3942 }
3943
3944 if (lyp_yin_parse_subnode_ext(module, stmt, stmt_type, sub, LYEXT_SUBSTMT_STATUS, 0, unres)) {
3945 goto error;
3946 }
3947 } else if ((opt & (OPT_CFG_PARSE | OPT_CFG_IGNORE)) && !strcmp(sub->name, "config")) {
3948 if (opt & OPT_CFG_PARSE) {
3949 if (node->flags & LYS_CONFIG_MASK) {
3950 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, xmlnode->name);
3951 goto error;
3952 }
3953 GETVAL(ctx, value, sub, "value");
3954 if (!strcmp(value, "false")) {
3955 node->flags |= LYS_CONFIG_R;
3956 } else if (!strcmp(value, "true")) {
3957 node->flags |= LYS_CONFIG_W;
3958 } else {
3959 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
3960 goto error;
3961 }
3962 node->flags |= LYS_CONFIG_SET;
3963
3964 if (lyp_yin_parse_subnode_ext(module, stmt, stmt_type, sub, LYEXT_SUBSTMT_CONFIG, 0, unres)) {
3965 goto error;
3966 }
3967 }
3968 } else {
3969 /* skip the lyxml_free */
3970 continue;
3971 }
3972 lyxml_free(ctx, sub);
3973 }
3974
3975 if ((opt & OPT_CFG_INHERIT) && !(node->flags & LYS_CONFIG_MASK)) {
3976 /* get config flag from parent */
3977 if (parent) {
3978 node->flags |= parent->flags & LYS_CONFIG_MASK;
3979 } else if (!parent) {
3980 /* default config is true */
3981 node->flags |= LYS_CONFIG_W;
3982 }
3983 }
3984
3985 if (parent && (parent->flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
3986 /* status is not inherited by specification, but it not make sense to have
3987 * current in deprecated or deprecated in obsolete, so we print warning
3988 * and fix the schema by inheriting */
3989 if (!(node->flags & (LYS_STATUS_MASK))) {
3990 /* status not explicitely specified on the current node -> inherit */
3991 if (stmt_type == LYEXT_PAR_NODE) {
3992 p = node->parent;
3993 node->parent = parent;
3994 str = lys_path(node, LYS_PATH_FIRST_PREFIX);
3995 node->parent = p;
3996 } else {
3997 str = lys_path(parent, LYS_PATH_FIRST_PREFIX);
3998 }
3999 LOGWRN(ctx, "Missing status in %s subtree (%s), inheriting.",
4000 parent->flags & LYS_STATUS_DEPRC ? "deprecated" : "obsolete", str);
4001 free(str);
4002 node->flags |= parent->flags & LYS_STATUS_MASK;
4003 } else if ((parent->flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
4004 /* invalid combination of statuses */
4005 switch (node->flags & LYS_STATUS_MASK) {
4006 case 0:
4007 case LYS_STATUS_CURR:
4008 LOGVAL(ctx, LYE_INSTATUS, LY_VLOG_LYS, parent, "current", xmlnode->name, "is child of",
4009 parent->flags & LYS_STATUS_DEPRC ? "deprecated" : "obsolete", parent->name);
4010 break;
4011 case LYS_STATUS_DEPRC:
4012 LOGVAL(ctx, LYE_INSTATUS, LY_VLOG_LYS, parent, "deprecated", xmlnode->name, "is child of",
4013 "obsolete", parent->name);
4014 break;
4015 }
4016 goto error;
4017 }
4018 }
4019
4020 return EXIT_SUCCESS;
4021
4022 error:
4023 return EXIT_FAILURE;
4024 }
4025
4026 /* logs directly */
4027 static struct lys_when *
read_yin_when(struct lys_module * module,struct lyxml_elem * yin,struct unres_schema * unres)4028 read_yin_when(struct lys_module *module, struct lyxml_elem *yin, struct unres_schema *unres)
4029 {
4030 struct ly_ctx *ctx = module->ctx;
4031 struct lys_when *retval = NULL;
4032 struct lyxml_elem *child, *next;
4033 const char *value;
4034
4035 retval = calloc(1, sizeof *retval);
4036 LY_CHECK_ERR_RETURN(!retval, LOGMEM(ctx), NULL);
4037
4038 GETVAL(ctx, value, yin, "condition");
4039 retval->cond = transform_schema2json(module, value);
4040 if (!retval->cond) {
4041 goto error;
4042 }
4043
4044 LY_TREE_FOR_SAFE(yin->child, next, child) {
4045 if (!child->ns) {
4046 /* garbage */
4047 continue;
4048 } else if (strcmp(child->ns->value, LY_NSYIN)) {
4049 /* extensions */
4050 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_WHEN, child, LYEXT_SUBSTMT_SELF, 0, unres)) {
4051 goto error;
4052 }
4053 } else if (!strcmp(child->name, "description")) {
4054 if (retval->dsc) {
4055 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
4056 goto error;
4057 }
4058
4059 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_WHEN, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
4060 goto error;
4061 }
4062
4063 retval->dsc = read_yin_subnode(ctx, child, "text");
4064 if (!retval->dsc) {
4065 goto error;
4066 }
4067 } else if (!strcmp(child->name, "reference")) {
4068 if (retval->ref) {
4069 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
4070 goto error;
4071 }
4072
4073 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_WHEN, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
4074 goto error;
4075 }
4076
4077 retval->ref = read_yin_subnode(ctx, child, "text");
4078 if (!retval->ref) {
4079 goto error;
4080 }
4081 } else {
4082 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
4083 goto error;
4084 }
4085 }
4086
4087 return retval;
4088
4089 error:
4090 lys_when_free(ctx, retval, NULL);
4091 return NULL;
4092 }
4093
4094 /* logs directly */
4095 static struct lys_node *
read_yin_case(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)4096 read_yin_case(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
4097 struct unres_schema *unres)
4098 {
4099 struct ly_ctx *ctx = module->ctx;
4100 struct lyxml_elem *sub, *next, root;
4101 struct lys_node_case *cs;
4102 struct lys_node *retval, *node = NULL;
4103 int c_ftrs = 0, c_ext = 0, ret;
4104 void *reallocated;
4105
4106 /* init */
4107 memset(&root, 0, sizeof root);
4108
4109 cs = calloc(1, sizeof *cs);
4110 LY_CHECK_ERR_RETURN(!cs, LOGMEM(ctx), NULL);
4111 cs->nodetype = LYS_CASE;
4112 cs->prev = (struct lys_node *)cs;
4113 retval = (struct lys_node *)cs;
4114
4115 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
4116 OPT_IDENT | OPT_MODULE | (!(options & LYS_PARSE_OPT_CFG_MASK) ? OPT_CFG_INHERIT : 0), unres)) {
4117 goto error;
4118 }
4119
4120 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
4121
4122 /* insert the node into the schema tree */
4123 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
4124 goto error;
4125 }
4126
4127 /* process choice's specific children */
4128 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4129 if (strcmp(sub->ns->value, LY_NSYIN)) {
4130 /* extension */
4131 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "case", error);
4132 c_ext++;
4133 } else if (!strcmp(sub->name, "container") ||
4134 !strcmp(sub->name, "leaf-list") ||
4135 !strcmp(sub->name, "leaf") ||
4136 !strcmp(sub->name, "list") ||
4137 !strcmp(sub->name, "uses") ||
4138 !strcmp(sub->name, "choice") ||
4139 !strcmp(sub->name, "anyxml") ||
4140 !strcmp(sub->name, "anydata")) {
4141
4142 lyxml_unlink_elem(ctx, sub, 2);
4143 lyxml_add_child(ctx, &root, sub);
4144 } else if (!strcmp(sub->name, "if-feature")) {
4145 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "case", error);
4146 c_ftrs++;
4147 } else if (!strcmp(sub->name, "when")) {
4148 if (cs->when) {
4149 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4150 goto error;
4151 }
4152
4153 cs->when = read_yin_when(module, sub, unres);
4154 if (!cs->when) {
4155 goto error;
4156 }
4157
4158 lyxml_free(ctx, sub);
4159 } else {
4160 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
4161 goto error;
4162 }
4163 }
4164
4165 if (c_ftrs) {
4166 cs->iffeature = calloc(c_ftrs, sizeof *cs->iffeature);
4167 LY_CHECK_ERR_GOTO(!cs->iffeature, LOGMEM(ctx), error);
4168 }
4169 if (c_ext) {
4170 /* some extensions may be already present from the substatements */
4171 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
4172 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
4173 retval->ext = reallocated;
4174
4175 /* init memory */
4176 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
4177 }
4178
4179 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4180 if (strcmp(sub->ns->value, LY_NSYIN)) {
4181 /* extension */
4182 ret = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
4183 if (ret) {
4184 goto error;
4185 }
4186 } else {
4187 /* if-feature */
4188 ret = fill_yin_iffeature(retval, 0, sub, &cs->iffeature[cs->iffeature_size], unres);
4189 cs->iffeature_size++;
4190 if (ret) {
4191 goto error;
4192 }
4193 }
4194 }
4195
4196 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
4197
4198 /* last part - process data nodes */
4199 LY_TREE_FOR_SAFE(root.child, next, sub) {
4200 if (!strcmp(sub->name, "container")) {
4201 node = read_yin_container(module, retval, sub, options, unres);
4202 } else if (!strcmp(sub->name, "leaf-list")) {
4203 node = read_yin_leaflist(module, retval, sub, options, unres);
4204 } else if (!strcmp(sub->name, "leaf")) {
4205 node = read_yin_leaf(module, retval, sub, options, unres);
4206 } else if (!strcmp(sub->name, "list")) {
4207 node = read_yin_list(module, retval, sub, options, unres);
4208 } else if (!strcmp(sub->name, "choice")) {
4209 node = read_yin_choice(module, retval, sub, options, unres);
4210 } else if (!strcmp(sub->name, "uses")) {
4211 node = read_yin_uses(module, retval, sub, options, unres);
4212 } else if (!strcmp(sub->name, "anyxml")) {
4213 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
4214 } else if (!strcmp(sub->name, "anydata")) {
4215 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
4216 }
4217 if (!node) {
4218 goto error;
4219 }
4220
4221 lyxml_free(ctx, sub);
4222 }
4223
4224 /* check XPath dependencies */
4225 if (!(ctx->models.flags & LY_CTX_TRUSTED) && cs->when) {
4226 if (options & LYS_PARSE_OPT_INGRP) {
4227 if (lyxp_node_check_syntax(retval)) {
4228 goto error;
4229 }
4230 } else {
4231 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
4232 goto error;
4233 }
4234 }
4235 }
4236
4237 return retval;
4238
4239 error:
4240 while (root.child) {
4241 lyxml_free(ctx, root.child);
4242 }
4243 lys_node_free(ctx, retval, NULL, 0);
4244
4245 return NULL;
4246 }
4247
4248 /* logs directly */
4249 static struct lys_node *
read_yin_choice(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)4250 read_yin_choice(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
4251 struct unres_schema *unres)
4252 {
4253 struct lyxml_elem *sub, *next, *dflt = NULL;
4254 struct ly_ctx *const ctx = module->ctx;
4255 struct lys_node *retval, *node = NULL;
4256 struct lys_node_choice *choice;
4257 const char *value;
4258 int f_mand = 0, c_ftrs = 0, c_ext = 0, ret;
4259 void *reallocated;
4260
4261 choice = calloc(1, sizeof *choice);
4262 LY_CHECK_ERR_RETURN(!choice, LOGMEM(ctx), NULL);
4263
4264 choice->nodetype = LYS_CHOICE;
4265 choice->prev = (struct lys_node *)choice;
4266 retval = (struct lys_node *)choice;
4267
4268 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
4269 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
4270 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT),
4271 unres)) {
4272 goto error;
4273 }
4274
4275 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
4276
4277 /* insert the node into the schema tree */
4278 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
4279 goto error;
4280 }
4281
4282 /* process choice's specific children */
4283 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4284 if (strcmp(sub->ns->value, LY_NSYIN)) {
4285 /* extension */
4286 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "choice", error);
4287 c_ext++;
4288 /* keep it for later processing, skip lyxml_free() */
4289 continue;
4290 } else if (!strcmp(sub->name, "container")) {
4291 if (!(node = read_yin_container(module, retval, sub, options, unres))) {
4292 goto error;
4293 }
4294 } else if (!strcmp(sub->name, "leaf-list")) {
4295 if (!(node = read_yin_leaflist(module, retval, sub, options, unres))) {
4296 goto error;
4297 }
4298 } else if (!strcmp(sub->name, "leaf")) {
4299 if (!(node = read_yin_leaf(module, retval, sub, options, unres))) {
4300 goto error;
4301 }
4302 } else if (!strcmp(sub->name, "list")) {
4303 if (!(node = read_yin_list(module, retval, sub, options, unres))) {
4304 goto error;
4305 }
4306 } else if (!strcmp(sub->name, "case")) {
4307 if (!(node = read_yin_case(module, retval, sub, options, unres))) {
4308 goto error;
4309 }
4310 } else if (!strcmp(sub->name, "anyxml")) {
4311 if (!(node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres))) {
4312 goto error;
4313 }
4314 } else if (!strcmp(sub->name, "anydata")) {
4315 if (!(node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres))) {
4316 goto error;
4317 }
4318 } else if (!strcmp(sub->name, "default")) {
4319 if (dflt) {
4320 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4321 goto error;
4322 }
4323
4324 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_DEFAULT, 0, unres)) {
4325 goto error;
4326 }
4327
4328 dflt = sub;
4329 lyxml_unlink_elem(ctx, dflt, 0);
4330 continue;
4331 /* skip lyxml_free() at the end of the loop, the sub node is processed later as dflt */
4332
4333 } else if (!strcmp(sub->name, "mandatory")) {
4334 if (f_mand) {
4335 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4336 goto error;
4337 }
4338 /* just checking the flags in leaf is not sufficient, we would allow
4339 * multiple mandatory statements with the "false" value
4340 */
4341 f_mand = 1;
4342
4343 GETVAL(ctx, value, sub, "value");
4344 if (!strcmp(value, "true")) {
4345 choice->flags |= LYS_MAND_TRUE;
4346 } else if (!strcmp(value, "false")) {
4347 choice->flags |= LYS_MAND_FALSE;
4348 } else {
4349 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4350 goto error;
4351 } /* else false is the default value, so we can ignore it */
4352
4353 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
4354 goto error;
4355 }
4356 } else if (!strcmp(sub->name, "when")) {
4357 if (choice->when) {
4358 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4359 goto error;
4360 }
4361
4362 choice->when = read_yin_when(module, sub, unres);
4363 if (!choice->when) {
4364 goto error;
4365 }
4366 } else if (!strcmp(sub->name, "if-feature")) {
4367 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "choice", error);
4368 c_ftrs++;
4369
4370 /* skip lyxml_free() at the end of the loop, the sub node is processed later */
4371 continue;
4372 } else if (module->version >= 2 && !strcmp(sub->name, "choice")) {
4373 if (!(node = read_yin_choice(module, retval, sub, options, unres))) {
4374 goto error;
4375 }
4376 } else {
4377 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
4378 goto error;
4379 }
4380
4381 node = NULL;
4382 lyxml_free(ctx, sub);
4383 }
4384
4385 if (c_ftrs) {
4386 choice->iffeature = calloc(c_ftrs, sizeof *choice->iffeature);
4387 LY_CHECK_ERR_GOTO(!choice->iffeature, LOGMEM(ctx), error);
4388 }
4389 if (c_ext) {
4390 /* some extensions may be already present from the substatements */
4391 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
4392 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
4393 retval->ext = reallocated;
4394
4395 /* init memory */
4396 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
4397 }
4398
4399 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4400 if (strcmp(sub->ns->value, LY_NSYIN)) {
4401 /* extension */
4402 ret = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
4403 if (ret) {
4404 goto error;
4405 }
4406 } else {
4407 ret = fill_yin_iffeature(retval, 0, sub, &choice->iffeature[choice->iffeature_size], unres);
4408 choice->iffeature_size++;
4409 if (ret) {
4410 goto error;
4411 }
4412 }
4413 }
4414
4415 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
4416
4417 /* check - default is prohibited in combination with mandatory */
4418 if (dflt && (choice->flags & LYS_MAND_TRUE)) {
4419 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, retval, "default", "choice");
4420 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "The \"default\" statement is forbidden on choices with \"mandatory\".");
4421 goto error;
4422 }
4423
4424 /* link default with the case */
4425 if (dflt) {
4426 GETVAL(ctx, value, dflt, "value");
4427 if (unres_schema_add_str(module, unres, choice, UNRES_CHOICE_DFLT, value) == -1) {
4428 goto error;
4429 }
4430 lyxml_free(ctx, dflt);
4431 }
4432
4433 /* check XPath dependencies */
4434 if (!(ctx->models.flags & LY_CTX_TRUSTED) && choice->when) {
4435 if (options & LYS_PARSE_OPT_INGRP) {
4436 if (lyxp_node_check_syntax(retval)) {
4437 goto error;
4438 }
4439 } else {
4440 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
4441 goto error;
4442 }
4443 }
4444 }
4445
4446 return retval;
4447
4448 error:
4449 lyxml_free(ctx, dflt);
4450 lys_node_free(ctx, retval, NULL, 0);
4451 return NULL;
4452 }
4453
4454 /* logs directly */
4455 static struct lys_node *
read_yin_anydata(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,LYS_NODE type,int options,struct unres_schema * unres)4456 read_yin_anydata(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, LYS_NODE type,
4457 int options, struct unres_schema *unres)
4458 {
4459 struct ly_ctx *ctx = module->ctx;
4460 struct lys_node *retval;
4461 struct lys_node_anydata *anyxml;
4462 struct lyxml_elem *sub, *next;
4463 const char *value;
4464 int r;
4465 int f_mand = 0;
4466 int c_must = 0, c_ftrs = 0, c_ext = 0;
4467 void *reallocated;
4468
4469 anyxml = calloc(1, sizeof *anyxml);
4470 LY_CHECK_ERR_RETURN(!anyxml, LOGMEM(ctx), NULL);
4471
4472 anyxml->nodetype = type;
4473 anyxml->prev = (struct lys_node *)anyxml;
4474 retval = (struct lys_node *)anyxml;
4475
4476 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
4477 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
4478 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT), unres)) {
4479 goto error;
4480 }
4481
4482 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
4483
4484 /* insert the node into the schema tree */
4485 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
4486 goto error;
4487 }
4488
4489 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4490 if (strcmp(sub->ns->value, LY_NSYIN)) {
4491 /* extension */
4492 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "anydata", error);
4493 c_ext++;
4494 } else if (!strcmp(sub->name, "mandatory")) {
4495 if (f_mand) {
4496 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4497 goto error;
4498 }
4499 /* just checking the flags in leaf is not sufficient, we would allow
4500 * multiple mandatory statements with the "false" value
4501 */
4502 f_mand = 1;
4503
4504 GETVAL(ctx, value, sub, "value");
4505 if (!strcmp(value, "true")) {
4506 anyxml->flags |= LYS_MAND_TRUE;
4507 } else if (!strcmp(value, "false")) {
4508 anyxml->flags |= LYS_MAND_FALSE;
4509 } else {
4510 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4511 goto error;
4512 }
4513 /* else false is the default value, so we can ignore it */
4514
4515 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
4516 goto error;
4517 }
4518 lyxml_free(ctx, sub);
4519 } else if (!strcmp(sub->name, "when")) {
4520 if (anyxml->when) {
4521 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4522 goto error;
4523 }
4524
4525 anyxml->when = read_yin_when(module, sub, unres);
4526 if (!anyxml->when) {
4527 lyxml_free(ctx, sub);
4528 goto error;
4529 }
4530 lyxml_free(ctx, sub);
4531 } else if (!strcmp(sub->name, "must")) {
4532 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, anyxml->must_size, "musts", "anydata", error);
4533 c_must++;
4534 } else if (!strcmp(sub->name, "if-feature")) {
4535 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "anydata", error);
4536 c_ftrs++;
4537
4538 } else {
4539 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
4540 goto error;
4541 }
4542 }
4543
4544 /* middle part - process nodes with cardinality of 0..n */
4545 if (c_must) {
4546 anyxml->must = calloc(c_must, sizeof *anyxml->must);
4547 LY_CHECK_ERR_GOTO(!anyxml->must, LOGMEM(ctx), error);
4548 }
4549 if (c_ftrs) {
4550 anyxml->iffeature = calloc(c_ftrs, sizeof *anyxml->iffeature);
4551 LY_CHECK_ERR_GOTO(!anyxml->iffeature, LOGMEM(ctx), error);
4552 }
4553 if (c_ext) {
4554 /* some extensions may be already present from the substatements */
4555 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
4556 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
4557 retval->ext = reallocated;
4558
4559 /* init memory */
4560 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
4561 }
4562
4563 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4564 if (strcmp(sub->ns->value, LY_NSYIN)) {
4565 /* extension */
4566 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
4567 if (r) {
4568 goto error;
4569 }
4570 } else if (!strcmp(sub->name, "must")) {
4571 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size], unres);
4572 anyxml->must_size++;
4573 if (r) {
4574 goto error;
4575 }
4576 } else if (!strcmp(sub->name, "if-feature")) {
4577 r = fill_yin_iffeature(retval, 0, sub, &anyxml->iffeature[anyxml->iffeature_size], unres);
4578 anyxml->iffeature_size++;
4579 if (r) {
4580 goto error;
4581 }
4582 }
4583 }
4584
4585 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
4586
4587 /* check XPath dependencies */
4588 if (!(ctx->models.flags & LY_CTX_TRUSTED) && (anyxml->when || anyxml->must)) {
4589 if (options & LYS_PARSE_OPT_INGRP) {
4590 if (lyxp_node_check_syntax(retval)) {
4591 goto error;
4592 }
4593 } else {
4594 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
4595 goto error;
4596 }
4597 }
4598 }
4599
4600 for (r = 0; r < retval->ext_size; ++r) {
4601 /* set flag, which represent LYEXT_OPT_VALID */
4602 if (retval->ext[r] && (retval->ext[r]->flags & LYEXT_OPT_VALID)) {
4603 retval->flags |= LYS_VALID_EXT;
4604 break;
4605 }
4606 }
4607
4608 return retval;
4609
4610 error:
4611 lys_node_free(ctx, retval, NULL, 0);
4612 return NULL;
4613 }
4614
4615 /* logs directly */
4616 static struct lys_node *
read_yin_leaf(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)4617 read_yin_leaf(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
4618 struct unres_schema *unres)
4619 {
4620 struct ly_ctx *ctx = module->ctx;
4621 struct lys_node *retval;
4622 struct lys_node_leaf *leaf;
4623 struct lyxml_elem *sub, *next;
4624 const char *value;
4625 int r, has_type = 0;
4626 int c_must = 0, c_ftrs = 0, f_mand = 0, c_ext = 0;
4627 void *reallocated;
4628
4629 leaf = calloc(1, sizeof *leaf);
4630 LY_CHECK_ERR_RETURN(!leaf, LOGMEM(ctx), NULL);
4631
4632 leaf->nodetype = LYS_LEAF;
4633 leaf->prev = (struct lys_node *)leaf;
4634 retval = (struct lys_node *)leaf;
4635
4636 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
4637 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
4638 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT),
4639 unres)) {
4640 goto error;
4641 }
4642
4643 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
4644
4645 /* insert the node into the schema tree */
4646 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
4647 goto error;
4648 }
4649
4650 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4651 if (strcmp(sub->ns->value, LY_NSYIN)) {
4652 /* extension */
4653 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "leaf", error);
4654 c_ext++;
4655 continue;
4656 } else if (!strcmp(sub->name, "type")) {
4657 if (has_type) {
4658 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4659 goto error;
4660 }
4661 /* HACK for unres */
4662 leaf->type.der = (struct lys_tpdf *)sub;
4663 leaf->type.parent = (struct lys_tpdf *)leaf;
4664 /* postpone type resolution when if-feature parsing is done since we need
4665 * if-feature for check_leafref_features() */
4666 has_type = 1;
4667 } else if (!strcmp(sub->name, "default")) {
4668 if (leaf->dflt) {
4669 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4670 goto error;
4671 }
4672 GETVAL(ctx, value, sub, "value");
4673 leaf->dflt = lydict_insert(ctx, value, strlen(value));
4674
4675 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_DEFAULT, 0, unres)) {
4676 goto error;
4677 }
4678 } else if (!strcmp(sub->name, "units")) {
4679 if (leaf->units) {
4680 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4681 goto error;
4682 }
4683 GETVAL(ctx, value, sub, "name");
4684 leaf->units = lydict_insert(ctx, value, strlen(value));
4685
4686 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_UNITS, 0, unres)) {
4687 goto error;
4688 }
4689 } else if (!strcmp(sub->name, "mandatory")) {
4690 if (f_mand) {
4691 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4692 goto error;
4693 }
4694 /* just checking the flags in leaf is not sufficient, we would allow
4695 * multiple mandatory statements with the "false" value
4696 */
4697 f_mand = 1;
4698
4699 GETVAL(ctx, value, sub, "value");
4700 if (!strcmp(value, "true")) {
4701 leaf->flags |= LYS_MAND_TRUE;
4702 } else if (!strcmp(value, "false")) {
4703 leaf->flags |= LYS_MAND_FALSE;
4704 } else {
4705 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4706 goto error;
4707 } /* else false is the default value, so we can ignore it */
4708
4709 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
4710 goto error;
4711 }
4712 } else if (!strcmp(sub->name, "when")) {
4713 if (leaf->when) {
4714 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4715 goto error;
4716 }
4717
4718 leaf->when = read_yin_when(module, sub, unres);
4719 if (!leaf->when) {
4720 goto error;
4721 }
4722
4723 } else if (!strcmp(sub->name, "must")) {
4724 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, leaf->must_size, "musts", "leaf", error);
4725 c_must++;
4726 continue;
4727 } else if (!strcmp(sub->name, "if-feature")) {
4728 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "musts", "leaf", error);
4729 c_ftrs++;
4730 continue;
4731
4732 } else {
4733 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
4734 goto error;
4735 }
4736
4737 /* do not free sub, it could have been unlinked and stored in unres */
4738 }
4739
4740 /* check mandatory parameters */
4741 if (!has_type) {
4742 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, retval, "type", yin->name);
4743 goto error;
4744 }
4745 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
4746 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, retval, "mandatory", "leaf");
4747 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
4748 "The \"mandatory\" statement is forbidden on leaf with the \"default\" statement.");
4749 goto error;
4750 }
4751
4752 /* middle part - process nodes with cardinality of 0..n */
4753 if (c_must) {
4754 leaf->must = calloc(c_must, sizeof *leaf->must);
4755 LY_CHECK_ERR_GOTO(!leaf->must, LOGMEM(ctx), error);
4756 }
4757 if (c_ftrs) {
4758 leaf->iffeature = calloc(c_ftrs, sizeof *leaf->iffeature);
4759 LY_CHECK_ERR_GOTO(!leaf->iffeature, LOGMEM(ctx), error);
4760 }
4761 if (c_ext) {
4762 /* some extensions may be already present from the substatements */
4763 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
4764 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
4765 retval->ext = reallocated;
4766
4767 /* init memory */
4768 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
4769 }
4770
4771 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4772 if (strcmp(sub->ns->value, LY_NSYIN)) {
4773 /* extension */
4774 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
4775 if (r) {
4776 goto error;
4777 }
4778 } else if (!strcmp(sub->name, "must")) {
4779 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size], unres);
4780 leaf->must_size++;
4781 if (r) {
4782 goto error;
4783 }
4784 } else if (!strcmp(sub->name, "if-feature")) {
4785 r = fill_yin_iffeature(retval, 0, sub, &leaf->iffeature[leaf->iffeature_size], unres);
4786 leaf->iffeature_size++;
4787 if (r) {
4788 goto error;
4789 }
4790 }
4791 }
4792
4793 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
4794
4795 /* finalize type parsing */
4796 if (unres_schema_add_node(module, unres, &leaf->type, UNRES_TYPE_DER, retval) == -1) {
4797 leaf->type.der = NULL;
4798 goto error;
4799 }
4800
4801 /* check default value (if not defined, there still could be some restrictions
4802 * that need to be checked against a default value from a derived type) */
4803 if (!(ctx->models.flags & LY_CTX_TRUSTED) &&
4804 (unres_schema_add_node(module, unres, &leaf->type, UNRES_TYPE_DFLT,
4805 (struct lys_node *)(&leaf->dflt)) == -1)) {
4806 goto error;
4807 }
4808
4809 /* check XPath dependencies */
4810 if (!(ctx->models.flags & LY_CTX_TRUSTED) && (leaf->when || leaf->must)) {
4811 if (options & LYS_PARSE_OPT_INGRP) {
4812 if (lyxp_node_check_syntax(retval)) {
4813 goto error;
4814 }
4815 } else {
4816 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
4817 goto error;
4818 }
4819 }
4820 }
4821
4822 for (r = 0; r < retval->ext_size; ++r) {
4823 /* set flag, which represent LYEXT_OPT_VALID */
4824 if (retval->ext[r] && (retval->ext[r]->flags & LYEXT_OPT_VALID)) {
4825 retval->flags |= LYS_VALID_EXT;
4826 break;
4827 }
4828 }
4829
4830 return retval;
4831
4832 error:
4833 lys_node_free(ctx, retval, NULL, 0);
4834 return NULL;
4835 }
4836
4837 /* logs directly */
4838 static struct lys_node *
read_yin_leaflist(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)4839 read_yin_leaflist(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
4840 struct unres_schema *unres)
4841 {
4842 struct ly_ctx *ctx = module->ctx;
4843 struct lys_node *retval;
4844 struct lys_node_leaflist *llist;
4845 struct lyxml_elem *sub, *next;
4846 const char *value;
4847 char *endptr;
4848 unsigned long val;
4849 int r, has_type = 0;
4850 int c_must = 0, c_ftrs = 0, c_dflt = 0, c_ext = 0;
4851 int f_ordr = 0, f_min = 0, f_max = 0;
4852 void *reallocated;
4853
4854 llist = calloc(1, sizeof *llist);
4855 LY_CHECK_ERR_RETURN(!llist, LOGMEM(ctx), NULL);
4856
4857 llist->nodetype = LYS_LEAFLIST;
4858 llist->prev = (struct lys_node *)llist;
4859 retval = (struct lys_node *)llist;
4860
4861 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
4862 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
4863 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT),
4864 unres)) {
4865 goto error;
4866 }
4867
4868 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
4869
4870 /* insert the node into the schema tree */
4871 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
4872 goto error;
4873 }
4874
4875 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4876 if (strcmp(sub->ns->value, LY_NSYIN)) {
4877 /* extension */
4878 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "leaf-list", error);
4879 c_ext++;
4880 continue;
4881 } else if (!strcmp(sub->name, "type")) {
4882 if (has_type) {
4883 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4884 goto error;
4885 }
4886 /* HACK for unres */
4887 llist->type.der = (struct lys_tpdf *)sub;
4888 llist->type.parent = (struct lys_tpdf *)llist;
4889 /* postpone type resolution when if-feature parsing is done since we need
4890 * if-feature for check_leafref_features() */
4891 has_type = 1;
4892 } else if (!strcmp(sub->name, "units")) {
4893 if (llist->units) {
4894 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4895 goto error;
4896 }
4897 GETVAL(ctx, value, sub, "name");
4898 llist->units = lydict_insert(ctx, value, strlen(value));
4899
4900 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_UNITS, 0, unres)) {
4901 goto error;
4902 }
4903 } else if (!strcmp(sub->name, "ordered-by")) {
4904 if (f_ordr) {
4905 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4906 goto error;
4907 }
4908 /* just checking the flags in llist is not sufficient, we would
4909 * allow multiple ordered-by statements with the "system" value
4910 */
4911 f_ordr = 1;
4912
4913 if (llist->flags & LYS_CONFIG_R) {
4914 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
4915 * state data
4916 */
4917 lyxml_free(ctx, sub);
4918 continue;
4919 }
4920
4921 GETVAL(ctx, value, sub, "value");
4922 if (!strcmp(value, "user")) {
4923 llist->flags |= LYS_USERORDERED;
4924 } else if (strcmp(value, "system")) {
4925 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4926 goto error;
4927 } /* else system is the default value, so we can ignore it */
4928
4929 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_ORDEREDBY, 0, unres)) {
4930 goto error;
4931 }
4932 } else if (!strcmp(sub->name, "must")) {
4933 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, llist->must_size, "musts", "leaf-list", error);
4934 c_must++;
4935 continue;
4936 } else if (!strcmp(sub->name, "if-feature")) {
4937 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "leaf-list", error);
4938 c_ftrs++;
4939 continue;
4940 } else if ((module->version >= 2) && !strcmp(sub->name, "default")) {
4941 /* read the default's extension instances */
4942 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_DEFAULT, c_dflt, unres)) {
4943 goto error;
4944 }
4945
4946 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dflt, llist->dflt_size, "defaults", "leaf-list", error);
4947 c_dflt++;
4948 continue;
4949
4950 } else if (!strcmp(sub->name, "min-elements")) {
4951 if (f_min) {
4952 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4953 goto error;
4954 }
4955 f_min = 1;
4956
4957 GETVAL(ctx, value, sub, "value");
4958 while (isspace(value[0])) {
4959 value++;
4960 }
4961
4962 /* convert it to uint32_t */
4963 errno = 0;
4964 endptr = NULL;
4965 val = strtoul(value, &endptr, 10);
4966 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
4967 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4968 goto error;
4969 }
4970 llist->min = (uint32_t) val;
4971 if (llist->max && (llist->min > llist->max)) {
4972 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
4973 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4974 goto error;
4975 }
4976
4977 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MIN, 0, unres)) {
4978 goto error;
4979 }
4980 } else if (!strcmp(sub->name, "max-elements")) {
4981 if (f_max) {
4982 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
4983 goto error;
4984 }
4985 f_max = 1;
4986
4987 GETVAL(ctx, value, sub, "value");
4988 while (isspace(value[0])) {
4989 value++;
4990 }
4991
4992 if (!strcmp(value, "unbounded")) {
4993 llist->max = 0;
4994 } else {
4995 /* convert it to uint32_t */
4996 errno = 0;
4997 endptr = NULL;
4998 val = strtoul(value, &endptr, 10);
4999 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
5000 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5001 goto error;
5002 }
5003 llist->max = (uint32_t) val;
5004 if (llist->min > llist->max) {
5005 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5006 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"max-elements\" is smaller than \"min-elements\".");
5007 goto error;
5008 }
5009 }
5010
5011 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MAX, 0, unres)) {
5012 goto error;
5013 }
5014 } else if (!strcmp(sub->name, "when")) {
5015 if (llist->when) {
5016 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5017 goto error;
5018 }
5019
5020 llist->when = read_yin_when(module, sub, unres);
5021 if (!llist->when) {
5022 goto error;
5023 }
5024 } else {
5025 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
5026 goto error;
5027 }
5028
5029 /* do not free sub, it could have been unlinked and stored in unres */
5030 }
5031
5032 /* check constraints */
5033 if (!has_type) {
5034 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, retval, "type", yin->name);
5035 goto error;
5036 }
5037
5038 /* middle part - process nodes with cardinality of 0..n */
5039 if (c_must) {
5040 llist->must = calloc(c_must, sizeof *llist->must);
5041 LY_CHECK_ERR_GOTO(!llist->must, LOGMEM(ctx), error);
5042 }
5043 if (c_ftrs) {
5044 llist->iffeature = calloc(c_ftrs, sizeof *llist->iffeature);
5045 LY_CHECK_ERR_GOTO(!llist->iffeature, LOGMEM(ctx), error);
5046 }
5047 if (c_dflt) {
5048 llist->dflt = calloc(c_dflt, sizeof *llist->dflt);
5049 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), error);
5050 }
5051 if (c_ext) {
5052 /* some extensions may be already present from the substatements */
5053 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
5054 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
5055 retval->ext = reallocated;
5056
5057 /* init memory */
5058 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
5059 }
5060
5061 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5062 if (strcmp(sub->ns->value, LY_NSYIN)) {
5063 /* extension */
5064 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
5065 if (r) {
5066 goto error;
5067 }
5068 } else if (!strcmp(sub->name, "must")) {
5069 r = fill_yin_must(module, sub, &llist->must[llist->must_size], unres);
5070 llist->must_size++;
5071 if (r) {
5072 goto error;
5073 }
5074 } else if (!strcmp(sub->name, "if-feature")) {
5075 r = fill_yin_iffeature(retval, 0, sub, &llist->iffeature[llist->iffeature_size], unres);
5076 llist->iffeature_size++;
5077 if (r) {
5078 goto error;
5079 }
5080 } else if (!strcmp(sub->name, "default")) {
5081 GETVAL(ctx, value, sub, "value");
5082
5083 /* check for duplicity in case of configuration data,
5084 * in case of status data duplicities are allowed */
5085 if (llist->flags & LYS_CONFIG_W) {
5086 for (r = 0; r < llist->dflt_size; r++) {
5087 if (ly_strequal(llist->dflt[r], value, 1)) {
5088 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, "default");
5089 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Duplicated default value \"%s\".", value);
5090 goto error;
5091 }
5092 }
5093 }
5094 llist->dflt[llist->dflt_size++] = lydict_insert(ctx, value, strlen(value));
5095 }
5096 }
5097
5098 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
5099
5100 /* finalize type parsing */
5101 if (unres_schema_add_node(module, unres, &llist->type, UNRES_TYPE_DER, retval) == -1) {
5102 llist->type.der = NULL;
5103 goto error;
5104 }
5105
5106 if (llist->dflt_size && llist->min) {
5107 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, retval, "min-elements", "leaf-list");
5108 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
5109 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5110 goto error;
5111 }
5112
5113 /* check default value (if not defined, there still could be some restrictions
5114 * that need to be checked against a default value from a derived type) */
5115 for (r = 0; r < llist->dflt_size; r++) {
5116 if (!(ctx->models.flags & LY_CTX_TRUSTED) &&
5117 (unres_schema_add_node(module, unres, &llist->type, UNRES_TYPE_DFLT,
5118 (struct lys_node *)(&llist->dflt[r])) == -1)) {
5119 goto error;
5120 }
5121 }
5122
5123 /* check XPath dependencies */
5124 if (!(ctx->models.flags & LY_CTX_TRUSTED) && (llist->when || llist->must)) {
5125 if (options & LYS_PARSE_OPT_INGRP) {
5126 if (lyxp_node_check_syntax(retval)) {
5127 goto error;
5128 }
5129 } else {
5130 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
5131 goto error;
5132 }
5133 }
5134 }
5135
5136 for (r = 0; r < retval->ext_size; ++r) {
5137 /* set flag, which represent LYEXT_OPT_VALID */
5138 if (retval->ext[r] && (retval->ext[r]->flags & LYEXT_OPT_VALID)) {
5139 retval->flags |= LYS_VALID_EXT;
5140 break;
5141 }
5142 }
5143
5144 return retval;
5145
5146 error:
5147 lys_node_free(ctx, retval, NULL, 0);
5148 return NULL;
5149 }
5150
5151 /* logs directly */
5152 static struct lys_node *
read_yin_list(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)5153 read_yin_list(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
5154 struct unres_schema *unres)
5155 {
5156 struct ly_ctx *ctx = module->ctx;
5157 struct lys_node *retval, *node;
5158 struct lys_node_list *list;
5159 struct lyxml_elem *sub, *next, root, uniq;
5160 int r;
5161 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0, c_ext = 0;
5162 int f_ordr = 0, f_max = 0, f_min = 0;
5163 const char *value;
5164 char *auxs;
5165 unsigned long val;
5166 void *reallocated;
5167
5168 /* init */
5169 memset(&root, 0, sizeof root);
5170 memset(&uniq, 0, sizeof uniq);
5171
5172 list = calloc(1, sizeof *list);
5173 LY_CHECK_ERR_RETURN(!list, LOGMEM(ctx), NULL);
5174
5175 list->nodetype = LYS_LIST;
5176 list->prev = (struct lys_node *)list;
5177 retval = (struct lys_node *)list;
5178
5179 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
5180 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
5181 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT),
5182 unres)) {
5183 goto error;
5184 }
5185
5186 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
5187
5188 /* insert the node into the schema tree */
5189 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
5190 goto error;
5191 }
5192
5193 /* process list's specific children */
5194 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5195 if (strcmp(sub->ns->value, LY_NSYIN)) {
5196 /* extension */
5197 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "list", error);
5198 c_ext++;
5199 continue;
5200
5201 /* data statements */
5202 } else if (!strcmp(sub->name, "container") ||
5203 !strcmp(sub->name, "leaf-list") ||
5204 !strcmp(sub->name, "leaf") ||
5205 !strcmp(sub->name, "list") ||
5206 !strcmp(sub->name, "choice") ||
5207 !strcmp(sub->name, "uses") ||
5208 !strcmp(sub->name, "grouping") ||
5209 !strcmp(sub->name, "anyxml") ||
5210 !strcmp(sub->name, "anydata") ||
5211 !strcmp(sub->name, "action") ||
5212 !strcmp(sub->name, "notification")) {
5213 lyxml_unlink_elem(ctx, sub, 2);
5214 lyxml_add_child(ctx, &root, sub);
5215
5216 /* array counters */
5217 } else if (!strcmp(sub->name, "key")) {
5218 /* check cardinality 0..1 */
5219 if (list->keys_size) {
5220 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, list->name);
5221 goto error;
5222 }
5223
5224 /* count the number of keys */
5225 GETVAL(ctx, value, sub, "value");
5226 list->keys_str = lydict_insert(ctx, value, 0);
5227 while ((value = strpbrk(value, " \t\n"))) {
5228 list->keys_size++;
5229 while (isspace(*value)) {
5230 value++;
5231 }
5232 }
5233 list->keys_size++;
5234 list->keys = calloc(list->keys_size, sizeof *list->keys);
5235 LY_CHECK_ERR_GOTO(!list->keys, LOGMEM(ctx), error);
5236
5237 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_KEY, 0, unres)) {
5238 goto error;
5239 }
5240 lyxml_free(ctx, sub);
5241 } else if (!strcmp(sub->name, "unique")) {
5242 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_uniq, list->unique_size, "uniques", "list", error);
5243 c_uniq++;
5244 lyxml_unlink_elem(ctx, sub, 2);
5245 lyxml_add_child(ctx, &uniq, sub);
5246 } else if (!strcmp(sub->name, "typedef")) {
5247 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, list->tpdf_size, "typedefs", "list", error);
5248 c_tpdf++;
5249 } else if (!strcmp(sub->name, "must")) {
5250 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, list->must_size, "musts", "list", error);
5251 c_must++;
5252 } else if (!strcmp(sub->name, "if-feature")) {
5253 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "list", error);
5254 c_ftrs++;
5255
5256 /* optional stetments */
5257 } else if (!strcmp(sub->name, "ordered-by")) {
5258 if (f_ordr) {
5259 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5260 goto error;
5261 }
5262 /* just checking the flags in llist is not sufficient, we would
5263 * allow multiple ordered-by statements with the "system" value
5264 */
5265 f_ordr = 1;
5266
5267 if (list->flags & LYS_CONFIG_R) {
5268 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
5269 * state data
5270 */
5271 lyxml_free(ctx, sub);
5272 continue;
5273 }
5274
5275 GETVAL(ctx, value, sub, "value");
5276 if (!strcmp(value, "user")) {
5277 list->flags |= LYS_USERORDERED;
5278 } else if (strcmp(value, "system")) {
5279 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5280 goto error;
5281 } /* else system is the default value, so we can ignore it */
5282
5283 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_ORDEREDBY, 0, unres)) {
5284 goto error;
5285 }
5286 lyxml_free(ctx, sub);
5287 } else if (!strcmp(sub->name, "min-elements")) {
5288 if (f_min) {
5289 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5290 goto error;
5291 }
5292 f_min = 1;
5293
5294 GETVAL(ctx, value, sub, "value");
5295 while (isspace(value[0])) {
5296 value++;
5297 }
5298
5299 /* convert it to uint32_t */
5300 errno = 0;
5301 auxs = NULL;
5302 val = strtoul(value, &auxs, 10);
5303 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
5304 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5305 goto error;
5306 }
5307 list->min = (uint32_t) val;
5308 if (list->max && (list->min > list->max)) {
5309 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5310 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5311 lyxml_free(ctx, sub);
5312 goto error;
5313 }
5314 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MIN, 0, unres)) {
5315 goto error;
5316 }
5317 lyxml_free(ctx, sub);
5318 } else if (!strcmp(sub->name, "max-elements")) {
5319 if (f_max) {
5320 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5321 goto error;
5322 }
5323 f_max = 1;
5324
5325 GETVAL(ctx, value, sub, "value");
5326 while (isspace(value[0])) {
5327 value++;
5328 }
5329
5330 if (!strcmp(value, "unbounded")) {
5331 list->max = 0;;
5332 } else {
5333 /* convert it to uint32_t */
5334 errno = 0;
5335 auxs = NULL;
5336 val = strtoul(value, &auxs, 10);
5337 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
5338 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5339 goto error;
5340 }
5341 list->max = (uint32_t) val;
5342 if (list->min > list->max) {
5343 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, retval, value, sub->name);
5344 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"max-elements\" is smaller than \"min-elements\".");
5345 goto error;
5346 }
5347 }
5348 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_MAX, 0, unres)) {
5349 goto error;
5350 }
5351 lyxml_free(ctx, sub);
5352 } else if (!strcmp(sub->name, "when")) {
5353 if (list->when) {
5354 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5355 goto error;
5356 }
5357
5358 list->when = read_yin_when(module, sub, unres);
5359 if (!list->when) {
5360 lyxml_free(ctx, sub);
5361 goto error;
5362 }
5363 lyxml_free(ctx, sub);
5364 } else {
5365 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
5366 goto error;
5367 }
5368 }
5369
5370 /* check - if list is configuration, key statement is mandatory
5371 * (but only if we are not in a grouping or augment, then the check is deferred) */
5372 for (node = retval; node && !(node->nodetype & (LYS_GROUPING | LYS_AUGMENT | LYS_EXT)); node = node->parent);
5373 if (!node && (list->flags & LYS_CONFIG_W) && !list->keys_str) {
5374 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, retval, "key", "list");
5375 goto error;
5376 }
5377
5378 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5379 if (c_tpdf) {
5380 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
5381 LY_CHECK_ERR_GOTO(!list->tpdf, LOGMEM(ctx), error);
5382 }
5383 if (c_must) {
5384 list->must = calloc(c_must, sizeof *list->must);
5385 LY_CHECK_ERR_GOTO(!list->must, LOGMEM(ctx), error);
5386 }
5387 if (c_ftrs) {
5388 list->iffeature = calloc(c_ftrs, sizeof *list->iffeature);
5389 LY_CHECK_ERR_GOTO(!list->iffeature, LOGMEM(ctx), error);
5390 }
5391 if (c_ext) {
5392 /* some extensions may be already present from the substatements */
5393 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
5394 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
5395 retval->ext = reallocated;
5396
5397 /* init memory */
5398 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
5399 }
5400
5401 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5402 if (strcmp(sub->ns->value, LY_NSYIN)) {
5403 /* extension */
5404 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
5405 if (r) {
5406 goto error;
5407 }
5408 } else if (!strcmp(sub->name, "typedef")) {
5409 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size], unres);
5410 list->tpdf_size++;
5411 if (r) {
5412 goto error;
5413 }
5414 } else if (!strcmp(sub->name, "if-feature")) {
5415 r = fill_yin_iffeature(retval, 0, sub, &list->iffeature[list->iffeature_size], unres);
5416 list->iffeature_size++;
5417 if (r) {
5418 goto error;
5419 }
5420 } else if (!strcmp(sub->name, "must")) {
5421 r = fill_yin_must(module, sub, &list->must[list->must_size], unres);
5422 list->must_size++;
5423 if (r) {
5424 goto error;
5425 }
5426 }
5427 }
5428
5429 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
5430
5431 /* last part - process data nodes */
5432 LY_TREE_FOR_SAFE(root.child, next, sub) {
5433 if (!strcmp(sub->name, "container")) {
5434 node = read_yin_container(module, retval, sub, options, unres);
5435 } else if (!strcmp(sub->name, "leaf-list")) {
5436 node = read_yin_leaflist(module, retval, sub, options, unres);
5437 } else if (!strcmp(sub->name, "leaf")) {
5438 node = read_yin_leaf(module, retval, sub, options, unres);
5439 } else if (!strcmp(sub->name, "list")) {
5440 node = read_yin_list(module, retval, sub, options, unres);
5441 } else if (!strcmp(sub->name, "choice")) {
5442 node = read_yin_choice(module, retval, sub, options, unres);
5443 } else if (!strcmp(sub->name, "uses")) {
5444 node = read_yin_uses(module, retval, sub, options, unres);
5445 } else if (!strcmp(sub->name, "grouping")) {
5446 node = read_yin_grouping(module, retval, sub, options, unres);
5447 } else if (!strcmp(sub->name, "anyxml")) {
5448 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
5449 } else if (!strcmp(sub->name, "anydata")) {
5450 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
5451 } else if (!strcmp(sub->name, "action")) {
5452 node = read_yin_rpc_action(module, retval, sub, options, unres);
5453 } else if (!strcmp(sub->name, "notification")) {
5454 node = read_yin_notif(module, retval, sub, options, unres);
5455 } else {
5456 LOGINT(ctx);
5457 goto error;
5458 }
5459 if (!node) {
5460 goto error;
5461 }
5462
5463 lyxml_free(ctx, sub);
5464 }
5465
5466 if (list->keys_str) {
5467 if (unres_schema_add_node(module, unres, list, UNRES_LIST_KEYS, NULL) == -1) {
5468 goto error;
5469 }
5470 } /* else config false list without a key, key_str presence in case of config true is checked earlier */
5471
5472 /* process unique statements */
5473 if (c_uniq) {
5474 list->unique = calloc(c_uniq, sizeof *list->unique);
5475 LY_CHECK_ERR_GOTO(!list->unique, LOGMEM(ctx), error);
5476
5477 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
5478 r = fill_yin_unique(module, retval, sub, &list->unique[list->unique_size], unres);
5479 list->unique_size++;
5480 if (r) {
5481 goto error;
5482 }
5483
5484 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub,
5485 LYEXT_SUBSTMT_UNIQUE, list->unique_size - 1, unres)) {
5486 goto error;
5487 }
5488 lyxml_free(ctx, sub);
5489 }
5490 }
5491
5492 /* check XPath dependencies */
5493 if (!(ctx->models.flags & LY_CTX_TRUSTED) && (list->when || list->must)) {
5494 if (options & LYS_PARSE_OPT_INGRP) {
5495 if (lyxp_node_check_syntax(retval)) {
5496 goto error;
5497 }
5498 } else {
5499 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
5500 goto error;
5501 }
5502 }
5503 }
5504
5505 for (r = 0; r < retval->ext_size; ++r) {
5506 /* set flag, which represent LYEXT_OPT_VALID */
5507 if (retval->ext[r] && (retval->ext[r]->flags & LYEXT_OPT_VALID)) {
5508 retval->flags |= LYS_VALID_EXT;
5509 if (retval->ext[r]->flags & LYEXT_OPT_VALID_SUBTREE) {
5510 retval->flags |= LYS_VALID_EXT_SUBTREE;
5511 break;
5512 }
5513 }
5514 }
5515
5516 return retval;
5517
5518 error:
5519
5520 lys_node_free(ctx, retval, NULL, 0);
5521 while (root.child) {
5522 lyxml_free(ctx, root.child);
5523 }
5524 while (uniq.child) {
5525 lyxml_free(ctx, uniq.child);
5526 }
5527
5528 return NULL;
5529 }
5530
5531 /* logs directly */
5532 static struct lys_node *
read_yin_container(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)5533 read_yin_container(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
5534 struct unres_schema *unres)
5535 {
5536 struct ly_ctx *ctx = module->ctx;
5537 struct lyxml_elem *sub, *next, root;
5538 struct lys_node *node = NULL;
5539 struct lys_node *retval;
5540 struct lys_node_container *cont;
5541 const char *value;
5542 void *reallocated;
5543 int r;
5544 int c_tpdf = 0, c_must = 0, c_ftrs = 0, c_ext = 0;
5545
5546 /* init */
5547 memset(&root, 0, sizeof root);
5548
5549 cont = calloc(1, sizeof *cont);
5550 LY_CHECK_ERR_RETURN(!cont, LOGMEM(ctx), NULL);
5551
5552 cont->nodetype = LYS_CONTAINER;
5553 cont->prev = (struct lys_node *)cont;
5554 retval = (struct lys_node *)cont;
5555
5556 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin,
5557 OPT_IDENT | OPT_MODULE | ((options & LYS_PARSE_OPT_CFG_IGNORE) ? OPT_CFG_IGNORE :
5558 (options & LYS_PARSE_OPT_CFG_NOINHERIT) ? OPT_CFG_PARSE : OPT_CFG_PARSE | OPT_CFG_INHERIT),
5559 unres)) {
5560 goto error;
5561 }
5562
5563 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
5564
5565 /* insert the node into the schema tree */
5566 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
5567 goto error;
5568 }
5569
5570 /* process container's specific children */
5571 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5572 if (strcmp(sub->ns->value, LY_NSYIN)) {
5573 /* extension */
5574 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "container", error);
5575 c_ext++;
5576 } else if (!strcmp(sub->name, "presence")) {
5577 if (cont->presence) {
5578 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5579 goto error;
5580 }
5581 GETVAL(ctx, value, sub, "value");
5582 cont->presence = lydict_insert(ctx, value, strlen(value));
5583
5584 if (lyp_yin_parse_subnode_ext(module, retval, LYEXT_PAR_NODE, sub, LYEXT_SUBSTMT_PRESENCE, 0, unres)) {
5585 goto error;
5586 }
5587 lyxml_free(ctx, sub);
5588 } else if (!strcmp(sub->name, "when")) {
5589 if (cont->when) {
5590 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
5591 goto error;
5592 }
5593
5594 cont->when = read_yin_when(module, sub, unres);
5595 if (!cont->when) {
5596 lyxml_free(ctx, sub);
5597 goto error;
5598 }
5599 lyxml_free(ctx, sub);
5600
5601 /* data statements */
5602 } else if (!strcmp(sub->name, "container") ||
5603 !strcmp(sub->name, "leaf-list") ||
5604 !strcmp(sub->name, "leaf") ||
5605 !strcmp(sub->name, "list") ||
5606 !strcmp(sub->name, "choice") ||
5607 !strcmp(sub->name, "uses") ||
5608 !strcmp(sub->name, "grouping") ||
5609 !strcmp(sub->name, "anyxml") ||
5610 !strcmp(sub->name, "anydata") ||
5611 !strcmp(sub->name, "action") ||
5612 !strcmp(sub->name, "notification")) {
5613 lyxml_unlink_elem(ctx, sub, 2);
5614 lyxml_add_child(ctx, &root, sub);
5615
5616 /* array counters */
5617 } else if (!strcmp(sub->name, "typedef")) {
5618 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, cont->tpdf_size, "typedefs", "container", error);
5619 c_tpdf++;
5620 } else if (!strcmp(sub->name, "must")) {
5621 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, cont->must_size, "musts", "container", error);
5622 c_must++;
5623 } else if (!strcmp(sub->name, "if-feature")) {
5624 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "container", error);
5625 c_ftrs++;
5626 } else {
5627 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
5628 goto error;
5629 }
5630 }
5631
5632 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5633 if (c_tpdf) {
5634 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
5635 LY_CHECK_ERR_GOTO(!cont->tpdf, LOGMEM(ctx), error);
5636 }
5637 if (c_must) {
5638 cont->must = calloc(c_must, sizeof *cont->must);
5639 LY_CHECK_ERR_GOTO(!cont->must, LOGMEM(ctx), error);
5640 }
5641 if (c_ftrs) {
5642 cont->iffeature = calloc(c_ftrs, sizeof *cont->iffeature);
5643 LY_CHECK_ERR_GOTO(!cont->iffeature, LOGMEM(ctx), error);
5644 }
5645 if (c_ext) {
5646 /* some extensions may be already present from the substatements */
5647 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
5648 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
5649 retval->ext = reallocated;
5650
5651 /* init memory */
5652 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
5653 }
5654
5655 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5656 if (strcmp(sub->ns->value, LY_NSYIN)) {
5657 /* extension */
5658 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
5659 if (r) {
5660 goto error;
5661 }
5662 } else if (!strcmp(sub->name, "typedef")) {
5663 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size], unres);
5664 cont->tpdf_size++;
5665 if (r) {
5666 goto error;
5667 }
5668 } else if (!strcmp(sub->name, "must")) {
5669 r = fill_yin_must(module, sub, &cont->must[cont->must_size], unres);
5670 cont->must_size++;
5671 if (r) {
5672 goto error;
5673 }
5674 } else if (!strcmp(sub->name, "if-feature")) {
5675 r = fill_yin_iffeature(retval, 0, sub, &cont->iffeature[cont->iffeature_size], unres);
5676 cont->iffeature_size++;
5677 if (r) {
5678 goto error;
5679 }
5680 }
5681 }
5682
5683 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
5684
5685 /* last part - process data nodes */
5686 LY_TREE_FOR_SAFE(root.child, next, sub) {
5687 if (!strcmp(sub->name, "container")) {
5688 node = read_yin_container(module, retval, sub, options, unres);
5689 } else if (!strcmp(sub->name, "leaf-list")) {
5690 node = read_yin_leaflist(module, retval, sub, options, unres);
5691 } else if (!strcmp(sub->name, "leaf")) {
5692 node = read_yin_leaf(module, retval, sub, options, unres);
5693 } else if (!strcmp(sub->name, "list")) {
5694 node = read_yin_list(module, retval, sub, options, unres);
5695 } else if (!strcmp(sub->name, "choice")) {
5696 node = read_yin_choice(module, retval, sub, options, unres);
5697 } else if (!strcmp(sub->name, "uses")) {
5698 node = read_yin_uses(module, retval, sub, options, unres);
5699 } else if (!strcmp(sub->name, "grouping")) {
5700 node = read_yin_grouping(module, retval, sub, options, unres);
5701 } else if (!strcmp(sub->name, "anyxml")) {
5702 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
5703 } else if (!strcmp(sub->name, "anydata")) {
5704 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
5705 } else if (!strcmp(sub->name, "action")) {
5706 node = read_yin_rpc_action(module, retval, sub, options, unres);
5707 } else if (!strcmp(sub->name, "notification")) {
5708 node = read_yin_notif(module, retval, sub, options, unres);
5709 }
5710 if (!node) {
5711 goto error;
5712 }
5713
5714 lyxml_free(ctx, sub);
5715 }
5716
5717 /* check XPath dependencies */
5718 if (!(ctx->models.flags & LY_CTX_TRUSTED) && (cont->when || cont->must)) {
5719 if (options & LYS_PARSE_OPT_INGRP) {
5720 if (lyxp_node_check_syntax(retval)) {
5721 goto error;
5722 }
5723 } else {
5724 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
5725 goto error;
5726 }
5727 }
5728 }
5729
5730 for (r = 0; r < retval->ext_size; ++r) {
5731 /* extension instance may not yet be resolved */
5732 if (retval->ext[r] && (retval->ext[r]->flags & LYEXT_OPT_VALID)) {
5733 /* set flag, which represent LYEXT_OPT_VALID */
5734 retval->flags |= LYS_VALID_EXT;
5735 if (retval->ext[r]->flags & LYEXT_OPT_VALID_SUBTREE) {
5736 retval->flags |= LYS_VALID_EXT_SUBTREE;
5737 break;
5738 }
5739 }
5740 }
5741
5742 return retval;
5743
5744 error:
5745 lys_node_free(ctx, retval, NULL, 0);
5746 while (root.child) {
5747 lyxml_free(ctx, root.child);
5748 }
5749 return NULL;
5750 }
5751
5752 /* logs directly */
5753 static struct lys_node *
read_yin_grouping(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)5754 read_yin_grouping(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
5755 struct unres_schema *unres)
5756 {
5757 struct ly_ctx *ctx = module->ctx;
5758 struct lyxml_elem *sub, *next, root;
5759 struct lys_node *node = NULL;
5760 struct lys_node *retval;
5761 struct lys_node_grp *grp;
5762 int r;
5763 int c_tpdf = 0, c_ext = 0;
5764 void *reallocated;
5765
5766 /* init */
5767 memset(&root, 0, sizeof root);
5768
5769 grp = calloc(1, sizeof *grp);
5770 LY_CHECK_ERR_RETURN(!grp, LOGMEM(ctx), NULL);
5771
5772 grp->nodetype = LYS_GROUPING;
5773 grp->prev = (struct lys_node *)grp;
5774 retval = (struct lys_node *)grp;
5775
5776 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin, OPT_IDENT | OPT_MODULE , unres)) {
5777 goto error;
5778 }
5779
5780 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
5781
5782 /* insert the node into the schema tree */
5783 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
5784 goto error;
5785 }
5786
5787 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5788 if (strcmp(sub->ns->value, LY_NSYIN)) {
5789 /* extension */
5790 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "grouping", error);
5791 c_ext++;
5792
5793 /* data statements */
5794 } else if (!strcmp(sub->name, "container") ||
5795 !strcmp(sub->name, "leaf-list") ||
5796 !strcmp(sub->name, "leaf") ||
5797 !strcmp(sub->name, "list") ||
5798 !strcmp(sub->name, "choice") ||
5799 !strcmp(sub->name, "uses") ||
5800 !strcmp(sub->name, "grouping") ||
5801 !strcmp(sub->name, "anyxml") ||
5802 !strcmp(sub->name, "anydata") ||
5803 !strcmp(sub->name, "action") ||
5804 !strcmp(sub->name, "notification")) {
5805 lyxml_unlink_elem(ctx, sub, 2);
5806 lyxml_add_child(ctx, &root, sub);
5807
5808 /* array counters */
5809 } else if (!strcmp(sub->name, "typedef")) {
5810 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, grp->tpdf_size, "typedefs", "grouping", error);
5811 c_tpdf++;
5812 } else {
5813 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
5814 goto error;
5815 }
5816 }
5817
5818 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5819 if (c_tpdf) {
5820 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
5821 LY_CHECK_ERR_GOTO(!grp->tpdf, LOGMEM(ctx), error);
5822 }
5823 if (c_ext) {
5824 /* some extensions may be already present from the substatements */
5825 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
5826 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
5827 retval->ext = reallocated;
5828
5829 /* init memory */
5830 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
5831 }
5832 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5833 if (strcmp(sub->ns->value, LY_NSYIN)) {
5834 /* extension */
5835 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
5836 if (r) {
5837 goto error;
5838 }
5839 } else {
5840 /* typedef */
5841 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size], unres);
5842 grp->tpdf_size++;
5843 if (r) {
5844 goto error;
5845 }
5846 }
5847 }
5848
5849 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
5850
5851 /* last part - process data nodes */
5852 if (!root.child) {
5853 LOGWRN(ctx, "Grouping \"%s\" without children.", retval->name);
5854 }
5855 options |= LYS_PARSE_OPT_INGRP;
5856 LY_TREE_FOR_SAFE(root.child, next, sub) {
5857 if (!strcmp(sub->name, "container")) {
5858 node = read_yin_container(module, retval, sub, options, unres);
5859 } else if (!strcmp(sub->name, "leaf-list")) {
5860 node = read_yin_leaflist(module, retval, sub, options, unres);
5861 } else if (!strcmp(sub->name, "leaf")) {
5862 node = read_yin_leaf(module, retval, sub, options, unres);
5863 } else if (!strcmp(sub->name, "list")) {
5864 node = read_yin_list(module, retval, sub, options, unres);
5865 } else if (!strcmp(sub->name, "choice")) {
5866 node = read_yin_choice(module, retval, sub, options, unres);
5867 } else if (!strcmp(sub->name, "uses")) {
5868 node = read_yin_uses(module, retval, sub, options, unres);
5869 } else if (!strcmp(sub->name, "grouping")) {
5870 node = read_yin_grouping(module, retval, sub, options, unres);
5871 } else if (!strcmp(sub->name, "anyxml")) {
5872 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
5873 } else if (!strcmp(sub->name, "anydata")) {
5874 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
5875 } else if (!strcmp(sub->name, "action")) {
5876 node = read_yin_rpc_action(module, retval, sub, options, unres);
5877 } else if (!strcmp(sub->name, "notification")) {
5878 node = read_yin_notif(module, retval, sub, options, unres);
5879 }
5880 if (!node) {
5881 goto error;
5882 }
5883
5884 lyxml_free(ctx, sub);
5885 }
5886
5887 return retval;
5888
5889 error:
5890 lys_node_free(ctx, retval, NULL, 0);
5891 while (root.child) {
5892 lyxml_free(ctx, root.child);
5893 }
5894 return NULL;
5895 }
5896
5897 /* logs directly */
5898 static struct lys_node *
read_yin_input_output(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)5899 read_yin_input_output(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
5900 int options, struct unres_schema *unres)
5901 {
5902 struct ly_ctx *ctx = module->ctx;
5903 struct lyxml_elem *sub, *next, root;
5904 struct lys_node *node = NULL;
5905 struct lys_node *retval = NULL;
5906 struct lys_node_inout *inout;
5907 int r;
5908 int c_tpdf = 0, c_must = 0, c_ext = 0;
5909
5910 /* init */
5911 memset(&root, 0, sizeof root);
5912
5913 inout = calloc(1, sizeof *inout);
5914 LY_CHECK_ERR_RETURN(!inout, LOGMEM(ctx), NULL);
5915 inout->prev = (struct lys_node *)inout;
5916
5917 if (!strcmp(yin->name, "input")) {
5918 inout->nodetype = LYS_INPUT;
5919 inout->name = lydict_insert(ctx, "input", 0);
5920 } else if (!strcmp(yin->name, "output")) {
5921 inout->nodetype = LYS_OUTPUT;
5922 inout->name = lydict_insert(ctx, "output", 0);
5923 } else {
5924 LOGINT(ctx);
5925 free(inout);
5926 goto error;
5927 }
5928
5929 retval = (struct lys_node *)inout;
5930 retval->module = module;
5931
5932 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
5933
5934 /* insert the node into the schema tree */
5935 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
5936 goto error;
5937 }
5938
5939 /* data statements */
5940 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5941 if (!sub->ns) {
5942 /* garbage */
5943 lyxml_free(ctx, sub);
5944 } else if (strcmp(sub->ns->value, LY_NSYIN)) {
5945 /* extension */
5946 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions",
5947 inout->nodetype == LYS_INPUT ? "input" : "output", error);
5948 c_ext++;
5949 } else if (!strcmp(sub->name, "container") ||
5950 !strcmp(sub->name, "leaf-list") ||
5951 !strcmp(sub->name, "leaf") ||
5952 !strcmp(sub->name, "list") ||
5953 !strcmp(sub->name, "choice") ||
5954 !strcmp(sub->name, "uses") ||
5955 !strcmp(sub->name, "grouping") ||
5956 !strcmp(sub->name, "anyxml") ||
5957 !strcmp(sub->name, "anydata")) {
5958 lyxml_unlink_elem(ctx, sub, 2);
5959 lyxml_add_child(ctx, &root, sub);
5960
5961 /* array counters */
5962 } else if (!strcmp(sub->name, "typedef")) {
5963 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, inout->tpdf_size, "typedefs",
5964 inout->nodetype == LYS_INPUT ? "input" : "output", error);
5965 c_tpdf++;
5966
5967 } else if ((module->version >= 2) && !strcmp(sub->name, "must")) {
5968 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, inout->must_size, "musts",
5969 inout->nodetype == LYS_INPUT ? "input" : "output", error);
5970 c_must++;
5971
5972 } else {
5973 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
5974 goto error;
5975 }
5976 }
5977
5978 if (!root.child) {
5979 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, retval, "schema-node", strnodetype(retval->nodetype));
5980 goto error;
5981 }
5982
5983 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5984 if (c_tpdf) {
5985 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
5986 LY_CHECK_ERR_GOTO(!inout->tpdf, LOGMEM(ctx), error);
5987 }
5988 if (c_must) {
5989 inout->must = calloc(c_must, sizeof *inout->must);
5990 LY_CHECK_ERR_GOTO(!inout->must, LOGMEM(ctx), error);
5991 }
5992 if (c_ext) {
5993 inout->ext = calloc(c_ext, sizeof *inout->ext);
5994 LY_CHECK_ERR_GOTO(!inout->ext, LOGMEM(ctx), error);
5995 }
5996
5997 LY_TREE_FOR_SAFE(yin->child, next, sub) {
5998 if (strcmp(sub->ns->value, LY_NSYIN)) {
5999 /* extension */
6000 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
6001 if (r) {
6002 goto error;
6003 }
6004 } else if (!strcmp(sub->name, "must")) {
6005 r = fill_yin_must(module, sub, &inout->must[inout->must_size], unres);
6006 inout->must_size++;
6007 if (r) {
6008 goto error;
6009 }
6010 } else { /* typedef */
6011 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size], unres);
6012 inout->tpdf_size++;
6013 if (r) {
6014 goto error;
6015 }
6016 }
6017 }
6018
6019 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
6020
6021 /* last part - process data nodes */
6022 options |= LYS_PARSE_OPT_CFG_IGNORE;
6023 LY_TREE_FOR_SAFE(root.child, next, sub) {
6024 if (!strcmp(sub->name, "container")) {
6025 node = read_yin_container(module, retval, sub, options, unres);
6026 } else if (!strcmp(sub->name, "leaf-list")) {
6027 node = read_yin_leaflist(module, retval, sub, options, unres);
6028 } else if (!strcmp(sub->name, "leaf")) {
6029 node = read_yin_leaf(module, retval, sub, options, unres);
6030 } else if (!strcmp(sub->name, "list")) {
6031 node = read_yin_list(module, retval, sub, options, unres);
6032 } else if (!strcmp(sub->name, "choice")) {
6033 node = read_yin_choice(module, retval, sub, options, unres);
6034 } else if (!strcmp(sub->name, "uses")) {
6035 node = read_yin_uses(module, retval, sub, options, unres);
6036 } else if (!strcmp(sub->name, "grouping")) {
6037 node = read_yin_grouping(module, retval, sub, options, unres);
6038 } else if (!strcmp(sub->name, "anyxml")) {
6039 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
6040 } else if (!strcmp(sub->name, "anydata")) {
6041 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
6042 }
6043 if (!node) {
6044 goto error;
6045 }
6046
6047 lyxml_free(ctx, sub);
6048 }
6049
6050 /* check XPath dependencies */
6051 if (!(ctx->models.flags & LY_CTX_TRUSTED) && inout->must) {
6052 if (options & LYS_PARSE_OPT_INGRP) {
6053 if (lyxp_node_check_syntax(retval)) {
6054 goto error;
6055 }
6056 } else {
6057 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
6058 goto error;
6059 }
6060 }
6061 }
6062
6063 return retval;
6064
6065 error:
6066 lys_node_free(ctx, retval, NULL, 0);
6067 while (root.child) {
6068 lyxml_free(ctx, root.child);
6069 }
6070 return NULL;
6071 }
6072
6073 /* logs directly */
6074 static struct lys_node *
read_yin_notif(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)6075 read_yin_notif(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
6076 int options, struct unres_schema *unres)
6077 {
6078 struct ly_ctx *ctx = module->ctx;
6079 struct lyxml_elem *sub, *next, root;
6080 struct lys_node *node = NULL;
6081 struct lys_node *retval;
6082 struct lys_node_notif *notif;
6083 int r;
6084 int c_tpdf = 0, c_ftrs = 0, c_must = 0, c_ext = 0;
6085 void *reallocated;
6086
6087 if (parent && (module->version < 2)) {
6088 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, parent, "notification");
6089 return NULL;
6090 }
6091
6092 memset(&root, 0, sizeof root);
6093
6094 notif = calloc(1, sizeof *notif);
6095 LY_CHECK_ERR_RETURN(!notif, LOGMEM(ctx), NULL);
6096
6097 notif->nodetype = LYS_NOTIF;
6098 notif->prev = (struct lys_node *)notif;
6099 retval = (struct lys_node *)notif;
6100
6101 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin, OPT_IDENT | OPT_MODULE, unres)) {
6102 goto error;
6103 }
6104
6105 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
6106
6107 /* insert the node into the schema tree */
6108 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
6109 goto error;
6110 }
6111
6112 /* process rpc's specific children */
6113 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6114 if (strcmp(sub->ns->value, LY_NSYIN)) {
6115 /* extension */
6116 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "notification", error);
6117 c_ext++;
6118 continue;
6119
6120 /* data statements */
6121 } else if (!strcmp(sub->name, "container") ||
6122 !strcmp(sub->name, "leaf-list") ||
6123 !strcmp(sub->name, "leaf") ||
6124 !strcmp(sub->name, "list") ||
6125 !strcmp(sub->name, "choice") ||
6126 !strcmp(sub->name, "uses") ||
6127 !strcmp(sub->name, "grouping") ||
6128 !strcmp(sub->name, "anyxml") ||
6129 !strcmp(sub->name, "anydata")) {
6130 lyxml_unlink_elem(ctx, sub, 2);
6131 lyxml_add_child(ctx, &root, sub);
6132
6133 /* array counters */
6134 } else if (!strcmp(sub->name, "typedef")) {
6135 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, notif->tpdf_size, "typedefs", "notification", error);
6136 c_tpdf++;
6137 } else if (!strcmp(sub->name, "if-feature")) {
6138 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "notification", error);
6139 c_ftrs++;
6140 } else if ((module->version >= 2) && !strcmp(sub->name, "must")) {
6141 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, notif->must_size, "musts", "notification", error);
6142 c_must++;
6143 } else {
6144 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
6145 goto error;
6146 }
6147 }
6148
6149 /* middle part - process nodes with cardinality of 0..n except the data nodes */
6150 if (c_tpdf) {
6151 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
6152 LY_CHECK_ERR_GOTO(!notif->tpdf, LOGMEM(ctx), error);
6153 }
6154 if (c_ftrs) {
6155 notif->iffeature = calloc(c_ftrs, sizeof *notif->iffeature);
6156 LY_CHECK_ERR_GOTO(!notif->iffeature, LOGMEM(ctx), error);
6157 }
6158 if (c_must) {
6159 notif->must = calloc(c_must, sizeof *notif->must);
6160 LY_CHECK_ERR_GOTO(!notif->must, LOGMEM(ctx), error);
6161 }
6162 if (c_ext) {
6163 /* some extensions may be already present from the substatements */
6164 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
6165 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
6166 retval->ext = reallocated;
6167
6168 /* init memory */
6169 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
6170 }
6171
6172 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6173 if (strcmp(sub->ns->value, LY_NSYIN)) {
6174 /* extension */
6175 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
6176 if (r) {
6177 goto error;
6178 }
6179 } else if (!strcmp(sub->name, "typedef")) {
6180 r = fill_yin_typedef(module, retval, sub, ¬if->tpdf[notif->tpdf_size], unres);
6181 notif->tpdf_size++;
6182 if (r) {
6183 goto error;
6184 }
6185 } else if (!strcmp(sub->name, "if-feature")) {
6186 r = fill_yin_iffeature(retval, 0, sub, ¬if->iffeature[notif->iffeature_size], unres);
6187 notif->iffeature_size++;
6188 if (r) {
6189 goto error;
6190 }
6191 } else if (!strcmp(sub->name, "must")) {
6192 r = fill_yin_must(module, sub, ¬if->must[notif->must_size], unres);
6193 notif->must_size++;
6194 if (r) {
6195 goto error;
6196 }
6197 }
6198 }
6199
6200 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
6201
6202 /* last part - process data nodes */
6203 options |= LYS_PARSE_OPT_CFG_IGNORE;
6204 LY_TREE_FOR_SAFE(root.child, next, sub) {
6205 if (!strcmp(sub->name, "container")) {
6206 node = read_yin_container(module, retval, sub, options, unres);
6207 } else if (!strcmp(sub->name, "leaf-list")) {
6208 node = read_yin_leaflist(module, retval, sub, options, unres);
6209 } else if (!strcmp(sub->name, "leaf")) {
6210 node = read_yin_leaf(module, retval, sub, options, unres);
6211 } else if (!strcmp(sub->name, "list")) {
6212 node = read_yin_list(module, retval, sub, options, unres);
6213 } else if (!strcmp(sub->name, "choice")) {
6214 node = read_yin_choice(module, retval, sub, options, unres);
6215 } else if (!strcmp(sub->name, "uses")) {
6216 node = read_yin_uses(module, retval, sub, options, unres);
6217 } else if (!strcmp(sub->name, "grouping")) {
6218 node = read_yin_grouping(module, retval, sub, options, unres);
6219 } else if (!strcmp(sub->name, "anyxml")) {
6220 node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
6221 } else if (!strcmp(sub->name, "anydata")) {
6222 node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
6223 }
6224 if (!node) {
6225 goto error;
6226 }
6227
6228 lyxml_free(ctx, sub);
6229 }
6230
6231 /* check XPath dependencies */
6232 if (!(ctx->models.flags & LY_CTX_TRUSTED) && notif->must) {
6233 if (options & LYS_PARSE_OPT_INGRP) {
6234 if (lyxp_node_check_syntax(retval)) {
6235 goto error;
6236 }
6237 } else {
6238 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
6239 goto error;
6240 }
6241 }
6242 }
6243
6244 return retval;
6245
6246 error:
6247 lys_node_free(ctx, retval, NULL, 0);
6248 while (root.child) {
6249 lyxml_free(ctx, root.child);
6250 }
6251 return NULL;
6252 }
6253
6254 /* logs directly */
6255 static struct lys_node *
read_yin_rpc_action(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)6256 read_yin_rpc_action(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
6257 int options, struct unres_schema *unres)
6258 {
6259 struct ly_ctx *ctx = module->ctx;
6260 struct lyxml_elem *sub, *next, root;
6261 struct lys_node *node = NULL;
6262 struct lys_node *retval;
6263 struct lys_node_rpc_action *rpc;
6264 int r;
6265 int c_tpdf = 0, c_ftrs = 0, c_input = 0, c_output = 0, c_ext = 0;
6266 void *reallocated;
6267
6268 if (!strcmp(yin->name, "action") && (module->version < 2)) {
6269 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, parent, "action");
6270 return NULL;
6271 }
6272
6273 /* init */
6274 memset(&root, 0, sizeof root);
6275
6276 rpc = calloc(1, sizeof *rpc);
6277 LY_CHECK_ERR_RETURN(!rpc, LOGMEM(ctx), NULL);
6278
6279 rpc->nodetype = (!strcmp(yin->name, "rpc") ? LYS_RPC : LYS_ACTION);
6280 rpc->prev = (struct lys_node *)rpc;
6281 retval = (struct lys_node *)rpc;
6282
6283 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin, OPT_IDENT | OPT_MODULE, unres)) {
6284 goto error;
6285 }
6286
6287 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
6288
6289 /* insert the node into the schema tree */
6290 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
6291 goto error;
6292 }
6293
6294 /* process rpc's specific children */
6295 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6296 if (strcmp(sub->ns->value, LY_NSYIN)) {
6297 /* extension */
6298 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions",
6299 rpc->nodetype == LYS_RPC ? "rpc" : "action", error);
6300 c_ext++;
6301 continue;
6302 } else if (!strcmp(sub->name, "input")) {
6303 if (c_input) {
6304 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
6305 goto error;
6306 }
6307 c_input++;
6308 lyxml_unlink_elem(ctx, sub, 2);
6309 lyxml_add_child(ctx, &root, sub);
6310 } else if (!strcmp(sub->name, "output")) {
6311 if (c_output) {
6312 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
6313 goto error;
6314 }
6315 c_output++;
6316 lyxml_unlink_elem(ctx, sub, 2);
6317 lyxml_add_child(ctx, &root, sub);
6318
6319 /* data statements */
6320 } else if (!strcmp(sub->name, "grouping")) {
6321 lyxml_unlink_elem(ctx, sub, 2);
6322 lyxml_add_child(ctx, &root, sub);
6323
6324 /* array counters */
6325 } else if (!strcmp(sub->name, "typedef")) {
6326 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, rpc->tpdf_size, "typedefs",
6327 rpc->nodetype == LYS_RPC ? "rpc" : "action", error);
6328 c_tpdf++;
6329 } else if (!strcmp(sub->name, "if-feature")) {
6330 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features",
6331 rpc->nodetype == LYS_RPC ? "rpc" : "action", error);
6332 c_ftrs++;
6333 } else {
6334 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
6335 goto error;
6336 }
6337 }
6338
6339 /* middle part - process nodes with cardinality of 0..n except the data nodes */
6340 if (c_tpdf) {
6341 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
6342 LY_CHECK_ERR_GOTO(!rpc->tpdf, LOGMEM(ctx), error);
6343 }
6344 if (c_ftrs) {
6345 rpc->iffeature = calloc(c_ftrs, sizeof *rpc->iffeature);
6346 LY_CHECK_ERR_GOTO(!rpc->iffeature, LOGMEM(ctx), error);
6347 }
6348 if (c_ext) {
6349 /* some extensions may be already present from the substatements */
6350 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
6351 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
6352 retval->ext = reallocated;
6353
6354 /* init memory */
6355 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
6356 }
6357
6358 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6359 if (strcmp(sub->ns->value, LY_NSYIN)) {
6360 /* extension */
6361 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
6362 if (r) {
6363 goto error;
6364 }
6365 } else if (!strcmp(sub->name, "typedef")) {
6366 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size], unres);
6367 rpc->tpdf_size++;
6368 if (r) {
6369 goto error;
6370 }
6371 } else if (!strcmp(sub->name, "if-feature")) {
6372 r = fill_yin_iffeature(retval, 0, sub, &rpc->iffeature[rpc->iffeature_size], unres);
6373 rpc->iffeature_size++;
6374 if (r) {
6375 goto error;
6376 }
6377 }
6378 }
6379
6380 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
6381
6382 /* last part - process data nodes */
6383 LY_TREE_FOR_SAFE(root.child, next, sub) {
6384 if (!strcmp(sub->name, "grouping")) {
6385 node = read_yin_grouping(module, retval, sub, options, unres);
6386 } else if (!strcmp(sub->name, "input") || !strcmp(sub->name, "output")) {
6387 node = read_yin_input_output(module, retval, sub, options, unres);
6388 }
6389 if (!node) {
6390 goto error;
6391 }
6392
6393 lyxml_free(ctx, sub);
6394 }
6395
6396 return retval;
6397
6398 error:
6399 lys_node_free(ctx, retval, NULL, 0);
6400 while (root.child) {
6401 lyxml_free(ctx, root.child);
6402 }
6403 return NULL;
6404 }
6405
6406 /* logs directly
6407 *
6408 * resolve - referenced grouping should be bounded to the namespace (resolved)
6409 * only when uses does not appear in grouping. In a case of grouping's uses,
6410 * we just get information but we do not apply augment or refine to it.
6411 */
6412 static struct lys_node *
read_yin_uses(struct lys_module * module,struct lys_node * parent,struct lyxml_elem * yin,int options,struct unres_schema * unres)6413 read_yin_uses(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin,
6414 int options, struct unres_schema *unres)
6415 {
6416 struct ly_ctx *ctx = module->ctx;
6417 struct lyxml_elem *sub, *next;
6418 struct lys_node *retval;
6419 struct lys_node_uses *uses;
6420 const char *value;
6421 int c_ref = 0, c_aug = 0, c_ftrs = 0, c_ext = 0;
6422 int r;
6423 void *reallocated;
6424
6425 uses = calloc(1, sizeof *uses);
6426 LY_CHECK_ERR_RETURN(!uses, LOGMEM(ctx), NULL);
6427
6428 uses->nodetype = LYS_USES;
6429 uses->prev = (struct lys_node *)uses;
6430 retval = (struct lys_node *)uses;
6431
6432 GETVAL(ctx, value, yin, "name");
6433 uses->name = lydict_insert(ctx, value, 0);
6434
6435 if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin, OPT_MODULE, unres)) {
6436 goto error;
6437 }
6438
6439 LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);
6440
6441 /* insert the node into the schema tree */
6442 if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
6443 goto error;
6444 }
6445
6446 /* get other properties of uses */
6447 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6448 if (strcmp(sub->ns->value, LY_NSYIN)) {
6449 /* extension */
6450 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "uses", error);
6451 c_ext++;
6452 continue;
6453 } else if (!strcmp(sub->name, "refine")) {
6454 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ref, uses->refine_size, "refines", "uses", error);
6455 c_ref++;
6456 } else if (!strcmp(sub->name, "augment")) {
6457 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_aug, uses->augment_size, "augments", "uses", error);
6458 c_aug++;
6459 } else if (!strcmp(sub->name, "if-feature")) {
6460 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, retval->iffeature_size, "if-features", "uses", error);
6461 c_ftrs++;
6462 } else if (!strcmp(sub->name, "when")) {
6463 if (uses->when) {
6464 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYS, retval, sub->name, yin->name);
6465 goto error;
6466 }
6467
6468 uses->when = read_yin_when(module, sub, unres);
6469 if (!uses->when) {
6470 lyxml_free(ctx, sub);
6471 goto error;
6472 }
6473 lyxml_free(ctx, sub);
6474 } else {
6475 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
6476 goto error;
6477 }
6478 }
6479
6480 /* process properties with cardinality 0..n */
6481 if (c_ref) {
6482 uses->refine = calloc(c_ref, sizeof *uses->refine);
6483 LY_CHECK_ERR_GOTO(!uses->refine, LOGMEM(ctx), error);
6484 }
6485 if (c_aug) {
6486 uses->augment = calloc(c_aug, sizeof *uses->augment);
6487 LY_CHECK_ERR_GOTO(!uses->augment, LOGMEM(ctx), error);
6488 }
6489 if (c_ftrs) {
6490 uses->iffeature = calloc(c_ftrs, sizeof *uses->iffeature);
6491 LY_CHECK_ERR_GOTO(!uses->iffeature, LOGMEM(ctx), error);
6492 }
6493 if (c_ext) {
6494 /* some extensions may be already present from the substatements */
6495 reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
6496 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
6497 retval->ext = reallocated;
6498
6499 /* init memory */
6500 memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
6501 }
6502
6503 LY_TREE_FOR_SAFE(yin->child, next, sub) {
6504 if (strcmp(sub->ns->value, LY_NSYIN)) {
6505 /* extension */
6506 r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
6507 if (r) {
6508 goto error;
6509 }
6510 } else if (!strcmp(sub->name, "refine")) {
6511 r = fill_yin_refine(retval, sub, &uses->refine[uses->refine_size], unres);
6512 uses->refine_size++;
6513 if (r) {
6514 goto error;
6515 }
6516 } else if (!strcmp(sub->name, "augment")) {
6517 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size], options, unres);
6518 uses->augment_size++;
6519 if (r) {
6520 goto error;
6521 }
6522 } else if (!strcmp(sub->name, "if-feature")) {
6523 r = fill_yin_iffeature(retval, 0, sub, &uses->iffeature[uses->iffeature_size], unres);
6524 uses->iffeature_size++;
6525 if (r) {
6526 goto error;
6527 }
6528 }
6529 }
6530
6531 lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);
6532
6533 if (unres_schema_add_node(module, unres, uses, UNRES_USES, NULL) == -1) {
6534 goto error;
6535 }
6536
6537 /* check XPath dependencies */
6538 if (!(ctx->models.flags & LY_CTX_TRUSTED) && uses->when) {
6539 if (options & LYS_PARSE_OPT_INGRP) {
6540 if (lyxp_node_check_syntax(retval)) {
6541 goto error;
6542 }
6543 } else {
6544 if (unres_schema_add_node(module, unres, retval, UNRES_XPATH, NULL) == -1) {
6545 goto error;
6546 }
6547 }
6548 }
6549
6550 return retval;
6551
6552 error:
6553 lys_node_free(ctx, retval, NULL, 0);
6554 return NULL;
6555 }
6556
6557 /* logs directly
6558 *
6559 * common code for yin_read_module() and yin_read_submodule()
6560 */
6561 static int
read_sub_module(struct lys_module * module,struct lys_submodule * submodule,struct lyxml_elem * yin,struct unres_schema * unres)6562 read_sub_module(struct lys_module *module, struct lys_submodule *submodule, struct lyxml_elem *yin,
6563 struct unres_schema *unres)
6564 {
6565 struct ly_ctx *ctx = module->ctx;
6566 struct lyxml_elem *next, *child, root, grps, augs, revs, exts;
6567 struct lys_node *node = NULL;
6568 struct lys_module *trg;
6569 const char *value;
6570 int i, r, ret = -1;
6571 int version_flag = 0;
6572 /* (sub)module substatements are ordered in groups, increment this value when moving to another group
6573 * 0 - header-stmts, 1 - linkage-stmts, 2 - meta-stmts, 3 - revision-stmts, 4 - body-stmts */
6574 int substmt_group;
6575 /* just remember last substatement for logging */
6576 const char *substmt_prev;
6577 /* counters */
6578 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0, c_dev = 0;
6579 int c_ext = 0, c_extinst = 0;
6580 void *reallocated;
6581
6582 /* to simplify code, store the module/submodule being processed as trg */
6583 trg = submodule ? (struct lys_module *)submodule : module;
6584
6585 /* init */
6586 memset(&root, 0, sizeof root);
6587 memset(&grps, 0, sizeof grps);
6588 memset(&augs, 0, sizeof augs);
6589 memset(&exts, 0, sizeof exts);
6590 memset(&revs, 0, sizeof revs);
6591
6592 /*
6593 * in the first run, we process elements with cardinality of 1 or 0..1 and
6594 * count elements with cardinality 0..n. Data elements (choices, containers,
6595 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
6596 * need have all top-level and groupings already prepared at that time. In
6597 * the middle loop, we process other elements with carinality of 0..n since
6598 * we need to allocate arrays to store them.
6599 */
6600 substmt_group = 0;
6601 substmt_prev = NULL;
6602 LY_TREE_FOR_SAFE(yin->child, next, child) {
6603 if (!child->ns) {
6604 /* garbage */
6605 lyxml_free(ctx, child);
6606 continue;
6607 } else if (strcmp(child->ns->value, LY_NSYIN)) {
6608 /* possible extension instance */
6609 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_extinst, trg->ext_size, "extension instances",
6610 submodule ? "submodule" : "module", error);
6611 lyxml_unlink_elem(ctx, child, 2);
6612 lyxml_add_child(ctx, &exts, child);
6613 c_extinst++;
6614 } else if (!submodule && !strcmp(child->name, "namespace")) {
6615 if (substmt_group > 0) {
6616 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6617 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6618 child->name, substmt_prev);
6619 goto error;
6620 }
6621
6622 if (trg->ns) {
6623 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6624 goto error;
6625 }
6626 GETVAL(ctx, value, child, "uri");
6627 trg->ns = lydict_insert(ctx, value, strlen(value));
6628
6629 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_NAMESPACE, 0, unres)) {
6630 goto error;
6631 }
6632 lyxml_free(ctx, child);
6633
6634 substmt_prev = "namespace";
6635 } else if (!submodule && !strcmp(child->name, "prefix")) {
6636 if (substmt_group > 0) {
6637 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6638 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6639 child->name, substmt_prev);
6640 goto error;
6641 }
6642
6643 if (trg->prefix) {
6644 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6645 goto error;
6646 }
6647 GETVAL(ctx, value, child, "value");
6648 if (lyp_check_identifier(ctx, value, LY_IDENT_PREFIX, trg, NULL)) {
6649 goto error;
6650 }
6651 trg->prefix = lydict_insert(ctx, value, strlen(value));
6652
6653 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_PREFIX, 0, unres)) {
6654 goto error;
6655 }
6656 lyxml_free(ctx, child);
6657
6658 substmt_prev = "prefix";
6659 } else if (submodule && !strcmp(child->name, "belongs-to")) {
6660 if (substmt_group > 0) {
6661 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6662 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6663 child->name, substmt_prev);
6664 goto error;
6665 }
6666
6667 if (trg->prefix) {
6668 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6669 goto error;
6670 }
6671 GETVAL(ctx, value, child, "module");
6672 if (!ly_strequal(value, submodule->belongsto->name, 1)) {
6673 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, child->name);
6674 goto error;
6675 }
6676
6677 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_BELONGSTO, 0, unres)) {
6678 goto error;
6679 }
6680
6681 /* get the prefix substatement, start with checks */
6682 if (!child->child) {
6683 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", child->name);
6684 goto error;
6685 } else if (strcmp(child->child->name, "prefix")) {
6686 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->child->name);
6687 goto error;
6688 } else if (child->child->next) {
6689 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->child->next->name);
6690 goto error;
6691 }
6692 /* and now finally get the value */
6693 GETVAL(ctx, value, child->child, "value");
6694 /* check here differs from a generic prefix check, since this prefix
6695 * don't have to be unique
6696 */
6697 if (lyp_check_identifier(ctx, value, LY_IDENT_NAME, NULL, NULL)) {
6698 goto error;
6699 }
6700 submodule->prefix = lydict_insert(ctx, value, strlen(value));
6701
6702 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child->child, LYEXT_SUBSTMT_PREFIX, 0, unres)) {
6703 goto error;
6704 }
6705
6706 /* we are done with belongs-to */
6707 lyxml_free(ctx, child);
6708
6709 substmt_prev = "belongs-to";
6710
6711 /* counters (statements with n..1 cardinality) */
6712 } else if (!strcmp(child->name, "import")) {
6713 if (substmt_group > 1) {
6714 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6715 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6716 child->name, substmt_prev);
6717 goto error;
6718 }
6719 substmt_group = 1;
6720 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_imp, trg->imp_size, "imports",
6721 submodule ? "submodule" : "module", error);
6722 c_imp++;
6723
6724 substmt_prev = "import";
6725 } else if (!strcmp(child->name, "revision")) {
6726 if (substmt_group > 3) {
6727 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6728 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6729 child->name, substmt_prev);
6730 goto error;
6731 }
6732 substmt_group = 3;
6733 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_rev, trg->rev_size, "revisions",
6734 submodule ? "submodule" : "module", error);
6735 c_rev++;
6736
6737 lyxml_unlink_elem(ctx, child, 2);
6738 lyxml_add_child(ctx, &revs, child);
6739
6740 substmt_prev = "revision";
6741 } else if (!strcmp(child->name, "typedef")) {
6742 substmt_group = 4;
6743 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, trg->tpdf_size, "typedefs",
6744 submodule ? "submodule" : "module", error);
6745 c_tpdf++;
6746
6747 substmt_prev = "typedef";
6748 } else if (!strcmp(child->name, "identity")) {
6749 substmt_group = 4;
6750 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ident, trg->ident_size, "identities",
6751 submodule ? "submodule" : "module", error);
6752 c_ident++;
6753
6754 substmt_prev = "identity";
6755 } else if (!strcmp(child->name, "include")) {
6756 if (substmt_group > 1) {
6757 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6758 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6759 child->name, substmt_prev);
6760 goto error;
6761 }
6762 substmt_group = 1;
6763 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_inc, trg->inc_size, "includes",
6764 submodule ? "submodule" : "module", error);
6765 c_inc++;
6766
6767 substmt_prev = "include";
6768 } else if (!strcmp(child->name, "augment")) {
6769 substmt_group = 4;
6770 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_aug, trg->augment_size, "augments",
6771 submodule ? "submodule" : "module", error);
6772 c_aug++;
6773 /* keep augments separated, processed last */
6774 lyxml_unlink_elem(ctx, child, 2);
6775 lyxml_add_child(ctx, &augs, child);
6776
6777 substmt_prev = "augment";
6778 } else if (!strcmp(child->name, "feature")) {
6779 substmt_group = 4;
6780 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, trg->features_size, "features",
6781 submodule ? "submodule" : "module", error);
6782 c_ftrs++;
6783
6784 substmt_prev = "feature";
6785
6786 /* data statements */
6787 } else if (!strcmp(child->name, "container") ||
6788 !strcmp(child->name, "leaf-list") ||
6789 !strcmp(child->name, "leaf") ||
6790 !strcmp(child->name, "list") ||
6791 !strcmp(child->name, "choice") ||
6792 !strcmp(child->name, "uses") ||
6793 !strcmp(child->name, "anyxml") ||
6794 !strcmp(child->name, "anydata") ||
6795 !strcmp(child->name, "rpc") ||
6796 !strcmp(child->name, "notification")) {
6797 substmt_group = 4;
6798
6799 lyxml_unlink_elem(ctx, child, 2);
6800 lyxml_add_child(ctx, &root, child);
6801
6802 substmt_prev = "data definition";
6803 } else if (!strcmp(child->name, "grouping")) {
6804 substmt_group = 4;
6805
6806 /* keep groupings separated and process them before other data statements */
6807 lyxml_unlink_elem(ctx, child, 2);
6808 lyxml_add_child(ctx, &grps, child);
6809
6810 substmt_prev = "grouping";
6811 /* optional statements */
6812 } else if (!strcmp(child->name, "description")) {
6813 if (substmt_group > 2) {
6814 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6815 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6816 child->name, substmt_prev);
6817 goto error;
6818 }
6819 substmt_group = 2;
6820
6821 if (trg->dsc) {
6822 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6823 goto error;
6824 }
6825 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
6826 goto error;
6827 }
6828 trg->dsc = read_yin_subnode(ctx, child, "text");
6829 lyxml_free(ctx, child);
6830 if (!trg->dsc) {
6831 goto error;
6832 }
6833
6834 substmt_prev = "description";
6835 } else if (!strcmp(child->name, "reference")) {
6836 if (substmt_group > 2) {
6837 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6838 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6839 child->name, substmt_prev);
6840 goto error;
6841 }
6842 substmt_group = 2;
6843
6844 if (trg->ref) {
6845 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6846 goto error;
6847 }
6848 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
6849 goto error;
6850 }
6851 trg->ref = read_yin_subnode(ctx, child, "text");
6852 lyxml_free(ctx, child);
6853 if (!trg->ref) {
6854 goto error;
6855 }
6856
6857 substmt_prev = "reference";
6858 } else if (!strcmp(child->name, "organization")) {
6859 if (substmt_group > 2) {
6860 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6861 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6862 child->name, substmt_prev);
6863 goto error;
6864 }
6865 substmt_group = 2;
6866
6867 if (trg->org) {
6868 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6869 goto error;
6870 }
6871 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_ORGANIZATION, 0, unres)) {
6872 goto error;
6873 }
6874 trg->org = read_yin_subnode(ctx, child, "text");
6875 lyxml_free(ctx, child);
6876 if (!trg->org) {
6877 goto error;
6878 }
6879
6880 substmt_prev = "organization";
6881 } else if (!strcmp(child->name, "contact")) {
6882 if (substmt_group > 2) {
6883 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6884 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6885 child->name, substmt_prev);
6886 goto error;
6887 }
6888 substmt_group = 2;
6889
6890 if (trg->contact) {
6891 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6892 goto error;
6893 }
6894 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_CONTACT, 0, unres)) {
6895 goto error;
6896 }
6897 trg->contact = read_yin_subnode(ctx, child, "text");
6898 lyxml_free(ctx, child);
6899 if (!trg->contact) {
6900 goto error;
6901 }
6902
6903 substmt_prev = "contact";
6904 } else if (!strcmp(child->name, "yang-version")) {
6905 if (substmt_group > 0) {
6906 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6907 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Statement \"%s\" cannot appear after \"%s\" statement.",
6908 child->name, substmt_prev);
6909 goto error;
6910 }
6911
6912 if (version_flag) {
6913 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
6914 goto error;
6915 }
6916 GETVAL(ctx, value, child, "value");
6917 if (strcmp(value, "1") && strcmp(value, "1.1")) {
6918 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "yang-version");
6919 goto error;
6920 }
6921 version_flag = 1;
6922 if (!strcmp(value, "1")) {
6923 if (submodule) {
6924 if (module->version > 1) {
6925 LOGVAL(ctx, LYE_INVER, LY_VLOG_NONE, NULL);
6926 goto error;
6927 }
6928 submodule->version = 1;
6929 } else {
6930 module->version = 1;
6931 }
6932 } else {
6933 if (submodule) {
6934 if (module->version < 2) {
6935 LOGVAL(ctx, LYE_INVER, LY_VLOG_NONE, NULL);
6936 goto error;
6937 }
6938 submodule->version = 2;
6939 } else {
6940 module->version = 2;
6941 }
6942 }
6943
6944 if (lyp_yin_parse_subnode_ext(trg, trg, LYEXT_PAR_MODULE, child, LYEXT_SUBSTMT_VERSION, 0, unres)) {
6945 goto error;
6946 }
6947 lyxml_free(ctx, child);
6948
6949 substmt_prev = "yang-version";
6950 } else if (!strcmp(child->name, "extension")) {
6951 substmt_group = 4;
6952 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, trg->extensions_size, "extensions",
6953 submodule ? "submodule" : "module", error);
6954 c_ext++;
6955
6956 substmt_prev = "extension";
6957 } else if (!strcmp(child->name, "deviation")) {
6958 substmt_group = 4;
6959 YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dev, trg->deviation_size, "deviations",
6960 submodule ? "submodule" : "module", error);
6961 c_dev++;
6962
6963 substmt_prev = "deviation";
6964 } else {
6965 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
6966 goto error;
6967 }
6968 }
6969
6970 /* check for mandatory statements */
6971 if (submodule) {
6972 if (!submodule->prefix) {
6973 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "belongs-to", "submodule");
6974 goto error;
6975 }
6976 if (!version_flag) {
6977 /* check version compatibility with the main module */
6978 if (module->version > 1) {
6979 LOGVAL(ctx, LYE_INVER, LY_VLOG_NONE, NULL);
6980 goto error;
6981 }
6982 }
6983 } else {
6984 if (!trg->ns) {
6985 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "namespace", "module");
6986 goto error;
6987 }
6988 if (!trg->prefix) {
6989 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", "module");
6990 goto error;
6991 }
6992 }
6993
6994 /* allocate arrays for elements with cardinality of 0..n */
6995 if (c_imp) {
6996 trg->imp = calloc(c_imp, sizeof *trg->imp);
6997 LY_CHECK_ERR_GOTO(!trg->imp, LOGMEM(ctx), error);
6998 }
6999 if (c_rev) {
7000 trg->rev = calloc(c_rev, sizeof *trg->rev);
7001 LY_CHECK_ERR_GOTO(!trg->rev, LOGMEM(ctx), error);
7002 }
7003 if (c_tpdf) {
7004 trg->tpdf = calloc(c_tpdf, sizeof *trg->tpdf);
7005 LY_CHECK_ERR_GOTO(!trg->tpdf, LOGMEM(ctx), error);
7006 }
7007 if (c_ident) {
7008 trg->ident = calloc(c_ident, sizeof *trg->ident);
7009 LY_CHECK_ERR_GOTO(!trg->ident, LOGMEM(ctx), error);
7010 }
7011 if (c_inc) {
7012 trg->inc = calloc(c_inc, sizeof *trg->inc);
7013 LY_CHECK_ERR_GOTO(!trg->inc, LOGMEM(ctx), error);
7014 }
7015 if (c_aug) {
7016 trg->augment = calloc(c_aug, sizeof *trg->augment);
7017 LY_CHECK_ERR_GOTO(!trg->augment, LOGMEM(ctx), error);
7018 }
7019 if (c_ftrs) {
7020 trg->features = calloc(c_ftrs, sizeof *trg->features);
7021 LY_CHECK_ERR_GOTO(!trg->features, LOGMEM(ctx), error);
7022 }
7023 if (c_dev) {
7024 trg->deviation = calloc(c_dev, sizeof *trg->deviation);
7025 LY_CHECK_ERR_GOTO(!trg->deviation, LOGMEM(ctx), error);
7026 }
7027 if (c_ext) {
7028 trg->extensions = calloc(c_ext, sizeof *trg->extensions);
7029 LY_CHECK_ERR_GOTO(!trg->extensions, LOGMEM(ctx), error);
7030 }
7031
7032 /* middle part 1 - process revision and then check whether this (sub)module was not already parsed, add it there */
7033 LY_TREE_FOR_SAFE(revs.child, next, child) {
7034 r = fill_yin_revision(trg, child, &trg->rev[trg->rev_size], unres);
7035 trg->rev_size++;
7036 if (r) {
7037 goto error;
7038 }
7039
7040 /* check uniqueness of the revision date - not required by RFC */
7041 for (i = 0; i < (trg->rev_size - 1); i++) {
7042 if (!strcmp(trg->rev[i].date, trg->rev[trg->rev_size - 1].date)) {
7043 LOGWRN(ctx, "Module's revisions are not unique (%s).", trg->rev[trg->rev_size - 1].date);
7044 break;
7045 }
7046 }
7047
7048 lyxml_free(ctx, child);
7049 }
7050
7051 /* check the module with respect to the context now */
7052 if (!submodule) {
7053 switch (lyp_ctx_check_module(module)) {
7054 case -1:
7055 goto error;
7056 case 0:
7057 break;
7058 case 1:
7059 /* it's already there */
7060 ret = 1;
7061 goto error;
7062 }
7063 }
7064
7065 /* check first definition of extensions */
7066 if (c_ext) {
7067 LY_TREE_FOR_SAFE(yin->child, next, child) {
7068 if (!strcmp(child->name, "extension")) {
7069 r = fill_yin_extension(trg, child, &trg->extensions[trg->extensions_size], unres);
7070 trg->extensions_size++;
7071 if (r) {
7072 goto error;
7073 }
7074
7075 }
7076 }
7077 }
7078
7079 /* middle part 2 - process nodes with cardinality of 0..n except the data nodes and augments */
7080 LY_TREE_FOR_SAFE(yin->child, next, child) {
7081 if (!strcmp(child->name, "import")) {
7082 r = fill_yin_import(trg, child, &trg->imp[trg->imp_size], unres);
7083 trg->imp_size++;
7084 if (r) {
7085 goto error;
7086 }
7087
7088 } else if (!strcmp(child->name, "include")) {
7089 r = fill_yin_include(module, submodule, child, &trg->inc[trg->inc_size], unres);
7090 trg->inc_size++;
7091 if (r) {
7092 goto error;
7093 }
7094
7095 } else if (!strcmp(child->name, "typedef")) {
7096 r = fill_yin_typedef(trg, NULL, child, &trg->tpdf[trg->tpdf_size], unres);
7097 trg->tpdf_size++;
7098 if (r) {
7099 goto error;
7100 }
7101
7102 } else if (!strcmp(child->name, "identity")) {
7103 r = fill_yin_identity(trg, child, &trg->ident[trg->ident_size], unres);
7104 trg->ident_size++;
7105 if (r) {
7106 goto error;
7107 }
7108
7109 } else if (!strcmp(child->name, "feature")) {
7110 r = fill_yin_feature(trg, child, &trg->features[trg->features_size], unres);
7111 trg->features_size++;
7112 if (r) {
7113 goto error;
7114 }
7115
7116 } else if (!strcmp(child->name, "deviation")) {
7117 /* must be implemented in this case */
7118 trg->implemented = 1;
7119
7120 r = fill_yin_deviation(trg, child, &trg->deviation[trg->deviation_size], unres);
7121 trg->deviation_size++;
7122 if (r) {
7123 goto error;
7124 }
7125 }
7126 }
7127
7128 /* process extension instances */
7129 if (c_extinst) {
7130 /* some extensions may be already present from the substatements */
7131 reallocated = realloc(trg->ext, (c_extinst + trg->ext_size) * sizeof *trg->ext);
7132 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
7133 trg->ext = reallocated;
7134
7135 /* init memory */
7136 memset(&trg->ext[trg->ext_size], 0, c_extinst * sizeof *trg->ext);
7137
7138 LY_TREE_FOR_SAFE(exts.child, next, child) {
7139 r = lyp_yin_fill_ext(trg, LYEXT_PAR_MODULE, 0, 0, trg, child, &trg->ext, &trg->ext_size, unres);
7140 if (r) {
7141 goto error;
7142 }
7143 }
7144
7145 lyp_reduce_ext_list(&trg->ext, trg->ext_size, c_ext + trg->ext_size);
7146 }
7147
7148 /* process data nodes. Start with groupings to allow uses
7149 * refer to them. Submodule's data nodes are stored in the
7150 * main module data tree.
7151 */
7152 LY_TREE_FOR_SAFE(grps.child, next, child) {
7153 node = read_yin_grouping(trg, NULL, child, 0, unres);
7154 if (!node) {
7155 goto error;
7156 }
7157
7158 lyxml_free(ctx, child);
7159 }
7160
7161 /* parse data nodes, ... */
7162 LY_TREE_FOR_SAFE(root.child, next, child) {
7163
7164 if (!strcmp(child->name, "container")) {
7165 node = read_yin_container(trg, NULL, child, 0, unres);
7166 } else if (!strcmp(child->name, "leaf-list")) {
7167 node = read_yin_leaflist(trg, NULL, child, 0, unres);
7168 } else if (!strcmp(child->name, "leaf")) {
7169 node = read_yin_leaf(trg, NULL, child, 0, unres);
7170 } else if (!strcmp(child->name, "list")) {
7171 node = read_yin_list(trg, NULL, child, 0, unres);
7172 } else if (!strcmp(child->name, "choice")) {
7173 node = read_yin_choice(trg, NULL, child, 0, unres);
7174 } else if (!strcmp(child->name, "uses")) {
7175 node = read_yin_uses(trg, NULL, child, 0, unres);
7176 } else if (!strcmp(child->name, "anyxml")) {
7177 node = read_yin_anydata(trg, NULL, child, LYS_ANYXML, 0, unres);
7178 } else if (!strcmp(child->name, "anydata")) {
7179 node = read_yin_anydata(trg, NULL, child, LYS_ANYDATA, 0, unres);
7180 } else if (!strcmp(child->name, "rpc")) {
7181 node = read_yin_rpc_action(trg, NULL, child, 0, unres);
7182 } else if (!strcmp(child->name, "notification")) {
7183 node = read_yin_notif(trg, NULL, child, 0, unres);
7184 }
7185 if (!node) {
7186 goto error;
7187 }
7188
7189 lyxml_free(ctx, child);
7190 }
7191
7192 /* ... and finally augments (last, so we can augment our data, for instance) */
7193 LY_TREE_FOR_SAFE(augs.child, next, child) {
7194 r = fill_yin_augment(trg, NULL, child, &trg->augment[trg->augment_size], 0, unres);
7195 trg->augment_size++;
7196
7197 if (r) {
7198 goto error;
7199 }
7200 lyxml_free(ctx, child);
7201 }
7202
7203 return 0;
7204
7205 error:
7206 while (root.child) {
7207 lyxml_free(ctx, root.child);
7208 }
7209 while (grps.child) {
7210 lyxml_free(ctx, grps.child);
7211 }
7212 while (augs.child) {
7213 lyxml_free(ctx, augs.child);
7214 }
7215 while (revs.child) {
7216 lyxml_free(ctx, revs.child);
7217 }
7218 while (exts.child) {
7219 lyxml_free(ctx, exts.child);
7220 }
7221
7222 return ret;
7223 }
7224
7225 /* logs directly */
7226 struct lys_submodule *
yin_read_submodule(struct lys_module * module,const char * data,struct unres_schema * unres)7227 yin_read_submodule(struct lys_module *module, const char *data, struct unres_schema *unres)
7228 {
7229 struct ly_ctx *ctx = module->ctx;
7230 struct lyxml_elem *yin;
7231 struct lys_submodule *submodule = NULL;
7232 const char *value;
7233
7234 yin = lyxml_parse_mem(ctx, data, LYXML_PARSE_NOMIXEDCONTENT);
7235 if (!yin) {
7236 return NULL;
7237 }
7238
7239 /* check root element */
7240 if (!yin->name || strcmp(yin->name, "submodule")) {
7241 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, yin->name);
7242 goto error;
7243 }
7244
7245 GETVAL(ctx, value, yin, "name");
7246 if (lyp_check_identifier(ctx, value, LY_IDENT_NAME, NULL, NULL)) {
7247 goto error;
7248 }
7249
7250 submodule = calloc(1, sizeof *submodule);
7251 LY_CHECK_ERR_GOTO(!submodule, LOGMEM(ctx), error);
7252
7253 submodule->ctx = ctx;
7254 submodule->name = lydict_insert(ctx, value, strlen(value));
7255 submodule->type = 1;
7256 submodule->implemented = module->implemented;
7257 submodule->belongsto = module;
7258
7259 /* add into the list of processed modules */
7260 if (lyp_check_circmod_add((struct lys_module *)submodule)) {
7261 goto error;
7262 }
7263
7264 LOGVRB("Reading submodule \"%s\".", submodule->name);
7265 /* module cannot be changed in this case and 1 cannot be returned */
7266 if (read_sub_module(module, submodule, yin, unres)) {
7267 goto error;
7268 }
7269
7270 lyp_sort_revisions((struct lys_module *)submodule);
7271
7272 /* cleanup */
7273 lyxml_free(ctx, yin);
7274 lyp_check_circmod_pop(ctx);
7275
7276 LOGVRB("Submodule \"%s\" successfully parsed.", submodule->name);
7277 return submodule;
7278
7279 error:
7280 /* cleanup */
7281 lyxml_free(ctx, yin);
7282 if (!submodule) {
7283 LOGERR(ctx, ly_errno, "Submodule parsing failed.");
7284 return NULL;
7285 }
7286
7287 LOGERR(ctx, ly_errno, "Submodule \"%s\" parsing failed.", submodule->name);
7288
7289 unres_schema_free((struct lys_module *)submodule, &unres, 0);
7290 lyp_check_circmod_pop(ctx);
7291 lys_sub_module_remove_devs_augs((struct lys_module *)submodule);
7292 lys_submodule_module_data_free(submodule);
7293 lys_submodule_free(submodule, NULL);
7294 return NULL;
7295 }
7296
7297 /* logs directly */
7298 struct lys_module *
yin_read_module_(struct ly_ctx * ctx,struct lyxml_elem * yin,const char * revision,int implement)7299 yin_read_module_(struct ly_ctx *ctx, struct lyxml_elem *yin, const char *revision, int implement)
7300 {
7301 struct lys_module *module = NULL;
7302 struct unres_schema *unres;
7303 const char *value;
7304 int ret;
7305 uint8_t i;
7306
7307 unres = calloc(1, sizeof *unres);
7308 LY_CHECK_ERR_RETURN(!unres, LOGMEM(ctx), NULL);
7309
7310 /* check root element */
7311 if (!yin->name || strcmp(yin->name, "module")) {
7312 if (ly_strequal("submodule", yin->name, 0)) {
7313 LOGVAL(ctx, LYE_SUBMODULE, LY_VLOG_NONE, NULL);
7314 } else {
7315 LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, yin->name);
7316 }
7317 goto error;
7318 }
7319
7320 GETVAL(ctx, value, yin, "name");
7321 if (lyp_check_identifier(ctx, value, LY_IDENT_NAME, NULL, NULL)) {
7322 goto error;
7323 }
7324
7325 /* in some really invalid situations there can be a circular import and
7326 * we can check it only after we have parsed the module name */
7327 for (i = 0; i < ctx->models.parsing_sub_modules_count; ++i) {
7328 if (!strcmp(ctx->models.parsing_sub_modules[i]->name, value)) {
7329 LOGVAL(ctx, LYE_CIRC_IMPORTS, LY_VLOG_NONE, NULL, value);
7330 goto error;
7331 }
7332 }
7333
7334 module = calloc(1, sizeof *module);
7335 LY_CHECK_ERR_GOTO(!module, LOGMEM(ctx), error);
7336
7337 module->ctx = ctx;
7338 module->name = lydict_insert(ctx, value, strlen(value));
7339 module->type = 0;
7340 module->implemented = (implement ? 1 : 0);
7341
7342 /* add into the list of processed modules */
7343 if (lyp_check_circmod_add(module)) {
7344 goto error;
7345 }
7346
7347 LOGVRB("Reading module \"%s\".", module->name);
7348 ret = read_sub_module(module, NULL, yin, unres);
7349 if (ret == -1) {
7350 goto error;
7351 }
7352
7353 if (ret == 1) {
7354 assert(!unres->count);
7355 } else {
7356 /* make this module implemented if was not from start */
7357 if (!implement && module->implemented && (unres_schema_add_node(module, unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1)) {
7358 goto error;
7359 }
7360
7361 /* resolve rest of unres items */
7362 if (unres->count && resolve_unres_schema(module, unres)) {
7363 goto error;
7364 }
7365
7366 /* check correctness of includes */
7367 if (lyp_check_include_missing(module)) {
7368 goto error;
7369 }
7370 }
7371
7372 lyp_sort_revisions(module);
7373
7374 if (lyp_rfn_apply_ext(module) || lyp_deviation_apply_ext(module)) {
7375 goto error;
7376 }
7377
7378 if (revision) {
7379 /* check revision of the parsed model */
7380 if (!module->rev_size || strcmp(revision, module->rev[0].date)) {
7381 LOGVRB("Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
7382 module->name, module->rev[0].date, revision);
7383 goto error;
7384 }
7385 }
7386
7387 /* add into context if not already there */
7388 if (!ret) {
7389 if (lyp_ctx_add_module(module)) {
7390 goto error;
7391 }
7392
7393 /* remove our submodules from the parsed submodules list */
7394 lyp_del_includedup(module, 0);
7395 } else {
7396 /* free what was parsed */
7397 lys_free(module, NULL, 0, 0);
7398
7399 /* get the model from the context */
7400 module = (struct lys_module *)ly_ctx_get_module(ctx, value, revision, 0);
7401 assert(module);
7402 }
7403
7404 unres_schema_free(NULL, &unres, 0);
7405 lyp_check_circmod_pop(ctx);
7406 LOGVRB("Module \"%s%s%s\" successfully parsed as %s.", module->name, (module->rev_size ? "@" : ""),
7407 (module->rev_size ? module->rev[0].date : ""), (module->implemented ? "implemented" : "imported"));
7408 return module;
7409
7410 error:
7411 /* cleanup */
7412 unres_schema_free(module, &unres, 1);
7413
7414 if (!module) {
7415 if (ly_vecode(ctx) != LYVE_SUBMODULE) {
7416 LOGERR(ctx, ly_errno, "Module parsing failed.");
7417 }
7418 return NULL;
7419 }
7420
7421 LOGERR(ctx, ly_errno, "Module \"%s\" parsing failed.", module->name);
7422
7423 lyp_check_circmod_pop(ctx);
7424 lys_sub_module_remove_devs_augs(module);
7425 lyp_del_includedup(module, 1);
7426 lys_free(module, NULL, 0, 1);
7427 return NULL;
7428 }
7429
7430 /* logs directly */
7431 struct lys_module *
yin_read_module(struct ly_ctx * ctx,const char * data,const char * revision,int implement)7432 yin_read_module(struct ly_ctx *ctx, const char *data, const char *revision, int implement)
7433 {
7434 struct lyxml_elem *yin;
7435 struct lys_module *result;
7436
7437 yin = lyxml_parse_mem(ctx, data, LYXML_PARSE_NOMIXEDCONTENT);
7438 if (!yin) {
7439 LOGERR(ctx, ly_errno, "Module parsing failed.");
7440 return NULL;
7441 }
7442
7443 result = yin_read_module_(ctx, yin, revision, implement);
7444
7445 lyxml_free(ctx, yin);
7446
7447 return result;
7448 }
7449
7450 static int
yin_parse_extcomplex_bool(struct lys_module * mod,struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt,const char * true_val,const char * false_val,struct unres_schema * unres)7451 yin_parse_extcomplex_bool(struct lys_module *mod, struct lyxml_elem *node,
7452 struct lys_ext_instance_complex *ext, LY_STMT stmt,
7453 const char *true_val, const char *false_val, struct unres_schema *unres)
7454 {
7455 uint8_t *val;
7456 const char *str;
7457 struct lyext_substmt *info;
7458
7459 val = lys_ext_complex_get_substmt(stmt, ext, &info);
7460 if (!val) {
7461 LOGVAL(mod->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7462 return EXIT_FAILURE;
7463 }
7464 if (*val) {
7465 LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7466 return EXIT_FAILURE;
7467 }
7468
7469 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, (LYEXT_SUBSTMT)stmt, 0, unres)) {
7470 return EXIT_FAILURE;
7471 }
7472
7473 str = lyxml_get_attr(node, "value", NULL);
7474 if (!str) {
7475 LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->name);
7476 } else if (true_val && !strcmp(true_val, str)) {
7477 /* true value */
7478 *val = 1;
7479 } else if (false_val && !strcmp(false_val, str)) {
7480 /* false value */
7481 *val = 2;
7482 } else {
7483 /* unknown value */
7484 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, str, node->name);
7485 return EXIT_FAILURE;
7486 }
7487
7488 return EXIT_SUCCESS;
7489 }
7490
7491 /*
7492 * argelem - 1 if the value is stored in a standalone YIN element, 0 if stored as attribute
7493 * argname - name of the element/attribute where the value is stored
7494 */
7495 static int
yin_parse_extcomplex_str(struct lys_module * mod,struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt,int argelem,const char * argname,struct unres_schema * unres)7496 yin_parse_extcomplex_str(struct lys_module *mod, struct lyxml_elem *node,
7497 struct lys_ext_instance_complex *ext, LY_STMT stmt,
7498 int argelem, const char *argname, struct unres_schema *unres)
7499 {
7500 int c;
7501 const char **str, ***p = NULL, *value;
7502 void *reallocated;
7503 struct lyext_substmt *info;
7504
7505 str = lys_ext_complex_get_substmt(stmt, ext, &info);
7506 if (!str) {
7507 LOGVAL(mod->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7508 return EXIT_FAILURE;
7509 }
7510 if (info->cardinality < LY_STMT_CARD_SOME && *str) {
7511 LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7512 return EXIT_FAILURE;
7513 }
7514
7515 c = 0;
7516 if (info->cardinality >= LY_STMT_CARD_SOME) {
7517 /* there can be multiple instances, str is actually const char *** */
7518 p = (const char ***)str;
7519 if (!p[0]) {
7520 /* allocate initial array */
7521 p[0] = malloc(2 * sizeof(const char *));
7522 LY_CHECK_ERR_RETURN(!p[0], LOGMEM(mod->ctx), EXIT_FAILURE);
7523 if (stmt == LY_STMT_BELONGSTO) {
7524 /* allocate another array for the belongs-to's prefixes */
7525 p[1] = malloc(2 * sizeof(const char *));
7526 LY_CHECK_ERR_RETURN(!p[1], LOGMEM(mod->ctx), EXIT_FAILURE);
7527 } else if (stmt == LY_STMT_ARGUMENT) {
7528 /* allocate another array for the yin element */
7529 ((uint8_t **)p)[1] = malloc(2 * sizeof(uint8_t));
7530 LY_CHECK_ERR_RETURN(!p[1], LOGMEM(mod->ctx), EXIT_FAILURE);
7531 }
7532 } else {
7533 /* get the index in the array to add new item */
7534 for (c = 0; p[0][c]; c++);
7535 }
7536 str = p[0];
7537 }
7538 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, (LYEXT_SUBSTMT)stmt, c, unres)) {
7539 return EXIT_FAILURE;
7540 }
7541
7542 if (argelem) {
7543 str[c] = read_yin_subnode(mod->ctx, node, argname);
7544 if (!str[c]) {
7545 return EXIT_FAILURE;
7546 }
7547 } else {
7548 str[c] = lyxml_get_attr(node, argname, NULL);
7549 if (!str[c]) {
7550 LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, argname, node->name);
7551 return EXIT_FAILURE;
7552 } else {
7553 str[c] = lydict_insert(mod->ctx, str[c], 0);
7554 }
7555
7556 if (stmt == LY_STMT_BELONGSTO) {
7557 /* get the belongs-to's mandatory prefix substatement */
7558 if (!node->child) {
7559 LOGVAL(mod->ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", node->name);
7560 return EXIT_FAILURE;
7561 } else if (strcmp(node->child->name, "prefix")) {
7562 LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->name);
7563 return EXIT_FAILURE;
7564 } else if (node->child->next) {
7565 LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->next->name);
7566 return EXIT_FAILURE;
7567 }
7568 /* and now finally get the value */
7569 if (p) {
7570 str = p[1];
7571 } else {
7572 str++;
7573 }
7574 str[c] = lyxml_get_attr(node->child, "value", ((void *)0));
7575 if (!str[c]) {
7576 LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->child->name);
7577 return EXIT_FAILURE;
7578 }
7579 str[c] = lydict_insert(mod->ctx, str[c], 0);
7580
7581 if (!str[c] || lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node->child, LYEXT_SUBSTMT_PREFIX, c, unres)) {
7582 return EXIT_FAILURE;
7583 }
7584 } else if (stmt == LY_STMT_ARGUMENT) {
7585 str = (p) ? p[1] : str + 1;
7586 if (!node->child) {
7587 /* default value of yin element */
7588 ((uint8_t *)str)[c] = 2;
7589 } else {
7590 /* get optional yin-element substatement */
7591 if (strcmp(node->child->name, "yin-element")) {
7592 LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->name);
7593 return EXIT_FAILURE;
7594 } else if (node->child->next) {
7595 LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->next->name);
7596 return EXIT_FAILURE;
7597 } else {
7598 /* and now finally get the value */
7599 value = lyxml_get_attr(node->child, "value", NULL);
7600 if (!value) {
7601 LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->child->name);
7602 return EXIT_FAILURE;
7603 }
7604 if (ly_strequal(value, "true", 0)) {
7605 ((uint8_t *)str)[c] = 1;
7606 } else if (ly_strequal(value, "false", 0)) {
7607 ((uint8_t *)str)[c] = 2;
7608 } else {
7609 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, str, node->name);
7610 return EXIT_FAILURE;
7611 }
7612
7613 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node->child, LYEXT_SUBSTMT_YINELEM, c, unres)) {
7614 return EXIT_FAILURE;
7615 }
7616 }
7617 }
7618 }
7619 }
7620 if (p) {
7621 /* enlarge the array(s) */
7622 reallocated = realloc(p[0], (c + 2) * sizeof(const char *));
7623 if (!reallocated) {
7624 LOGMEM(mod->ctx);
7625 lydict_remove(mod->ctx, p[0][c]);
7626 p[0][c] = NULL;
7627 return EXIT_FAILURE;
7628 }
7629 p[0] = reallocated;
7630 p[0][c + 1] = NULL;
7631
7632 if (stmt == LY_STMT_BELONGSTO) {
7633 /* enlarge the second belongs-to's array with prefixes */
7634 reallocated = realloc(p[1], (c + 2) * sizeof(const char *));
7635 if (!reallocated) {
7636 LOGMEM(mod->ctx);
7637 lydict_remove(mod->ctx, p[1][c]);
7638 p[1][c] = NULL;
7639 return EXIT_FAILURE;
7640 }
7641 p[1] = reallocated;
7642 p[1][c + 1] = NULL;
7643 } else if (stmt == LY_STMT_ARGUMENT){
7644 /* enlarge the second argument's array with yin element */
7645 reallocated = realloc(p[1], (c + 2) * sizeof(uint8_t));
7646 if (!reallocated) {
7647 LOGMEM(mod->ctx);
7648 ((uint8_t *)p[1])[c] = 0;
7649 return EXIT_FAILURE;
7650 }
7651 p[1] = reallocated;
7652 ((uint8_t *)p[1])[c + 1] = 0;
7653 }
7654 }
7655
7656 return EXIT_SUCCESS;
7657 }
7658
7659 static void *
yin_getplace_for_extcomplex_flags(struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt,uint16_t mask)7660 yin_getplace_for_extcomplex_flags(struct lyxml_elem *node, struct lys_ext_instance_complex *ext, LY_STMT stmt,
7661 uint16_t mask)
7662 {
7663 void *data;
7664 struct lyext_substmt *info;
7665
7666 data = lys_ext_complex_get_substmt(stmt, ext, &info);
7667 if (!data) {
7668 LOGVAL(ext->module->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7669 return NULL;
7670 }
7671 if (info->cardinality < LY_STMT_CARD_SOME && ((*(uint16_t *)data) & mask)) {
7672 LOGVAL(ext->module->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7673 return NULL;
7674 }
7675
7676 return data;
7677 }
7678
7679 static int
yin_parse_extcomplex_flag(struct lys_module * mod,struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt,const char * val1_str,const char * val2_str,uint16_t mask,uint16_t val1,uint16_t val2,struct unres_schema * unres)7680 yin_parse_extcomplex_flag(struct lys_module *mod, struct lyxml_elem *node,
7681 struct lys_ext_instance_complex *ext, LY_STMT stmt,
7682 const char *val1_str, const char *val2_str, uint16_t mask,
7683 uint16_t val1, uint16_t val2, struct unres_schema *unres)
7684 {
7685 uint16_t *val;
7686 const char *str;
7687
7688 val = yin_getplace_for_extcomplex_flags(node, ext, stmt, mask);
7689 if (!val) {
7690 return EXIT_FAILURE;
7691 }
7692
7693 str = lyxml_get_attr(node, "value", NULL);
7694 if (!str) {
7695 LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->name);
7696 } else if (!strcmp(val1_str, str)) {
7697 *val = *val | val1;
7698 } else if (!strcmp(val2_str, str)) {
7699 *val = *val | val2;
7700 } else {
7701 /* unknown value */
7702 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, str, node->name);
7703 return EXIT_FAILURE;
7704 }
7705 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, (LYEXT_SUBSTMT)stmt, 0, unres)) {
7706 return EXIT_FAILURE;
7707 }
7708 return EXIT_SUCCESS;
7709 }
7710
7711 static struct lys_node **
yin_getplace_for_extcomplex_node(struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt)7712 yin_getplace_for_extcomplex_node(struct lyxml_elem *node, struct lys_ext_instance_complex *ext, LY_STMT stmt)
7713 {
7714 struct lyext_substmt *info;
7715 struct lys_node **snode, *siter;
7716
7717 snode = lys_ext_complex_get_substmt(stmt, ext, &info);
7718 if (!snode) {
7719 LOGVAL(ext->module->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7720 return NULL;
7721 }
7722 if (info->cardinality < LY_STMT_CARD_SOME) {
7723 LY_TREE_FOR(*snode, siter) {
7724 if (stmt == lys_snode2stmt(siter->nodetype)) {
7725 LOGVAL(ext->module->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7726 return NULL;
7727 }
7728 }
7729 }
7730
7731 return snode;
7732 }
7733
7734 static void **
yin_getplace_for_extcomplex_struct(struct lyxml_elem * node,struct lys_ext_instance_complex * ext,LY_STMT stmt)7735 yin_getplace_for_extcomplex_struct(struct lyxml_elem *node, struct lys_ext_instance_complex *ext, LY_STMT stmt)
7736 {
7737 int c;
7738 void **data, ***p = NULL;
7739 void *reallocated;
7740 struct lyext_substmt *info;
7741
7742 data = lys_ext_complex_get_substmt(stmt, ext, &info);
7743 if (!data) {
7744 LOGVAL(ext->module->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7745 return NULL;
7746 }
7747 if (info->cardinality < LY_STMT_CARD_SOME && *data) {
7748 LOGVAL(ext->module->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
7749 return NULL;
7750 }
7751
7752 c = 0;
7753 if (info->cardinality >= LY_STMT_CARD_SOME) {
7754 /* there can be multiple instances, so instead of pointer to array,
7755 * we have in data pointer to pointer to array */
7756 p = (void ***)data;
7757 data = *p;
7758 if (!data) {
7759 /* allocate initial array */
7760 *p = data = malloc(2 * sizeof(void *));
7761 LY_CHECK_ERR_RETURN(!data, LOGMEM(ext->module->ctx), NULL);
7762 } else {
7763 for (c = 0; *data; data++, c++);
7764 }
7765 }
7766
7767 if (p) {
7768 /* enlarge the array */
7769 reallocated = realloc(*p, (c + 2) * sizeof(void *));
7770 LY_CHECK_ERR_RETURN(!reallocated, LOGMEM(ext->module->ctx), NULL);
7771 *p = reallocated;
7772 data = *p;
7773 data[c + 1] = NULL;
7774 }
7775
7776 return &data[c];
7777 }
7778
7779 int
lyp_yin_parse_complex_ext(struct lys_module * mod,struct lys_ext_instance_complex * ext,struct lyxml_elem * yin,struct unres_schema * unres)7780 lyp_yin_parse_complex_ext(struct lys_module *mod, struct lys_ext_instance_complex *ext, struct lyxml_elem *yin,
7781 struct unres_schema *unres)
7782 {
7783 struct lyxml_elem *next, *node, *child;
7784 struct lys_type **type;
7785 void **pp, *p, *reallocated;
7786 const char *value, *name;
7787 char *endptr, modifier;
7788 struct lyext_substmt *info;
7789 long int v;
7790 long long int ll;
7791 unsigned long u;
7792 int i, j;
7793
7794 #define YIN_STORE_VALUE(TYPE, FROM, TO) \
7795 *(TYPE **)TO = malloc(sizeof(TYPE)); \
7796 if (!*(TYPE **)TO) { LOGMEM(mod->ctx); goto error; } \
7797 (**(TYPE **)TO) = (TYPE)FROM;
7798
7799 #define YIN_EXTCOMPLEX_GETPLACE(STMT, TYPE) \
7800 p = lys_ext_complex_get_substmt(STMT, ext, &info); \
7801 if (!p) { \
7802 LOGVAL(mod->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name); \
7803 goto error; \
7804 } \
7805 if (info->cardinality < LY_STMT_CARD_SOME && (*(TYPE*)p)) { \
7806 LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name); \
7807 goto error; \
7808 } \
7809 pp = NULL; i = 0; \
7810 if (info->cardinality >= LY_STMT_CARD_SOME) { \
7811 /* there can be multiple instances */ \
7812 pp = p; \
7813 if (!(*pp)) { \
7814 *pp = malloc(2 * sizeof(TYPE)); /* allocate initial array */ \
7815 LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error); \
7816 } else { \
7817 for (i = 0; (*(TYPE**)pp)[i]; i++); \
7818 } \
7819 p = &(*(TYPE**)pp)[i]; \
7820 }
7821 #define YIN_EXTCOMPLEX_ENLARGE(TYPE) \
7822 if (pp) { \
7823 /* enlarge the array */ \
7824 reallocated = realloc(*pp, (i + 2) * sizeof(TYPE*)); \
7825 LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(mod->ctx), error); \
7826 *pp = reallocated; \
7827 (*(TYPE**)pp)[i + 1] = 0; \
7828 }
7829 #define YIN_EXTCOMPLEX_PARSE_SNODE(STMT, FUNC, ARGS...) \
7830 pp = (void**)yin_getplace_for_extcomplex_node(node, ext, STMT); \
7831 if (!pp) { goto error; } \
7832 if (!FUNC(mod, (struct lys_node*)ext, node, ##ARGS, LYS_PARSE_OPT_CFG_NOINHERIT, unres)) { goto error; }
7833 #define YIN_EXTCOMPLEX_PARSE_RESTR(STMT) \
7834 YIN_EXTCOMPLEX_GETPLACE(STMT, struct lys_restr*); \
7835 GETVAL(mod->ctx, value, node, "value"); \
7836 *(struct lys_restr **)p = calloc(1, sizeof(struct lys_restr)); \
7837 LY_CHECK_ERR_GOTO(!*(struct lys_restr **)p, LOGMEM(mod->ctx), error); \
7838 (*(struct lys_restr **)p)->expr = lydict_insert(mod->ctx, value, 0); \
7839 if (read_restr_substmt(mod, *(struct lys_restr **)p, node, unres)) { \
7840 goto error; \
7841 } \
7842 YIN_EXTCOMPLEX_ENLARGE(struct lys_restr*);
7843
7844 LY_TREE_FOR_SAFE(yin->child, next, node) {
7845 if (!node->ns) {
7846 /* garbage */
7847 } else if (node->ns == yin->ns && (ext->flags & LYS_YINELEM) && ly_strequal(node->name, ext->def->argument, 1)) {
7848 /* we have the extension's argument */
7849 if (ext->arg_value) {
7850 LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
7851 goto error;
7852 }
7853 ext->arg_value = node->content;
7854 node->content = NULL;
7855 } else if (strcmp(node->ns->value, LY_NSYIN)) {
7856 /* extension */
7857 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_SELF, 0, unres)) {
7858 goto error;
7859 }
7860 } else if (!strcmp(node->name, "description")) {
7861 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_DESCRIPTION, 1, "text", unres)) {
7862 goto error;
7863 }
7864 } else if (!strcmp(node->name, "reference")) {
7865 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_REFERENCE, 1, "text", unres)) {
7866 goto error;
7867 }
7868 } else if (!strcmp(node->name, "units")) {
7869 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_UNITS, 0, "name", unres)) {
7870 goto error;
7871 }
7872 } else if (!strcmp(node->name, "type")) {
7873 type = (struct lys_type **)yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_TYPE);
7874 if (!type) {
7875 goto error;
7876 }
7877 /* allocate type structure */
7878 (*type) = calloc(1, sizeof **type);
7879 LY_CHECK_ERR_GOTO(!*type, LOGMEM(mod->ctx), error);
7880
7881 /* HACK for unres */
7882 lyxml_unlink(mod->ctx, node);
7883 (*type)->der = (struct lys_tpdf *)node;
7884 (*type)->parent = (struct lys_tpdf *)ext;
7885
7886 if (unres_schema_add_node(mod, unres, *type, UNRES_TYPE_DER_EXT, NULL) == -1) {
7887 (*type)->der = NULL;
7888 goto error;
7889 }
7890 continue; /* skip lyxml_free() */
7891 } else if (!strcmp(node->name, "typedef")) {
7892 pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_TYPEDEF);
7893 if (!pp) {
7894 goto error;
7895 }
7896 /* allocate typedef structure */
7897 (*pp) = calloc(1, sizeof(struct lys_tpdf));
7898 LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);
7899
7900 if (fill_yin_typedef(mod, (struct lys_node *)ext, node, *((struct lys_tpdf **)pp), unres)) {
7901 goto error;
7902 }
7903 } else if (!strcmp(node->name, "if-feature")) {
7904 pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_IFFEATURE);
7905 if (!pp) {
7906 goto error;
7907 }
7908 /* allocate iffeature structure */
7909 (*pp) = calloc(1, sizeof(struct lys_iffeature));
7910 LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);
7911
7912 if (fill_yin_iffeature((struct lys_node *)ext, 0, node, *((struct lys_iffeature **)pp), unres)) {
7913 goto error;
7914 }
7915 } else if (!strcmp(node->name, "status")) {
7916 p = yin_getplace_for_extcomplex_flags(node, ext, LY_STMT_STATUS, LYS_STATUS_MASK);
7917 if (!p) {
7918 goto error;
7919 }
7920
7921 GETVAL(mod->ctx, value, node, "value");
7922 if (!strcmp(value, "current")) {
7923 *(uint16_t*)p |= LYS_STATUS_CURR;
7924 } else if (!strcmp(value, "deprecated")) {
7925 *(uint16_t*)p |= LYS_STATUS_DEPRC;
7926 } else if (!strcmp(value, "obsolete")) {
7927 *(uint16_t*)p |= LYS_STATUS_OBSLT;
7928 } else {
7929 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
7930 goto error;
7931 }
7932
7933 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_STATUS, 0, unres)) {
7934 goto error;
7935 }
7936 } else if (!strcmp(node->name, "config")) {
7937 if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_MANDATORY, "true", "false", LYS_CONFIG_MASK,
7938 LYS_CONFIG_W | LYS_CONFIG_SET, LYS_CONFIG_R | LYS_CONFIG_SET, unres)) {
7939 goto error;
7940 }
7941 } else if (!strcmp(node->name, "argument")) {
7942 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ARGUMENT, 0, "name", unres)) {
7943 goto error;
7944 }
7945 } else if (!strcmp(node->name, "default")) {
7946 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_DEFAULT, 0, "value", unres)) {
7947 goto error;
7948 }
7949 } else if (!strcmp(node->name, "mandatory")) {
7950 if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_MANDATORY,
7951 "true", "false", LYS_MAND_MASK, LYS_MAND_TRUE, LYS_MAND_FALSE, unres)) {
7952 goto error;
7953 }
7954 } else if (!strcmp(node->name, "error-app-tag")) {
7955 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ERRTAG, 0, "value", unres)) {
7956 goto error;
7957 }
7958 } else if (!strcmp(node->name, "error-message")) {
7959 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ERRMSG, 1, "value", unres)) {
7960 goto error;
7961 }
7962 } else if (!strcmp(node->name, "prefix")) {
7963 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PREFIX, 0, "value", unres)) {
7964 goto error;
7965 }
7966 } else if (!strcmp(node->name, "namespace")) {
7967 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_NAMESPACE, 0, "uri", unres)) {
7968 goto error;
7969 }
7970 } else if (!strcmp(node->name, "presence")) {
7971 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PRESENCE, 0, "value", unres)) {
7972 goto error;
7973 }
7974 } else if (!strcmp(node->name, "revision-date")) {
7975 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_REVISIONDATE, 0, "date", unres)) {
7976 goto error;
7977 }
7978 } else if (!strcmp(node->name, "key")) {
7979 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_KEY, 0, "value", unres)) {
7980 goto error;
7981 }
7982 } else if (!strcmp(node->name, "base")) {
7983 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_BASE, 0, "name", unres)) {
7984 goto error;
7985 }
7986 } else if (!strcmp(node->name, "ordered-by")) {
7987 if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_ORDEREDBY,
7988 "user", "system", LYS_USERORDERED, LYS_USERORDERED, 0, unres)) {
7989 goto error;
7990 }
7991 } else if (!strcmp(node->name, "belongs-to")) {
7992 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_BELONGSTO, 0, "module", unres)) {
7993 goto error;
7994 }
7995 } else if (!strcmp(node->name, "contact")) {
7996 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_CONTACT, 1, "text", unres)) {
7997 goto error;
7998 }
7999 } else if (!strcmp(node->name, "organization")) {
8000 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ORGANIZATION, 1, "text", unres)) {
8001 goto error;
8002 }
8003 } else if (!strcmp(node->name, "path")) {
8004 if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PATH, 0, "value", unres)) {
8005 goto error;
8006 }
8007 } else if (!strcmp(node->name, "require-instance")) {
8008 if (yin_parse_extcomplex_bool(mod, node, ext, LY_STMT_REQINSTANCE, "true", "false", unres)) {
8009 goto error;
8010 }
8011 } else if (!strcmp(node->name, "modifier")) {
8012 if (yin_parse_extcomplex_bool(mod, node, ext, LY_STMT_MODIFIER, "invert-match", NULL, unres)) {
8013 goto error;
8014 }
8015 } else if (!strcmp(node->name, "fraction-digits")) {
8016 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_DIGITS, uint8_t);
8017
8018 GETVAL(mod->ctx, value, node, "value");
8019 v = strtol(value, NULL, 10);
8020
8021 /* range check */
8022 if (v < 1 || v > 18) {
8023 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
8024 goto error;
8025 }
8026
8027 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_STATUS, i, unres)) {
8028 goto error;
8029 }
8030
8031 /* store the value */
8032 (*(uint8_t *)p) = (uint8_t)v;
8033
8034 YIN_EXTCOMPLEX_ENLARGE(uint8_t);
8035 } else if (!strcmp(node->name, "max-elements")) {
8036 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_MAX, uint32_t*);
8037
8038 GETVAL(mod->ctx, value, node, "value");
8039 while (isspace(value[0])) {
8040 value++;
8041 }
8042
8043 if (!strcmp(value, "unbounded")) {
8044 u = 0;
8045 } else {
8046 /* convert it to uint32_t */
8047 errno = 0; endptr = NULL;
8048 u = strtoul(value, &endptr, 10);
8049 if (*endptr || value[0] == '-' || errno || u == 0 || u > UINT32_MAX) {
8050 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
8051 goto error;
8052 }
8053 }
8054
8055 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_MAX, i, unres)) {
8056 goto error;
8057 }
8058
8059 /* store the value */
8060 YIN_STORE_VALUE(uint32_t, u, p)
8061
8062 YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
8063 } else if (!strcmp(node->name, "min-elements")) {
8064 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_MIN, uint32_t*);
8065
8066 GETVAL(mod->ctx, value, node, "value");
8067 while (isspace(value[0])) {
8068 value++;
8069 }
8070
8071 /* convert it to uint32_t */
8072 errno = 0;
8073 endptr = NULL;
8074 u = strtoul(value, &endptr, 10);
8075 if (*endptr || value[0] == '-' || errno || u > UINT32_MAX) {
8076 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
8077 goto error;
8078 }
8079
8080 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_MAX, i, unres)) {
8081 goto error;
8082 }
8083
8084 /* store the value */
8085 YIN_STORE_VALUE(uint32_t, u, p)
8086
8087 YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
8088 } else if (!strcmp(node->name, "value")) {
8089 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_VALUE, int32_t*);
8090
8091 GETVAL(mod->ctx, value, node, "value");
8092 while (isspace(value[0])) {
8093 value++;
8094 }
8095
8096 /* convert it to int32_t */
8097 ll = strtoll(value, NULL, 10);
8098
8099 /* range check */
8100 if (ll < INT32_MIN || ll > INT32_MAX) {
8101 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
8102 goto error;
8103 }
8104
8105 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_VALUE, i, unres)) {
8106 goto error;
8107 }
8108
8109 /* store the value */
8110 YIN_STORE_VALUE(int32_t, ll, p)
8111
8112 YIN_EXTCOMPLEX_ENLARGE(int32_t*);
8113 } else if (!strcmp(node->name, "position")) {
8114 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_POSITION, uint32_t*);
8115
8116 GETVAL(mod->ctx, value, node, "value");
8117 ll = strtoll(value, NULL, 10);
8118
8119 /* range check */
8120 if (ll < 0 || ll > UINT32_MAX) {
8121 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
8122 goto error;
8123 }
8124
8125 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_POSITION, i, unres)) {
8126 goto error;
8127 }
8128
8129 /* store the value */
8130 YIN_STORE_VALUE(uint32_t, ll, p)
8131
8132 YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
8133 } else if (!strcmp(node->name, "module")) {
8134 pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_MODULE);
8135 if (!pp) {
8136 goto error;
8137 }
8138
8139 *(struct lys_module **)pp = yin_read_module_(mod->ctx, node, NULL, mod->implemented);
8140 if (!(*pp)) {
8141 goto error;
8142 }
8143 } else if (!strcmp(node->name, "when")) {
8144 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_WHEN, struct lys_when*);
8145
8146 *(struct lys_when**)p = read_yin_when(mod, node, unres);
8147 if (!*(struct lys_when**)p) {
8148 goto error;
8149 }
8150
8151 YIN_EXTCOMPLEX_ENLARGE(struct lys_when*);
8152 } else if (!strcmp(node->name, "revision")) {
8153 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_REVISION, struct lys_revision*);
8154
8155 *(struct lys_revision**)p = calloc(1, sizeof(struct lys_revision));
8156 LY_CHECK_ERR_GOTO(!*(struct lys_revision**)p, LOGMEM(mod->ctx), error);
8157 if (fill_yin_revision(mod, node, *(struct lys_revision**)p, unres)) {
8158 goto error;
8159 }
8160
8161 /* check uniqueness of the revision dates - not required by RFC */
8162 if (pp) {
8163 for (j = 0; j < i; j++) {
8164 if (!strcmp((*(struct lys_revision***)pp)[j]->date, (*(struct lys_revision**)p)->date)) {
8165 LOGWRN(mod->ctx, "Module's revisions are not unique (%s).", (*(struct lys_revision**)p)->date);
8166 }
8167 }
8168 }
8169
8170 YIN_EXTCOMPLEX_ENLARGE(struct lys_revision*);
8171 } else if (!strcmp(node->name, "unique")) {
8172 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_UNIQUE, struct lys_unique*);
8173
8174 *(struct lys_unique**)p = calloc(1, sizeof(struct lys_unique));
8175 LY_CHECK_ERR_GOTO(!*(struct lys_unique**)p, LOGMEM(mod->ctx), error);
8176 if (fill_yin_unique(mod, (struct lys_node*)ext, node, *(struct lys_unique**)p, unres)) {
8177 goto error;
8178 }
8179
8180 if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_UNIQUE, i, unres)) {
8181 goto error;
8182 }
8183 YIN_EXTCOMPLEX_ENLARGE(struct lys_unique*);
8184 } else if (!strcmp(node->name, "action")) {
8185 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ACTION, read_yin_rpc_action);
8186 } else if (!strcmp(node->name, "anydata")) {
8187 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ANYDATA, read_yin_anydata, LYS_ANYDATA);
8188 } else if (!strcmp(node->name, "anyxml")) {
8189 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ANYXML, read_yin_anydata, LYS_ANYXML);
8190 } else if (!strcmp(node->name, "case")) {
8191 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CASE, read_yin_case);
8192 } else if (!strcmp(node->name, "choice")) {
8193 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CHOICE, read_yin_choice);
8194 } else if (!strcmp(node->name, "container")) {
8195 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CONTAINER, read_yin_container);
8196 } else if (!strcmp(node->name, "grouping")) {
8197 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_GROUPING, read_yin_grouping);
8198 } else if (!strcmp(node->name, "output")) {
8199 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_OUTPUT, read_yin_input_output);
8200 } else if (!strcmp(node->name, "input")) {
8201 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_INPUT, read_yin_input_output);
8202 } else if (!strcmp(node->name, "leaf")) {
8203 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LEAF, read_yin_leaf);
8204 } else if (!strcmp(node->name, "leaf-list")) {
8205 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LEAFLIST, read_yin_leaflist);
8206 } else if (!strcmp(node->name, "list")) {
8207 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LIST, read_yin_list);
8208 } else if (!strcmp(node->name, "notification")) {
8209 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_NOTIFICATION, read_yin_notif);
8210 } else if (!strcmp(node->name, "uses")) {
8211 YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_USES, read_yin_uses);
8212 } else if (!strcmp(node->name, "length")) {
8213 YIN_EXTCOMPLEX_PARSE_RESTR(LY_STMT_LENGTH);
8214 } else if (!strcmp(node->name, "must")) {
8215 pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_MUST);
8216 if (!pp) {
8217 goto error;
8218 }
8219 /* allocate structure for must */
8220 (*pp) = calloc(1, sizeof(struct lys_restr));
8221 LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);
8222
8223 if (fill_yin_must(mod, node, *((struct lys_restr **)pp), unres)) {
8224 goto error;
8225 }
8226 } else if (!strcmp(node->name, "pattern")) {
8227 YIN_EXTCOMPLEX_GETPLACE(LY_STMT_PATTERN, struct lys_restr*);
8228 GETVAL(mod->ctx, value, node, "value");
8229 if (lyp_check_pattern(mod->ctx, value, NULL)) {
8230 goto error;
8231 }
8232
8233 *(struct lys_restr **)p = calloc(1, sizeof(struct lys_restr));
8234 LY_CHECK_ERR_GOTO(!*(struct lys_restr **)p, LOGMEM(mod->ctx), error);
8235
8236 modifier = 0x06; /* ACK */
8237 if (mod->version >= 2) {
8238 name = NULL;
8239 LY_TREE_FOR(node->child, child) {
8240 if (child->ns && !strcmp(child->ns->value, LY_NSYIN) && !strcmp(child->name, "modifier")) {
8241 if (name) {
8242 LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "modifier", node->name);
8243 goto error;
8244 }
8245
8246 GETVAL(mod->ctx, name, child, "value");
8247 if (!strcmp(name, "invert-match")) {
8248 modifier = 0x15; /* NACK */
8249 } else {
8250 LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, name, "modifier");
8251 goto error;
8252 }
8253 /* get extensions of the modifier */
8254 if (lyp_yin_parse_subnode_ext(mod, *(struct lys_restr **)p, LYEXT_PAR_RESTR, child,
8255 LYEXT_SUBSTMT_MODIFIER, 0, unres)) {
8256 goto error;
8257 }
8258 }
8259 }
8260 }
8261
8262 /* store the value: modifier byte + value + terminating NULL byte */
8263 (*(struct lys_restr **)p)->expr = malloc((strlen(value) + 2) * sizeof(char));
8264 LY_CHECK_ERR_GOTO(!(*(struct lys_restr **)p)->expr, LOGMEM(mod->ctx), error);
8265 ((char *)(*(struct lys_restr **)p)->expr)[0] = modifier;
8266 strcpy(&((char *)(*(struct lys_restr **)p)->expr)[1], value);
8267 lydict_insert_zc(mod->ctx, (char *)(*(struct lys_restr **)p)->expr);
8268
8269 /* get possible sub-statements */
8270 if (read_restr_substmt(mod, *(struct lys_restr **)p, node, unres)) {
8271 goto error;
8272 }
8273
8274 YIN_EXTCOMPLEX_ENLARGE(struct lys_restr*);
8275 } else if (!strcmp(node->name, "range")) {
8276 YIN_EXTCOMPLEX_PARSE_RESTR(LY_STMT_RANGE);
8277 } else {
8278 LOGERR(mod->ctx, ly_errno, "Extension's substatement \"%s\" not supported.", node->name);
8279 }
8280 lyxml_free(mod->ctx, node);
8281 }
8282
8283 if (ext->substmt && lyp_mand_check_ext(ext, yin->name)) {
8284 return EXIT_FAILURE;
8285 }
8286
8287 return EXIT_SUCCESS;
8288
8289 error:
8290 return EXIT_FAILURE;
8291 }
8292