blob: 05b226de928cc421cda8e28cdc95051c15a0fcfd [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file yin.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief YIN parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Radek Krejci812b10a2015-05-28 16:48:25 +020022#include <assert.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020023#include <ctype.h>
Radek Krejci8b4f23c2015-06-02 16:09:25 +020024#include <errno.h>
25#include <limits.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020026#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020027#include <stdlib.h>
28#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020029#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020030
Radek Krejciefdd0ce2015-05-26 16:48:29 +020031#include "../libyang.h"
32#include "../common.h"
33#include "../context.h"
34#include "../dict.h"
35#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020036
Radek Krejciefdd0ce2015-05-26 16:48:29 +020037#include "../tree_internal.h"
38#include "../xml.h"
39
Radek Krejcice7fb782015-05-29 16:52:34 +020040enum LY_IDENT {
Radek Krejci994b6f62015-06-18 16:47:27 +020041 LY_IDENT_SIMPLE, /* only syntax rules */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020042 LY_IDENT_FEATURE,
43 LY_IDENT_IDENTITY,
44 LY_IDENT_TYPE,
45 LY_IDENT_NODE,
Radek Krejci994b6f62015-06-18 16:47:27 +020046 LY_IDENT_NAME, /* uniqueness across the siblings */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020047 LY_IDENT_PREFIX
Radek Krejcice7fb782015-05-29 16:52:34 +020048};
49
Radek Krejciefdd0ce2015-05-26 16:48:29 +020050#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020051
Radek Krejcice7fb782015-05-29 16:52:34 +020052#define GETVAL(value, node, arg) \
53 value = lyxml_get_attr(node, arg, NULL); \
54 if (!value) { \
55 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
56 goto error; \
57 }
58
Radek Krejcib388c152015-06-04 17:03:03 +020059#define OPT_IDENT 0x01
60#define OPT_CONFIG 0x02
61#define OPT_MODULE 0x04
62#define OPT_INHERIT 0x08
63static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
64
Radek Krejci8de7b0f2015-07-02 11:43:42 +020065struct obj_list {
66 void *obj;
67 struct obj_list *next;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020068 unsigned int line;
Radek Krejci74705112015-06-05 10:25:44 +020069};
70
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020071static struct ly_mnode *read_yin_choice(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020072 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020073static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020074 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020075static struct ly_mnode *read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
76 int resolve);
77static struct ly_mnode *read_yin_container(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020078 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020079static struct ly_mnode *read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
80 int resolve);
81static struct ly_mnode *read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
82 int resolve);
83static struct ly_mnode *read_yin_list(struct ly_module *module,struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020084 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020085static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020086 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020087static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020088 int resolve, struct obj_list **unres);
Radek Krejcib0af6ba2015-06-18 15:01:03 +020089static struct ly_when *read_yin_when(struct ly_module *module,struct lyxml_elem *yin);
Radek Krejci74705112015-06-05 10:25:44 +020090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091static int
92dup_typedef_check(const char *type, struct ly_tpdf *tpdf, int size)
Radek Krejcieac35532015-05-31 19:09:15 +020093{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020095
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020096 for (i = 0; i < size; i++) {
97 if (!strcmp(type, tpdf[i].name)) {
98 /* name collision */
99 return EXIT_FAILURE;
100 }
101 }
Radek Krejcieac35532015-05-31 19:09:15 +0200102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200104}
105
Radek Krejcib05774c2015-06-18 13:52:59 +0200106
107static int
108dup_feature_check(const char *id, struct ly_module *module)
109{
110 int i;
111
112 for (i = 0; i < module->features_size; i++) {
113 if (!strcmp(id, module->features[i].name)) {
114 return EXIT_FAILURE;
115 }
116 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +0200117
118 return EXIT_SUCCESS;
Radek Krejcib05774c2015-06-18 13:52:59 +0200119}
120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200121static int
122dup_prefix_check(const char *prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200123{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200124 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
127 return EXIT_FAILURE;
128 }
129 for (i = 0; i < module->imp_size; i++) {
130 if (!strcmp(module->imp[i].prefix, prefix)) {
131 return EXIT_FAILURE;
132 }
133 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200134
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200135 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200136}
137
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200138static int
139check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
140 struct ly_module *module, struct ly_mnode *parent)
Radek Krejcice7fb782015-05-29 16:52:34 +0200141{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200142 int i;
143 int size;
144 struct ly_tpdf *tpdf;
145 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200147 assert(id);
Radek Krejcice7fb782015-05-29 16:52:34 +0200148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200149 /* check id syntax */
150 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
151 LOGVAL(VE_INID, line, id, "invalid start character");
152 return EXIT_FAILURE;
153 }
154 for (i = 1; id[i]; i++) {
155 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
156 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
157 LOGVAL(VE_INID, line, id, "invalid character");
158 return EXIT_FAILURE;
159 }
160 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200162 if (i > 64) {
163 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
164 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 switch (type) {
167 case LY_IDENT_NAME:
168 /* check uniqueness of the node within its siblings */
169 if (!parent) {
170 break;
171 }
Radek Krejcib4cf2022015-06-03 14:40:05 +0200172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200173 LY_TREE_FOR(parent->child, mnode) {
174 if (mnode->name == id) {
175 LOGVAL(VE_INID, line, id, "name duplication");
176 return EXIT_FAILURE;
177 }
178 }
179 break;
180 case LY_IDENT_TYPE:
181 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200183 /* check collision with the built-in types */
184 if (!strcmp(id, "binary") || !strcmp(id, "bits") ||
185 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
186 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
187 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
188 !strcmp(id, "int8") || !strcmp(id, "int16") ||
189 !strcmp(id, "int32") || !strcmp(id, "int64") ||
190 !strcmp(id, "leafref") || !strcmp(id, "string") ||
191 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
192 !strcmp(id, "uint32") || !strcmp(id, "uint64") || !strcmp(id, "union")) {
193 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
194 return EXIT_FAILURE;
195 }
Radek Krejcieac35532015-05-31 19:09:15 +0200196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200197 /* check locally scoped typedefs (avoid name shadowing) */
198 for (; parent; parent = parent->parent) {
199 switch (parent->nodetype) {
200 case LY_NODE_CONTAINER:
201 size = ((struct ly_mnode_container *)parent)->tpdf_size;
202 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
203 break;
204 case LY_NODE_LIST:
205 size = ((struct ly_mnode_list *)parent)->tpdf_size;
206 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
207 break;
208 case LY_NODE_GROUPING:
209 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
210 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
211 break;
212 default:
213 continue;
214 }
Radek Krejcieac35532015-05-31 19:09:15 +0200215
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200216 if (dup_typedef_check(id, tpdf, size)) {
217 LOGVAL(VE_DUPID, line, "typedef", id);
218 return EXIT_FAILURE;
219 }
220 }
Radek Krejcieac35532015-05-31 19:09:15 +0200221
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200222 /* check top-level names */
223 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
224 LOGVAL(VE_DUPID, line, "typedef", id);
225 return EXIT_FAILURE;
226 }
Radek Krejcieac35532015-05-31 19:09:15 +0200227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200228 /* check submodule's top-level names */
229 for (i = 0; i < module->inc_size; i++) {
230 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
231 LOGVAL(VE_DUPID, line, "typedef", id);
232 return EXIT_FAILURE;
233 }
234 }
Radek Krejcieac35532015-05-31 19:09:15 +0200235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200236 /* check top-level names in the main module */
237 if (module->type) {
238 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
239 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
240 LOGVAL(VE_DUPID, line, "typedef", id);
241 return EXIT_FAILURE;
242 }
243 }
Radek Krejcieac35532015-05-31 19:09:15 +0200244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200245 break;
246 case LY_IDENT_PREFIX:
247 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200249 if (module->type) {
250 /* go to the main module */
251 module = ((struct ly_submodule *)module)->belongsto;
252 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200253
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200254 /* check the main module itself */
255 if (dup_prefix_check(id, module)) {
256 LOGVAL(VE_DUPID, line, "prefix", id);
257 return EXIT_FAILURE;
258 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200260 /* and all its submodules */
261 for (i = 0; i < module->inc_size; i++) {
262 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
263 LOGVAL(VE_DUPID, line, "prefix", id);
264 return EXIT_FAILURE;
265 }
266 }
267 break;
Radek Krejcib05774c2015-06-18 13:52:59 +0200268 case LY_IDENT_FEATURE:
269 assert(module);
270
271 /* check feature name uniqness*/
Radek Krejci49babf32015-06-18 13:56:17 +0200272 /* check features in the current module */
Radek Krejcib05774c2015-06-18 13:52:59 +0200273 if (dup_feature_check(id, module)) {
274 LOGVAL(VE_DUPID, line, "feature", id);
275 return EXIT_FAILURE;
276 }
277
278 /* and all its submodules */
279 for (i = 0; i < module->inc_size; i++) {
280 if (dup_feature_check(id, (struct ly_module *)module->inc[i].submodule)) {
281 LOGVAL(VE_DUPID, line, "feature", id);
282 return EXIT_FAILURE;
283 }
284 }
285 break;
286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200287 default:
288 /* no check required */
289 break;
290 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200292 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200293}
294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200295static int
296check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
297 const char *name, int len)
Radek Krejci345ad742015-06-03 11:04:18 +0200298{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200299 char *dup = NULL;
300 int j;
Radek Krejci345ad742015-06-03 11:04:18 +0200301
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200302 /* existence */
303 if (!key) {
304 if (name[len] != '\0') {
305 dup = strdup(name);
306 dup[len] = '\0';
307 name = dup;
308 }
309 LOGVAL(VE_KEY_MISS, line, name);
310 free(dup);
311 return EXIT_FAILURE;
312 }
Radek Krejci345ad742015-06-03 11:04:18 +0200313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200314 /* uniqueness */
315 for (j = index - 1; j >= 0; j--) {
316 if (list[index] == list[j]) {
317 LOGVAL(VE_KEY_DUP, line, key->name);
318 return EXIT_FAILURE;
319 }
320 }
Radek Krejci345ad742015-06-03 11:04:18 +0200321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200322 /* key is a leaf */
323 if (key->nodetype != LY_NODE_LEAF) {
324 LOGVAL(VE_KEY_NLEAF, line, key->name);
325 return EXIT_FAILURE;
326 }
Radek Krejci345ad742015-06-03 11:04:18 +0200327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200328 /* type of the leaf is not built-in empty */
329 if (key->type.base == LY_TYPE_EMPTY) {
330 LOGVAL(VE_KEY_TYPE, line, key->name);
331 return EXIT_FAILURE;
332 }
Radek Krejci345ad742015-06-03 11:04:18 +0200333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200334 /* config attribute is the same as of the list */
335 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
336 LOGVAL(VE_KEY_CONFIG, line, key->name);
337 return EXIT_FAILURE;
338 }
Radek Krejci345ad742015-06-03 11:04:18 +0200339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200340 return EXIT_SUCCESS;
Radek Krejci345ad742015-06-03 11:04:18 +0200341}
342
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200343static int
Radek Krejci3de29a72015-06-16 15:23:03 +0200344check_mandatory(struct ly_mnode *mnode)
345{
346 struct ly_mnode *child;
347
348 assert(mnode);
349
350 if (mnode->flags & LY_NODE_MAND_TRUE) {
351 return EXIT_FAILURE;
352 }
353
Radek Krejcifd0bb0a2015-06-18 13:18:24 +0200354 if (mnode->nodetype == LY_NODE_CASE || mnode->nodetype == LY_NODE_CHOICE) {
355 LY_TREE_FOR(mnode->child, child) {
356 if (check_mandatory(child)) {
357 return EXIT_FAILURE;
358 }
Radek Krejci3de29a72015-06-16 15:23:03 +0200359 }
360 }
361
362 return EXIT_SUCCESS;
363}
364
365static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200366check_default(struct ly_type *type, const char *value)
Radek Krejcieac35532015-05-31 19:09:15 +0200367{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200368 /* TODO - RFC 6020, sec. 7.3.4 */
369 (void)type;
370 (void)value;
371 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200372}
373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200374static int
375check_date(const char *date, unsigned int line)
Radek Krejcice7fb782015-05-29 16:52:34 +0200376{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200377 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200378
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200379 assert(date);
Radek Krejcice7fb782015-05-29 16:52:34 +0200380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200381 if (strlen(date) != LY_REV_SIZE - 1) {
382 goto error;
383 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200385 for (i = 0; i < LY_REV_SIZE - 1; i++) {
386 if (i == 4 || i == 7) {
387 if (date[i] != '-') {
388 goto error;
389 }
390 } else if (!isdigit(date[i])) {
391 goto error;
392 }
393 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200394
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200395 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200396
397error:
398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200399 LOGVAL(VE_INDATE, line, date);
400 return EXIT_FAILURE;
Radek Krejcice7fb782015-05-29 16:52:34 +0200401}
402
Radek Krejci41726f92015-06-19 13:11:05 +0200403static int
404check_length(const char *expr, struct ly_type *type, unsigned int line)
405{
406 const char *c = expr;
407 char *tail;
408 uint64_t limit = 0, n;
409 int flg = 1; /* first run flag */
410
411 assert(expr);
412
413 /* TODO check compatibility with the restriction defined on type from which this type is derived,
414 * it will be the same function to check that the value from instance data respect the restriction */
415 (void)type;
416
417lengthpart:
418
419 while (isspace(*c)) {
420 c++;
421 }
422
423 /* lower boundary or explicit number */
424 if (!strncmp(c, "max", 3)) {
425max:
426 c += 3;
427 while (isspace(*c)) {
428 c++;
429 }
430 if (*c != '\0') {
431 goto error;
432 }
433
434 return EXIT_SUCCESS;
435
436 } else if (!strncmp(c, "min", 3)) {
437 if (!flg) {
438 /* min cannot be used elsewhere than in the first length-part */
439 goto error;
440 } else {
441 flg = 0;
442 /* remember value/lower boundary */
443 limit = 0;
444 }
445 c += 3;
446 while (isspace(*c)) {
447 c++;
448 }
449
450 if (*c == '|') {
451 c++;
452 /* process next length-parth */
453 goto lengthpart;
454 } else if (*c == '\0') {
455 return EXIT_SUCCESS;
456 } else if (!strncmp(c, "..", 2)) {
457upper:
458 c += 2;
459 while (isspace(*c)) {
460 c++;
461 }
462 if (*c == '\0') {
463 goto error;
464 }
465
466 /* upper boundary */
467 if (!strncmp(c, "max", 3)) {
468 goto max;
469 }
470
471 if (!isdigit(*c)) {
472 goto error;
473 }
474
475 n = strtol(c, &tail, 10);
476 c = tail;
477 while (isspace(*c)) {
478 c++;
479 }
480 if (n <= limit) {
481 goto error;
482 }
483 if (*c == '\0') {
484 return EXIT_SUCCESS;
485 } else if (*c == '|') {
486 c++;
487 /* remember the uppre boundary for check in next part */
488 limit = n;
489 /* process next length-parth */
490 goto lengthpart;
491 } else {
492 goto error;
493 }
494 } else {
495 goto error;
496 }
497
498 } else if (isdigit(*c)) {
499 /* number */
500 n = strtol(c, &tail, 10);
501 c = tail;
502 while (isspace(*c)) {
503 c++;
504 }
505 /* skip limit check in first length-part check */
506 if (!flg && n <= limit) {
507 goto error;
508 }
509 flg = 0;
510 limit = n;
511
512 if (*c == '|') {
513 c++;
514 /* process next length-parth */
515 goto lengthpart;
516 } else if (*c == '\0') {
517 return EXIT_SUCCESS;
518 } else if (!strncmp(c, "..", 2)) {
519 goto upper;
520 }
521 } /* else error */
522
523error:
524
525 LOGVAL(VE_INARG, line, expr, "length");
526 return EXIT_FAILURE;
527}
528
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200529static const char *
530read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200531{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200532 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200534 /* there should be <text> child */
535 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
536 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
537 } else if (node->child->content) {
538 len = strlen(node->child->content);
539 return lydict_insert(ctx, node->child->content, len);
540 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200542 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
543 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200544}
545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200546static struct ly_tpdf *
547find_superior_type(const char *name, struct ly_module *module, struct ly_mnode *parent)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200548{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200549 int i, j, found = 0;
550 int prefix_len = 0;
551 const char *qname;
552 struct ly_tpdf *tpdf;
553 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200555 qname = strchr(name, ':');
Radek Krejcida04f4a2015-05-21 12:54:09 +0200556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200557 if (!qname) {
558 /* no prefix, try built-in types */
559 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
560 if (!strcmp(ly_types[i].def->name, name)) {
561 return ly_types[i].def;
562 }
563 }
564 qname = name;
565 } else {
566 /* set qname to correct position after colon */
567 prefix_len = qname - name;
568 qname++;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200570 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
571 /* prefix refers to the current module, ignore it */
572 prefix_len = 0;
573 }
574 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200576 if (!prefix_len && parent) {
577 /* search in local typedefs */
578 while (parent) {
579 switch (parent->nodetype) {
580 case LY_NODE_CONTAINER:
581 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
582 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
583 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200584
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200585 case LY_NODE_LIST:
586 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
587 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
588 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200589
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200590 case LY_NODE_GROUPING:
591 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
592 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
593 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200594
Radek Krejci3cf9e222015-06-18 11:37:50 +0200595 /* TODO add rpc, notification, input, output */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200596 default:
597 parent = parent->parent;
598 continue;
599 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200601 for (i = 0; i < tpdf_size; i++) {
602 if (!strcmp(tpdf[i].name, qname)) {
603 return &tpdf[i];
604 }
605 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200607 parent = parent->parent;
608 }
609 } else if (prefix_len) {
610 /* get module where to search */
611 for (i = 0; i < module->imp_size; i++) {
612 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
613 module = module->imp[i].module;
614 found = 1;
615 break;
616 }
617 }
618 if (!found) {
619 return NULL;
620 }
621 }
622
623 /* search in top level typedefs */
624 for (i = 0; i < module->tpdf_size; i++) {
625 if (!strcmp(module->tpdf[i].name, qname)) {
626 return &module->tpdf[i];
627 }
628 }
629
630 /* search in submodules */
631 for (i = 0; i < module->inc_size; i++) {
632 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
633 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
634 return &module->inc[i].submodule->tpdf[j];
635 }
636 }
637 }
638
639 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200640}
641
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200642static struct ly_ident *
643find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
Radek Krejciefaeba32015-05-27 14:30:57 +0200644{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200645 unsigned int i;
646 struct ly_ident *base_iter;
647 struct ly_ident_der *der;
Radek Krejciefaeba32015-05-27 14:30:57 +0200648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200649 for (i = 0; i < module->ident_size; i++) {
650 if (!strcmp(basename, module->ident[i].name)) {
651 /* we are done */
Radek Krejciefaeba32015-05-27 14:30:57 +0200652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200653 if (!ident) {
654 /* just search for type, so do not modify anything, just return
655 * the base identity pointer
656 */
657 return &module->ident[i];
658 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200660 /* we are resolving identity definition, so now update structures */
661 ident->base = base_iter = &module->ident[i];
Radek Krejciefaeba32015-05-27 14:30:57 +0200662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200663 while (base_iter) {
664 for (der = base_iter->der; der && der->next; der = der->next);
665 if (der) {
666 der->next = malloc(sizeof *der);
667 der = der->next;
668 } else {
669 ident->base->der = der = malloc(sizeof *der);
670 }
671 der->next = NULL;
672 der->ident = ident;
Radek Krejciefaeba32015-05-27 14:30:57 +0200673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200674 base_iter = base_iter->base;
675 }
676 return ident->base;
677 }
678 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200679
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200680 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200681}
682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200683static struct ly_ident *
684find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200685{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200686 const char *name;
687 int prefix_len = 0;
688 int i, found = 0;
689 struct ly_ident *result;
690 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200692 basename = lyxml_get_attr(node, "name", NULL);
693 if (!basename) {
694 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
695 return NULL;
696 }
Radek Krejci04581c62015-05-22 21:24:00 +0200697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200698 /* search for the base identity */
699 name = strchr(basename, ':');
700 if (name) {
701 /* set name to correct position after colon */
702 prefix_len = name - basename;
703 name++;
Radek Krejci04581c62015-05-22 21:24:00 +0200704
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200705 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
706 /* prefix refers to the current module, ignore it */
707 prefix_len = 0;
708 }
709 } else {
710 name = basename;
711 }
Radek Krejci04581c62015-05-22 21:24:00 +0200712
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200713 if (prefix_len) {
714 /* get module where to search */
715 for (i = 0; i < module->imp_size; i++) {
716 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
717 && !module->imp[i].prefix[prefix_len]) {
718 module = module->imp[i].module;
719 found = 1;
720 break;
721 }
722 }
723 if (!found) {
724 /* identity refers unknown data model */
725 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
726 return NULL;
727 }
728 } else {
729 /* search in submodules */
730 for (i = 0; i < module->inc_size; i++) {
731 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
732 if (result) {
733 return result;
734 }
735 }
736 }
Radek Krejci04581c62015-05-22 21:24:00 +0200737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200738 /* search in the identified module */
739 result = find_base_ident_sub(module, ident, name);
740 if (!result) {
741 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
742 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200743
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200744 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200745}
746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200747static int
748fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
Radek Krejci04581c62015-05-22 21:24:00 +0200749{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200750 struct lyxml_elem *node, *next;
Radek Krejci04581c62015-05-22 21:24:00 +0200751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200752 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
753 return EXIT_FAILURE;
754 }
Radek Krejci04581c62015-05-22 21:24:00 +0200755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200756 LY_TREE_FOR_SAFE(yin->child, next, node) {
757 if (!strcmp(node->name, "base")) {
758 if (ident->base) {
759 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
760 return EXIT_FAILURE;
761 }
762 if (!find_base_ident(module, ident, node)) {
763 return EXIT_FAILURE;
764 }
765 } else {
766 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
767 return EXIT_FAILURE;
768 }
Radek Krejci04581c62015-05-22 21:24:00 +0200769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200770 lyxml_free_elem(module->ctx, node);
771 }
Radek Krejci04581c62015-05-22 21:24:00 +0200772
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200773 return EXIT_SUCCESS;
Radek Krejci04581c62015-05-22 21:24:00 +0200774}
775
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200776static int
Radek Krejci0bd5db42015-06-19 13:30:07 +0200777read_restr_substmt(struct ly_ctx *ctx, struct ly_restr *restr, struct lyxml_elem *yin)
Radek Krejci41726f92015-06-19 13:11:05 +0200778{
779 struct lyxml_elem *next, *child;
Radek Krejci461d1622015-06-30 14:06:28 +0200780 const char *value;
Radek Krejci41726f92015-06-19 13:11:05 +0200781
782 LY_TREE_FOR_SAFE(yin->child, next, child) {
783 if (!strcmp(child->name, "description")) {
784 if (restr->dsc) {
785 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
786 return EXIT_FAILURE;
787 }
788 restr->dsc = read_yin_subnode(ctx, child, "text");
789 if (!restr->dsc) {
790 return EXIT_FAILURE;
791 }
792 } else if (!strcmp(child->name, "reference")) {
793 if (restr->ref) {
794 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
795 return EXIT_FAILURE;
796 }
797 restr->ref = read_yin_subnode(ctx, child, "text");
798 if (!restr->ref) {
799 return EXIT_FAILURE;
800 }
801 } else if (!strcmp(child->name, "error-app-tag")) {
802 if (restr->eapptag) {
803 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
804 return EXIT_FAILURE;
805 }
Radek Krejci461d1622015-06-30 14:06:28 +0200806 GETVAL(value, yin, "value");
807 restr->eapptag = lydict_insert(ctx, value, 0);
Radek Krejci41726f92015-06-19 13:11:05 +0200808 } else if (!strcmp(child->name, "error-message")) {
809 if (restr->emsg) {
810 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
811 return EXIT_FAILURE;
812 }
813 restr->emsg = read_yin_subnode(ctx, child, "value");
814 if (!restr->emsg) {
815 return EXIT_FAILURE;
816 }
817 } else {
818 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
819 return EXIT_FAILURE;
820 }
821
822 lyxml_free_elem(ctx, child);
823 }
824
825 return EXIT_SUCCESS;
Michal Vaskoc8ef47f2015-06-29 14:56:19 +0200826
827error:
828 return EXIT_FAILURE;
Radek Krejci41726f92015-06-19 13:11:05 +0200829}
830
831static int
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200832fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200833{
Radek Krejcif2860132015-06-20 12:37:20 +0200834 const char *value, *delim, *name;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200835 struct lyxml_elem *next, *node;
Radek Krejcif2860132015-06-20 12:37:20 +0200836 struct ly_restr **restr;
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200837 struct obj_list *unres_new;
Radek Krejci994b6f62015-06-18 16:47:27 +0200838 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200839 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200840 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200841
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200842 GETVAL(value, yin, "name");
843
844 if (!type->prefix) {
845 /* if we are trying to resolve unresolved type,
846 * prefix is already stored
847 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200848 delim = strchr(value, ':');
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200849 if (delim) {
850 type->prefix = lydict_insert(module->ctx, value, delim - value);
851 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200852 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200853
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200854 type->der = find_superior_type(value, module, parent);
855 if (!type->der) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200856 if (unres) {
857 /* store it for later resolving */
858 LOGVRB("Unresolved type of \"%s\" (line %d), trying to resolve it later", value, LOGLINE(yin));
859 unres_new = calloc(1, sizeof *unres_new);
860 if (*unres) {
861 unres_new->next = *unres;
862 }
863 /* keep XML data for later processing */
864 type->der = (struct ly_tpdf *)lyxml_dup_elem(module->ctx, yin, NULL, 1);
865
866 unres_new->obj = type;
867 unres_new->line = LOGLINE(yin);
868
869 /* put it at the beginning of the unresolved list */
870 *unres = unres_new;
871 return EXIT_SUCCESS;
872 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200873 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
874 goto error;
875 }
876 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200877
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200878 switch (type->base) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200879 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200880 /* RFC 6020 9.7.4 - bit */
881
882 /* get bit specifications, at least one must be present */
883 LY_TREE_FOR_SAFE(yin->child, next, node) {
884 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200885 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200886 } else {
887 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
888 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200889 }
890 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200891 if (!type->info.bits.count) {
892 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +0200893 /* this is just a derived type with no bit specified/required */
Radek Krejci994b6f62015-06-18 16:47:27 +0200894 break;
895 }
896 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
897 goto error;
898 }
899
900 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200901 for (i = p = 0; yin->child; i++) {
902 GETVAL(value, yin->child, "name");
903 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200904 goto error;
905 }
906 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200907 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], yin->child, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200908 type->info.bits.count = i + 1;
909 goto error;
910 }
911
912 /* check the name uniqueness */
913 for (j = 0; j < i; j++) {
914 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200915 LOGVAL(VE_BITS_DUPNAME, LOGLINE(yin->child), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200916 type->info.bits.count = i + 1;
917 goto error;
918 }
919 }
920
Radek Krejci5fbc9162015-06-19 14:11:11 +0200921 node = yin->child->child;
Radek Krejci994b6f62015-06-18 16:47:27 +0200922 if (node && !strcmp(node->name, "position")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +0200923 GETVAL(value, node, "value");
Radek Krejci994b6f62015-06-18 16:47:27 +0200924 p_ = strtol(value, NULL, 10);
925
926 /* range check */
927 if (p_ < 0 || p_ > UINT32_MAX) {
928 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
929 type->info.bits.count = i + 1;
930 goto error;
931 }
932 type->info.bits.bit[i].pos = (uint32_t)p_;
933
934 /* keep the highest enum value for automatic increment */
935 if (type->info.bits.bit[i].pos > p) {
936 p = type->info.bits.bit[i].pos;
937 p++;
938 } else {
939 /* check that the value is unique */
940 for (j = 0; j < i; j++) {
941 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
942 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
943 type->info.bits.count = i + 1;
944 goto error;
945 }
946 }
947 }
948 } else {
949 /* assign value automatically */
950 if (p > UINT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200951 LOGVAL(VE_INARG, LOGLINE(yin->child), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +0200952 type->info.bits.count = i + 1;
953 goto error;
954 }
955 type->info.bits.bit[i].pos = (uint32_t)p;
956 p++;
957 }
Radek Krejci5fbc9162015-06-19 14:11:11 +0200958 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci994b6f62015-06-18 16:47:27 +0200959 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200960 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200961
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200962 case LY_TYPE_DEC64:
Radek Krejcif9401c32015-06-26 16:47:36 +0200963 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
964 LY_TREE_FOR_SAFE(yin->child, next, node) {
965 if (!strcmp(node->name, "range")) {
966 if (type->info.dec64.range) {
967 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
968 goto error;
969 }
970
971 GETVAL(value, node, "value");
972 if (check_length(value, type, LOGLINE(node))) {
973 goto error;
974 }
975 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
976 type->info.dec64.range->expr = lydict_insert(module->ctx, value, 0);
977
978 /* get possible substatements */
979 if (read_restr_substmt(module->ctx, type->info.dec64.range, node)) {
980 goto error;
981 }
982 } else if (!strcmp(node->name, "fraction-digits")) {
983 if (type->info.dec64.dig) {
984 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
985 goto error;
986 }
987 GETVAL(value, node, "value");
988 v = strtol(value, NULL, 10);
989
990 /* range check */
991 if (v < 1 || v > 18) {
992 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
993 goto error;
994 }
995 type->info.dec64.dig = (uint8_t)v;
996 } else {
997 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
998 goto error;
999 }
1000 lyxml_free_elem(module->ctx, node);
1001 }
1002
1003 /* mandatory sub-statement(s) check */
1004 if (!type->info.dec64.dig && !type->der->type.der) {
1005 /* decimal64 type directly derived from built-in type requires fraction-digits */
1006 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "fraction-digits", "type");
1007 goto error;
1008 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001009 break;
Radek Krejci25d782a2015-05-22 15:03:23 +02001010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001011 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +02001012 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +02001013
Radek Krejci994b6f62015-06-18 16:47:27 +02001014 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001015 LY_TREE_FOR_SAFE(yin->child, next, node) {
1016 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001017 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +02001018 } else {
1019 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1020 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001021 }
1022 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001023 if (!type->info.enums.count) {
1024 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001025 /* this is just a derived type with no enum specified/required */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001026 break;
1027 }
1028 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
1029 goto error;
1030 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001031
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001032 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +02001033 for (i = v = 0; yin->child; i++) {
1034 GETVAL(value, yin->child, "name");
1035 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001036 goto error;
1037 }
1038 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +02001039 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001040 type->info.enums.count = i + 1;
1041 goto error;
1042 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001043
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001044 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1045 value = type->info.enums.list[i].name;
1046 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001047 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001048 type->info.enums.count = i + 1;
1049 goto error;
1050 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001052 /* check the name uniqueness */
1053 for (j = 0; j < i; j++) {
1054 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001055 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001056 type->info.enums.count = i + 1;
1057 goto error;
1058 }
1059 }
Radek Krejci04581c62015-05-22 21:24:00 +02001060
Radek Krejci5fbc9162015-06-19 14:11:11 +02001061 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001062 if (node && !strcmp(node->name, "value")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +02001063 GETVAL(value, node, "value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001064 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001065
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001066 /* range check */
1067 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1068 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1069 type->info.enums.count = i + 1;
1070 goto error;
1071 }
1072 type->info.enums.list[i].value = v_;
1073
1074 /* keep the highest enum value for automatic increment */
1075 if (type->info.enums.list[i].value > v) {
1076 v = type->info.enums.list[i].value;
1077 v++;
1078 } else {
1079 /* check that the value is unique */
1080 for (j = 0; j < i; j++) {
1081 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001082 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value, type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001083 type->info.enums.count = i + 1;
1084 goto error;
1085 }
1086 }
1087 }
1088 } else {
1089 /* assign value automatically */
1090 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001091 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001092 type->info.enums.count = i + 1;
1093 goto error;
1094 }
1095 type->info.enums.list[i].value = v;
1096 v++;
1097 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001098 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001099 }
1100 break;
1101
1102 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001103 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001104
1105 /* get base specification, exactly one must be present */
1106 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001107 if (type->der->type.der) {
1108 /* this is just a derived type with no base specified/required */
1109 break;
1110 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001111 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1112 goto error;
1113 }
1114 if (strcmp(yin->child->name, "base")) {
1115 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1116 goto error;
1117 }
1118 if (yin->child->next) {
1119 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1120 goto error;
1121 }
1122 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1123 if (!type->info.ident.ref) {
1124 return EXIT_FAILURE;
1125 }
1126 break;
1127
1128 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001129 /* RFC 6020 9.13.2 - require-instance */
1130 LY_TREE_FOR_SAFE(yin->child, next, node) {
1131 if (!strcmp(node->name, "require-instance")) {
1132 if (type->info.inst.req) {
1133 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1134 goto error;
1135 }
1136 GETVAL(value, node, "value");
1137 if (strcmp(value, "true")) {
1138 type->info.inst.req = 1;
1139 } else if (strcmp(value, "false")) {
1140 type->info.inst.req = -1;
1141 } else {
1142 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1143 goto error;
1144 }
1145 } else {
1146 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1147 goto error;
1148 }
1149 lyxml_free_elem(module->ctx, node);
1150 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001151 break;
1152
Radek Krejcif2860132015-06-20 12:37:20 +02001153 case LY_TYPE_BINARY:
1154 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001155 case LY_TYPE_INT8:
1156 case LY_TYPE_INT16:
1157 case LY_TYPE_INT32:
1158 case LY_TYPE_INT64:
1159 case LY_TYPE_UINT8:
1160 case LY_TYPE_UINT16:
1161 case LY_TYPE_UINT32:
1162 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001163 /* RFC 6020 9.2.4 - range */
1164
1165 /* length and range are actually the same restriction, so process
1166 * them by this common code, we just need to differ the name and
1167 * structure where the information will be stored
1168 */
1169 if (type->base == LY_TYPE_BINARY) {
1170 restr = &type->info.binary.length;
1171 name = "length";
1172 } else {
1173 restr = &type->info.num.range;
1174 name = "range";
1175 }
1176
1177 LY_TREE_FOR_SAFE(yin->child, next, node) {
1178 if (!strcmp(node->name, name)) {
1179 if (*restr) {
1180 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1181 goto error;
1182 }
1183
1184 GETVAL(value, node, "value");
1185 if (check_length(value, type, LOGLINE(node))) {
1186 goto error;
1187 }
1188 *restr = calloc(1, sizeof **restr);
1189 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1190
1191 /* get possible substatements */
1192 if (read_restr_substmt(module->ctx, *restr, node)) {
1193 goto error;
1194 }
1195 } else {
1196 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1197 goto error;
1198 }
1199 lyxml_free_elem(module->ctx, node);
1200 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001201 break;
1202
1203 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001204 /* RFC 6020 9.9.2 - path */
1205 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001206 if (type->der->type.der) {
1207 /* this is just a derived type with no path specified/required */
1208 break;
1209 }
Radek Krejcidc4c1412015-06-19 15:39:54 +02001210 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1211 goto error;
1212 }
1213 LY_TREE_FOR_SAFE(yin->child, next, node) {
1214 if (!strcmp(node->name, "path")) {
1215 if (type->info.lref.path) {
1216 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1217 goto error;
1218 }
1219
1220 GETVAL(value, node, "value");
1221 /* TODO
1222 * it would be nice to perform here a check that target is leaf or leaf-list,
Radek Krejcic63c9b02015-06-26 16:51:31 +02001223 * but schema is not finished yet and path can point almost to anywhere, so
Radek Krejcidc4c1412015-06-19 15:39:54 +02001224 * we will have to check the path at the end of parsing the schema.
1225 */
1226 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1227 } else {
1228 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1229 goto error;
1230 }
1231 lyxml_free_elem(module->ctx, node);
1232 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001233 break;
1234
1235 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001236 /* RFC 6020 9.4.4 - length */
1237 /* RFC 6020 9.4.6 - pattern */
1238 LY_TREE_FOR_SAFE(yin->child, next, node) {
1239 if (!strcmp(node->name, "length")) {
1240 if (type->info.str.length) {
1241 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1242 goto error;
1243 }
1244
1245 GETVAL(value, node, "value");
1246 if (check_length(value, type, LOGLINE(node))) {
1247 goto error;
1248 }
1249 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1250 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1251
Radek Krejci5fbc9162015-06-19 14:11:11 +02001252 /* get possible sub-statements */
1253 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001254 goto error;
1255 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001256 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001257 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001258 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001259 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001260 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001261 goto error;
1262 }
1263 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001264 /* store patterns in array */
1265 if (type->info.str.pat_count) {
1266 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1267 for (i = 0; yin->child; i++) {
1268 GETVAL(value, yin->child, "value");
1269 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1270
1271 /* get possible sub-statements */
1272 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1273 goto error;
1274 }
1275 lyxml_free_elem(module->ctx, yin->child);
1276 }
1277 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001278 break;
1279
1280 case LY_TYPE_UNION:
Radek Krejcie4c366b2015-07-02 10:11:31 +02001281 /* RFC 6020 7.4 - type */
1282 /* count number of types in union */
1283 i = 0;
1284 LY_TREE_FOR(yin->child, node) {
1285 if (!strcmp(node->name, "type")) {
1286 i++;
1287 } else {
1288 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1289 goto error;
1290 }
1291 }
1292
1293 if (!i) {
1294 if (type->der->type.der) {
1295 /* this is just a derived type with no base specified/required */
1296 break;
1297 }
1298 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", "(union) type");
1299 goto error;
1300 }
1301
1302 /* allocate array for union's types ... */
1303 type->info.uni.type = calloc(i, sizeof *type->info.uni.type);
1304 /* ... and fill the structures */
1305 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001306 if (fill_yin_type(module, parent, node, &type->info.uni.type[type->info.uni.count], unres)) {
Radek Krejcie4c366b2015-07-02 10:11:31 +02001307 goto error;
1308 }
1309 type->info.uni.count++;
1310
1311 /* union's type cannot be empty or leafref */
1312 if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_EMPTY) {
1313 LOGVAL(VE_INARG, LOGLINE(node), "empty", node->name);
1314 goto error;
1315 } else if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_LEAFREF) {
1316 LOGVAL(VE_INARG, LOGLINE(node), "leafref", node->name);
1317 goto error;
1318 }
1319
1320 lyxml_free_elem(module->ctx, node);
1321 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001322 break;
1323
1324 default:
Radek Krejci6e328cd2015-06-26 16:24:11 +02001325 /* no sub-statement allowed in:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001326 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1327 */
Radek Krejci6e328cd2015-06-26 16:24:11 +02001328 if (yin->child) {
1329 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1330 goto error;
1331 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001332 break;
1333 }
1334
1335 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001336
1337error:
1338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001339 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001340}
1341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001342static int
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001343fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_tpdf *tpdf, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001344{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001345 const char *value;
1346 struct lyxml_elem *node, *next;
1347 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001348
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001349 GETVAL(value, yin, "name");
1350 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1351 goto error;
1352 }
1353 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001354
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001355 /* generic part - status, description, reference */
1356 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1357 goto error;
1358 }
Radek Krejcieac35532015-05-31 19:09:15 +02001359
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001360 LY_TREE_FOR_SAFE(yin->child, next, node) {
1361 if (!strcmp(node->name, "type")) {
1362 if (tpdf->type.der) {
1363 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1364 goto error;
1365 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001366 r = fill_yin_type(module, parent, node, &tpdf->type, unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001367 } else if (!strcmp(node->name, "default")) {
1368 if (tpdf->dflt) {
1369 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1370 goto error;
1371 }
1372 GETVAL(value, node, "value");
1373 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1374 } else if (!strcmp(node->name, "units")) {
1375 if (tpdf->units) {
1376 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1377 goto error;
1378 }
1379 GETVAL(value, node, "name");
1380 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1381 } else {
1382 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1383 r = 1;
1384 }
1385 lyxml_free_elem(module->ctx, node);
1386 if (r) {
1387 goto error;
1388 }
1389 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001391 /* check mandatory value */
1392 if (!tpdf->type.der) {
1393 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1394 goto error;
1395 }
Radek Krejcieac35532015-05-31 19:09:15 +02001396
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001397 /* check default value */
1398 if (check_default(&tpdf->type, tpdf->dflt)) {
1399 goto error;
1400 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001401
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001402 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001403
1404error:
1405
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001406 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001407}
1408
Radek Krejci3cf9e222015-06-18 11:37:50 +02001409static struct ly_feature *
1410resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1411{
1412 const char *prefix;
1413 unsigned int prefix_len = 0;
1414 int i, j, found = 0;
1415
1416 assert(name);
1417 assert(module);
1418
1419 /* check prefix */
1420 prefix = name;
1421 name = strchr(prefix, ':');
1422 if (name) {
1423 /* there is prefix */
1424 prefix_len = name - prefix;
1425 name++;
1426
1427 /* check whether the prefix points to the current module */
1428 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1429 /* then ignore prefix and works as there is no prefix */
1430 prefix_len = 0;
1431 }
1432 } else {
1433 /* no prefix, set pointers correctly */
1434 name = prefix;
1435 }
1436
1437 if (prefix_len) {
1438 /* search in imported modules */
1439 for (i = 0; i < module->imp_size; i++) {
1440 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1441 module = module->imp[i].module;
1442 found = 1;
1443 break;
1444 }
1445 }
1446 if (!found) {
1447 /* identity refers unknown data model */
1448 LOGVAL(VE_INPREFIX, line, prefix);
1449 return NULL;
1450 }
1451 } else {
1452 /* search in submodules */
1453 for (i = 0; i < module->inc_size; i++) {
1454 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1455 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1456 return &(module->inc[i].submodule->features[j]);
1457 }
1458 }
1459 }
1460 }
1461
1462 /* search in the identified module */
1463 for (j = 0; j < module->features_size; j++) {
1464 if (!strcmp(name, module->features[j].name)) {
1465 return &module->features[j];
1466 }
1467 }
1468
1469 /* not found */
1470 return NULL;
1471}
1472
1473static int
1474fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1475{
1476 const char *value;
1477 struct lyxml_elem *child, *next;
1478 int c = 0;
1479
Radek Krejcib05774c2015-06-18 13:52:59 +02001480 GETVAL(value, yin, "name");
1481 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1482 goto error;
1483 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001484 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001485
Radek Krejci7e97c352015-06-19 16:26:34 +02001486 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, OPT_MODULE)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001487 goto error;
1488 }
1489
1490 LY_TREE_FOR_SAFE(yin->child, next, child) {
1491 if (!strcmp(child->name, "if-feature")) {
1492 c++;
1493 } else {
1494 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1495 goto error;
1496 }
1497 }
1498
1499 if (c) {
1500 f->features = calloc(c, sizeof *f->features);
1501 }
1502
1503 LY_TREE_FOR_SAFE(yin->child, next, child) {
1504 GETVAL(value, child, "name");
1505 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1506 if (!f->features[f->features_size]) {
1507 goto error;
1508 }
1509 f->features_size++;
1510 }
1511
Radek Krejci3cf9e222015-06-18 11:37:50 +02001512 return EXIT_SUCCESS;
1513
1514error:
1515
1516 return EXIT_FAILURE;
1517}
1518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001519static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001520fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001521{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001522 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001523
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001524 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001525 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001526
Radek Krejci41726f92015-06-19 13:11:05 +02001527 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001528
Radek Krejci41726f92015-06-19 13:11:05 +02001529error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001531 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001532}
1533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001534static int
Radek Krejcieb00f512015-07-01 16:44:58 +02001535parse_unique(struct ly_mnode *parent, struct lyxml_elem *node, struct ly_unique *uniq_s)
1536{
1537 const char *value;
Radek Krejcie82ce862015-07-01 16:49:39 +02001538 char *uniq_str = NULL, *uniq_val, *start;
Radek Krejcieb00f512015-07-01 16:44:58 +02001539 int i, j;
1540
1541 /* count the number of unique values */
1542 GETVAL(value, node, "tag");
1543 uniq_val = uniq_str = strdup(value);
1544 uniq_s->leafs_size = 0;
1545 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1546 uniq_s->leafs_size++;
1547 while (isspace(*uniq_val)) {
1548 uniq_val++;
1549 }
1550 }
1551 uniq_s->leafs_size++;
1552 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1553
1554 /* interconnect unique values with the leafs */
1555 uniq_val = uniq_str;
1556 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1557 start = uniq_val;
1558 if ((uniq_val = strpbrk(start, " \t\n"))) {
1559 *uniq_val = '\0'; /* add terminating NULL byte */
1560 uniq_val++;
1561 while (isspace(*uniq_val)) {
1562 uniq_val++;
1563 }
1564 } /* else only one nodeid present/left already NULL byte terminated */
1565
1566 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LY_NODE_USES);
1567 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LY_NODE_LEAF) {
1568 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1569 if (!uniq_s->leafs[i]) {
1570 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
1571 } else {
1572 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
1573 }
1574 goto error;
1575 }
1576
1577 for (j = 0; j < i; j++) {
1578 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
1579 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1580 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
1581 goto error;
1582 }
1583 }
1584 }
1585
1586 free(uniq_str);
1587 return EXIT_SUCCESS;
1588
1589error:
1590
1591 free(uniq_s->leafs);
1592 free(uniq_str);
1593
1594 return EXIT_FAILURE;
1595}
1596
1597/*
1598 * type: 0 - min, 1 - max
1599 */
1600static int
1601deviate_minmax(struct ly_mnode *target, struct lyxml_elem *node, struct ly_deviate *d, int type)
1602{
1603 const char *value;
1604 char *endptr;
1605 unsigned long val;
1606 uint32_t *ui32val;
1607
1608 /* check target node type */
1609 if (target->nodetype == LY_NODE_LEAFLIST) {
1610 if (type) {
1611 ui32val = &((struct ly_mnode_leaflist *)target)->max;
1612 } else {
1613 ui32val = &((struct ly_mnode_leaflist *)target)->min;
1614 }
1615 } else if (target->nodetype == LY_NODE_LIST) {
1616 if (type) {
1617 ui32val = &((struct ly_mnode_list *)target)->max;
1618 } else {
1619 ui32val = &((struct ly_mnode_list *)target)->min;
1620 }
1621 } else {
1622 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1623 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", node->name);
1624 goto error;
1625 }
1626
1627 GETVAL(value, node, "value");
1628 while (isspace(value[0])) {
1629 value++;
1630 }
1631
1632 /* convert it to uint32_t */
1633 errno = 0;
1634 endptr = NULL;
1635 val = strtoul(value, &endptr, 10);
1636 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1637 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1638 goto error;
1639 }
1640 if (type) {
1641 d->max = (uint32_t)val;
1642 } else {
1643 d->min = (uint32_t)val;
1644 }
1645
1646 if (d->mod == LY_DEVIATE_ADD) {
1647 /* check that there is no current value */
1648 if (*ui32val) {
1649 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1650 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1651 goto error;
1652 }
1653 }
1654
1655 if (d->mod == LY_DEVIATE_DEL) {
1656 /* check values */
1657 if ((uint32_t)val != *ui32val) {
1658 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1659 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1660 goto error;
1661 }
1662 /* remove current min-elements value of the target */
1663 *ui32val = 0;
1664 } else { /* add (already checked) and replace */
1665 /* set new value specified in deviation */
1666 *ui32val = (uint32_t)val;
1667 }
1668
1669 return EXIT_SUCCESS;
1670
1671error:
1672
1673 return EXIT_FAILURE;
1674}
1675
1676static int
1677fill_yin_deviation(struct ly_module *module, struct lyxml_elem *yin, struct ly_deviation *dev)
1678{
1679 const char *value, **stritem;
1680 struct lyxml_elem *next, *child, *develem;
1681 int c_dev = 0, c_must, c_uniq;
1682 int f_min = 0; /* flags */
1683 int i, j;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001684 struct ly_deviate *d = NULL;
1685 struct ly_mnode *mnode = NULL;
1686 struct ly_mnode_choice *choice = NULL;
1687 struct ly_mnode_leaf *leaf = NULL;
1688 struct ly_mnode_list *list = NULL;
1689 struct ly_type *t = NULL;
Radek Krejcie4c366b2015-07-02 10:11:31 +02001690 uint8_t *trg_must_size = NULL;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001691 struct ly_restr **trg_must = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001692
1693 GETVAL(value, yin, "target-node");
1694 dev->target_name = lydict_insert(module->ctx, value, 0);
1695
1696 /* resolve target node */
1697 dev->target = resolve_schema_nodeid(dev->target_name, NULL, module, LY_NODE_AUGMENT);
1698 if (!dev->target) {
1699 LOGVAL(VE_INARG, LOGLINE(yin), dev->target_name, yin->name);
1700 goto error;
1701 }
1702 if (dev->target->module == module) {
1703 LOGVAL(VE_SPEC, LOGLINE(yin), "Deviating own module is not allowed.");
1704 goto error;
1705 }
1706 /* mark the target module as deviated */
1707 dev->target->module->deviated = 1;
1708
1709 LY_TREE_FOR_SAFE(yin->child, next, child) {
1710 if (!strcmp(child->name, "description")) {
1711 if (dev->dsc) {
1712 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1713 goto error;
1714 }
1715 dev->dsc = read_yin_subnode(module->ctx, child, "text");
1716 if (!dev->dsc) {
1717 goto error;
1718 }
1719 } else if (!strcmp(child->name, "reference")) {
1720 if (dev->ref) {
1721 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1722 goto error;
1723 }
1724 dev->ref = read_yin_subnode(module->ctx, child, "text");
1725 if (!dev->ref) {
1726 goto error;
1727 }
1728 } else if (!strcmp(child->name, "deviate")) {
1729 c_dev++;
1730
1731 /* skip lyxml_free_elem() at the end of the loop, node will be
1732 * further processed later
1733 */
1734 continue;
1735 } else {
1736 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1737 goto error;
1738 }
1739
1740 lyxml_free_elem(module->ctx, child);
1741 }
1742
1743 if (c_dev) {
1744 dev->deviate = calloc(c_dev, sizeof *dev->deviate);
1745 }
1746
1747 LY_TREE_FOR(yin->child, develem) {
1748 /* init */
1749 f_min = 0;
1750 c_must = 0;
1751 c_uniq = 0;
1752
1753 /* get deviation type */
1754 GETVAL(value, develem, "value");
1755 if (!strcmp(value, "not-supported")) {
1756 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_NO;
1757 /* no property expected in this case */
1758 if (develem->child) {
1759 LOGVAL(VE_INSTMT, LOGLINE(develem->child), develem->child->name);
1760 goto error;
1761 }
1762
Radek Krejci5b917642015-07-02 09:03:13 +02001763 /* and neither any other deviate statement is expected,
1764 * not-supported deviation must be the only deviation of the target
1765 */
1766 if (dev->deviate_size || develem->next) {
1767 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1768 LOGVAL(VE_SPEC, 0, "\"not-supported\" deviation cannot be combined with any other deviation.");
1769 goto error;
1770 }
1771
1772
Radek Krejcieb00f512015-07-01 16:44:58 +02001773 /* remove target node */
1774 ly_mnode_free(dev->target);
Radek Krejci5b917642015-07-02 09:03:13 +02001775 dev->target = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001776
Radek Krejci5b917642015-07-02 09:03:13 +02001777 dev->deviate_size = 1;
1778 return EXIT_SUCCESS;
Radek Krejcieb00f512015-07-01 16:44:58 +02001779 } else if (!strcmp(value, "add")) {
1780 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_ADD;
1781 } else if (!strcmp(value, "replace")) {
1782 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_RPL;
1783 } else if (!strcmp(value, "delete")) {
1784 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_DEL;
1785 } else {
1786 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1787 goto error;
1788 }
1789 d = &dev->deviate[dev->deviate_size];
1790
1791 /* process deviation properties */
1792 LY_TREE_FOR_SAFE(develem->child, next, child) {
1793 if (!strcmp(child->name, "config")) {
1794 if (d->flags & LY_NODE_CONFIG_MASK) {
1795 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1796 goto error;
1797 }
1798
1799 /* for we deviate from RFC 6020 and allow config property even it is/is not
1800 * specified in the target explicitly since config property inherits. So we expect
1801 * that config is specified in every node. But for delete, we check that the value
1802 * is the same as here in deviation
1803 */
1804 GETVAL(value, child, "value");
1805 if (!strcmp(value, "false")) {
1806 d->flags |= LY_NODE_CONFIG_R;
1807 } else if (!strcmp(value, "true")) {
1808 d->flags |= LY_NODE_CONFIG_W;
1809 } else {
1810 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1811 goto error;
1812 }
1813
1814 if (d->mod == LY_DEVIATE_DEL) {
1815 /* check values */
1816 if ((d->flags & LY_NODE_CONFIG_MASK) != (dev->target->flags & LY_NODE_CONFIG_MASK)) {
1817 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1818 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1819 goto error;
1820 }
1821 /* remove current config value of the target ... */
1822 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1823
1824 /* ... and inherit config value from the target's parent */
1825 if (dev->target->parent) {
1826 dev->target->flags |= dev->target->parent->flags & LY_NODE_CONFIG_MASK;
1827 } else {
1828 /* default config is true */
1829 dev->target->flags |= LY_NODE_CONFIG_W;
1830 }
1831 } else { /* add and replace are the same in this case */
1832 /* remove current config value of the target ... */
1833 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1834
1835 /* ... and replace it with the value specified in deviation */
1836 dev->target->flags |= d->flags & LY_NODE_CONFIG_MASK;
1837 }
1838 } else if (!strcmp(child->name, "default")) {
1839 if (d->dflt) {
1840 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1841 goto error;
1842 }
1843 GETVAL(value, child, "value");
1844 d->dflt = lydict_insert(module->ctx, value, 0);
1845
1846 if (dev->target->nodetype == LY_NODE_CHOICE) {
1847 choice = (struct ly_mnode_choice *)dev->target;
1848
1849 if (d->mod == LY_DEVIATE_ADD) {
1850 /* check that there is no current value */
1851 if (choice->dflt) {
1852 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1853 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1854 goto error;
1855 }
1856 }
1857
1858 mnode = resolve_schema_nodeid(d->dflt, (struct ly_mnode *)choice, choice->module, LY_NODE_CHOICE);
1859 if (d->mod == LY_DEVIATE_DEL) {
1860 if (!choice->dflt || choice->dflt != mnode) {
1861 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1862 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1863 goto error;
1864 }
1865 } else { /* add (already checked) and replace */
1866 choice->dflt = mnode;
1867 if (!choice->dflt) {
1868 /* default branch not found */
1869 LOGVAL(VE_INARG, LOGLINE(yin), value, "default");
1870 goto error;
1871 }
1872 }
1873 } else if (dev->target->nodetype == LY_NODE_LEAF) {
1874 leaf = (struct ly_mnode_leaf *)dev->target;
1875
1876 if (d->mod == LY_DEVIATE_ADD) {
1877 /* check that there is no current value */
1878 if (leaf->dflt) {
1879 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1880 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1881 goto error;
1882 }
1883 }
1884
1885 if (d->mod == LY_DEVIATE_DEL) {
1886 if (!leaf->dflt || leaf->dflt != d->dflt) {
1887 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1888 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1889 goto error;
1890 }
1891 /* remove value */
1892 lydict_remove(leaf->module->ctx, leaf->dflt);
1893 leaf->dflt = NULL;
1894 } else { /* add (already checked) and replace */
1895 /* remove value */
1896 lydict_remove(leaf->module->ctx, leaf->dflt);
1897
1898 /* set new value */
1899 leaf->dflt = lydict_insert(leaf->module->ctx, d->dflt, 0);
1900 }
1901 } else {
1902 /* invalid target for default value */
1903 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1904 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1905 goto error;
1906 }
1907 } else if (!strcmp(child->name, "mandatory")) {
1908 if (d->flags & LY_NODE_MAND_MASK) {
1909 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1910 goto error;
1911 }
1912
1913 /* check target node type */
1914 if (!(dev->target->nodetype &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML))) {
1915 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1916 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1917 goto error;
1918 }
1919
1920 GETVAL(value, child, "value");
1921 if (!strcmp(value, "false")) {
1922 d->flags |= LY_NODE_MAND_FALSE;
1923 } else if (!strcmp(value, "true")) {
1924 d->flags |= LY_NODE_MAND_TRUE;
1925 } else {
1926 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1927 goto error;
1928 }
1929
1930 if (d->mod == LY_DEVIATE_ADD) {
1931 /* check that there is no current value */
1932 if (dev->target->flags & LY_NODE_MAND_MASK) {
1933 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1934 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1935 goto error;
1936 }
1937 }
1938
1939 if (d->mod == LY_DEVIATE_DEL) {
1940 /* check values */
1941 if ((d->flags & LY_NODE_MAND_MASK) != (dev->target->flags & LY_NODE_MAND_MASK)) {
1942 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1943 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1944 goto error;
1945 }
1946 /* remove current mandatory value of the target */
1947 dev->target->flags &= ~LY_NODE_MAND_MASK;
1948 } else { /* add (already checked) and replace */
1949 /* remove current mandatory value of the target ... */
1950 dev->target->flags &= ~LY_NODE_MAND_MASK;
1951
1952 /* ... and replace it with the value specified in deviation */
1953 dev->target->flags |= d->flags & LY_NODE_MAND_MASK;
1954 }
1955 } else if (!strcmp(child->name, "min-elements")) {
1956 if (f_min) {
1957 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1958 goto error;
1959 }
1960 f_min = 1;
1961
1962 if (deviate_minmax(dev->target, child, d, 0)) {
1963 goto error;
1964 }
1965 } else if (!strcmp(child->name, "max-elements")) {
1966 if (d->max) {
1967 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1968 goto error;
1969 }
1970
1971 if (deviate_minmax(dev->target, child, d, 1)) {
1972 goto error;
1973 }
1974 } else if (!strcmp(child->name, "must")) {
1975 c_must++;
1976
1977 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
1978 continue;
1979 } else if (!strcmp(child->name, "type")) {
1980 if (d->type) {
1981 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1982 goto error;
1983 }
1984
1985 /* check target node type */
1986 if (dev->target->nodetype == LY_NODE_LEAF) {
1987 t = &((struct ly_mnode_leaf *)dev->target)->type;
1988 } else if (dev->target->nodetype == LY_NODE_LEAFLIST) {
1989 t = &((struct ly_mnode_leaflist *)dev->target)->type;
1990 } else {
1991 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1992 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1993 goto error;
1994 }
1995
1996 if (d->mod == LY_DEVIATE_ADD) {
1997 /* not allowed, type is always present at the target */
1998 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1999 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2000 goto error;
2001 } else if (d->mod == LY_DEVIATE_DEL) {
2002 /* not allowed, type cannot be deleted from the target */
2003 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2004 LOGVAL(VE_SPEC, 0, "Deleteing type from the target is not allowed.");
2005 goto error;
2006 }
2007
2008 /* replace */
2009 /* remove current units value of the target ... */
2010 ly_type_free(dev->target->module->ctx, t);
2011
2012 /* ... and replace it with the value specified in deviation */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02002013 if (fill_yin_type(module, dev->target, child, t, NULL)) {
Radek Krejcieb00f512015-07-01 16:44:58 +02002014 goto error;
2015 }
2016 d->type = t;
2017 } else if (!strcmp(child->name, "unique")) {
2018 c_uniq++;
2019
2020 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
2021 continue;
2022 } else if (!strcmp(child->name, "units")) {
2023 if (d->units) {
2024 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2025 goto error;
2026 }
2027
2028 /* check target node type */
2029 if (dev->target->nodetype == LY_NODE_LEAFLIST) {
2030 stritem = &((struct ly_mnode_leaflist *)dev->target)->units;
2031 } else if (dev->target->nodetype == LY_NODE_LEAF) {
2032 stritem = &((struct ly_mnode_leaf *)dev->target)->units;
2033 } else {
2034 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2035 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2036 goto error;
2037 }
2038
2039 /* get units value */
2040 GETVAL(value, child, "name");
2041 d->units = lydict_insert(module->ctx, value, 0);
2042
2043 /* apply to target */
2044 if (d->mod == LY_DEVIATE_ADD) {
2045 /* check that there is no current value */
2046 if (*stritem) {
2047 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2048 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2049 goto error;
2050 }
2051 }
2052
2053 if (d->mod == LY_DEVIATE_DEL) {
2054 /* check values */
2055 if (*stritem != d->units) {
2056 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2057 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2058 goto error;
2059 }
2060 /* remove current units value of the target */
2061 lydict_remove(dev->target->module->ctx, *stritem);
2062 } else { /* add (already checked) and replace */
2063 /* remove current units value of the target ... */
2064 lydict_remove(dev->target->module->ctx, *stritem);
2065
2066 /* ... and replace it with the value specified in deviation */
2067 *stritem = lydict_insert(module->ctx, value, 0);
2068 }
2069 } else {
2070 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2071 goto error;
2072 }
2073
2074 lyxml_free_elem(module->ctx, child);
2075 }
2076
2077 if (c_must) {
2078 /* check target node type */
2079 switch (dev->target->nodetype) {
2080 case LY_NODE_LEAF:
2081 trg_must = &((struct ly_mnode_leaf *)dev->target)->must;
2082 trg_must_size = &((struct ly_mnode_leaf *)dev->target)->must_size;
2083 break;
2084 case LY_NODE_CONTAINER:
2085 trg_must = &((struct ly_mnode_container *)dev->target)->must;
2086 trg_must_size = &((struct ly_mnode_container *)dev->target)->must_size;
2087 break;
2088 case LY_NODE_LEAFLIST:
2089 trg_must = &((struct ly_mnode_leaflist *)dev->target)->must;
2090 trg_must_size = &((struct ly_mnode_leaflist *)dev->target)->must_size;
2091 break;
2092 case LY_NODE_LIST:
2093 trg_must = &((struct ly_mnode_list *)dev->target)->must;
2094 trg_must_size = &((struct ly_mnode_list *)dev->target)->must_size;
2095 break;
2096 case LY_NODE_ANYXML:
2097 trg_must = &((struct ly_mnode_anyxml *)dev->target)->must;
2098 trg_must_size = &((struct ly_mnode_anyxml *)dev->target)->must_size;
2099 break;
2100 default:
2101 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2102 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2103 goto error;
2104 }
2105
2106 if (d->mod == LY_DEVIATE_RPL) {
2107 /* remove target's musts and allocate new array for it */
2108 if (!*trg_must) {
2109 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2110 LOGVAL(VE_SPEC, 0, "Property \"must\" to replace does not exists in target.");
2111 goto error;
2112 }
2113
2114 for (i = 0; i < list->must_size; i++) {
2115 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2116 }
2117 free(*trg_must);
2118 *trg_must = d->must = calloc(c_must, sizeof *d->must);
2119 d->must_size = c_must;
2120 *trg_must_size = 0;
2121 } else if (d->mod == LY_DEVIATE_ADD) {
2122 /* reallocate the must array of the target */
2123 d->must = realloc(*trg_must, (c_must + *trg_must_size) * sizeof *d->must);
2124 *trg_must = d->must;
2125 d->must = &(*trg_must[*trg_must_size]);
2126 d->must_size = c_must;
2127 } else { /* LY_DEVIATE_DEL */
2128 d->must = calloc(c_must, sizeof *d->must);
2129 }
2130 }
2131 if (c_uniq) {
2132 /* check target node type */
2133 if (dev->target->nodetype != LY_NODE_LIST) {
2134 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2135 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2136 goto error;
2137 }
2138
2139 list = (struct ly_mnode_list *)dev->target;
2140 if (d->mod == LY_DEVIATE_RPL) {
2141 /* remove target's unique and allocate new array for it */
2142 if (!list->unique) {
2143 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2144 LOGVAL(VE_SPEC, 0, "Property \"unique\" to replace does not exists in target.");
2145 goto error;
2146 }
2147
2148 for (i = 0; i < list->unique_size; i++) {
2149 free(list->unique[i].leafs);
2150 }
2151 free(list->unique);
2152 list->unique = d->unique = calloc(c_uniq, sizeof *d->unique);
2153 d->unique_size = c_uniq;
2154 list->unique_size = 0;
2155 } else if (d->mod == LY_DEVIATE_ADD) {
2156 /* reallocate the unique array of the target */
2157 d->unique = realloc(list->unique, (c_uniq + list->unique_size) * sizeof *d->unique);
2158 list->unique = d->unique;
2159 d->unique = &list->unique[list->unique_size];
2160 d->unique_size = c_uniq;
2161 } else { /* LY_DEVIATE_DEL */
2162 d->unique = calloc(c_uniq, sizeof *d->unique);
2163 }
2164 }
2165
2166 /* process deviation properties with 0..n cardinality */
2167 LY_TREE_FOR_SAFE(develem->child, next, child) {
2168 if (!strcmp(child->name, "must")) {
2169 if (d->mod == LY_DEVIATE_DEL) {
2170 if (fill_yin_must(module, child, &d->must[d->must_size])) {
2171 goto error;
2172 }
2173
2174 /* find must to delete, we are ok with just matching conditions */
2175 for (i = 0; i < *trg_must_size; i++) {
2176 if (d->must[d->must_size].expr == (*trg_must)[i].expr) {
2177 /* we have a match, free the must structure ... */
2178 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2179 /* ... and maintain the array */
2180 (*trg_must_size)--;
2181 if (i != *trg_must_size) {
2182 (*trg_must)[i].expr = (*trg_must)[*trg_must_size].expr;
2183 (*trg_must)[i].dsc = (*trg_must)[*trg_must_size].dsc;
2184 (*trg_must)[i].ref = (*trg_must)[*trg_must_size].ref;
2185 (*trg_must)[i].eapptag = (*trg_must)[*trg_must_size].eapptag;
2186 (*trg_must)[i].emsg = (*trg_must)[*trg_must_size].emsg;
2187 }
2188 if (!(*trg_must_size)) {
2189 free(*trg_must);
2190 *trg_must = NULL;
2191 } else {
2192 (*trg_must)[*trg_must_size].expr = NULL;
2193 (*trg_must)[*trg_must_size].dsc = NULL;
2194 (*trg_must)[*trg_must_size].ref = NULL;
2195 (*trg_must)[*trg_must_size].eapptag = NULL;
2196 (*trg_must)[*trg_must_size].emsg = NULL;
2197 }
2198
2199 i = -1; /* set match flag */
2200 break;
2201 }
2202 }
2203 d->must_size++;
2204 if (i != -1) {
2205 /* no match found */
2206 LOGVAL(VE_INARG, LOGLINE(child), d->must[d->must_size - 1].expr, child->name);
2207 LOGVAL(VE_SPEC, 0, "Value does not match any must from the target.");
2208 goto error;
2209 }
2210 } else { /* replace or add */
2211 if (fill_yin_must(dev->target->module, child, &((*trg_must)[*trg_must_size]))) {
2212 goto error;
2213 }
2214 (*trg_must_size)++;
2215 }
2216 } else if (!strcmp(child->name, "unique")) {
2217 if (d->mod == LY_DEVIATE_DEL) {
2218 if (parse_unique(dev->target, child, &d->unique[d->unique_size])) {
2219 goto error;
2220 }
2221
2222 /* find unique structures to delete */
2223 for (i = 0; i < list->unique_size; i++) {
2224 if (list->unique[i].leafs_size != d->unique[d->unique_size].leafs_size) {
2225 continue;
2226 }
2227
2228 for (j = 0; j < d->unique[d->unique_size].leafs_size; j++) {
2229 if (list->unique[i].leafs[j] != d->unique[d->unique_size].leafs[j]) {
2230 break;
2231 }
2232 }
2233
2234 if (j == d->unique[d->unique_size].leafs_size) {
2235 /* we have a match, free the unique structure ... */
2236 free(list->unique[i].leafs);
2237 /* ... and maintain the array */
2238 list->unique_size--;
2239 if (i != list->unique_size) {
2240 list->unique[i].leafs_size = list->unique[list->unique_size].leafs_size;
2241 list->unique[i].leafs = list->unique[list->unique_size].leafs;
2242 }
2243
2244 if (!list->unique_size) {
2245 free(list->unique);
2246 list->unique = NULL;
2247 } else {
2248 list->unique[list->unique_size].leafs_size = 0;
2249 list->unique[list->unique_size].leafs = NULL;
2250 }
2251
2252 i = -1; /* set match flag */
2253 break;
2254 }
2255 }
2256
2257 d->unique_size++;
2258 if (i != -1) {
2259 /* no match found */
2260 LOGVAL(VE_INARG, LOGLINE(child), lyxml_get_attr(child, "tag", NULL), child->name);
2261 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2262 goto error;
2263 }
2264 } else { /* replace or add */
2265 if (parse_unique(dev->target, child, &list->unique[list->unique_size])) {
2266 goto error;
2267 }
2268 list->unique_size++;
2269 }
2270 }
2271 lyxml_free_elem(module->ctx, child);
2272 }
Radek Krejci5b917642015-07-02 09:03:13 +02002273
2274 dev->deviate_size++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002275 }
2276
Radek Krejcieb00f512015-07-01 16:44:58 +02002277 return EXIT_SUCCESS;
2278
2279error:
2280
2281 if (dev->deviate) {
2282 for (i = 0; i < dev->deviate_size; i++) {
2283 lydict_remove(module->ctx, dev->deviate[i].dflt);
2284 lydict_remove(module->ctx, dev->deviate[i].units);
2285
2286 if (dev->deviate[i].mod == LY_DEVIATE_DEL) {
2287 for (j = 0; j < dev->deviate[i].must_size; j++) {
2288 ly_restr_free(module->ctx, &dev->deviate[i].must[j]);
2289 }
2290 free(dev->deviate[i].must);
2291
2292 for (j = 0; j < dev->deviate[i].unique_size; j++) {
2293 free(dev->deviate[i].unique[j].leafs);
2294 }
2295 free(dev->deviate[i].unique);
2296 }
2297 }
2298 free(dev->deviate);
2299 }
2300
2301 return EXIT_FAILURE;
2302}
2303
2304static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002305fill_yin_augment(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_augment *aug)
Radek Krejci106efc02015-06-10 14:36:27 +02002306{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002307 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002308 struct lyxml_elem *next, *child;
2309 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02002310
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002311 GETVAL(value, yin, "target-node");
2312 aug->target_name = lydict_insert(module->ctx, value, 0);
2313 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02002314
Radek Krejci3cf9e222015-06-18 11:37:50 +02002315 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
2316 goto error;
2317 }
2318
2319 LY_TREE_FOR_SAFE(yin->child, next, child) {
2320 if (!strcmp(child->name, "if-feature")) {
2321 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002322 } else if (!strcmp(child->name, "when")) {
2323 if (aug->when) {
2324 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2325 goto error;
2326 }
2327
2328 aug->when = read_yin_when(module, child);
2329 lyxml_free_elem(module->ctx, child);
2330
2331 if (!aug->when) {
2332 goto error;
2333 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002334
2335 /* check allowed sub-statements */
2336 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
2337 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
2338 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
2339 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2340 goto error;
2341 }
2342 }
2343
2344 if (c) {
2345 aug->features = calloc(c, sizeof *aug->features);
2346 }
2347
2348 LY_TREE_FOR_SAFE(yin->child, next, child) {
2349 if (!strcmp(child->name, "if-feature")) {
2350 GETVAL(value, child, "name");
2351 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
2352 if (!aug->features[aug->features_size]) {
2353 goto error;
2354 }
2355 aug->features_size++;
2356 } else {
2357 /* keep the data nodes */
2358 continue;
2359 }
2360
2361 lyxml_free_elem(module->ctx, child);
2362 }
2363
2364 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002365 * when we will have the target node
2366 */
2367 lyxml_unlink_elem(yin);
2368 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02002369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002370 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02002371
2372error:
2373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002374 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02002375}
2376
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002377static int
2378fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02002379{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002380 struct lyxml_elem *sub, *next;
2381 const char *value;
2382 char *endptr;
2383 int f_mand = 0, f_min = 0, f_max = 0;
2384 int c_must = 0;
2385 int r;
2386 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002387
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002388 GETVAL(value, yin, "target-node");
2389 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02002390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002391 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
2392 goto error;
2393 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002394
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002395 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2396 /* limited applicability */
2397 if (!strcmp(sub->name, "default")) {
2398 /* leaf or choice */
2399 if (rfn->mod.dflt) {
2400 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2401 goto error;
2402 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002403
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002404 /* check possibility of statements combination */
2405 if (rfn->target_type) {
2406 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
2407 if (!rfn->target_type) {
2408 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2409 goto error;
2410 }
2411 } else {
2412 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
2413 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002414
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002415 GETVAL(value, sub, "value");
2416 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
2417 } else if (!strcmp(sub->name, "mandatory")) {
2418 /* leaf, choice or anyxml */
2419 if (f_mand) {
2420 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2421 goto error;
2422 }
2423 /* just checking the flags in leaf is not sufficient, we would allow
2424 * multiple mandatory statements with the "false" value
2425 */
2426 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002427
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002428 /* check possibility of statements combination */
2429 if (rfn->target_type) {
2430 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
2431 if (!rfn->target_type) {
2432 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2433 goto error;
2434 }
2435 } else {
2436 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
2437 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002438
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002439 GETVAL(value, sub, "value");
2440 if (!strcmp(value, "true")) {
2441 rfn->flags |= LY_NODE_MAND_TRUE;
2442 } else if (!strcmp(value, "false")) {
2443 rfn->flags |= LY_NODE_MAND_FALSE;
2444 } else {
2445 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2446 goto error;
2447 }
2448 } else if (!strcmp(sub->name, "min-elements")) {
2449 /* list or leaf-list */
2450 if (f_min) {
2451 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2452 goto error;
2453 }
2454 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002455
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002456 /* check possibility of statements combination */
2457 if (rfn->target_type) {
2458 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2459 if (!rfn->target_type) {
2460 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2461 goto error;
2462 }
2463 } else {
2464 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2465 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002466
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002467 GETVAL(value, sub, "value");
2468 while (isspace(value[0])) {
2469 value++;
2470 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002471
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002472 /* convert it to uint32_t */
2473 errno = 0;
2474 endptr = NULL;
2475 val = strtoul(value, &endptr, 10);
2476 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2477 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2478 goto error;
2479 }
2480 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002481
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002482 /* magic - bit 3 in flags means min set */
2483 rfn->flags |= 0x04;
2484 } else if (!strcmp(sub->name, "max-elements")) {
2485 /* list or leaf-list */
2486 if (f_max) {
2487 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2488 goto error;
2489 }
2490 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002491
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002492 /* check possibility of statements combination */
2493 if (rfn->target_type) {
2494 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2495 if (!rfn->target_type) {
2496 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2497 goto error;
2498 }
2499 } else {
2500 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2501 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002502
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002503 GETVAL(value, sub, "value");
2504 while (isspace(value[0])) {
2505 value++;
2506 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002508 /* convert it to uint32_t */
2509 errno = 0;
2510 endptr = NULL;
2511 val = strtoul(value, &endptr, 10);
2512 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2513 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2514 goto error;
2515 }
2516 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002518 /* magic - bit 4 in flags means min set */
2519 rfn->flags |= 0x08;
2520 } else if (!strcmp(sub->name, "presence")) {
2521 /* container */
2522 if (rfn->mod.presence) {
2523 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2524 goto error;
2525 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002526
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002527 /* check possibility of statements combination */
2528 if (rfn->target_type) {
2529 rfn->target_type &= LY_NODE_CONTAINER;
2530 if (!rfn->target_type) {
2531 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2532 goto error;
2533 }
2534 } else {
2535 rfn->target_type = LY_NODE_CONTAINER;
2536 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002537
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002538 GETVAL(value, sub, "value");
2539 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
2540 } else if (!strcmp(sub->name, "must")) {
2541 /* leaf-list, list, container or anyxml */
2542 /* check possibility of statements combination */
2543 if (rfn->target_type) {
2544 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
2545 if (!rfn->target_type) {
2546 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2547 goto error;
2548 }
2549 } else {
2550 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
2551 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002553 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002555 } else {
2556 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2557 goto error;
2558 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002560 lyxml_free_elem(module->ctx, sub);
2561 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002562
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002563 /* process nodes with cardinality of 0..n */
2564 if (c_must) {
2565 rfn->must = calloc(c_must, sizeof *rfn->must);
2566 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002567
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002568 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2569 if (!strcmp(sub->name, "must")) {
2570 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
2571 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002573 if (r) {
2574 goto error;
2575 }
2576 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002578 lyxml_free_elem(module->ctx, sub);
2579 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002581 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002582
2583error:
2584
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002585 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002586}
2587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002588static int
2589fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02002590{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002591 struct lyxml_elem *child;
2592 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002593
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002594 LY_TREE_FOR(yin->child, child) {
2595 if (!strcmp(child->name, "prefix")) {
2596 GETVAL(value, child, "value");
2597 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
2598 goto error;
2599 }
2600 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
2601 } else if (!strcmp(child->name, "revision-date")) {
2602 if (imp->rev[0]) {
2603 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2604 goto error;
2605 }
2606 GETVAL(value, child, "date");
2607 if (check_date(value, LOGLINE(child))) {
2608 goto error;
2609 }
2610 memcpy(imp->rev, value, LY_REV_SIZE - 1);
2611 } else {
2612 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2613 goto error;
2614 }
2615 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002616
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002617 /* check mandatory information */
2618 if (!imp->prefix) {
2619 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
2620 goto error;
2621 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002622
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002623 GETVAL(value, yin, "module");
2624 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
2625 if (!imp->module) {
2626 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
2627 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2628 goto error;
2629 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002631 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002632
2633error:
2634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002635 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002636}
2637
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002638static int
2639fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02002640{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002641 struct lyxml_elem *child;
2642 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002644 LY_TREE_FOR(yin->child, child) {
2645 if (!strcmp(child->name, "revision-date")) {
2646 if (inc->rev[0]) {
2647 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2648 goto error;
2649 }
2650 GETVAL(value, child, "date");
2651 if (check_date(value, LOGLINE(child))) {
2652 goto error;
2653 }
2654 memcpy(inc->rev, value, LY_REV_SIZE - 1);
2655 } else {
2656 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2657 goto error;
2658 }
2659 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002660
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002661 GETVAL(value, yin, "module");
2662 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
2663 if (!inc->submodule) {
2664 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
2665 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2666 goto error;
2667 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002669 /* check that belongs-to corresponds */
2670 if (module->type) {
2671 module = ((struct ly_submodule *)module)->belongsto;
2672 }
2673 if (inc->submodule->belongsto != module) {
2674 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2675 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
2676 goto error;
2677 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002679 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002680
2681error:
2682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002683 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002684}
2685
Radek Krejcida04f4a2015-05-21 12:54:09 +02002686/*
2687 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02002688 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02002689 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02002690 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002691static int
2692read_yin_common(struct ly_module *module, struct ly_mnode *parent,
2693 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002694{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002695 const char *value;
2696 struct lyxml_elem *sub, *next;
2697 struct ly_ctx *const ctx = module->ctx;
2698 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002699
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002700 if (opt & OPT_MODULE) {
2701 mnode->module = module;
2702 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002703
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002704 if (opt & OPT_IDENT) {
2705 GETVAL(value, xmlnode, "name");
2706 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
2707 goto error;
2708 }
2709 mnode->name = lydict_insert(ctx, value, strlen(value));
2710 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002711
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002712 /* process local parameters */
2713 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
2714 if (!strcmp(sub->name, "description")) {
2715 if (mnode->dsc) {
2716 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2717 goto error;
2718 }
2719 mnode->dsc = read_yin_subnode(ctx, sub, "text");
2720 if (!mnode->dsc) {
2721 r = 1;
2722 }
2723 } else if (!strcmp(sub->name, "reference")) {
2724 if (mnode->ref) {
2725 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2726 goto error;
2727 }
2728 mnode->ref = read_yin_subnode(ctx, sub, "text");
2729 if (!mnode->ref) {
2730 r = 1;
2731 }
2732 } else if (!strcmp(sub->name, "status")) {
2733 if (mnode->flags & LY_NODE_STATUS_MASK) {
2734 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2735 goto error;
2736 }
2737 GETVAL(value, sub, "value");
2738 if (!strcmp(value, "current")) {
2739 mnode->flags |= LY_NODE_STATUS_CURR;
2740 } else if (!strcmp(value, "deprecated")) {
2741 mnode->flags |= LY_NODE_STATUS_DEPRC;
2742 } else if (!strcmp(value, "obsolete")) {
2743 mnode->flags |= LY_NODE_STATUS_OBSLT;
2744 } else {
2745 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2746 r = 1;
2747 }
2748 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
2749 if (mnode->flags & LY_NODE_CONFIG_MASK) {
2750 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2751 goto error;
2752 }
2753 GETVAL(value, sub, "value");
2754 if (!strcmp(value, "false")) {
2755 mnode->flags |= LY_NODE_CONFIG_R;
2756 } else if (!strcmp(value, "true")) {
2757 mnode->flags |= LY_NODE_CONFIG_W;
2758 } else {
2759 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2760 r = 1;
2761 }
2762 } else {
2763 /* skip the lyxml_free_elem */
2764 continue;
2765 }
2766 lyxml_free_elem(ctx, sub);
2767 if (r) {
2768 goto error;
2769 }
2770 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002771
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002772 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
2773 /* get config flag from parent */
2774 if (parent) {
2775 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2776 } else {
2777 /* default config is true */
2778 mnode->flags |= LY_NODE_CONFIG_W;
2779 }
2780 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002781
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002782 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02002783
2784error:
2785
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002786 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002787}
2788
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002789static struct ly_when *
2790read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
2791{
Radek Krejci53ebfb12015-06-19 09:35:59 +02002792 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002793 struct lyxml_elem *next, *child;
2794 const char *value;
2795
2796 retval = calloc(1, sizeof *retval);
2797
2798 GETVAL(value, yin, "condition");
2799 retval->cond = lydict_insert(module->ctx, value, 0);
2800
2801 LY_TREE_FOR_SAFE(yin->child, next, child) {
2802 if (!strcmp(child->name, "description")) {
2803 if (retval->dsc) {
2804 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2805 goto error;
2806 }
2807 retval->dsc = read_yin_subnode(module->ctx, child, "text");
2808 if (!retval->dsc) {
2809 goto error;
2810 }
2811 } else if (!strcmp(child->name, "reference")) {
2812 if (retval->ref) {
2813 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2814 goto error;
2815 }
2816 retval->ref = read_yin_subnode(module->ctx, child, "text");
2817 if (!retval->ref) {
2818 goto error;
2819 }
2820 } else {
2821 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2822 goto error;
2823 }
2824
2825 lyxml_free_elem(module->ctx, child);
2826 }
2827
2828 return retval;
2829
2830error:
2831
Radek Krejci53ebfb12015-06-19 09:35:59 +02002832 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002833 return NULL;
2834}
2835
Radek Krejcib4cf2022015-06-03 14:40:05 +02002836/* additional check in case statement - the child must be unique across
2837 * all other case names and its data children
2838 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002839static int
2840check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002841{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002842 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002843
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002844 if (new->nodetype == LY_NODE_CHOICE) {
2845 /* we have nested choice in case, so we need recursion */
2846 LY_TREE_FOR(new->child, mnode) {
2847 if (mnode->nodetype == LY_NODE_CASE) {
2848 LY_TREE_FOR(mnode->child, submnode) {
2849 if (check_branch_id(parent, submnode, new, line)) {
2850 return EXIT_FAILURE;
2851 }
2852 }
2853 } else if (check_branch_id(parent, mnode, new, line)) {
2854 return EXIT_FAILURE;
2855 }
2856 }
2857 } else {
2858 LY_TREE_FOR(parent->child, mnode) {
2859 if (mnode == excl) {
2860 continue;
2861 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002863 if (!strcmp(new->name, mnode->name)) {
2864 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2865 return EXIT_FAILURE;
2866 }
2867 if (mnode->nodetype == LY_NODE_CASE) {
2868 LY_TREE_FOR(mnode->child, submnode) {
2869 if (!strcmp(new->name, submnode->name)) {
2870 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2871 return EXIT_FAILURE;
2872 }
2873 }
2874 }
2875 }
2876 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002877
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002878 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002879}
2880
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002881static struct ly_mnode *
2882read_yin_case(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02002883 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002884{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002885 struct lyxml_elem *sub, *next;
2886 struct ly_mnode_case *mcase;
2887 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002888 int c_ftrs = 0;
2889 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002891 mcase = calloc(1, sizeof *mcase);
2892 mcase->nodetype = LY_NODE_CASE;
2893 mcase->prev = (struct ly_mnode *)mcase;
2894 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002896 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
2897 goto error;
2898 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002899
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002900 /* process choice's specific children */
2901 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2902 if (!strcmp(sub->name, "container")) {
2903 mnode = read_yin_container(module, retval, sub, resolve, unres);
2904 } else if (!strcmp(sub->name, "leaf-list")) {
2905 mnode = read_yin_leaflist(module, retval, sub, resolve);
2906 } else if (!strcmp(sub->name, "leaf")) {
2907 mnode = read_yin_leaf(module, retval, sub, resolve);
2908 } else if (!strcmp(sub->name, "list")) {
2909 mnode = read_yin_list(module, retval, sub, resolve, unres);
2910 } else if (!strcmp(sub->name, "uses")) {
2911 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2912 } else if (!strcmp(sub->name, "choice")) {
2913 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2914 } else if (!strcmp(sub->name, "anyxml")) {
2915 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002916 } else if (!strcmp(sub->name, "if-feature")) {
2917 c_ftrs++;
2918
2919 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
2920 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002921 } else if (!strcmp(sub->name, "when")) {
2922 if (mcase->when) {
2923 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2924 goto error;
2925 }
2926
2927 mcase->when = read_yin_when(module, sub);
2928 if (!mcase->when) {
2929 goto error;
2930 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002931 } else {
2932 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2933 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002934 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002935
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002936 if (!mnode) {
2937 goto error;
2938 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
2939 goto error;
2940 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002941
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002942 mnode = NULL;
2943 lyxml_free_elem(module->ctx, sub);
2944 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002945
Radek Krejci3cf9e222015-06-18 11:37:50 +02002946 if (c_ftrs) {
2947 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2948 }
2949 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2950 GETVAL(value, sub, "name");
2951 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2952 if (!mcase->features[mcase->features_size]) {
2953 goto error;
2954 }
2955 mcase->features_size++;
2956 lyxml_free_elem(module->ctx, sub);
2957 }
2958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002959 /* inherit config flag */
2960 if (parent) {
2961 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2962 } else {
2963 /* default config is true */
2964 retval->flags |= LY_NODE_CONFIG_W;
2965 }
Radek Krejcib388c152015-06-04 17:03:03 +02002966
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002967 /* insert the node into the schema tree */
2968 if (ly_mnode_addchild(parent, retval)) {
2969 goto error;
2970 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002971
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002972 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002973
2974error:
2975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002976 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002977
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002978 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002979}
2980
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002981static struct ly_mnode *
2982read_yin_choice(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02002983 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002984{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002985 struct lyxml_elem *sub, *next;
2986 struct ly_ctx *const ctx = module->ctx;
2987 struct ly_mnode *retval, *mnode = NULL;
2988 struct ly_mnode_choice *choice;
2989 const char *value;
2990 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002991 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002992
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002993 choice = calloc(1, sizeof *choice);
2994 choice->nodetype = LY_NODE_CHOICE;
2995 choice->prev = (struct ly_mnode *)choice;
2996 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002998 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2999 goto error;
3000 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003002 /* process choice's specific children */
3003 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3004 if (!strcmp(sub->name, "container")) {
3005 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
3006 goto error;
3007 }
3008 } else if (!strcmp(sub->name, "leaf-list")) {
3009 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
3010 goto error;
3011 }
3012 } else if (!strcmp(sub->name, "leaf")) {
3013 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
3014 goto error;
3015 }
3016 } else if (!strcmp(sub->name, "list")) {
3017 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
3018 goto error;
3019 }
3020 } else if (!strcmp(sub->name, "case")) {
3021 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
3022 goto error;
3023 }
3024 } else if (!strcmp(sub->name, "anyxml")) {
3025 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
3026 goto error;
3027 }
3028 } else if (!strcmp(sub->name, "default")) {
3029 if (dflt_str) {
3030 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3031 goto error;
3032 }
3033 GETVAL(value, sub, "value");
3034 dflt_str = strdup(value);
3035 } else if (!strcmp(sub->name, "mandatory")) {
3036 if (f_mand) {
3037 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3038 goto error;
3039 }
3040 /* just checking the flags in leaf is not sufficient, we would allow
3041 * multiple mandatory statements with the "false" value
3042 */
3043 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003044
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003045 GETVAL(value, sub, "value");
3046 if (!strcmp(value, "true")) {
3047 choice->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003048 } else if (!strcmp(value, "false")) {
3049 choice->flags |= LY_NODE_MAND_FALSE;
3050 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003051 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3052 goto error;
3053 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003054 } else if (!strcmp(sub->name, "when")) {
3055 if (choice->when) {
3056 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3057 goto error;
3058 }
3059
3060 choice->when = read_yin_when(module, sub);
3061 if (!choice->when) {
3062 goto error;
3063 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003064 } else if (!strcmp(sub->name, "if-feature")) {
3065 c_ftrs++;
3066
3067 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
3068 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003069 } else {
3070 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3071 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003072 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003073
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003074 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
3075 goto error;
3076 }
3077 mnode = NULL;
3078 lyxml_free_elem(ctx, sub);
3079 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003080
Radek Krejci3cf9e222015-06-18 11:37:50 +02003081 if (c_ftrs) {
3082 choice->features = calloc(c_ftrs, sizeof *choice->features);
3083 }
3084
3085 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3086 GETVAL(value, sub, "name");
3087 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
3088 if (!choice->features[choice->features_size]) {
3089 goto error;
3090 }
3091 choice->features_size++;
3092 lyxml_free_elem(ctx, sub);
3093 }
3094
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003095 /* check - default is prohibited in combination with mandatory */
3096 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
3097 LOGVAL(VE_SPEC, LOGLINE(yin),
3098 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
3099 goto error;
3100 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003101
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003102 /* link default with the case */
3103 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02003104 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003105 if (!choice->dflt) {
3106 /* default branch not found */
3107 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
3108 goto error;
3109 }
3110 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003111
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003112 /* insert the node into the schema tree */
3113 if (parent && ly_mnode_addchild(parent, retval)) {
3114 goto error;
3115 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003116
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003117 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02003118
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003119 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003120
3121error:
3122
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003123 ly_mnode_free(retval);
3124 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003126 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003127}
3128
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003129static struct ly_mnode *
3130read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02003131{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003132 struct ly_mnode *retval;
3133 struct ly_mnode_leaf *anyxml;
3134 struct lyxml_elem *sub, *next;
3135 const char *value;
3136 int r;
3137 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003138 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02003139
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003140 anyxml = calloc(1, sizeof *anyxml);
3141 anyxml->nodetype = LY_NODE_ANYXML;
3142 anyxml->prev = (struct ly_mnode *)anyxml;
3143 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02003144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003145 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3146 goto error;
3147 }
Radek Krejci863c2852015-06-03 15:47:11 +02003148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003149 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3150 if (!strcmp(sub->name, "mandatory")) {
3151 if (f_mand) {
3152 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3153 goto error;
3154 }
3155 /* just checking the flags in leaf is not sufficient, we would allow
3156 * multiple mandatory statements with the "false" value
3157 */
3158 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02003159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003160 GETVAL(value, sub, "value");
3161 if (!strcmp(value, "true")) {
3162 anyxml->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003163 } else if (!strcmp(value, "false")) {
3164 anyxml->flags |= LY_NODE_MAND_FALSE;
3165 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003166 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3167 goto error;
3168 }
3169 /* else false is the default value, so we can ignore it */
3170 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003171 } else if (!strcmp(sub->name, "when")) {
3172 if (anyxml->when) {
3173 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3174 goto error;
3175 }
3176
3177 anyxml->when = read_yin_when(module, sub);
3178 lyxml_free_elem(module->ctx, sub);
3179
3180 if (!anyxml->when) {
3181 goto error;
3182 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003183 } else if (!strcmp(sub->name, "must")) {
3184 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003185 } else if (!strcmp(sub->name, "if-feature")) {
3186 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02003187
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003188 } else {
3189 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3190 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003191 }
3192 }
Radek Krejci863c2852015-06-03 15:47:11 +02003193
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003194 /* middle part - process nodes with cardinality of 0..n */
3195 if (c_must) {
3196 anyxml->must = calloc(c_must, sizeof *anyxml->must);
3197 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003198 if (c_ftrs) {
3199 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
3200 }
Radek Krejci863c2852015-06-03 15:47:11 +02003201
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003202 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3203 if (!strcmp(sub->name, "must")) {
3204 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
3205 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02003206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003207 if (r) {
3208 goto error;
3209 }
Radek Krejci0b24d752015-07-02 15:02:27 +02003210 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003211 GETVAL(value, sub, "name");
3212 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
3213 if (!anyxml->features[anyxml->features_size]) {
3214 goto error;
3215 }
3216 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003217 }
Radek Krejci863c2852015-06-03 15:47:11 +02003218
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003219 lyxml_free_elem(module->ctx, sub);
3220 }
Radek Krejci863c2852015-06-03 15:47:11 +02003221
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003222 if (parent && ly_mnode_addchild(parent, retval)) {
3223 goto error;
3224 }
Radek Krejci863c2852015-06-03 15:47:11 +02003225
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003226 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02003227
3228error:
3229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003230 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02003231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003232 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02003233}
3234
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003235static struct ly_mnode *
3236read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003237{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003238 struct ly_mnode *retval;
3239 struct ly_mnode_leaf *leaf;
3240 struct lyxml_elem *sub, *next;
3241 const char *value;
3242 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003243 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003245 leaf = calloc(1, sizeof *leaf);
3246 leaf->nodetype = LY_NODE_LEAF;
3247 leaf->prev = (struct ly_mnode *)leaf;
3248 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003249
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003250 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3251 goto error;
3252 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003253
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003254 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3255 if (!strcmp(sub->name, "type")) {
3256 if (leaf->type.der) {
3257 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3258 goto error;
3259 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003260 if (fill_yin_type(module, parent, sub, &leaf->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003261 goto error;
3262 }
3263 } else if (!strcmp(sub->name, "default")) {
3264 if (leaf->dflt) {
3265 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3266 goto error;
3267 }
3268 GETVAL(value, sub, "value");
3269 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
3270 } else if (!strcmp(sub->name, "units")) {
3271 if (leaf->units) {
3272 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3273 goto error;
3274 }
3275 GETVAL(value, sub, "name");
3276 leaf->units = lydict_insert(module->ctx, value, strlen(value));
3277 } else if (!strcmp(sub->name, "mandatory")) {
3278 if (f_mand) {
3279 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3280 goto error;
3281 }
3282 /* just checking the flags in leaf is not sufficient, we would allow
3283 * multiple mandatory statements with the "false" value
3284 */
3285 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02003286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003287 GETVAL(value, sub, "value");
3288 if (!strcmp(value, "true")) {
3289 leaf->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003290 } else if (!strcmp(value, "false")) {
3291 leaf->flags |= LY_NODE_MAND_FALSE;
3292 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003293 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3294 goto error;
3295 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003296 } else if (!strcmp(sub->name, "when")) {
3297 if (leaf->when) {
3298 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3299 goto error;
3300 }
3301
3302 leaf->when = read_yin_when(module, sub);
3303 if (!leaf->when) {
3304 goto error;
3305 }
3306
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003307 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003308 c_must++; /* else false is the default value, so we can ignore it */
3309 } else if (!strcmp(sub->name, "if-feature")) {
3310 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003311
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003312 /* skip element free at the end of the loop */
3313 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003314 } else {
3315 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3316 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003317 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003318
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003319 lyxml_free_elem(module->ctx, sub);
3320 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003322 /* check mandatory parameters */
3323 if (!leaf->type.der) {
3324 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3325 goto error;
3326 }
3327 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
3328 goto error;
3329 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003331 /* middle part - process nodes with cardinality of 0..n */
3332 if (c_must) {
3333 leaf->must = calloc(c_must, sizeof *leaf->must);
3334 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003335 if (c_ftrs) {
3336 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
3337 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003339 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3340 if (!strcmp(sub->name, "must")) {
3341 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
3342 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003344 if (r) {
3345 goto error;
3346 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003347 } else if (!strcmp(sub->name, "if-feature")) {
3348 GETVAL(value, sub, "name");
3349 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
3350 if (!leaf->features[leaf->features_size]) {
3351 goto error;
3352 }
3353 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003354 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003355
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003356 lyxml_free_elem(module->ctx, sub);
3357 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003358
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003359 if (parent && ly_mnode_addchild(parent, retval)) {
3360 goto error;
3361 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003363 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003364
3365error:
3366
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003367 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003368
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003369 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003370}
3371
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003372static struct ly_mnode *
3373read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003374{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003375 struct ly_mnode *retval;
3376 struct ly_mnode_leaflist *llist;
3377 struct lyxml_elem *sub, *next;
3378 const char *value;
3379 char *endptr;
3380 unsigned long val;
3381 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003382 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003383 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003385 llist = calloc(1, sizeof *llist);
3386 llist->nodetype = LY_NODE_LEAFLIST;
3387 llist->prev = (struct ly_mnode *)llist;
3388 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003389
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003390 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3391 goto error;
3392 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003393
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003394 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3395 if (!strcmp(sub->name, "type")) {
3396 if (llist->type.der) {
3397 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3398 goto error;
3399 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003400 if (fill_yin_type(module, parent, sub, &llist->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003401 goto error;
3402 }
3403 } else if (!strcmp(sub->name, "units")) {
3404 if (llist->units) {
3405 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3406 goto error;
3407 }
3408 GETVAL(value, sub, "name");
3409 llist->units = lydict_insert(module->ctx, value, strlen(value));
3410 } else if (!strcmp(sub->name, "ordered-by")) {
3411 if (f_ordr) {
3412 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3413 goto error;
3414 }
3415 /* just checking the flags in llist is not sufficient, we would
3416 * allow multiple ordered-by statements with the "system" value
3417 */
3418 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003420 if (llist->flags & LY_NODE_CONFIG_R) {
3421 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3422 * state data
3423 */
3424 lyxml_free_elem(module->ctx, sub);
3425 continue;
3426 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003427
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003428 GETVAL(value, sub, "value");
3429 if (!strcmp(value, "user")) {
3430 llist->flags |= LY_NODE_USERORDERED;
3431 } else if (strcmp(value, "system")) {
3432 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3433 goto error;
3434 } /* else system is the default value, so we can ignore it */
3435 } else if (!strcmp(sub->name, "must")) {
3436 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003437 } else if (!strcmp(sub->name, "if-feature")) {
3438 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003439
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003440 /* skip element free at the end of the loop */
3441 continue;
3442 } else if (!strcmp(sub->name, "min-elements")) {
3443 if (f_min) {
3444 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3445 goto error;
3446 }
3447 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003449 GETVAL(value, sub, "value");
3450 while (isspace(value[0])) {
3451 value++;
3452 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003453
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003454 /* convert it to uint32_t */
3455 errno = 0;
3456 endptr = NULL;
3457 val = strtoul(value, &endptr, 10);
3458 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
3459 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3460 goto error;
3461 }
3462 llist->min = (uint32_t) val;
3463 } else if (!strcmp(sub->name, "max-elements")) {
3464 if (f_max) {
3465 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3466 goto error;
3467 }
3468 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003469
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003470 GETVAL(value, sub, "value");
3471 while (isspace(value[0])) {
3472 value++;
3473 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003475 /* convert it to uint32_t */
3476 errno = 0;
3477 endptr = NULL;
3478 val = strtoul(value, &endptr, 10);
3479 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3480 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3481 goto error;
3482 }
3483 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003484 } else if (!strcmp(sub->name, "when")) {
3485 if (llist->when) {
3486 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3487 goto error;
3488 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003489
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003490 llist->when = read_yin_when(module, sub);
3491 if (!llist->when) {
3492 goto error;
3493 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003494 } else {
3495 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3496 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003497 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003499 lyxml_free_elem(module->ctx, sub);
3500 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003502 /* check constraints */
3503 if (!llist->type.der) {
3504 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3505 goto error;
3506 }
3507 if (llist->max && llist->min > llist->max) {
3508 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3509 goto error;
3510 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003511
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003512 /* middle part - process nodes with cardinality of 0..n */
3513 if (c_must) {
3514 llist->must = calloc(c_must, sizeof *llist->must);
3515 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003516 if (c_ftrs) {
3517 llist->features = calloc(c_ftrs, sizeof *llist->features);
3518 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003519
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003520 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3521 if (!strcmp(sub->name, "must")) {
3522 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
3523 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003525 if (r) {
3526 goto error;
3527 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003528 } else if (!strcmp(sub->name, "if-feature")) {
3529 GETVAL(value, sub, "name");
3530 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
3531 if (!llist->features[llist->features_size]) {
3532 goto error;
3533 }
3534 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003535 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003536
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003537 lyxml_free_elem(module->ctx, sub);
3538 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003540 if (parent && ly_mnode_addchild(parent, retval)) {
3541 goto error;
3542 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003544 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003545
3546error:
3547
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003548 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003549
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003550 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003551}
3552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003553static struct ly_mnode *
3554read_yin_list(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003555 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003556{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003557 struct ly_mnode *retval, *mnode;
3558 struct ly_mnode_list *list;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003559 struct lyxml_elem *sub, *next, root, uniq;
3560 int i, r;
3561 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003562 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003563 int f_ordr = 0, f_max = 0, f_min = 0;
Radek Krejcieb00f512015-07-01 16:44:58 +02003564 const char *key_str = NULL, *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003565 char *auxs;
3566 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003567
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003568 /* init */
3569 memset(&root, 0, sizeof root);
3570 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02003571
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003572 list = calloc(1, sizeof *list);
3573 list->nodetype = LY_NODE_LIST;
3574 list->prev = (struct ly_mnode *)list;
3575 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003577 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3578 goto error;
3579 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003581 /* process list's specific children */
3582 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3583 /* data statements */
3584 if (!strcmp(sub->name, "container") ||
3585 !strcmp(sub->name, "leaf-list") ||
3586 !strcmp(sub->name, "leaf") ||
3587 !strcmp(sub->name, "list") ||
3588 !strcmp(sub->name, "choice") ||
3589 !strcmp(sub->name, "uses") ||
3590 !strcmp(sub->name, "grouping") ||
3591 !strcmp(sub->name, "anyxml")) {
3592 lyxml_unlink_elem(sub);
3593 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003594
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003595 /* array counters */
3596 } else if (!strcmp(sub->name, "key")) {
3597 /* check cardinality 0..1 */
3598 if (list->keys_size) {
3599 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
3600 goto error;
3601 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003602
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003603 /* count the number of keys */
3604 GETVAL(value, sub, "value");
3605 key_str = value;
3606 while ((value = strpbrk(value, " \t\n"))) {
3607 list->keys_size++;
3608 while (isspace(*value)) {
3609 value++;
3610 }
3611 }
3612 list->keys_size++;
3613 list->keys = calloc(list->keys_size, sizeof *list->keys);
3614 } else if (!strcmp(sub->name, "unique")) {
3615 c_uniq++;
3616 lyxml_unlink_elem(sub);
3617 lyxml_add_child(&uniq, sub);
3618 } else if (!strcmp(sub->name, "typedef")) {
3619 c_tpdf++;
3620 } else if (!strcmp(sub->name, "must")) {
3621 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003622 } else if (!strcmp(sub->name, "if-feature")) {
3623 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02003624
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003625 /* optional stetments */
3626 } else if (!strcmp(sub->name, "ordered-by")) {
3627 if (f_ordr) {
3628 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3629 goto error;
3630 }
3631 /* just checking the flags in llist is not sufficient, we would
3632 * allow multiple ordered-by statements with the "system" value
3633 */
3634 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003635
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003636 if (list->flags & LY_NODE_CONFIG_R) {
3637 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3638 * state data
3639 */
3640 lyxml_free_elem(module->ctx, sub);
3641 continue;
3642 }
Radek Krejci345ad742015-06-03 11:04:18 +02003643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003644 GETVAL(value, sub, "value");
3645 if (!strcmp(value, "user")) {
3646 list->flags |= LY_NODE_USERORDERED;
3647 } else if (strcmp(value, "system")) {
3648 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3649 goto error;
3650 }
3651 /* else system is the default value, so we can ignore it */
3652 lyxml_free_elem(module->ctx, sub);
3653 } else if (!strcmp(sub->name, "min-elements")) {
3654 if (f_min) {
3655 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3656 goto error;
3657 }
3658 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003660 GETVAL(value, sub, "value");
3661 while (isspace(value[0])) {
3662 value++;
3663 }
Radek Krejci345ad742015-06-03 11:04:18 +02003664
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003665 /* convert it to uint32_t */
3666 errno = 0;
3667 auxs = NULL;
3668 val = strtoul(value, &auxs, 10);
3669 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
3670 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3671 goto error;
3672 }
3673 list->min = (uint32_t) val;
3674 lyxml_free_elem(module->ctx, sub);
3675 } else if (!strcmp(sub->name, "max-elements")) {
3676 if (f_max) {
3677 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3678 goto error;
3679 }
3680 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003682 GETVAL(value, sub, "value");
3683 while (isspace(value[0])) {
3684 value++;
3685 }
Radek Krejci345ad742015-06-03 11:04:18 +02003686
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003687 /* convert it to uint32_t */
3688 errno = 0;
3689 auxs = NULL;
3690 val = strtoul(value, &auxs, 10);
3691 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3692 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3693 goto error;
3694 }
3695 list->max = (uint32_t) val;
3696 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003697 } else if (!strcmp(sub->name, "when")) {
3698 if (list->when) {
3699 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3700 goto error;
3701 }
3702
3703 list->when = read_yin_when(module, sub);
3704 lyxml_free_elem(module->ctx, sub);
3705
3706 if (!list->when) {
3707 goto error;
3708 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003709 } else {
3710 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3711 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003712 }
3713 }
Radek Krejci345ad742015-06-03 11:04:18 +02003714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003715 /* check - if list is configuration, key statement is mandatory */
3716 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
3717 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
3718 goto error;
3719 }
3720 if (list->max && list->min > list->max) {
3721 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3722 goto error;
3723 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003724
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003725 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3726 if (c_tpdf) {
3727 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
3728 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003729 if (c_must) {
3730 list->must = calloc(c_must, sizeof *list->must);
3731 }
3732 if (c_ftrs) {
3733 list->features = calloc(c_ftrs, sizeof *list->features);
3734 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003735 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3736 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003737 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003738 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02003739
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003740 if (r) {
3741 goto error;
3742 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003743 } else if (!strcmp(sub->name, "if-feature")) {
3744 GETVAL(value, sub, "name");
3745 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
3746 if (!list->features[list->features_size]) {
3747 goto error;
3748 }
3749 list->features_size++;
3750 } else if (!strcmp(sub->name, "must")) {
3751 r = fill_yin_must(module, sub, &list->must[list->must_size]);
3752 list->must_size++;
3753
3754 if (r) {
3755 goto error;
3756 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003757 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003758 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003759 }
Radek Krejci25d782a2015-05-22 15:03:23 +02003760
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003761 /* last part - process data nodes */
3762 LY_TREE_FOR_SAFE(root.child, next, sub) {
3763 if (!strcmp(sub->name, "container")) {
3764 mnode = read_yin_container(module, retval, sub, resolve, unres);
3765 } else if (!strcmp(sub->name, "leaf-list")) {
3766 mnode = read_yin_leaflist(module, retval, sub, resolve);
3767 } else if (!strcmp(sub->name, "leaf")) {
3768 mnode = read_yin_leaf(module, retval, sub, resolve);
3769 } else if (!strcmp(sub->name, "list")) {
3770 mnode = read_yin_list(module, retval, sub, resolve, unres);
3771 } else if (!strcmp(sub->name, "choice")) {
3772 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3773 } else if (!strcmp(sub->name, "uses")) {
3774 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3775 } else if (!strcmp(sub->name, "grouping")) {
3776 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3777 } else if (!strcmp(sub->name, "anyxml")) {
3778 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003779 }
3780 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003781
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003782 if (!mnode) {
3783 goto error;
3784 }
3785 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003786
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003787 if (parent && ly_mnode_addchild(parent, retval)) {
3788 goto error;
3789 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003790
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003791 if (!key_str) {
3792 /* config false list without a key */
3793 return retval;
3794 }
Radek Krejci812b10a2015-05-28 16:48:25 +02003795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003796 /* link key leafs into the list structure and check all constraints */
3797 for (i = 0; i < list->keys_size; i++) {
3798 /* get the key name */
3799 if ((value = strpbrk(key_str, " \t\n"))) {
3800 len = value - key_str;
3801 while (isspace(*value)) {
3802 value++;
3803 }
3804 } else {
3805 len = strlen(key_str);
3806 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02003807
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003808 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02003809
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003810 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
3811 goto error;
3812 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003813
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003814 /* prepare for next iteration */
3815 while (value && isspace(*value)) {
3816 value++;
3817 }
3818 key_str = value;
3819 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003820
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003821 /* process unique statements */
3822 if (c_uniq) {
3823 list->unique = calloc(c_uniq, sizeof *list->unique);
3824 }
3825 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
Radek Krejcieb00f512015-07-01 16:44:58 +02003826 if (parse_unique(retval, sub, &list->unique[list->unique_size++])) {
3827 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003828 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003829
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003830 lyxml_free_elem(module->ctx, sub);
3831 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003832
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003833 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003834
3835error:
3836
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003837 ly_mnode_free(retval);
3838 while (root.child) {
3839 lyxml_free_elem(module->ctx, root.child);
3840 }
3841 while (uniq.child) {
3842 lyxml_free_elem(module->ctx, uniq.child);
3843 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003845 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003846}
3847
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003848static struct ly_mnode *
3849read_yin_container(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003850 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003851{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003852 struct lyxml_elem *sub, *next, root;
3853 struct ly_mnode *mnode = NULL;
3854 struct ly_mnode *retval;
3855 struct ly_mnode_container *cont;
3856 const char *value;
3857 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003858 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003859
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003860 /* init */
3861 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003863 cont = calloc(1, sizeof *cont);
3864 cont->nodetype = LY_NODE_CONTAINER;
3865 cont->prev = (struct ly_mnode *)cont;
3866 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003867
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003868 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3869 goto error;
3870 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003871
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003872 /* process container's specific children */
3873 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3874 if (!strcmp(sub->name, "presence")) {
3875 if (cont->presence) {
3876 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3877 goto error;
3878 }
3879 GETVAL(value, sub, "value");
3880 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02003881
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003882 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003883 } else if (!strcmp(sub->name, "when")) {
3884 if (cont->when) {
3885 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3886 goto error;
3887 }
3888
3889 cont->when = read_yin_when(module, sub);
3890 lyxml_free_elem(module->ctx, sub);
3891
3892 if (!cont->when) {
3893 goto error;
3894 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003896 /* data statements */
3897 } else if (!strcmp(sub->name, "container") ||
3898 !strcmp(sub->name, "leaf-list") ||
3899 !strcmp(sub->name, "leaf") ||
3900 !strcmp(sub->name, "list") ||
3901 !strcmp(sub->name, "choice") ||
3902 !strcmp(sub->name, "uses") ||
3903 !strcmp(sub->name, "grouping") ||
3904 !strcmp(sub->name, "anyxml")) {
3905 lyxml_unlink_elem(sub);
3906 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003907
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003908 /* array counters */
3909 } else if (!strcmp(sub->name, "typedef")) {
3910 c_tpdf++;
3911 } else if (!strcmp(sub->name, "must")) {
3912 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003913 } else if (!strcmp(sub->name, "if-feature")) {
3914 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003915 } else {
3916 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3917 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003918 }
3919 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003920
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003921 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3922 if (c_tpdf) {
3923 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3924 }
3925 if (c_must) {
3926 cont->must = calloc(c_must, sizeof *cont->must);
3927 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003928 if (c_ftrs) {
3929 cont->features = calloc(c_ftrs, sizeof *cont->features);
3930 }
Radek Krejci800af702015-06-02 13:46:01 +02003931
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003932 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3933 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003934 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003935 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003936
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003937 if (r) {
3938 goto error;
3939 }
3940 } else if (!strcmp(sub->name, "must")) {
3941 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3942 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003943
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003944 if (r) {
3945 goto error;
3946 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003947 } else if (!strcmp(sub->name, "if-feature")) {
3948 GETVAL(value, sub, "name");
3949 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3950 if (!cont->features[cont->features_size]) {
3951 goto error;
3952 }
3953 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003954 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003955
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003956 lyxml_free_elem(module->ctx, sub);
3957 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003959 /* last part - process data nodes */
3960 LY_TREE_FOR_SAFE(root.child, next, sub) {
3961 if (!strcmp(sub->name, "container")) {
3962 mnode = read_yin_container(module, retval, sub, resolve, unres);
3963 } else if (!strcmp(sub->name, "leaf-list")) {
3964 mnode = read_yin_leaflist(module, retval, sub, resolve);
3965 } else if (!strcmp(sub->name, "leaf")) {
3966 mnode = read_yin_leaf(module, retval, sub, resolve);
3967 } else if (!strcmp(sub->name, "list")) {
3968 mnode = read_yin_list(module, retval, sub, resolve, unres);
3969 } else if (!strcmp(sub->name, "choice")) {
3970 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3971 } else if (!strcmp(sub->name, "uses")) {
3972 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3973 } else if (!strcmp(sub->name, "grouping")) {
3974 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3975 } else if (!strcmp(sub->name, "anyxml")) {
3976 mnode = read_yin_anyxml(module, retval, sub, resolve);
3977 }
3978 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003979
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003980 if (!mnode) {
3981 goto error;
3982 }
3983 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003985 if (parent && ly_mnode_addchild(parent, retval)) {
3986 goto error;
3987 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003989 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003990
3991error:
3992
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003993 ly_mnode_free(retval);
3994 while (root.child) {
3995 lyxml_free_elem(module->ctx, root.child);
3996 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003998 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003999}
4000
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004001static struct ly_mnode *
4002read_yin_grouping(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004003 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004004{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004005 struct lyxml_elem *sub, *next, root;
4006 struct ly_mnode *mnode = NULL;
4007 struct ly_mnode *retval;
4008 struct ly_mnode_grp *grp;
4009 int r;
4010 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004011
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004012 /* init */
4013 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02004014
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004015 grp = calloc(1, sizeof *grp);
4016 grp->nodetype = LY_NODE_GROUPING;
4017 grp->prev = (struct ly_mnode *)grp;
4018 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004020 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
4021 goto error;
4022 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004023
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004024 LY_TREE_FOR_SAFE(node->child, next, sub) {
4025 /* data statements */
4026 if (!strcmp(sub->name, "container") ||
4027 !strcmp(sub->name, "leaf-list") ||
4028 !strcmp(sub->name, "leaf") ||
4029 !strcmp(sub->name, "list") ||
4030 !strcmp(sub->name, "choice") ||
4031 !strcmp(sub->name, "uses") ||
4032 !strcmp(sub->name, "grouping") ||
4033 !strcmp(sub->name, "anyxml")) {
4034 lyxml_unlink_elem(sub);
4035 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004036
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004037 /* array counters */
4038 } else if (!strcmp(sub->name, "typedef")) {
4039 c_tpdf++;
4040 } else {
4041 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4042 goto error;
4043 }
4044 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004046 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4047 if (c_tpdf) {
4048 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
4049 }
4050 LY_TREE_FOR_SAFE(node->child, next, sub) {
4051 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004052 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004053 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004054
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004055 if (r) {
4056 goto error;
4057 }
4058 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004059
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004060 lyxml_free_elem(module->ctx, sub);
4061 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004062
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004063 /* last part - process data nodes */
4064 LY_TREE_FOR_SAFE(root.child, next, sub) {
4065 if (!strcmp(sub->name, "container")) {
4066 mnode = read_yin_container(module, retval, sub, resolve, unres);
4067 } else if (!strcmp(sub->name, "leaf-list")) {
4068 mnode = read_yin_leaflist(module, retval, sub, resolve);
4069 } else if (!strcmp(sub->name, "leaf")) {
4070 mnode = read_yin_leaf(module, retval, sub, resolve);
4071 } else if (!strcmp(sub->name, "list")) {
4072 mnode = read_yin_list(module, retval, sub, resolve, unres);
4073 } else if (!strcmp(sub->name, "choice")) {
4074 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4075 } else if (!strcmp(sub->name, "uses")) {
4076 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4077 } else if (!strcmp(sub->name, "grouping")) {
4078 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4079 } else if (!strcmp(sub->name, "anyxml")) {
4080 mnode = read_yin_anyxml(module, retval, sub, resolve);
4081 }
4082 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004083
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004084 if (!mnode) {
4085 goto error;
4086 }
4087 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004088
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004089 if (parent && ly_mnode_addchild(parent, retval)) {
4090 goto error;
4091 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004092
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004093 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004094
4095error:
4096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004097 ly_mnode_free(retval);
4098 while (root.child) {
4099 lyxml_free_elem(module->ctx, root.child);
4100 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004101
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004102 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004103}
4104
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004105static struct ly_mnode *
4106read_yin_input_output(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004107 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004108{
Radek Krejcie0674f82015-06-15 13:58:51 +02004109 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004110 struct ly_mnode *mnode = NULL;
4111 struct ly_mnode *retval;
4112 struct ly_mnode_input_output *inout;
4113 int r;
4114 int c_tpdf = 0;
4115
Radek Krejcie0674f82015-06-15 13:58:51 +02004116 /* init */
4117 memset(&root, 0, sizeof root);
4118
Michal Vasko38d01f72015-06-15 09:41:06 +02004119 inout = calloc(1, sizeof *inout);
4120
4121 if (!strcmp(yin->name, "input")) {
4122 inout->nodetype = LY_NODE_INPUT;
4123 } else if (!strcmp(yin->name, "output")) {
4124 inout->nodetype = LY_NODE_OUTPUT;
4125 } else {
4126 assert(0);
4127 }
4128
4129 inout->prev = (struct ly_mnode *)inout;
4130 retval = (struct ly_mnode *)inout;
4131
Michal Vaskoebeac942015-06-15 12:11:50 +02004132 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
4133 goto error;
4134 }
4135
Michal Vasko38d01f72015-06-15 09:41:06 +02004136 /* data statements */
4137 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4138 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004139 !strcmp(sub->name, "leaf-list") ||
4140 !strcmp(sub->name, "leaf") ||
4141 !strcmp(sub->name, "list") ||
4142 !strcmp(sub->name, "choice") ||
4143 !strcmp(sub->name, "uses") ||
4144 !strcmp(sub->name, "grouping") ||
4145 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004146 lyxml_unlink_elem(sub);
4147 lyxml_add_child(&root, sub);
4148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004149 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004150 } else if (!strcmp(sub->name, "typedef")) {
4151 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004152#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02004153 } else {
4154 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4155 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004156#else
Michal Vasko38d01f72015-06-15 09:41:06 +02004157 } else {
4158 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004159#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02004160 }
4161 }
4162
4163 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4164 if (c_tpdf) {
4165 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
4166 }
4167
4168 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4169 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004170 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size], NULL);
Michal Vasko38d01f72015-06-15 09:41:06 +02004171 inout->tpdf_size++;
4172
4173 if (r) {
4174 goto error;
4175 }
4176 }
4177
4178 lyxml_free_elem(module->ctx, sub);
4179 }
4180
4181 /* last part - process data nodes */
4182 LY_TREE_FOR_SAFE(root.child, next, sub) {
4183 if (!strcmp(sub->name, "container")) {
4184 mnode = read_yin_container(module, retval, sub, resolve, unres);
4185 } else if (!strcmp(sub->name, "leaf-list")) {
4186 mnode = read_yin_leaflist(module, retval, sub, resolve);
4187 } else if (!strcmp(sub->name, "leaf")) {
4188 mnode = read_yin_leaf(module, retval, sub, resolve);
4189 } else if (!strcmp(sub->name, "list")) {
4190 mnode = read_yin_list(module, retval, sub, resolve, unres);
4191 } else if (!strcmp(sub->name, "choice")) {
4192 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4193 } else if (!strcmp(sub->name, "uses")) {
4194 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4195 } else if (!strcmp(sub->name, "grouping")) {
4196 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4197 } else if (!strcmp(sub->name, "anyxml")) {
4198 mnode = read_yin_anyxml(module, retval, sub, resolve);
4199 }
4200 lyxml_free_elem(module->ctx, sub);
4201
4202 if (!mnode) {
4203 goto error;
4204 }
4205 }
4206
4207 if (parent && ly_mnode_addchild(parent, retval)) {
4208 goto error;
4209 }
4210
4211 return retval;
4212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004213error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004214
4215 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004216 while (root.child) {
4217 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004218 }
4219
4220 return NULL;
4221}
4222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004223static struct ly_mnode *
4224read_yin_notif(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004225 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02004226{
Michal Vaskoc6551b32015-06-16 10:51:43 +02004227 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02004228 struct ly_mnode *mnode = NULL;
4229 struct ly_mnode *retval;
4230 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004231 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02004232 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004233 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02004234
Michal Vaskoc6551b32015-06-16 10:51:43 +02004235 memset(&root, 0, sizeof root);
4236
Michal Vasko0ea41032015-06-16 08:53:55 +02004237 notif = calloc(1, sizeof *notif);
4238 notif->nodetype = LY_NODE_NOTIF;
4239 notif->prev = (struct ly_mnode *)notif;
4240 retval = (struct ly_mnode *)notif;
4241
4242 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
4243 goto error;
4244 }
4245
4246 /* process rpc's specific children */
4247 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4248 /* data statements */
4249 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004250 !strcmp(sub->name, "leaf-list") ||
4251 !strcmp(sub->name, "leaf") ||
4252 !strcmp(sub->name, "list") ||
4253 !strcmp(sub->name, "choice") ||
4254 !strcmp(sub->name, "uses") ||
4255 !strcmp(sub->name, "grouping") ||
4256 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004257 lyxml_unlink_elem(sub);
4258 lyxml_add_child(&root, sub);
4259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004260 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02004261 } else if (!strcmp(sub->name, "typedef")) {
4262 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004263 } else if (!strcmp(sub->name, "if-feature")) {
4264 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004265 } else {
4266 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4267 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02004268 }
4269 }
4270
4271 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4272 if (c_tpdf) {
4273 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
4274 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004275 if (c_ftrs) {
4276 notif->features = calloc(c_ftrs, sizeof *notif->features);
4277 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004278
4279 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4280 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004281 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size], NULL);
Michal Vasko0ea41032015-06-16 08:53:55 +02004282 notif->tpdf_size++;
4283
4284 if (r) {
4285 goto error;
4286 }
Radek Krejci0b24d752015-07-02 15:02:27 +02004287 } else if (!strcmp(sub->name, "if-features")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004288 GETVAL(value, sub, "name");
4289 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
4290 if (!notif->features[notif->features_size]) {
4291 goto error;
4292 }
4293 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004294 }
4295
4296 lyxml_free_elem(module->ctx, sub);
4297 }
4298
4299 /* last part - process data nodes */
4300 LY_TREE_FOR_SAFE(root.child, next, sub) {
4301 if (!strcmp(sub->name, "container")) {
4302 mnode = read_yin_container(module, retval, sub, resolve, unres);
4303 } else if (!strcmp(sub->name, "leaf-list")) {
4304 mnode = read_yin_leaflist(module, retval, sub, resolve);
4305 } else if (!strcmp(sub->name, "leaf")) {
4306 mnode = read_yin_leaf(module, retval, sub, resolve);
4307 } else if (!strcmp(sub->name, "list")) {
4308 mnode = read_yin_list(module, retval, sub, resolve, unres);
4309 } else if (!strcmp(sub->name, "choice")) {
4310 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4311 } else if (!strcmp(sub->name, "uses")) {
4312 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4313 } else if (!strcmp(sub->name, "grouping")) {
4314 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4315 } else if (!strcmp(sub->name, "anyxml")) {
4316 mnode = read_yin_anyxml(module, retval, sub, resolve);
4317 }
4318 lyxml_free_elem(module->ctx, sub);
4319
4320 if (!mnode) {
4321 goto error;
4322 }
4323 }
4324
4325 if (parent && ly_mnode_addchild(parent, retval)) {
4326 goto error;
4327 }
4328
4329 return retval;
4330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004331error:
Michal Vasko0ea41032015-06-16 08:53:55 +02004332
4333 ly_mnode_free(retval);
4334 while (root.child) {
4335 lyxml_free_elem(module->ctx, root.child);
4336 }
4337
4338 return NULL;
4339}
4340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004341static struct ly_mnode *
4342read_yin_rpc(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004343 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004344{
Radek Krejcie0674f82015-06-15 13:58:51 +02004345 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004346 struct ly_mnode *mnode = NULL;
4347 struct ly_mnode *retval;
4348 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004349 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02004350 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004351 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02004352
Radek Krejcie0674f82015-06-15 13:58:51 +02004353 /* init */
4354 memset(&root, 0, sizeof root);
4355
Michal Vasko38d01f72015-06-15 09:41:06 +02004356 rpc = calloc(1, sizeof *rpc);
4357 rpc->nodetype = LY_NODE_RPC;
4358 rpc->prev = (struct ly_mnode *)rpc;
4359 retval = (struct ly_mnode *)rpc;
4360
4361 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
4362 goto error;
4363 }
4364
4365 /* process rpc's specific children */
4366 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4367 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004368 if (rpc->child
4369 && (rpc->child->nodetype == LY_NODE_INPUT
4370 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004371 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4372 goto error;
4373 }
4374 lyxml_unlink_elem(sub);
4375 lyxml_add_child(&root, sub);
4376 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004377 if (rpc->child
4378 && (rpc->child->nodetype == LY_NODE_INPUT
4379 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004380 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4381 goto error;
4382 }
4383 lyxml_unlink_elem(sub);
4384 lyxml_add_child(&root, sub);
4385
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004386 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02004387 } else if (!strcmp(sub->name, "grouping")) {
4388 lyxml_unlink_elem(sub);
4389 lyxml_add_child(&root, sub);
4390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004391 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004392 } else if (!strcmp(sub->name, "typedef")) {
4393 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004394 } else if (!strcmp(sub->name, "if-feature")) {
4395 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004396 } else {
4397 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4398 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004399 }
4400 }
4401
4402 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4403 if (c_tpdf) {
4404 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
4405 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004406 if (c_ftrs) {
4407 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
4408 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004409
4410 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4411 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004412 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size], NULL);
Michal Vasko38d01f72015-06-15 09:41:06 +02004413 rpc->tpdf_size++;
4414
4415 if (r) {
4416 goto error;
4417 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004418 } else if (!strcmp(sub->name, "if-feature")) {
4419 GETVAL(value, sub, "name");
4420 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
4421 if (!rpc->features[rpc->features_size]) {
4422 goto error;
4423 }
4424 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004425 }
4426
4427 lyxml_free_elem(module->ctx, sub);
4428 }
4429
4430 /* last part - process data nodes */
4431 LY_TREE_FOR_SAFE(root.child, next, sub) {
4432 if (!strcmp(sub->name, "grouping")) {
4433 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4434 } else if (!strcmp(sub->name, "input")) {
4435 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4436 } else if (!strcmp(sub->name, "output")) {
4437 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4438 }
4439 lyxml_free_elem(module->ctx, sub);
4440
4441 if (!mnode) {
4442 goto error;
4443 }
4444 }
4445
4446 if (parent && ly_mnode_addchild(parent, retval)) {
4447 goto error;
4448 }
4449
4450 return retval;
4451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004452error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004453
4454 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004455 while (root.child) {
4456 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004457 }
4458
4459 return NULL;
4460}
4461
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004462static int
4463find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004464{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004465 struct ly_module *searchmod = NULL, *module = uses->module;
4466 struct ly_mnode *mnode, *mnode_aux;
4467 const char *name;
4468 int prefix_len = 0;
4469 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004471 /* get referenced grouping */
4472 name = strchr(uses->name, ':');
4473 if (!name) {
4474 /* no prefix, search in local tree */
4475 name = uses->name;
4476 } else {
4477 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004478
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004479 /* set name to correct position after colon */
4480 prefix_len = name - uses->name;
4481 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004482
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004483 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
4484 /* prefix refers to the current module, ignore it */
4485 prefix_len = 0;
4486 }
4487 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004488
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004489 /* search */
4490 if (prefix_len) {
4491 /* in top-level groupings of some other module */
4492 for (i = 0; i < module->imp_size; i++) {
4493 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
4494 && !module->imp[i].prefix[prefix_len]) {
4495 searchmod = module->imp[i].module;
4496 break;
4497 }
4498 }
4499 if (!searchmod) {
4500 /* uses refers unknown data model */
4501 LOGVAL(VE_INPREFIX, line, name);
4502 return EXIT_FAILURE;
4503 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004504
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004505 LY_TREE_FOR(searchmod->data, mnode) {
4506 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4507 uses->grp = (struct ly_mnode_grp *)mnode;
4508 return EXIT_SUCCESS;
4509 }
4510 }
4511 } else {
4512 /* in local tree hierarchy */
4513 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
4514 LY_TREE_FOR(mnode_aux->child, mnode) {
4515 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4516 uses->grp = (struct ly_mnode_grp *)mnode;
4517 return EXIT_SUCCESS;
4518 }
4519 }
4520 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004521
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004522 /* search in top level of the current module */
4523 LY_TREE_FOR(module->data, mnode) {
4524 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4525 uses->grp = (struct ly_mnode_grp *)mnode;
4526 return EXIT_SUCCESS;
4527 }
4528 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004529
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004530 /* search in top-level of included modules */
4531 for (i = 0; i < module->inc_size; i++) {
4532 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
4533 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4534 uses->grp = (struct ly_mnode_grp *)mnode;
4535 return EXIT_SUCCESS;
4536 }
4537 }
4538 }
4539 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004540
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004541 /* not found, but no explicit error occured */
4542 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02004543}
4544
Radek Krejcif5be10f2015-06-16 13:29:36 +02004545static int
4546resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
4547{
4548 struct lyxml_elem *yin, *next, *sub;
4549 struct ly_mnode *mnode;
4550
4551 assert(module);
4552
4553 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004554 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004555 if (!aug->target) {
4556 LOGVAL(VE_INARG, line, aug->target, "uses");
4557 return EXIT_FAILURE;
4558 }
4559
4560 if (!aug->child) {
4561 /* nothing to do */
4562 return EXIT_SUCCESS;
4563 }
4564
4565 yin = (struct lyxml_elem *)aug->child;
4566
4567 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
4568 return EXIT_FAILURE;
4569 }
4570
4571 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4572 if (!strcmp(sub->name, "container")) {
4573 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
4574 } else if (!strcmp(sub->name, "leaf-list")) {
4575 mnode = read_yin_leaflist(module, aug->target, sub, 1);
4576 } else if (!strcmp(sub->name, "leaf")) {
4577 mnode = read_yin_leaf(module, aug->target, sub, 1);
4578 } else if (!strcmp(sub->name, "list")) {
4579 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
4580 } else if (!strcmp(sub->name, "uses")) {
4581 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
4582 } else if (!strcmp(sub->name, "choice")) {
4583 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4584 } else if (!strcmp(sub->name, "case")) {
4585 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4586 } else if (!strcmp(sub->name, "anyxml")) {
4587 mnode = read_yin_anyxml(module, aug->target, sub, 1);
4588#if 0
4589 } else {
4590 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02004591 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004592#else
4593 } else {
4594 continue;
4595#endif
4596 }
4597
4598 if (!mnode) {
4599 return EXIT_FAILURE;
4600 }
Radek Krejci3de29a72015-06-16 15:23:03 +02004601 /* check for mandatory nodes - if the target node is in another module
4602 * the added nodes cannot be mandatory
4603 */
4604 if (check_mandatory(mnode)) {
4605 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
4606 return EXIT_FAILURE;
4607 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004608
4609 lyxml_free_elem(module->ctx, sub);
4610
4611 /* the parent pointer will point to the augment node, but all
4612 * siblings pointers and possibly the child node in target does
4613 * not know about the augment and follow the standard schema tree
4614 * structure
4615 */
4616 mnode->parent = (struct ly_mnode *)aug;
4617 mnode = NULL;
4618 }
4619
4620 lyxml_free_elem(module->ctx, yin);
4621 aug->child = NULL;
4622
4623 return EXIT_SUCCESS;
4624}
4625
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004626int
4627resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02004628{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004629 struct ly_ctx *ctx;
4630 struct ly_mnode *mnode = NULL, *mnode_aux;
4631 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02004632 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004633 int i, j;
4634 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02004635
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004636 /* copy the data nodes from grouping into the uses context */
4637 LY_TREE_FOR(uses->grp->child, mnode) {
4638 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
4639 if (!mnode_aux) {
4640 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
4641 return EXIT_FAILURE;
4642 }
4643 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
4644 ly_mnode_free(mnode_aux);
4645 return EXIT_FAILURE;
4646 }
4647 }
4648 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02004649
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004650 /* apply refines */
4651 for (i = 0; i < uses->refine_size; i++) {
4652 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02004653 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004654 if (!mnode) {
4655 LOGVAL(VE_INARG, line, rfn->target, "uses");
4656 return EXIT_FAILURE;
4657 }
Radek Krejci106efc02015-06-10 14:36:27 +02004658
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004659 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
4660 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
4661 return EXIT_FAILURE;
4662 }
Radek Krejci106efc02015-06-10 14:36:27 +02004663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004664 /* description on any nodetype */
4665 if (rfn->dsc) {
4666 lydict_remove(ctx, mnode->dsc);
4667 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
4668 }
Radek Krejci106efc02015-06-10 14:36:27 +02004669
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004670 /* reference on any nodetype */
4671 if (rfn->ref) {
4672 lydict_remove(ctx, mnode->ref);
4673 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
4674 }
Radek Krejci106efc02015-06-10 14:36:27 +02004675
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004676 /* config on any nodetype */
4677 if (rfn->flags & LY_NODE_CONFIG_MASK) {
4678 mnode->flags &= ~LY_NODE_CONFIG_MASK;
4679 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
4680 }
Radek Krejci106efc02015-06-10 14:36:27 +02004681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004682 /* default value ... */
4683 if (rfn->mod.dflt) {
4684 if (mnode->nodetype == LY_NODE_LEAF) {
4685 /* leaf */
4686 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
4687 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
4688 } else if (mnode->nodetype == LY_NODE_CHOICE) {
4689 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004690 ((struct ly_mnode_choice *)mnode)->dflt = resolve_schema_nodeid(rfn->mod.dflt, mnode, mnode->module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004691 if (!((struct ly_mnode_choice *)mnode)->dflt) {
4692 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
4693 return EXIT_FAILURE;
4694 }
4695 }
4696 }
Radek Krejci106efc02015-06-10 14:36:27 +02004697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004698 /* mandatory on leaf, anyxml or choice */
Radek Krejcieb00f512015-07-01 16:44:58 +02004699 if (rfn->flags & LY_NODE_MAND_MASK) {
4700 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
4701 /* remove current value */
4702 mnode->flags &= ~LY_NODE_MAND_MASK;
4703
4704 /* set new value */
4705 mnode->flags |= (rfn->flags & LY_NODE_MAND_MASK);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004706 }
4707 }
Radek Krejci106efc02015-06-10 14:36:27 +02004708
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004709 /* presence on container */
4710 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
4711 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
4712 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
4713 }
Radek Krejci106efc02015-06-10 14:36:27 +02004714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004715 /* min/max-elements on list or leaf-list */
4716 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
4717 /* magic - bit 3 in flags means min set, bit 4 says max set */
4718 if (rfn->flags & 0x04) {
4719 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
4720 }
4721 if (rfn->flags & 0x08) {
4722 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
4723 }
4724 }
Radek Krejci106efc02015-06-10 14:36:27 +02004725
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004726 /* must in leaf, leaf-list, list, container or anyxml */
4727 if (rfn->must_size) {
4728 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
4729 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
4730 if (!newmust) {
4731 LOGMEM;
4732 return EXIT_FAILURE;
4733 }
4734 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02004735 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004736 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
4737 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
4738 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
4739 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
4740 }
Radek Krejci106efc02015-06-10 14:36:27 +02004741
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004742 ((struct ly_mnode_leaf *)mnode)->must = newmust;
4743 ((struct ly_mnode_leaf *)mnode)->must_size = size;
4744 }
4745 }
Radek Krejci106efc02015-06-10 14:36:27 +02004746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004747 /* apply augments */
4748 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004749 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004750 goto error;
4751 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004752 }
Radek Krejci106efc02015-06-10 14:36:27 +02004753
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004754 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02004755
4756error:
4757
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004758 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02004759}
Radek Krejci74705112015-06-05 10:25:44 +02004760
4761/*
4762 * resolve - referenced grouping should be bounded to the namespace (resolved)
4763 * only when uses does not appear in grouping. In a case of grouping's uses,
4764 * we just get information but we do not apply augment or refine to it.
4765 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004766static struct ly_mnode *
4767read_yin_uses(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004768 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02004769{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004770 struct lyxml_elem *sub, *next;
4771 struct ly_mnode *retval;
4772 struct ly_mnode_uses *uses;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004773 struct obj_list *unres_new;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004774 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004775 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004776 int r;
Radek Krejci74705112015-06-05 10:25:44 +02004777
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004778 uses = calloc(1, sizeof *uses);
4779 uses->nodetype = LY_NODE_USES;
4780 uses->prev = (struct ly_mnode *)uses;
4781 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02004782
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004783 GETVAL(value, node, "name");
4784 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02004785
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004786 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
4787 goto error;
4788 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004790 /* get other properties of uses */
4791 LY_TREE_FOR_SAFE(node->child, next, sub) {
4792 if (!strcmp(sub->name, "refine")) {
4793 c_ref++;
4794 } else if (!strcmp(sub->name, "augment")) {
4795 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004796 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02004797 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02004798 } else if (!strcmp(sub->name, "when")) {
4799 if (uses->when) {
4800 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
4801 goto error;
4802 }
4803
4804 uses->when = read_yin_when(module, sub);
4805 lyxml_free_elem(module->ctx, sub);
4806
4807 if (!uses->when) {
4808 goto error;
4809 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004810 } else {
4811 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4812 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004813 }
4814 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004815
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004816 /* process properties with cardinality 0..n */
4817 if (c_ref) {
4818 uses->refine = calloc(c_ref, sizeof *uses->refine);
4819 }
4820 if (c_aug) {
4821 uses->augment = calloc(c_aug, sizeof *uses->augment);
4822 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004823 if (c_ftrs) {
4824 uses->features = calloc(c_ftrs, sizeof *uses->features);
4825 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004826
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004827 LY_TREE_FOR_SAFE(node->child, next, sub) {
4828 if (!strcmp(sub->name, "refine")) {
4829 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
4830 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004831 lyxml_free_elem(module->ctx, sub);
4832 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004833 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
4834 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004835 } else if (!strcmp(sub->name, "if-feature")) {
4836 GETVAL(value, sub, "name");
4837 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
4838 if (!uses->features[uses->features_size]) {
4839 goto error;
4840 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02004841 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004842 uses->features_size++;
4843 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004844 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004845
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004846 if (r) {
4847 goto error;
4848 }
4849 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004850
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004851 if (find_grouping(parent, uses, LOGLINE(node))) {
4852 goto error;
4853 }
4854 if (!uses->grp) {
4855 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
4856 unres_new = calloc(1, sizeof *unres_new);
4857 if (*unres) {
4858 unres_new->next = *unres;
4859 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004860 unres_new->obj = retval;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004861 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02004862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004863 /* put it at the beginning of the unresolved list */
4864 *unres = unres_new;
4865 }
Radek Krejci74705112015-06-05 10:25:44 +02004866
Radek Krejci368c38f2015-06-15 15:09:55 +02004867 if (parent && ly_mnode_addchild(parent, retval)) {
4868 goto error;
4869 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004870
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004871 if (resolve) {
4872 /* inherit config flag */
4873 if (parent) {
4874 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
4875 } else {
4876 /* default config is true */
4877 retval->flags |= LY_NODE_CONFIG_W;
4878 }
4879 }
Radek Krejcib388c152015-06-04 17:03:03 +02004880
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004881 if (resolve && uses->grp) {
4882 /* copy the data nodes from grouping into the uses context */
4883 if (resolve_uses(uses, LOGLINE(node))) {
4884 goto error;
4885 }
4886 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004887
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004888 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004889
4890error:
4891
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004892 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004893
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004894 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004895}
4896
Radek Krejciefaeba32015-05-27 14:30:57 +02004897/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004898static int
4899read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004900{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004901 struct ly_ctx *ctx = module->ctx;
4902 struct ly_submodule *submodule = (struct ly_submodule *)module;
4903 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
4904 struct ly_mnode *mnode = NULL;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004905 struct obj_list *unres = NULL, *unres_next; /* unresolved objects */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004906 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004907 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02004908 int i;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004909 int unres_flag = 0; /* 0 for uses, 1 for types */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004910 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004911 /* counters */
Radek Krejcieb00f512015-07-01 16:44:58 +02004912 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;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004913
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004914 /* init */
4915 memset(&root, 0, sizeof root);
4916 memset(&grps, 0, sizeof grps);
4917 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004918 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004919
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004920 /*
4921 * in the first run, we process elements with cardinality of 1 or 0..1 and
4922 * count elements with cardinality 0..n. Data elements (choices, containers,
4923 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4924 * need have all top-level and groupings already prepared at that time. In
4925 * the middle loop, we process other elements with carinality of 0..n since
4926 * we need to allocate arrays to store them.
4927 */
4928 LY_TREE_FOR_SAFE(yin->child, next, node) {
4929 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4930 lyxml_free_elem(ctx, node);
4931 continue;
4932 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004933
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004934 if (!module->type && !strcmp(node->name, "namespace")) {
4935 if (module->ns) {
4936 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4937 goto error;
4938 }
4939 GETVAL(value, node, "uri");
4940 module->ns = lydict_insert(ctx, value, strlen(value));
4941 lyxml_free_elem(ctx, node);
4942 } else if (!module->type && !strcmp(node->name, "prefix")) {
4943 if (module->prefix) {
4944 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4945 goto error;
4946 }
4947 GETVAL(value, node, "value");
4948 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4949 goto error;
4950 }
4951 module->prefix = lydict_insert(ctx, value, strlen(value));
4952 lyxml_free_elem(ctx, node);
4953 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4954 if (belongsto_flag) {
4955 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4956 goto error;
4957 }
4958 belongsto_flag = 1;
4959 GETVAL(value, node, "module");
4960 while (submodule->belongsto->type) {
4961 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4962 }
4963 if (value != submodule->belongsto->name) {
4964 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4965 goto error;
4966 }
Radek Krejcif3886932015-06-04 17:36:06 +02004967
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004968 /* get the prefix substatement, start with checks */
4969 if (!node->child) {
4970 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4971 goto error;
4972 } else if (strcmp(node->child->name, "prefix")) {
4973 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4974 goto error;
4975 } else if (node->child->next) {
4976 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4977 goto error;
4978 }
4979 /* and now finally get the value */
4980 GETVAL(value, node->child, "value");
4981 /* check here differs from a generic prefix check, since this prefix
4982 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004983 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004984 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4985 goto error;
4986 }
4987 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004989 /* we are done with belongs-to */
4990 lyxml_free_elem(ctx, node);
Radek Krejcieb00f512015-07-01 16:44:58 +02004991
4992 /* counters (statements with n..1 cardinality) */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004993 } else if (!strcmp(node->name, "import")) {
4994 c_imp++;
4995 } else if (!strcmp(node->name, "revision")) {
4996 c_rev++;
4997 } else if (!strcmp(node->name, "typedef")) {
4998 c_tpdf++;
4999 } else if (!strcmp(node->name, "identity")) {
5000 c_ident++;
5001 } else if (!strcmp(node->name, "include")) {
5002 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02005003 } else if (!strcmp(node->name, "augment")) {
5004 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005005 } else if (!strcmp(node->name, "feature")) {
5006 c_ftrs++;
Radek Krejcieb00f512015-07-01 16:44:58 +02005007 } else if (!strcmp(node->name, "deviation")) {
5008 c_dev++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005010 /* data statements */
5011 } else if (!strcmp(node->name, "container") ||
5012 !strcmp(node->name, "leaf-list") ||
5013 !strcmp(node->name, "leaf") ||
5014 !strcmp(node->name, "list") ||
5015 !strcmp(node->name, "choice") ||
5016 !strcmp(node->name, "uses") ||
5017 !strcmp(node->name, "anyxml")) {
5018 lyxml_unlink_elem(node);
5019 lyxml_add_child(&root, node);
5020 } else if (!strcmp(node->name, "grouping")) {
5021 /* keep groupings separated and process them before other data statements */
5022 lyxml_unlink_elem(node);
5023 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005024
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005025 /* optional statements */
5026 } else if (!strcmp(node->name, "description")) {
5027 if (module->dsc) {
5028 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5029 goto error;
5030 }
5031 module->dsc = read_yin_subnode(ctx, node, "text");
5032 lyxml_free_elem(ctx, node);
5033 if (!module->dsc) {
5034 goto error;
5035 }
5036 } else if (!strcmp(node->name, "reference")) {
5037 if (module->ref) {
5038 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5039 goto error;
5040 }
5041 module->ref = read_yin_subnode(ctx, node, "text");
5042 lyxml_free_elem(ctx, node);
5043 if (!module->ref) {
5044 goto error;
5045 }
5046 } else if (!strcmp(node->name, "organization")) {
5047 if (module->org) {
5048 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5049 goto error;
5050 }
5051 module->org = read_yin_subnode(ctx, node, "text");
5052 lyxml_free_elem(ctx, node);
5053 if (!module->org) {
5054 goto error;
5055 }
5056 } else if (!strcmp(node->name, "contact")) {
5057 if (module->contact) {
5058 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5059 goto error;
5060 }
5061 module->contact = read_yin_subnode(ctx, node, "text");
5062 lyxml_free_elem(ctx, node);
5063 if (!module->contact) {
5064 goto error;
5065 }
5066 } else if (!strcmp(node->name, "yang-version")) {
5067 /* TODO: support YANG 1.1 ? */
5068 if (module->version) {
5069 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5070 goto error;
5071 }
5072 GETVAL(value, node, "value");
5073 if (strcmp(value, "1")) {
5074 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
5075 goto error;
5076 }
5077 module->version = 1;
5078 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02005079
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005080 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02005081 } else if (!strcmp(node->name, "rpc")) {
5082 lyxml_unlink_elem(node);
5083 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02005084 } else if (!strcmp(node->name, "notification")) {
5085 lyxml_unlink_elem(node);
5086 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02005087#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005088 } else {
5089 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
5090 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02005091#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005092 } else {
5093 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02005094#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005095 }
5096 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005097
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005098 if (!submodule) {
5099 /* check for mandatory statements */
5100 if (!module->ns) {
5101 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
5102 goto error;
5103 }
5104 if (!module->prefix) {
5105 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
5106 goto error;
5107 }
5108 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02005109
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005110 /* allocate arrays for elements with cardinality of 0..n */
5111 if (c_imp) {
5112 module->imp = calloc(c_imp, sizeof *module->imp);
5113 }
5114 if (c_rev) {
5115 module->rev = calloc(c_rev, sizeof *module->rev);
5116 }
5117 if (c_tpdf) {
5118 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
5119 }
5120 if (c_ident) {
5121 module->ident = calloc(c_ident, sizeof *module->ident);
5122 }
5123 if (c_inc) {
5124 module->inc = calloc(c_inc, sizeof *module->inc);
5125 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005126 if (c_aug) {
5127 module->augment = calloc(c_aug, sizeof *module->augment);
5128 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005129 if (c_ftrs) {
5130 module->features = calloc(c_ftrs, sizeof *module->features);
5131 }
Radek Krejcieb00f512015-07-01 16:44:58 +02005132 if (c_dev) {
5133 module->deviation = calloc(c_dev, sizeof *module->deviation);
5134 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005135
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005136 /* now we are going to remember unresolved types, the flag is
5137 * used in case of error to get know how to free the structures
5138 * in unres list
5139 */
5140 unres_flag = 1;
5141
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005142 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5143 LY_TREE_FOR_SAFE(yin->child, next, node) {
5144 if (!strcmp(node->name, "import")) {
5145 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
5146 module->imp_size++;
5147 if (r) {
5148 goto error;
5149 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005151 /* check duplicities in imported modules */
5152 for (i = 0; i < module->imp_size - 1; i++) {
5153 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
5154 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
5155 goto error;
5156 }
5157 }
5158 } else if (!strcmp(node->name, "include")) {
5159 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
5160 module->inc_size++;
5161 if (r) {
5162 goto error;
5163 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005164
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005165 /* check duplications in include submodules */
5166 for (i = 0; i < module->inc_size - 1; i++) {
5167 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
5168 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
5169 module->inc[i].submodule->name);
5170 goto error;
5171 }
5172 }
5173 } else if (!strcmp(node->name, "revision")) {
5174 GETVAL(value, node, "date");
5175 if (check_date(value, LOGLINE(node))) {
5176 goto error;
5177 }
5178 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5179 /* check uniqueness of the revision date - not required by RFC */
5180 for (i = 0; i < module->rev_size; i++) {
5181 if (!strcmp(value, module->rev[i].date)) {
5182 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5183 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
5184 }
5185 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005186
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005187 LY_TREE_FOR(node->child, child) {
5188 if (!strcmp(child->name, "description")) {
5189 if (module->rev[module->rev_size].dsc) {
5190 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5191 goto error;
5192 }
5193 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
5194 if (!module->rev[module->rev_size].dsc) {
5195 goto error;
5196 }
5197 } else if (!strcmp(child->name, "reference")) {
5198 if (module->rev[module->rev_size].ref) {
5199 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5200 goto error;
5201 }
5202 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
5203 if (!module->rev[module->rev_size].ref) {
5204 goto error;
5205 }
5206 } else {
5207 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
5208 goto error;
5209 }
5210 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005211
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005212 /* keep the latest revision at position 0 */
5213 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
5214 /* switch their position */
5215 value = strdup(module->rev[0].date);
5216 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
5217 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5218 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02005219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005220 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
5221 value = module->rev[0].dsc;
5222 module->rev[0].dsc = module->rev[module->rev_size].dsc;
5223 module->rev[module->rev_size].dsc = value;
5224 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005225
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005226 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
5227 value = module->rev[0].ref;
5228 module->rev[0].ref = module->rev[module->rev_size].ref;
5229 module->rev[module->rev_size].ref = value;
5230 }
5231 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005232
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005233 module->rev_size++;
5234 } else if (!strcmp(node->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005235 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size], &unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005236 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02005237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005238 if (r) {
5239 goto error;
5240 }
5241 } else if (!strcmp(node->name, "identity")) {
5242 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
5243 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02005244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005245 if (r) {
5246 goto error;
5247 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005248 } else if (!strcmp(node->name, "feature")) {
5249 r = fill_yin_feature(module, node, &module->features[module->features_size]);
5250 module->features_size++;
5251
5252 if (r) {
5253 goto error;
5254 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005255 } else if (!strcmp(node->name, "augment")) {
5256 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
5257 module->augment_size++;
5258
5259 if (r) {
5260 goto error;
5261 }
5262
5263 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
5264 continue;
Radek Krejcieb00f512015-07-01 16:44:58 +02005265 } else if (!strcmp(node->name, "deviation")) {
5266 r = fill_yin_deviation(module, node, &module->deviation[module->deviation_size]);
5267 module->deviation_size++;
5268
5269 if (r) {
5270 goto error;
5271 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005272 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005274 lyxml_free_elem(ctx, node);
5275 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005276 /* resolve unresolved types (possible in typedef's with unions */
5277 while (unres) {
5278 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
5279 ((struct ly_type *)unres->obj)->der = NULL;
5280 r = fill_yin_type(module, NULL, node, (struct ly_type *)unres->obj, NULL);
5281 lyxml_free_elem(ctx, node);
5282
5283 unres_next = unres->next;
5284 free(unres);
5285 unres = unres_next;
5286
5287 if (r) {
5288 goto error;
5289 }
5290 }
5291 unres_flag = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005292
Radek Krejcif5be10f2015-06-16 13:29:36 +02005293 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005294 * refer to them
5295 */
5296 LY_TREE_FOR_SAFE(grps.child, next, node) {
5297 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
5298 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02005299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005300 if (!mnode) {
5301 goto error;
5302 }
Radek Krejci74705112015-06-05 10:25:44 +02005303
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005304 /* include data element */
5305 if (module->data) {
5306 module->data->prev->next = mnode;
5307 mnode->prev = module->data->prev;
5308 module->data->prev = mnode;
5309 } else {
5310 module->data = mnode;
5311 }
5312 }
5313 while (unres) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005314 if (find_grouping(((struct ly_mnode_uses *)unres->obj)->parent, (struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005315 goto error;
5316 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005317 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5318 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005319 goto error;
5320 }
5321 unres_next = unres->next;
5322 free(unres);
5323 unres = unres_next;
5324 }
Radek Krejci74705112015-06-05 10:25:44 +02005325
Radek Krejcif5be10f2015-06-16 13:29:36 +02005326 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005327 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02005328
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005329 if (!strcmp(node->name, "container")) {
5330 mnode = read_yin_container(module, NULL, node, 1, &unres);
5331 } else if (!strcmp(node->name, "leaf-list")) {
5332 mnode = read_yin_leaflist(module, NULL, node, 1);
5333 } else if (!strcmp(node->name, "leaf")) {
5334 mnode = read_yin_leaf(module, NULL, node, 1);
5335 } else if (!strcmp(node->name, "list")) {
5336 mnode = read_yin_list(module, NULL, node, 1, &unres);
5337 } else if (!strcmp(node->name, "choice")) {
5338 mnode = read_yin_choice(module, NULL, node, 1, &unres);
5339 } else if (!strcmp(node->name, "uses")) {
5340 mnode = read_yin_uses(module, NULL, node, 1, &unres);
5341 } else if (!strcmp(node->name, "anyxml")) {
5342 mnode = read_yin_anyxml(module, NULL, node, 1);
5343 }
5344 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005345
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005346 if (!mnode) {
5347 goto error;
5348 }
Radek Krejci25d782a2015-05-22 15:03:23 +02005349
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005350 /* include data element */
5351 if (module->data) {
5352 module->data->prev->next = mnode;
5353 mnode->prev = module->data->prev;
5354 module->data->prev = mnode;
5355 } else {
5356 module->data = mnode;
5357 }
5358 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005359
5360 /* ... rpcs ... */
5361 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
5362 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
5363 lyxml_free_elem(ctx, node);
5364
5365 if (!mnode) {
5366 goto error;
5367 }
5368
5369 /* include rpc element */
5370 if (module->rpc) {
5371 module->rpc->prev->next = mnode;
5372 mnode->prev = module->rpc->prev;
5373 module->rpc->prev = mnode;
5374 } else {
5375 module->rpc = mnode;
5376 }
5377 }
5378
5379 /* ... and notifications */
5380 LY_TREE_FOR_SAFE(notifs.child, next, node) {
5381 mnode = read_yin_notif(module, NULL, node, 0, &unres);
5382 lyxml_free_elem(ctx, node);
5383
5384 if (!mnode) {
5385 goto error;
5386 }
5387
5388 /* include notification element */
5389 if (module->notif) {
5390 module->notif->prev->next = mnode;
5391 mnode->prev = module->notif->prev;
5392 module->notif->prev = mnode;
5393 } else {
5394 module->notif = mnode;
5395 }
5396 }
5397
5398 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005399 while (unres) {
5400 /* find referenced grouping */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005401 if (find_grouping(((struct ly_mnode_uses *)unres->obj)->parent, (struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005402 goto error;
5403 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005404 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5405 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005406 goto error;
5407 }
Radek Krejci74705112015-06-05 10:25:44 +02005408
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005409 /* resolve uses by copying grouping content under the uses */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005410 if (resolve_uses((struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005411 goto error;
5412 }
Radek Krejci74705112015-06-05 10:25:44 +02005413
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005414 unres_next = unres->next;
5415 free(unres);
5416 unres = unres_next;
5417 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005418
Radek Krejcif5be10f2015-06-16 13:29:36 +02005419 /* and finally apply augments */
5420 for (i = 0; i < module->augment_size; i++) {
5421 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005422 goto error;
5423 }
Michal Vasko0ea41032015-06-16 08:53:55 +02005424 }
5425
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005426 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02005427
5428error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005429 /* cleanup */
5430 while (root.child) {
5431 lyxml_free_elem(module->ctx, root.child);
5432 }
5433 while (grps.child) {
5434 lyxml_free_elem(module->ctx, grps.child);
5435 }
5436 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005437 lyxml_free_elem(module->ctx, rpcs.child);
5438 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005439
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005440 while (unres) {
5441 unres_next = unres->next;
5442 if (unres_flag) {
5443 /* free the XML subtrees kept in unresolved type structures */
5444 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
5445 lyxml_free_elem(ctx, node);
5446 }
5447
5448 free(unres);
5449 unres = unres_next;
5450 }
5451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005452 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02005453}
5454
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005455struct ly_submodule *
5456yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005457{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005458 struct lyxml_elem *yin;
5459 struct ly_submodule *submodule = NULL;
5460 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02005461
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005462 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02005463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005464 yin = lyxml_read(module->ctx, data, 0);
5465 if (!yin) {
5466 return NULL;
5467 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005468
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005469 /* check root element */
5470 if (!yin->name || strcmp(yin->name, "submodule")) {
5471 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5472 goto error;
5473 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005475 GETVAL(value, yin, "name");
5476 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5477 goto error;
5478 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005479
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005480 submodule = calloc(1, sizeof *submodule);
5481 if (!submodule) {
5482 LOGMEM;
5483 goto error;
5484 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005485
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005486 submodule->ctx = module->ctx;
5487 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
5488 submodule->type = 1;
5489 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02005490
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005491 LOGVRB("reading submodule %s", submodule->name);
5492 if (read_sub_module((struct ly_module *)submodule, yin)) {
5493 goto error;
5494 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005495
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005496 /* cleanup */
5497 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02005498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005499 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02005500
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005501 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02005502
5503error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005504 /* cleanup */
5505 lyxml_free_elem(module->ctx, yin);
5506 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02005507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005508 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02005509}
5510
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005511struct ly_module *
5512yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005513{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005514 struct lyxml_elem *yin;
5515 struct ly_module *module = NULL, **newlist = NULL;
5516 const char *value;
5517 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02005518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005519 yin = lyxml_read(ctx, data, 0);
5520 if (!yin) {
5521 return NULL;
5522 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005523
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005524 /* check root element */
5525 if (!yin->name || strcmp(yin->name, "module")) {
5526 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5527 goto error;
5528 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005529
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005530 GETVAL(value, yin, "name");
5531 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5532 goto error;
5533 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005534
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005535 module = calloc(1, sizeof *module);
5536 if (!module) {
5537 LOGMEM;
5538 goto error;
5539 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005540
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005541 module->ctx = ctx;
5542 module->name = lydict_insert(ctx, value, strlen(value));
5543 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02005544
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005545 LOGVRB("reading module %s", module->name);
5546 if (read_sub_module(module, yin)) {
5547 goto error;
5548 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005549
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005550 /* add to the context's list of modules */
5551 if (ctx->models.used == ctx->models.size) {
5552 newlist = realloc(ctx->models.list, ctx->models.size * 2);
5553 if (!newlist) {
5554 LOGMEM;
5555 goto error;
5556 }
5557 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
5558 newlist[i] = NULL;
5559 }
5560 ctx->models.size *= 2;
5561 ctx->models.list = newlist;
5562 }
5563 for (i = 0; ctx->models.list[i]; i++) {
5564 /* check name (name/revision) and namespace uniqueness */
5565 if (!strcmp(ctx->models.list[i]->name, module->name)) {
5566 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
5567 /* both data models are same, with no revision specified */
5568 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
5569 module->name);
5570 goto error;
5571 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
5572 /* one of the models does not have a revision, so they differs */
5573 continue;
5574 } else {
5575 /* both models have a revision statement which we have to
5576 * compare, revision at position 0 is the last revision
5577 */
5578 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
5579 /* we have the same modules */
5580 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
5581 module->rev[0].date);
5582 goto error;
5583 }
5584 }
5585 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
5586 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
5587 ctx->models.list[i]->name, module->name, module->ns);
5588 goto error;
5589 }
5590 }
5591 ctx->models.list[i] = module;
5592 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005593
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005594 /* cleanup */
5595 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005596
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005597 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005598
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005599 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005600
5601error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005602 /* cleanup */
5603 lyxml_free_elem(ctx, yin);
5604 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005606 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005607}