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, &notif->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, &notif->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, &notif->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