blob: 6b9cb099ece3deb8e8d0f8a541c6b2415eb0eda8 [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 Krejci74705112015-06-05 10:25:44 +020065struct mnode_list {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020066 struct ly_mnode *mnode;
67 struct mnode_list *next;
68 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,
72 int resolve, struct mnode_list **unres);
73static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
74 int resolve, struct mnode_list **unres);
75static 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,
78 int resolve, struct mnode_list **unres);
79static 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,
84 int resolve, struct mnode_list **unres);
85static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
86 int resolve, struct mnode_list **unres);
87static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
88 int resolve, struct mnode_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 Krejci41726f92015-06-19 13:11:05 +0200777read_restr_substmt(struct ly_ctx *ctx, struct ly_must *restr, struct lyxml_elem *yin)
778{
779 struct lyxml_elem *next, *child;
780
781 LY_TREE_FOR_SAFE(yin->child, next, child) {
782 if (!strcmp(child->name, "description")) {
783 if (restr->dsc) {
784 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
785 return EXIT_FAILURE;
786 }
787 restr->dsc = read_yin_subnode(ctx, child, "text");
788 if (!restr->dsc) {
789 return EXIT_FAILURE;
790 }
791 } else if (!strcmp(child->name, "reference")) {
792 if (restr->ref) {
793 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
794 return EXIT_FAILURE;
795 }
796 restr->ref = read_yin_subnode(ctx, child, "text");
797 if (!restr->ref) {
798 return EXIT_FAILURE;
799 }
800 } else if (!strcmp(child->name, "error-app-tag")) {
801 if (restr->eapptag) {
802 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
803 return EXIT_FAILURE;
804 }
805 restr->eapptag = read_yin_subnode(ctx, child, "value");
806 if (!restr->eapptag) {
807 return EXIT_FAILURE;
808 }
809 } else if (!strcmp(child->name, "error-message")) {
810 if (restr->emsg) {
811 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
812 return EXIT_FAILURE;
813 }
814 restr->emsg = read_yin_subnode(ctx, child, "value");
815 if (!restr->emsg) {
816 return EXIT_FAILURE;
817 }
818 } else {
819 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
820 return EXIT_FAILURE;
821 }
822
823 lyxml_free_elem(ctx, child);
824 }
825
826 return EXIT_SUCCESS;
827}
828
829static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200830fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200831{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200832 const char *value, *delim;
833 struct lyxml_elem *next, *node, root;
Radek Krejci994b6f62015-06-18 16:47:27 +0200834 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200835 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200836 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200837
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200838 /* init */
839 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +0200840
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200841 GETVAL(value, yin, "name")
842 delim = strchr(value, ':');
843 if (delim) {
844 type->prefix = lydict_insert(module->ctx, value, delim - value);
845 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200846
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200847 type->der = find_superior_type(value, module, parent);
848 if (!type->der) {
849 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
850 goto error;
851 }
852 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200853
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200854 switch (type->base) {
855 case LY_TYPE_BINARY:
Radek Krejci41726f92015-06-19 13:11:05 +0200856 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
857 LY_TREE_FOR_SAFE(yin->child, next, node) {
858 if (!strcmp(node->name, "length")) {
859 if (type->info.binary.length) {
860 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
861 goto error;
862 }
863
864 GETVAL(value, node, "value");
865 if (check_length(value, type, LOGLINE(node))) {
866 goto error;
867 }
868 type->info.binary.length = calloc(1, sizeof *type->info.binary.length);
869 type->info.binary.length->expr = lydict_insert(module->ctx, value, 0);
870
871 /* get possible substatements */
872 if (read_restr_substmt(module->ctx, (struct ly_must *)type->info.binary.length, node)) {
873 goto error;
874 }
875 } else {
876 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
877 goto error;
878 }
879 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200880 break;
Radek Krejci04581c62015-05-22 21:24:00 +0200881
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200882 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200883 /* RFC 6020 9.7.4 - bit */
884
885 /* get bit specifications, at least one must be present */
886 LY_TREE_FOR_SAFE(yin->child, next, node) {
887 if (!strcmp(node->name, "bit")) {
888 lyxml_unlink_elem(node);
889 lyxml_add_child(&root, node);
890 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200891 } else {
892 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
893 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200894 }
895 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200896 if (!type->info.bits.count) {
897 if (type->der->type.der) {
898 /* this is just a derived type with no bit specified */
899 break;
900 }
901 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
902 goto error;
903 }
904
905 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
906 for (i = p = 0; root.child; i++) {
907 GETVAL(value, root.child, "name");
908 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(root.child), NULL, NULL)) {
909 goto error;
910 }
911 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
912 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], root.child, 0)) {
913 type->info.bits.count = i + 1;
914 goto error;
915 }
916
917 /* check the name uniqueness */
918 for (j = 0; j < i; j++) {
919 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
920 LOGVAL(VE_BITS_DUPNAME, LOGLINE(root.child), type->info.bits.bit[i].name);
921 type->info.bits.count = i + 1;
922 goto error;
923 }
924 }
925
926 node = root.child->child;
927 if (node && !strcmp(node->name, "position")) {
928 value = lyxml_get_attr(node, "value", NULL);
929 p_ = strtol(value, NULL, 10);
930
931 /* range check */
932 if (p_ < 0 || p_ > UINT32_MAX) {
933 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
934 type->info.bits.count = i + 1;
935 goto error;
936 }
937 type->info.bits.bit[i].pos = (uint32_t)p_;
938
939 /* keep the highest enum value for automatic increment */
940 if (type->info.bits.bit[i].pos > p) {
941 p = type->info.bits.bit[i].pos;
942 p++;
943 } else {
944 /* check that the value is unique */
945 for (j = 0; j < i; j++) {
946 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
947 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
948 type->info.bits.count = i + 1;
949 goto error;
950 }
951 }
952 }
953 } else {
954 /* assign value automatically */
955 if (p > UINT32_MAX) {
956 LOGVAL(VE_INARG, LOGLINE(root.child), "4294967295", "bit/position");
957 type->info.bits.count = i + 1;
958 goto error;
959 }
960 type->info.bits.bit[i].pos = (uint32_t)p;
961 p++;
962 }
963 lyxml_free_elem(module->ctx, root.child);
964 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200965 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200966
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200967 case LY_TYPE_DEC64:
968 /* TODO fraction-digits, 9.3.4
969 * - MUST, 1, nerekurzivni, hodnota 1-18 */
970 /* TODO range, 9.2.4
971 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
972 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200973
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200974 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200975 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200976
Radek Krejci994b6f62015-06-18 16:47:27 +0200977 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200978 LY_TREE_FOR_SAFE(yin->child, next, node) {
979 if (!strcmp(node->name, "enum")) {
980 lyxml_unlink_elem(node);
981 lyxml_add_child(&root, node);
982 type->info.enums.count++;
983 }
984 }
985 if (yin->child) {
986 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
987 goto error;
988 }
989 if (!type->info.enums.count) {
990 if (type->der->type.der) {
991 /* this is just a derived type with no enum specified */
992 break;
993 }
994 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
995 goto error;
996 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200998 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
999 for (i = v = 0; root.child; i++) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001000 GETVAL(value, root.child, "name");
1001 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(root.child), NULL, NULL)) {
1002 goto error;
1003 }
1004 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
1005 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001006 type->info.enums.count = i + 1;
1007 goto error;
1008 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001010 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1011 value = type->info.enums.list[i].name;
1012 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
1013 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
1014 type->info.enums.count = i + 1;
1015 goto error;
1016 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001017
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001018 /* check the name uniqueness */
1019 for (j = 0; j < i; j++) {
1020 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
1021 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
1022 type->info.enums.count = i + 1;
1023 goto error;
1024 }
1025 }
Radek Krejci04581c62015-05-22 21:24:00 +02001026
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001027 node = root.child->child;
1028 if (node && !strcmp(node->name, "value")) {
1029 value = lyxml_get_attr(node, "value", NULL);
1030 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001031
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001032 /* range check */
1033 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1034 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1035 type->info.enums.count = i + 1;
1036 goto error;
1037 }
1038 type->info.enums.list[i].value = v_;
1039
1040 /* keep the highest enum value for automatic increment */
1041 if (type->info.enums.list[i].value > v) {
1042 v = type->info.enums.list[i].value;
1043 v++;
1044 } else {
1045 /* check that the value is unique */
1046 for (j = 0; j < i; j++) {
1047 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001048 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 +02001049 type->info.enums.count = i + 1;
1050 goto error;
1051 }
1052 }
1053 }
1054 } else {
1055 /* assign value automatically */
1056 if (v > INT32_MAX) {
1057 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
1058 type->info.enums.count = i + 1;
1059 goto error;
1060 }
1061 type->info.enums.list[i].value = v;
1062 v++;
1063 }
1064 lyxml_free_elem(module->ctx, root.child);
1065 }
1066 break;
1067
1068 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001069 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001070
1071 /* get base specification, exactly one must be present */
1072 if (!yin->child) {
1073 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1074 goto error;
1075 }
1076 if (strcmp(yin->child->name, "base")) {
1077 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1078 goto error;
1079 }
1080 if (yin->child->next) {
1081 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1082 goto error;
1083 }
1084 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1085 if (!type->info.ident.ref) {
1086 return EXIT_FAILURE;
1087 }
1088 break;
1089
1090 case LY_TYPE_INST:
1091 /* TODO require-instance, 9.13.2
1092 * - 0..1, true/false */
1093 break;
1094
1095 case LY_TYPE_INT8:
1096 case LY_TYPE_INT16:
1097 case LY_TYPE_INT32:
1098 case LY_TYPE_INT64:
1099 case LY_TYPE_UINT8:
1100 case LY_TYPE_UINT16:
1101 case LY_TYPE_UINT32:
1102 case LY_TYPE_UINT64:
1103 /* TODO range, 9.2.4
1104 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
1105 break;
1106
1107 case LY_TYPE_LEAFREF:
1108 /* TODO path, 9.9.2
1109 * - 1, nerekurzivni, string */
1110 break;
1111
1112 case LY_TYPE_STRING:
1113 /* TODO length, 9.4.4
1114 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
1115 * pattern, 9.4.6
1116 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
1117 break;
1118
1119 case LY_TYPE_UNION:
1120 /* TODO type, 7.4
1121 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1122 break;
1123
1124 default:
1125 /* nothing needed :
1126 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1127 */
1128 break;
1129 }
1130
1131 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001132
1133error:
1134
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001135 LY_TREE_FOR_SAFE(root.child, next, node) {
1136 lyxml_free_elem(module->ctx, node);
1137 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001138
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001139 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001140}
1141
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001142static int
1143fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_tpdf *tpdf)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001144{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001145 const char *value;
1146 struct lyxml_elem *node, *next;
1147 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001149 GETVAL(value, yin, "name");
1150 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1151 goto error;
1152 }
1153 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001154
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001155 /* generic part - status, description, reference */
1156 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1157 goto error;
1158 }
Radek Krejcieac35532015-05-31 19:09:15 +02001159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001160 LY_TREE_FOR_SAFE(yin->child, next, node) {
1161 if (!strcmp(node->name, "type")) {
1162 if (tpdf->type.der) {
1163 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1164 goto error;
1165 }
1166 r = fill_yin_type(module, parent, node, &tpdf->type);
1167 } else if (!strcmp(node->name, "default")) {
1168 if (tpdf->dflt) {
1169 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1170 goto error;
1171 }
1172 GETVAL(value, node, "value");
1173 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1174 } else if (!strcmp(node->name, "units")) {
1175 if (tpdf->units) {
1176 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1177 goto error;
1178 }
1179 GETVAL(value, node, "name");
1180 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1181 } else {
1182 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1183 r = 1;
1184 }
1185 lyxml_free_elem(module->ctx, node);
1186 if (r) {
1187 goto error;
1188 }
1189 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001190
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001191 /* check mandatory value */
1192 if (!tpdf->type.der) {
1193 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1194 goto error;
1195 }
Radek Krejcieac35532015-05-31 19:09:15 +02001196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001197 /* check default value */
1198 if (check_default(&tpdf->type, tpdf->dflt)) {
1199 goto error;
1200 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001201
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001202 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001203
1204error:
1205
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001206 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001207}
1208
Radek Krejci3cf9e222015-06-18 11:37:50 +02001209static struct ly_feature *
1210resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1211{
1212 const char *prefix;
1213 unsigned int prefix_len = 0;
1214 int i, j, found = 0;
1215
1216 assert(name);
1217 assert(module);
1218
1219 /* check prefix */
1220 prefix = name;
1221 name = strchr(prefix, ':');
1222 if (name) {
1223 /* there is prefix */
1224 prefix_len = name - prefix;
1225 name++;
1226
1227 /* check whether the prefix points to the current module */
1228 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1229 /* then ignore prefix and works as there is no prefix */
1230 prefix_len = 0;
1231 }
1232 } else {
1233 /* no prefix, set pointers correctly */
1234 name = prefix;
1235 }
1236
1237 if (prefix_len) {
1238 /* search in imported modules */
1239 for (i = 0; i < module->imp_size; i++) {
1240 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1241 module = module->imp[i].module;
1242 found = 1;
1243 break;
1244 }
1245 }
1246 if (!found) {
1247 /* identity refers unknown data model */
1248 LOGVAL(VE_INPREFIX, line, prefix);
1249 return NULL;
1250 }
1251 } else {
1252 /* search in submodules */
1253 for (i = 0; i < module->inc_size; i++) {
1254 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1255 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1256 return &(module->inc[i].submodule->features[j]);
1257 }
1258 }
1259 }
1260 }
1261
1262 /* search in the identified module */
1263 for (j = 0; j < module->features_size; j++) {
1264 if (!strcmp(name, module->features[j].name)) {
1265 return &module->features[j];
1266 }
1267 }
1268
1269 /* not found */
1270 return NULL;
1271}
1272
1273static int
1274fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1275{
1276 const char *value;
1277 struct lyxml_elem *child, *next;
1278 int c = 0;
1279
Radek Krejcib05774c2015-06-18 13:52:59 +02001280 GETVAL(value, yin, "name");
1281 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1282 goto error;
1283 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001284 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001285
1286 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001287 goto error;
1288 }
1289
1290 LY_TREE_FOR_SAFE(yin->child, next, child) {
1291 if (!strcmp(child->name, "if-feature")) {
1292 c++;
1293 } else {
1294 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1295 goto error;
1296 }
1297 }
1298
1299 if (c) {
1300 f->features = calloc(c, sizeof *f->features);
1301 }
1302
1303 LY_TREE_FOR_SAFE(yin->child, next, child) {
1304 GETVAL(value, child, "name");
1305 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1306 if (!f->features[f->features_size]) {
1307 goto error;
1308 }
1309 f->features_size++;
1310 }
1311
1312 /* tmp TODO remove */
1313 f->flags |= LY_NODE_FENABLED;
1314
1315 return EXIT_SUCCESS;
1316
1317error:
1318
1319 return EXIT_FAILURE;
1320}
1321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001322static int
1323fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
Radek Krejci800af702015-06-02 13:46:01 +02001324{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001325 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001327 GETVAL(value, yin, "condition");
1328 must->cond = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001329
Radek Krejci41726f92015-06-19 13:11:05 +02001330 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001331
Radek Krejci41726f92015-06-19 13:11:05 +02001332error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001334 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001335}
1336
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001337static int
1338fill_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 +02001339{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001340 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001341 struct lyxml_elem *next, *child;
1342 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001344 GETVAL(value, yin, "target-node");
1345 aug->target_name = lydict_insert(module->ctx, value, 0);
1346 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001347
Radek Krejci3cf9e222015-06-18 11:37:50 +02001348 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1349 goto error;
1350 }
1351
1352 LY_TREE_FOR_SAFE(yin->child, next, child) {
1353 if (!strcmp(child->name, "if-feature")) {
1354 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001355 } else if (!strcmp(child->name, "when")) {
1356 if (aug->when) {
1357 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1358 goto error;
1359 }
1360
1361 aug->when = read_yin_when(module, child);
1362 lyxml_free_elem(module->ctx, child);
1363
1364 if (!aug->when) {
1365 goto error;
1366 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001367
1368 /* check allowed sub-statements */
1369 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1370 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1371 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1372 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1373 goto error;
1374 }
1375 }
1376
1377 if (c) {
1378 aug->features = calloc(c, sizeof *aug->features);
1379 }
1380
1381 LY_TREE_FOR_SAFE(yin->child, next, child) {
1382 if (!strcmp(child->name, "if-feature")) {
1383 GETVAL(value, child, "name");
1384 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1385 if (!aug->features[aug->features_size]) {
1386 goto error;
1387 }
1388 aug->features_size++;
1389 } else {
1390 /* keep the data nodes */
1391 continue;
1392 }
1393
1394 lyxml_free_elem(module->ctx, child);
1395 }
1396
1397 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001398 * when we will have the target node
1399 */
1400 lyxml_unlink_elem(yin);
1401 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001402
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001403 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001404
1405error:
1406
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001407 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001408}
1409
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001410static int
1411fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001412{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001413 struct lyxml_elem *sub, *next;
1414 const char *value;
1415 char *endptr;
1416 int f_mand = 0, f_min = 0, f_max = 0;
1417 int c_must = 0;
1418 int r;
1419 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001421 GETVAL(value, yin, "target-node");
1422 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001424 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1425 goto error;
1426 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001427
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001428 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1429 /* limited applicability */
1430 if (!strcmp(sub->name, "default")) {
1431 /* leaf or choice */
1432 if (rfn->mod.dflt) {
1433 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1434 goto error;
1435 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001436
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001437 /* check possibility of statements combination */
1438 if (rfn->target_type) {
1439 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1440 if (!rfn->target_type) {
1441 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1442 goto error;
1443 }
1444 } else {
1445 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1446 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001447
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001448 GETVAL(value, sub, "value");
1449 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1450 } else if (!strcmp(sub->name, "mandatory")) {
1451 /* leaf, choice or anyxml */
1452 if (f_mand) {
1453 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1454 goto error;
1455 }
1456 /* just checking the flags in leaf is not sufficient, we would allow
1457 * multiple mandatory statements with the "false" value
1458 */
1459 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001460
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001461 /* check possibility of statements combination */
1462 if (rfn->target_type) {
1463 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1464 if (!rfn->target_type) {
1465 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1466 goto error;
1467 }
1468 } else {
1469 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1470 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001471
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001472 GETVAL(value, sub, "value");
1473 if (!strcmp(value, "true")) {
1474 rfn->flags |= LY_NODE_MAND_TRUE;
1475 } else if (!strcmp(value, "false")) {
1476 rfn->flags |= LY_NODE_MAND_FALSE;
1477 } else {
1478 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1479 goto error;
1480 }
1481 } else if (!strcmp(sub->name, "min-elements")) {
1482 /* list or leaf-list */
1483 if (f_min) {
1484 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1485 goto error;
1486 }
1487 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001488
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001489 /* check possibility of statements combination */
1490 if (rfn->target_type) {
1491 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1492 if (!rfn->target_type) {
1493 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1494 goto error;
1495 }
1496 } else {
1497 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1498 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001499
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001500 GETVAL(value, sub, "value");
1501 while (isspace(value[0])) {
1502 value++;
1503 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001504
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001505 /* convert it to uint32_t */
1506 errno = 0;
1507 endptr = NULL;
1508 val = strtoul(value, &endptr, 10);
1509 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1510 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1511 goto error;
1512 }
1513 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001514
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001515 /* magic - bit 3 in flags means min set */
1516 rfn->flags |= 0x04;
1517 } else if (!strcmp(sub->name, "max-elements")) {
1518 /* list or leaf-list */
1519 if (f_max) {
1520 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1521 goto error;
1522 }
1523 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001525 /* check possibility of statements combination */
1526 if (rfn->target_type) {
1527 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1528 if (!rfn->target_type) {
1529 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1530 goto error;
1531 }
1532 } else {
1533 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1534 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001536 GETVAL(value, sub, "value");
1537 while (isspace(value[0])) {
1538 value++;
1539 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001540
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001541 /* convert it to uint32_t */
1542 errno = 0;
1543 endptr = NULL;
1544 val = strtoul(value, &endptr, 10);
1545 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1546 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1547 goto error;
1548 }
1549 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001550
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001551 /* magic - bit 4 in flags means min set */
1552 rfn->flags |= 0x08;
1553 } else if (!strcmp(sub->name, "presence")) {
1554 /* container */
1555 if (rfn->mod.presence) {
1556 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1557 goto error;
1558 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001560 /* check possibility of statements combination */
1561 if (rfn->target_type) {
1562 rfn->target_type &= LY_NODE_CONTAINER;
1563 if (!rfn->target_type) {
1564 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1565 goto error;
1566 }
1567 } else {
1568 rfn->target_type = LY_NODE_CONTAINER;
1569 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001570
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001571 GETVAL(value, sub, "value");
1572 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1573 } else if (!strcmp(sub->name, "must")) {
1574 /* leaf-list, list, container or anyxml */
1575 /* check possibility of statements combination */
1576 if (rfn->target_type) {
1577 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1578 if (!rfn->target_type) {
1579 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1580 goto error;
1581 }
1582 } else {
1583 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1584 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001585
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001586 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001588 } else {
1589 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1590 goto error;
1591 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001593 lyxml_free_elem(module->ctx, sub);
1594 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001596 /* process nodes with cardinality of 0..n */
1597 if (c_must) {
1598 rfn->must = calloc(c_must, sizeof *rfn->must);
1599 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001601 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1602 if (!strcmp(sub->name, "must")) {
1603 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1604 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001606 if (r) {
1607 goto error;
1608 }
1609 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001610
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001611 lyxml_free_elem(module->ctx, sub);
1612 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001613
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001614 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001615
1616error:
1617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001618 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001619}
1620
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001621static int
1622fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001623{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001624 struct lyxml_elem *child;
1625 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001626
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001627 LY_TREE_FOR(yin->child, child) {
1628 if (!strcmp(child->name, "prefix")) {
1629 GETVAL(value, child, "value");
1630 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1631 goto error;
1632 }
1633 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1634 } else if (!strcmp(child->name, "revision-date")) {
1635 if (imp->rev[0]) {
1636 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1637 goto error;
1638 }
1639 GETVAL(value, child, "date");
1640 if (check_date(value, LOGLINE(child))) {
1641 goto error;
1642 }
1643 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1644 } else {
1645 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1646 goto error;
1647 }
1648 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001649
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001650 /* check mandatory information */
1651 if (!imp->prefix) {
1652 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1653 goto error;
1654 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001655
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001656 GETVAL(value, yin, "module");
1657 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1658 if (!imp->module) {
1659 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1660 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1661 goto error;
1662 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001664 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001665
1666error:
1667
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001668 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001669}
1670
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001671static int
1672fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001673{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001674 struct lyxml_elem *child;
1675 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001677 LY_TREE_FOR(yin->child, child) {
1678 if (!strcmp(child->name, "revision-date")) {
1679 if (inc->rev[0]) {
1680 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1681 goto error;
1682 }
1683 GETVAL(value, child, "date");
1684 if (check_date(value, LOGLINE(child))) {
1685 goto error;
1686 }
1687 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1688 } else {
1689 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1690 goto error;
1691 }
1692 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001693
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001694 GETVAL(value, yin, "module");
1695 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1696 if (!inc->submodule) {
1697 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1698 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1699 goto error;
1700 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001701
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001702 /* check that belongs-to corresponds */
1703 if (module->type) {
1704 module = ((struct ly_submodule *)module)->belongsto;
1705 }
1706 if (inc->submodule->belongsto != module) {
1707 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1708 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1709 goto error;
1710 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001711
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001712 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001713
1714error:
1715
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001716 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001717}
1718
Radek Krejcida04f4a2015-05-21 12:54:09 +02001719/*
1720 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001721 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001722 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001723 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001724static int
1725read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1726 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001727{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001728 const char *value;
1729 struct lyxml_elem *sub, *next;
1730 struct ly_ctx *const ctx = module->ctx;
1731 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001732
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001733 if (opt & OPT_MODULE) {
1734 mnode->module = module;
1735 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001737 if (opt & OPT_IDENT) {
1738 GETVAL(value, xmlnode, "name");
1739 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1740 goto error;
1741 }
1742 mnode->name = lydict_insert(ctx, value, strlen(value));
1743 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001744
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001745 /* process local parameters */
1746 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1747 if (!strcmp(sub->name, "description")) {
1748 if (mnode->dsc) {
1749 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1750 goto error;
1751 }
1752 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1753 if (!mnode->dsc) {
1754 r = 1;
1755 }
1756 } else if (!strcmp(sub->name, "reference")) {
1757 if (mnode->ref) {
1758 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1759 goto error;
1760 }
1761 mnode->ref = read_yin_subnode(ctx, sub, "text");
1762 if (!mnode->ref) {
1763 r = 1;
1764 }
1765 } else if (!strcmp(sub->name, "status")) {
1766 if (mnode->flags & LY_NODE_STATUS_MASK) {
1767 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1768 goto error;
1769 }
1770 GETVAL(value, sub, "value");
1771 if (!strcmp(value, "current")) {
1772 mnode->flags |= LY_NODE_STATUS_CURR;
1773 } else if (!strcmp(value, "deprecated")) {
1774 mnode->flags |= LY_NODE_STATUS_DEPRC;
1775 } else if (!strcmp(value, "obsolete")) {
1776 mnode->flags |= LY_NODE_STATUS_OBSLT;
1777 } else {
1778 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1779 r = 1;
1780 }
1781 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1782 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1783 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1784 goto error;
1785 }
1786 GETVAL(value, sub, "value");
1787 if (!strcmp(value, "false")) {
1788 mnode->flags |= LY_NODE_CONFIG_R;
1789 } else if (!strcmp(value, "true")) {
1790 mnode->flags |= LY_NODE_CONFIG_W;
1791 } else {
1792 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1793 r = 1;
1794 }
1795 } else {
1796 /* skip the lyxml_free_elem */
1797 continue;
1798 }
1799 lyxml_free_elem(ctx, sub);
1800 if (r) {
1801 goto error;
1802 }
1803 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001804
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001805 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1806 /* get config flag from parent */
1807 if (parent) {
1808 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1809 } else {
1810 /* default config is true */
1811 mnode->flags |= LY_NODE_CONFIG_W;
1812 }
1813 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001815 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001816
1817error:
1818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001819 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001820}
1821
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001822static struct ly_when *
1823read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
1824{
Radek Krejci53ebfb12015-06-19 09:35:59 +02001825 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001826 struct lyxml_elem *next, *child;
1827 const char *value;
1828
1829 retval = calloc(1, sizeof *retval);
1830
1831 GETVAL(value, yin, "condition");
1832 retval->cond = lydict_insert(module->ctx, value, 0);
1833
1834 LY_TREE_FOR_SAFE(yin->child, next, child) {
1835 if (!strcmp(child->name, "description")) {
1836 if (retval->dsc) {
1837 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1838 goto error;
1839 }
1840 retval->dsc = read_yin_subnode(module->ctx, child, "text");
1841 if (!retval->dsc) {
1842 goto error;
1843 }
1844 } else if (!strcmp(child->name, "reference")) {
1845 if (retval->ref) {
1846 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1847 goto error;
1848 }
1849 retval->ref = read_yin_subnode(module->ctx, child, "text");
1850 if (!retval->ref) {
1851 goto error;
1852 }
1853 } else {
1854 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1855 goto error;
1856 }
1857
1858 lyxml_free_elem(module->ctx, child);
1859 }
1860
1861 return retval;
1862
1863error:
1864
Radek Krejci53ebfb12015-06-19 09:35:59 +02001865 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001866 return NULL;
1867}
1868
Radek Krejcib4cf2022015-06-03 14:40:05 +02001869/* additional check in case statement - the child must be unique across
1870 * all other case names and its data children
1871 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001872static int
1873check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001874{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001875 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001877 if (new->nodetype == LY_NODE_CHOICE) {
1878 /* we have nested choice in case, so we need recursion */
1879 LY_TREE_FOR(new->child, mnode) {
1880 if (mnode->nodetype == LY_NODE_CASE) {
1881 LY_TREE_FOR(mnode->child, submnode) {
1882 if (check_branch_id(parent, submnode, new, line)) {
1883 return EXIT_FAILURE;
1884 }
1885 }
1886 } else if (check_branch_id(parent, mnode, new, line)) {
1887 return EXIT_FAILURE;
1888 }
1889 }
1890 } else {
1891 LY_TREE_FOR(parent->child, mnode) {
1892 if (mnode == excl) {
1893 continue;
1894 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001896 if (!strcmp(new->name, mnode->name)) {
1897 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1898 return EXIT_FAILURE;
1899 }
1900 if (mnode->nodetype == LY_NODE_CASE) {
1901 LY_TREE_FOR(mnode->child, submnode) {
1902 if (!strcmp(new->name, submnode->name)) {
1903 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1904 return EXIT_FAILURE;
1905 }
1906 }
1907 }
1908 }
1909 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001910
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001911 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001912}
1913
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001914static struct ly_mnode *
1915read_yin_case(struct ly_module *module,
1916 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001917{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001918 struct lyxml_elem *sub, *next;
1919 struct ly_mnode_case *mcase;
1920 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001921 int c_ftrs = 0;
1922 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001924 mcase = calloc(1, sizeof *mcase);
1925 mcase->nodetype = LY_NODE_CASE;
1926 mcase->prev = (struct ly_mnode *)mcase;
1927 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001928
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001929 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
1930 goto error;
1931 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001932
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001933 /* process choice's specific children */
1934 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1935 if (!strcmp(sub->name, "container")) {
1936 mnode = read_yin_container(module, retval, sub, resolve, unres);
1937 } else if (!strcmp(sub->name, "leaf-list")) {
1938 mnode = read_yin_leaflist(module, retval, sub, resolve);
1939 } else if (!strcmp(sub->name, "leaf")) {
1940 mnode = read_yin_leaf(module, retval, sub, resolve);
1941 } else if (!strcmp(sub->name, "list")) {
1942 mnode = read_yin_list(module, retval, sub, resolve, unres);
1943 } else if (!strcmp(sub->name, "uses")) {
1944 mnode = read_yin_uses(module, retval, sub, resolve, unres);
1945 } else if (!strcmp(sub->name, "choice")) {
1946 mnode = read_yin_choice(module, retval, sub, resolve, unres);
1947 } else if (!strcmp(sub->name, "anyxml")) {
1948 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02001949 } else if (!strcmp(sub->name, "if-feature")) {
1950 c_ftrs++;
1951
1952 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
1953 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001954 } else if (!strcmp(sub->name, "when")) {
1955 if (mcase->when) {
1956 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1957 goto error;
1958 }
1959
1960 mcase->when = read_yin_when(module, sub);
1961 if (!mcase->when) {
1962 goto error;
1963 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001964 } else {
1965 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1966 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001967 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001968
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001969 if (!mnode) {
1970 goto error;
1971 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
1972 goto error;
1973 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001974
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001975 mnode = NULL;
1976 lyxml_free_elem(module->ctx, sub);
1977 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001978
Radek Krejci3cf9e222015-06-18 11:37:50 +02001979 if (c_ftrs) {
1980 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
1981 }
1982 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1983 GETVAL(value, sub, "name");
1984 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
1985 if (!mcase->features[mcase->features_size]) {
1986 goto error;
1987 }
1988 mcase->features_size++;
1989 lyxml_free_elem(module->ctx, sub);
1990 }
1991
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001992 /* inherit config flag */
1993 if (parent) {
1994 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1995 } else {
1996 /* default config is true */
1997 retval->flags |= LY_NODE_CONFIG_W;
1998 }
Radek Krejcib388c152015-06-04 17:03:03 +02001999
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002000 /* insert the node into the schema tree */
2001 if (ly_mnode_addchild(parent, retval)) {
2002 goto error;
2003 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002004
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002005 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002006
2007error:
2008
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002009 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002011 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002012}
2013
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002014static struct ly_mnode *
2015read_yin_choice(struct ly_module *module,
2016 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002017{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002018 struct lyxml_elem *sub, *next;
2019 struct ly_ctx *const ctx = module->ctx;
2020 struct ly_mnode *retval, *mnode = NULL;
2021 struct ly_mnode_choice *choice;
2022 const char *value;
2023 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002024 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002026 choice = calloc(1, sizeof *choice);
2027 choice->nodetype = LY_NODE_CHOICE;
2028 choice->prev = (struct ly_mnode *)choice;
2029 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002031 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2032 goto error;
2033 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002034
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002035 /* process choice's specific children */
2036 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2037 if (!strcmp(sub->name, "container")) {
2038 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2039 goto error;
2040 }
2041 } else if (!strcmp(sub->name, "leaf-list")) {
2042 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2043 goto error;
2044 }
2045 } else if (!strcmp(sub->name, "leaf")) {
2046 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2047 goto error;
2048 }
2049 } else if (!strcmp(sub->name, "list")) {
2050 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2051 goto error;
2052 }
2053 } else if (!strcmp(sub->name, "case")) {
2054 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2055 goto error;
2056 }
2057 } else if (!strcmp(sub->name, "anyxml")) {
2058 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2059 goto error;
2060 }
2061 } else if (!strcmp(sub->name, "default")) {
2062 if (dflt_str) {
2063 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2064 goto error;
2065 }
2066 GETVAL(value, sub, "value");
2067 dflt_str = strdup(value);
2068 } else if (!strcmp(sub->name, "mandatory")) {
2069 if (f_mand) {
2070 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2071 goto error;
2072 }
2073 /* just checking the flags in leaf is not sufficient, we would allow
2074 * multiple mandatory statements with the "false" value
2075 */
2076 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002078 GETVAL(value, sub, "value");
2079 if (!strcmp(value, "true")) {
2080 choice->flags |= LY_NODE_MAND_TRUE;
2081 } else if (strcmp(value, "false")) {
2082 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2083 goto error;
2084 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002085 } else if (!strcmp(sub->name, "when")) {
2086 if (choice->when) {
2087 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2088 goto error;
2089 }
2090
2091 choice->when = read_yin_when(module, sub);
2092 if (!choice->when) {
2093 goto error;
2094 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002095 } else if (!strcmp(sub->name, "if-feature")) {
2096 c_ftrs++;
2097
2098 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
2099 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002100 } else {
2101 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2102 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002103 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002104
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002105 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
2106 goto error;
2107 }
2108 mnode = NULL;
2109 lyxml_free_elem(ctx, sub);
2110 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002111
Radek Krejci3cf9e222015-06-18 11:37:50 +02002112 if (c_ftrs) {
2113 choice->features = calloc(c_ftrs, sizeof *choice->features);
2114 }
2115
2116 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2117 GETVAL(value, sub, "name");
2118 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
2119 if (!choice->features[choice->features_size]) {
2120 goto error;
2121 }
2122 choice->features_size++;
2123 lyxml_free_elem(ctx, sub);
2124 }
2125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002126 /* check - default is prohibited in combination with mandatory */
2127 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
2128 LOGVAL(VE_SPEC, LOGLINE(yin),
2129 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
2130 goto error;
2131 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002132
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002133 /* link default with the case */
2134 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02002135 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002136 if (!choice->dflt) {
2137 /* default branch not found */
2138 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
2139 goto error;
2140 }
2141 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002142
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002143 /* insert the node into the schema tree */
2144 if (parent && ly_mnode_addchild(parent, retval)) {
2145 goto error;
2146 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002147
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002148 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02002149
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002150 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002151
2152error:
2153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002154 ly_mnode_free(retval);
2155 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002156
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002157 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002158}
2159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002160static struct ly_mnode *
2161read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02002162{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002163 struct ly_mnode *retval;
2164 struct ly_mnode_leaf *anyxml;
2165 struct lyxml_elem *sub, *next;
2166 const char *value;
2167 int r;
2168 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002169 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02002170
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002171 anyxml = calloc(1, sizeof *anyxml);
2172 anyxml->nodetype = LY_NODE_ANYXML;
2173 anyxml->prev = (struct ly_mnode *)anyxml;
2174 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02002175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002176 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2177 goto error;
2178 }
Radek Krejci863c2852015-06-03 15:47:11 +02002179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002180 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2181 if (!strcmp(sub->name, "mandatory")) {
2182 if (f_mand) {
2183 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2184 goto error;
2185 }
2186 /* just checking the flags in leaf is not sufficient, we would allow
2187 * multiple mandatory statements with the "false" value
2188 */
2189 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02002190
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002191 GETVAL(value, sub, "value");
2192 if (!strcmp(value, "true")) {
2193 anyxml->flags |= LY_NODE_MAND_TRUE;
2194 } else if (strcmp(value, "false")) {
2195 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2196 goto error;
2197 }
2198 /* else false is the default value, so we can ignore it */
2199 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002200 } else if (!strcmp(sub->name, "when")) {
2201 if (anyxml->when) {
2202 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2203 goto error;
2204 }
2205
2206 anyxml->when = read_yin_when(module, sub);
2207 lyxml_free_elem(module->ctx, sub);
2208
2209 if (!anyxml->when) {
2210 goto error;
2211 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002212 } else if (!strcmp(sub->name, "must")) {
2213 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002214 } else if (!strcmp(sub->name, "if-feature")) {
2215 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02002216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002217 } else {
2218 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2219 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002220 }
2221 }
Radek Krejci863c2852015-06-03 15:47:11 +02002222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002223 /* middle part - process nodes with cardinality of 0..n */
2224 if (c_must) {
2225 anyxml->must = calloc(c_must, sizeof *anyxml->must);
2226 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002227 if (c_ftrs) {
2228 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
2229 }
Radek Krejci863c2852015-06-03 15:47:11 +02002230
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002231 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2232 if (!strcmp(sub->name, "must")) {
2233 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
2234 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02002235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002236 if (r) {
2237 goto error;
2238 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002239 } else if (!strcmp(sub->name, "must")) {
2240 GETVAL(value, sub, "name");
2241 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
2242 if (!anyxml->features[anyxml->features_size]) {
2243 goto error;
2244 }
2245 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002246 }
Radek Krejci863c2852015-06-03 15:47:11 +02002247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002248 lyxml_free_elem(module->ctx, sub);
2249 }
Radek Krejci863c2852015-06-03 15:47:11 +02002250
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002251 if (parent && ly_mnode_addchild(parent, retval)) {
2252 goto error;
2253 }
Radek Krejci863c2852015-06-03 15:47:11 +02002254
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002255 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02002256
2257error:
2258
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002259 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02002260
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002261 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02002262}
2263
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002264static struct ly_mnode *
2265read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002266{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002267 struct ly_mnode *retval;
2268 struct ly_mnode_leaf *leaf;
2269 struct lyxml_elem *sub, *next;
2270 const char *value;
2271 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002272 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002274 leaf = calloc(1, sizeof *leaf);
2275 leaf->nodetype = LY_NODE_LEAF;
2276 leaf->prev = (struct ly_mnode *)leaf;
2277 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002278
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002279 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2280 goto error;
2281 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002283 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2284 if (!strcmp(sub->name, "type")) {
2285 if (leaf->type.der) {
2286 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2287 goto error;
2288 }
2289 if (fill_yin_type(module, parent, sub, &leaf->type)) {
2290 goto error;
2291 }
2292 } else if (!strcmp(sub->name, "default")) {
2293 if (leaf->dflt) {
2294 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2295 goto error;
2296 }
2297 GETVAL(value, sub, "value");
2298 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
2299 } else if (!strcmp(sub->name, "units")) {
2300 if (leaf->units) {
2301 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2302 goto error;
2303 }
2304 GETVAL(value, sub, "name");
2305 leaf->units = lydict_insert(module->ctx, value, strlen(value));
2306 } else if (!strcmp(sub->name, "mandatory")) {
2307 if (f_mand) {
2308 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2309 goto error;
2310 }
2311 /* just checking the flags in leaf is not sufficient, we would allow
2312 * multiple mandatory statements with the "false" value
2313 */
2314 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002315
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002316 GETVAL(value, sub, "value");
2317 if (!strcmp(value, "true")) {
2318 leaf->flags |= LY_NODE_MAND_TRUE;
2319 } else if (strcmp(value, "false")) {
2320 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2321 goto error;
2322 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002323 } else if (!strcmp(sub->name, "when")) {
2324 if (leaf->when) {
2325 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2326 goto error;
2327 }
2328
2329 leaf->when = read_yin_when(module, sub);
2330 if (!leaf->when) {
2331 goto error;
2332 }
2333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002334 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002335 c_must++; /* else false is the default value, so we can ignore it */
2336 } else if (!strcmp(sub->name, "if-feature")) {
2337 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002339 /* skip element free at the end of the loop */
2340 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002341 } else {
2342 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2343 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002344 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002345
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002346 lyxml_free_elem(module->ctx, sub);
2347 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002348
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002349 /* check mandatory parameters */
2350 if (!leaf->type.der) {
2351 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2352 goto error;
2353 }
2354 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2355 goto error;
2356 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002357
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002358 /* middle part - process nodes with cardinality of 0..n */
2359 if (c_must) {
2360 leaf->must = calloc(c_must, sizeof *leaf->must);
2361 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002362 if (c_ftrs) {
2363 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2364 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002366 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2367 if (!strcmp(sub->name, "must")) {
2368 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2369 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002370
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002371 if (r) {
2372 goto error;
2373 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002374 } else if (!strcmp(sub->name, "if-feature")) {
2375 GETVAL(value, sub, "name");
2376 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2377 if (!leaf->features[leaf->features_size]) {
2378 goto error;
2379 }
2380 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002381 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002382
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002383 lyxml_free_elem(module->ctx, sub);
2384 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002385
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002386 if (parent && ly_mnode_addchild(parent, retval)) {
2387 goto error;
2388 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002389
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002390 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002391
2392error:
2393
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002394 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002396 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002397}
2398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002399static struct ly_mnode *
2400read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002401{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002402 struct ly_mnode *retval;
2403 struct ly_mnode_leaflist *llist;
2404 struct lyxml_elem *sub, *next;
2405 const char *value;
2406 char *endptr;
2407 unsigned long val;
2408 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002409 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002410 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002412 llist = calloc(1, sizeof *llist);
2413 llist->nodetype = LY_NODE_LEAFLIST;
2414 llist->prev = (struct ly_mnode *)llist;
2415 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002416
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002417 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2418 goto error;
2419 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002421 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2422 if (!strcmp(sub->name, "type")) {
2423 if (llist->type.der) {
2424 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2425 goto error;
2426 }
2427 if (fill_yin_type(module, parent, sub, &llist->type)) {
2428 goto error;
2429 }
2430 } else if (!strcmp(sub->name, "units")) {
2431 if (llist->units) {
2432 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2433 goto error;
2434 }
2435 GETVAL(value, sub, "name");
2436 llist->units = lydict_insert(module->ctx, value, strlen(value));
2437 } else if (!strcmp(sub->name, "ordered-by")) {
2438 if (f_ordr) {
2439 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2440 goto error;
2441 }
2442 /* just checking the flags in llist is not sufficient, we would
2443 * allow multiple ordered-by statements with the "system" value
2444 */
2445 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002447 if (llist->flags & LY_NODE_CONFIG_R) {
2448 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2449 * state data
2450 */
2451 lyxml_free_elem(module->ctx, sub);
2452 continue;
2453 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002454
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002455 GETVAL(value, sub, "value");
2456 if (!strcmp(value, "user")) {
2457 llist->flags |= LY_NODE_USERORDERED;
2458 } else if (strcmp(value, "system")) {
2459 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2460 goto error;
2461 } /* else system is the default value, so we can ignore it */
2462 } else if (!strcmp(sub->name, "must")) {
2463 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002464 } else if (!strcmp(sub->name, "if-feature")) {
2465 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002466
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002467 /* skip element free at the end of the loop */
2468 continue;
2469 } else if (!strcmp(sub->name, "min-elements")) {
2470 if (f_min) {
2471 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2472 goto error;
2473 }
2474 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002475
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002476 GETVAL(value, sub, "value");
2477 while (isspace(value[0])) {
2478 value++;
2479 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002481 /* convert it to uint32_t */
2482 errno = 0;
2483 endptr = NULL;
2484 val = strtoul(value, &endptr, 10);
2485 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2486 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2487 goto error;
2488 }
2489 llist->min = (uint32_t) val;
2490 } else if (!strcmp(sub->name, "max-elements")) {
2491 if (f_max) {
2492 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2493 goto error;
2494 }
2495 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002496
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002497 GETVAL(value, sub, "value");
2498 while (isspace(value[0])) {
2499 value++;
2500 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002502 /* convert it to uint32_t */
2503 errno = 0;
2504 endptr = NULL;
2505 val = strtoul(value, &endptr, 10);
2506 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2507 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2508 goto error;
2509 }
2510 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002511 } else if (!strcmp(sub->name, "when")) {
2512 if (llist->when) {
2513 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2514 goto error;
2515 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002516
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002517 llist->when = read_yin_when(module, sub);
2518 if (!llist->when) {
2519 goto error;
2520 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002521 } else {
2522 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2523 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002524 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002526 lyxml_free_elem(module->ctx, sub);
2527 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002528
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002529 /* check constraints */
2530 if (!llist->type.der) {
2531 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2532 goto error;
2533 }
2534 if (llist->max && llist->min > llist->max) {
2535 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2536 goto error;
2537 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002539 /* middle part - process nodes with cardinality of 0..n */
2540 if (c_must) {
2541 llist->must = calloc(c_must, sizeof *llist->must);
2542 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002543 if (c_ftrs) {
2544 llist->features = calloc(c_ftrs, sizeof *llist->features);
2545 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002546
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002547 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2548 if (!strcmp(sub->name, "must")) {
2549 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2550 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002551
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002552 if (r) {
2553 goto error;
2554 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002555 } else if (!strcmp(sub->name, "if-feature")) {
2556 GETVAL(value, sub, "name");
2557 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2558 if (!llist->features[llist->features_size]) {
2559 goto error;
2560 }
2561 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002562 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002563
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002564 lyxml_free_elem(module->ctx, sub);
2565 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002567 if (parent && ly_mnode_addchild(parent, retval)) {
2568 goto error;
2569 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002570
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002571 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002572
2573error:
2574
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002575 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002577 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002578}
2579
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002580static struct ly_mnode *
2581read_yin_list(struct ly_module *module,
2582 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002583{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002584 struct ly_mnode *retval, *mnode;
2585 struct ly_mnode_list *list;
2586 struct ly_unique *uniq_s;
2587 struct lyxml_elem *sub, *next, root, uniq;
2588 int i, r;
2589 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002590 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002591 int f_ordr = 0, f_max = 0, f_min = 0;
2592 const char *key_str = NULL, *uniq_str, *value;
2593 char *auxs;
2594 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002596 /* init */
2597 memset(&root, 0, sizeof root);
2598 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002599
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002600 list = calloc(1, sizeof *list);
2601 list->nodetype = LY_NODE_LIST;
2602 list->prev = (struct ly_mnode *)list;
2603 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002604
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002605 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2606 goto error;
2607 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002609 /* process list's specific children */
2610 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2611 /* data statements */
2612 if (!strcmp(sub->name, "container") ||
2613 !strcmp(sub->name, "leaf-list") ||
2614 !strcmp(sub->name, "leaf") ||
2615 !strcmp(sub->name, "list") ||
2616 !strcmp(sub->name, "choice") ||
2617 !strcmp(sub->name, "uses") ||
2618 !strcmp(sub->name, "grouping") ||
2619 !strcmp(sub->name, "anyxml")) {
2620 lyxml_unlink_elem(sub);
2621 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002622
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002623 /* array counters */
2624 } else if (!strcmp(sub->name, "key")) {
2625 /* check cardinality 0..1 */
2626 if (list->keys_size) {
2627 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2628 goto error;
2629 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002631 /* count the number of keys */
2632 GETVAL(value, sub, "value");
2633 key_str = value;
2634 while ((value = strpbrk(value, " \t\n"))) {
2635 list->keys_size++;
2636 while (isspace(*value)) {
2637 value++;
2638 }
2639 }
2640 list->keys_size++;
2641 list->keys = calloc(list->keys_size, sizeof *list->keys);
2642 } else if (!strcmp(sub->name, "unique")) {
2643 c_uniq++;
2644 lyxml_unlink_elem(sub);
2645 lyxml_add_child(&uniq, sub);
2646 } else if (!strcmp(sub->name, "typedef")) {
2647 c_tpdf++;
2648 } else if (!strcmp(sub->name, "must")) {
2649 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002650 } else if (!strcmp(sub->name, "if-feature")) {
2651 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002653 /* optional stetments */
2654 } else if (!strcmp(sub->name, "ordered-by")) {
2655 if (f_ordr) {
2656 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2657 goto error;
2658 }
2659 /* just checking the flags in llist is not sufficient, we would
2660 * allow multiple ordered-by statements with the "system" value
2661 */
2662 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002664 if (list->flags & LY_NODE_CONFIG_R) {
2665 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2666 * state data
2667 */
2668 lyxml_free_elem(module->ctx, sub);
2669 continue;
2670 }
Radek Krejci345ad742015-06-03 11:04:18 +02002671
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002672 GETVAL(value, sub, "value");
2673 if (!strcmp(value, "user")) {
2674 list->flags |= LY_NODE_USERORDERED;
2675 } else if (strcmp(value, "system")) {
2676 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2677 goto error;
2678 }
2679 /* else system is the default value, so we can ignore it */
2680 lyxml_free_elem(module->ctx, sub);
2681 } else if (!strcmp(sub->name, "min-elements")) {
2682 if (f_min) {
2683 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2684 goto error;
2685 }
2686 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002687
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002688 GETVAL(value, sub, "value");
2689 while (isspace(value[0])) {
2690 value++;
2691 }
Radek Krejci345ad742015-06-03 11:04:18 +02002692
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002693 /* convert it to uint32_t */
2694 errno = 0;
2695 auxs = NULL;
2696 val = strtoul(value, &auxs, 10);
2697 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2698 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2699 goto error;
2700 }
2701 list->min = (uint32_t) val;
2702 lyxml_free_elem(module->ctx, sub);
2703 } else if (!strcmp(sub->name, "max-elements")) {
2704 if (f_max) {
2705 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2706 goto error;
2707 }
2708 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002709
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002710 GETVAL(value, sub, "value");
2711 while (isspace(value[0])) {
2712 value++;
2713 }
Radek Krejci345ad742015-06-03 11:04:18 +02002714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002715 /* convert it to uint32_t */
2716 errno = 0;
2717 auxs = NULL;
2718 val = strtoul(value, &auxs, 10);
2719 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2720 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2721 goto error;
2722 }
2723 list->max = (uint32_t) val;
2724 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002725 } else if (!strcmp(sub->name, "when")) {
2726 if (list->when) {
2727 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2728 goto error;
2729 }
2730
2731 list->when = read_yin_when(module, sub);
2732 lyxml_free_elem(module->ctx, sub);
2733
2734 if (!list->when) {
2735 goto error;
2736 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002737 } else {
2738 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2739 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002740 }
2741 }
Radek Krejci345ad742015-06-03 11:04:18 +02002742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002743 /* check - if list is configuration, key statement is mandatory */
2744 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2745 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2746 goto error;
2747 }
2748 if (list->max && list->min > list->max) {
2749 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2750 goto error;
2751 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002752
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002753 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2754 if (c_tpdf) {
2755 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2756 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002757 if (c_must) {
2758 list->must = calloc(c_must, sizeof *list->must);
2759 }
2760 if (c_ftrs) {
2761 list->features = calloc(c_ftrs, sizeof *list->features);
2762 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002763 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2764 if (!strcmp(sub->name, "typedef")) {
2765 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2766 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002767
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002768 if (r) {
2769 goto error;
2770 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002771 } else if (!strcmp(sub->name, "if-feature")) {
2772 GETVAL(value, sub, "name");
2773 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2774 if (!list->features[list->features_size]) {
2775 goto error;
2776 }
2777 list->features_size++;
2778 } else if (!strcmp(sub->name, "must")) {
2779 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2780 list->must_size++;
2781
2782 if (r) {
2783 goto error;
2784 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002785 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002786 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002787 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002788
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002789 /* last part - process data nodes */
2790 LY_TREE_FOR_SAFE(root.child, next, sub) {
2791 if (!strcmp(sub->name, "container")) {
2792 mnode = read_yin_container(module, retval, sub, resolve, unres);
2793 } else if (!strcmp(sub->name, "leaf-list")) {
2794 mnode = read_yin_leaflist(module, retval, sub, resolve);
2795 } else if (!strcmp(sub->name, "leaf")) {
2796 mnode = read_yin_leaf(module, retval, sub, resolve);
2797 } else if (!strcmp(sub->name, "list")) {
2798 mnode = read_yin_list(module, retval, sub, resolve, unres);
2799 } else if (!strcmp(sub->name, "choice")) {
2800 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2801 } else if (!strcmp(sub->name, "uses")) {
2802 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2803 } else if (!strcmp(sub->name, "grouping")) {
2804 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2805 } else if (!strcmp(sub->name, "anyxml")) {
2806 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002807 }
2808 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002809
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002810 if (!mnode) {
2811 goto error;
2812 }
2813 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002815 if (parent && ly_mnode_addchild(parent, retval)) {
2816 goto error;
2817 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002819 if (!key_str) {
2820 /* config false list without a key */
2821 return retval;
2822 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002823
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002824 /* link key leafs into the list structure and check all constraints */
2825 for (i = 0; i < list->keys_size; i++) {
2826 /* get the key name */
2827 if ((value = strpbrk(key_str, " \t\n"))) {
2828 len = value - key_str;
2829 while (isspace(*value)) {
2830 value++;
2831 }
2832 } else {
2833 len = strlen(key_str);
2834 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002835
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002836 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002837
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002838 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2839 goto error;
2840 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002841
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002842 /* prepare for next iteration */
2843 while (value && isspace(*value)) {
2844 value++;
2845 }
2846 key_str = value;
2847 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002848
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002849 /* process unique statements */
2850 if (c_uniq) {
2851 list->unique = calloc(c_uniq, sizeof *list->unique);
2852 }
2853 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2854 /* count the number of unique values */
2855 GETVAL(value, sub, "tag");
2856 uniq_str = value;
2857 uniq_s = &list->unique[list->unique_size];
2858 while ((value = strpbrk(value, " \t\n"))) {
2859 uniq_s->leafs_size++;
2860 while (isspace(*value)) {
2861 value++;
2862 }
2863 }
2864 uniq_s->leafs_size++;
2865 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2866 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002867
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002868 /* interconnect unique values with the leafs */
2869 for (i = 0; i < uniq_s->leafs_size; i++) {
2870 if ((value = strpbrk(uniq_str, " \t\n"))) {
2871 len = value - uniq_str;
2872 while (isspace(*value)) {
2873 value++;
2874 }
2875 } else {
2876 len = strlen(uniq_str);
2877 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002878
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002879 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
2880 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
2881 goto error;
2882 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002883
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002884 /* prepare for next iteration */
2885 while (value && isspace(*value)) {
2886 value++;
2887 }
2888 uniq_str = value;
2889 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002891 lyxml_free_elem(module->ctx, sub);
2892 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002893
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002894 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002895
2896error:
2897
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002898 ly_mnode_free(retval);
2899 while (root.child) {
2900 lyxml_free_elem(module->ctx, root.child);
2901 }
2902 while (uniq.child) {
2903 lyxml_free_elem(module->ctx, uniq.child);
2904 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002905
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002906 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002907}
2908
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002909static struct ly_mnode *
2910read_yin_container(struct ly_module *module,
2911 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002912{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002913 struct lyxml_elem *sub, *next, root;
2914 struct ly_mnode *mnode = NULL;
2915 struct ly_mnode *retval;
2916 struct ly_mnode_container *cont;
2917 const char *value;
2918 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002919 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002920
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002921 /* init */
2922 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02002923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002924 cont = calloc(1, sizeof *cont);
2925 cont->nodetype = LY_NODE_CONTAINER;
2926 cont->prev = (struct ly_mnode *)cont;
2927 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002928
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002929 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2930 goto error;
2931 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002932
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002933 /* process container's specific children */
2934 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2935 if (!strcmp(sub->name, "presence")) {
2936 if (cont->presence) {
2937 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2938 goto error;
2939 }
2940 GETVAL(value, sub, "value");
2941 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02002942
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002943 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002944 } else if (!strcmp(sub->name, "when")) {
2945 if (cont->when) {
2946 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2947 goto error;
2948 }
2949
2950 cont->when = read_yin_when(module, sub);
2951 lyxml_free_elem(module->ctx, sub);
2952
2953 if (!cont->when) {
2954 goto error;
2955 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002956
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002957 /* data statements */
2958 } else if (!strcmp(sub->name, "container") ||
2959 !strcmp(sub->name, "leaf-list") ||
2960 !strcmp(sub->name, "leaf") ||
2961 !strcmp(sub->name, "list") ||
2962 !strcmp(sub->name, "choice") ||
2963 !strcmp(sub->name, "uses") ||
2964 !strcmp(sub->name, "grouping") ||
2965 !strcmp(sub->name, "anyxml")) {
2966 lyxml_unlink_elem(sub);
2967 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002968
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002969 /* array counters */
2970 } else if (!strcmp(sub->name, "typedef")) {
2971 c_tpdf++;
2972 } else if (!strcmp(sub->name, "must")) {
2973 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002974 } else if (!strcmp(sub->name, "if-feature")) {
2975 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002976 } else {
2977 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2978 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002979 }
2980 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002981
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002982 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2983 if (c_tpdf) {
2984 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
2985 }
2986 if (c_must) {
2987 cont->must = calloc(c_must, sizeof *cont->must);
2988 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002989 if (c_ftrs) {
2990 cont->features = calloc(c_ftrs, sizeof *cont->features);
2991 }
Radek Krejci800af702015-06-02 13:46:01 +02002992
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002993 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2994 if (!strcmp(sub->name, "typedef")) {
2995 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
2996 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002998 if (r) {
2999 goto error;
3000 }
3001 } else if (!strcmp(sub->name, "must")) {
3002 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3003 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003004
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003005 if (r) {
3006 goto error;
3007 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003008 } else if (!strcmp(sub->name, "if-feature")) {
3009 GETVAL(value, sub, "name");
3010 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3011 if (!cont->features[cont->features_size]) {
3012 goto error;
3013 }
3014 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003015 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003016
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003017 lyxml_free_elem(module->ctx, sub);
3018 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003020 /* last part - process data nodes */
3021 LY_TREE_FOR_SAFE(root.child, next, sub) {
3022 if (!strcmp(sub->name, "container")) {
3023 mnode = read_yin_container(module, retval, sub, resolve, unres);
3024 } else if (!strcmp(sub->name, "leaf-list")) {
3025 mnode = read_yin_leaflist(module, retval, sub, resolve);
3026 } else if (!strcmp(sub->name, "leaf")) {
3027 mnode = read_yin_leaf(module, retval, sub, resolve);
3028 } else if (!strcmp(sub->name, "list")) {
3029 mnode = read_yin_list(module, retval, sub, resolve, unres);
3030 } else if (!strcmp(sub->name, "choice")) {
3031 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3032 } else if (!strcmp(sub->name, "uses")) {
3033 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3034 } else if (!strcmp(sub->name, "grouping")) {
3035 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3036 } else if (!strcmp(sub->name, "anyxml")) {
3037 mnode = read_yin_anyxml(module, retval, sub, resolve);
3038 }
3039 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003040
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003041 if (!mnode) {
3042 goto error;
3043 }
3044 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003046 if (parent && ly_mnode_addchild(parent, retval)) {
3047 goto error;
3048 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003049
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003050 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003051
3052error:
3053
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003054 ly_mnode_free(retval);
3055 while (root.child) {
3056 lyxml_free_elem(module->ctx, root.child);
3057 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003058
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003059 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003060}
3061
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003062static struct ly_mnode *
3063read_yin_grouping(struct ly_module *module,
3064 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003065{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003066 struct lyxml_elem *sub, *next, root;
3067 struct ly_mnode *mnode = NULL;
3068 struct ly_mnode *retval;
3069 struct ly_mnode_grp *grp;
3070 int r;
3071 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003072
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003073 /* init */
3074 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003076 grp = calloc(1, sizeof *grp);
3077 grp->nodetype = LY_NODE_GROUPING;
3078 grp->prev = (struct ly_mnode *)grp;
3079 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003081 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3082 goto error;
3083 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003084
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003085 LY_TREE_FOR_SAFE(node->child, next, sub) {
3086 /* data statements */
3087 if (!strcmp(sub->name, "container") ||
3088 !strcmp(sub->name, "leaf-list") ||
3089 !strcmp(sub->name, "leaf") ||
3090 !strcmp(sub->name, "list") ||
3091 !strcmp(sub->name, "choice") ||
3092 !strcmp(sub->name, "uses") ||
3093 !strcmp(sub->name, "grouping") ||
3094 !strcmp(sub->name, "anyxml")) {
3095 lyxml_unlink_elem(sub);
3096 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003097
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003098 /* array counters */
3099 } else if (!strcmp(sub->name, "typedef")) {
3100 c_tpdf++;
3101 } else {
3102 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3103 goto error;
3104 }
3105 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003107 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3108 if (c_tpdf) {
3109 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3110 }
3111 LY_TREE_FOR_SAFE(node->child, next, sub) {
3112 if (!strcmp(sub->name, "typedef")) {
3113 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3114 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003115
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003116 if (r) {
3117 goto error;
3118 }
3119 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003121 lyxml_free_elem(module->ctx, sub);
3122 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003124 /* last part - process data nodes */
3125 LY_TREE_FOR_SAFE(root.child, next, sub) {
3126 if (!strcmp(sub->name, "container")) {
3127 mnode = read_yin_container(module, retval, sub, resolve, unres);
3128 } else if (!strcmp(sub->name, "leaf-list")) {
3129 mnode = read_yin_leaflist(module, retval, sub, resolve);
3130 } else if (!strcmp(sub->name, "leaf")) {
3131 mnode = read_yin_leaf(module, retval, sub, resolve);
3132 } else if (!strcmp(sub->name, "list")) {
3133 mnode = read_yin_list(module, retval, sub, resolve, unres);
3134 } else if (!strcmp(sub->name, "choice")) {
3135 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3136 } else if (!strcmp(sub->name, "uses")) {
3137 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3138 } else if (!strcmp(sub->name, "grouping")) {
3139 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3140 } else if (!strcmp(sub->name, "anyxml")) {
3141 mnode = read_yin_anyxml(module, retval, sub, resolve);
3142 }
3143 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003145 if (!mnode) {
3146 goto error;
3147 }
3148 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003149
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003150 if (parent && ly_mnode_addchild(parent, retval)) {
3151 goto error;
3152 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003154 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003155
3156error:
3157
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003158 ly_mnode_free(retval);
3159 while (root.child) {
3160 lyxml_free_elem(module->ctx, root.child);
3161 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003163 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003164}
3165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003166static struct ly_mnode *
3167read_yin_input_output(struct ly_module *module,
3168 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003169{
Radek Krejcie0674f82015-06-15 13:58:51 +02003170 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003171 struct ly_mnode *mnode = NULL;
3172 struct ly_mnode *retval;
3173 struct ly_mnode_input_output *inout;
3174 int r;
3175 int c_tpdf = 0;
3176
Radek Krejcie0674f82015-06-15 13:58:51 +02003177 /* init */
3178 memset(&root, 0, sizeof root);
3179
Michal Vasko38d01f72015-06-15 09:41:06 +02003180 inout = calloc(1, sizeof *inout);
3181
3182 if (!strcmp(yin->name, "input")) {
3183 inout->nodetype = LY_NODE_INPUT;
3184 } else if (!strcmp(yin->name, "output")) {
3185 inout->nodetype = LY_NODE_OUTPUT;
3186 } else {
3187 assert(0);
3188 }
3189
3190 inout->prev = (struct ly_mnode *)inout;
3191 retval = (struct ly_mnode *)inout;
3192
Michal Vaskoebeac942015-06-15 12:11:50 +02003193 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
3194 goto error;
3195 }
3196
Michal Vasko38d01f72015-06-15 09:41:06 +02003197 /* data statements */
3198 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3199 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003200 !strcmp(sub->name, "leaf-list") ||
3201 !strcmp(sub->name, "leaf") ||
3202 !strcmp(sub->name, "list") ||
3203 !strcmp(sub->name, "choice") ||
3204 !strcmp(sub->name, "uses") ||
3205 !strcmp(sub->name, "grouping") ||
3206 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003207 lyxml_unlink_elem(sub);
3208 lyxml_add_child(&root, sub);
3209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003210 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003211 } else if (!strcmp(sub->name, "typedef")) {
3212 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003213#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02003214 } else {
3215 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3216 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003217#else
Michal Vasko38d01f72015-06-15 09:41:06 +02003218 } else {
3219 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003220#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02003221 }
3222 }
3223
3224 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3225 if (c_tpdf) {
3226 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
3227 }
3228
3229 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3230 if (!strcmp(sub->name, "typedef")) {
3231 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
3232 inout->tpdf_size++;
3233
3234 if (r) {
3235 goto error;
3236 }
3237 }
3238
3239 lyxml_free_elem(module->ctx, sub);
3240 }
3241
3242 /* last part - process data nodes */
3243 LY_TREE_FOR_SAFE(root.child, next, sub) {
3244 if (!strcmp(sub->name, "container")) {
3245 mnode = read_yin_container(module, retval, sub, resolve, unres);
3246 } else if (!strcmp(sub->name, "leaf-list")) {
3247 mnode = read_yin_leaflist(module, retval, sub, resolve);
3248 } else if (!strcmp(sub->name, "leaf")) {
3249 mnode = read_yin_leaf(module, retval, sub, resolve);
3250 } else if (!strcmp(sub->name, "list")) {
3251 mnode = read_yin_list(module, retval, sub, resolve, unres);
3252 } else if (!strcmp(sub->name, "choice")) {
3253 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3254 } else if (!strcmp(sub->name, "uses")) {
3255 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3256 } else if (!strcmp(sub->name, "grouping")) {
3257 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3258 } else if (!strcmp(sub->name, "anyxml")) {
3259 mnode = read_yin_anyxml(module, retval, sub, resolve);
3260 }
3261 lyxml_free_elem(module->ctx, sub);
3262
3263 if (!mnode) {
3264 goto error;
3265 }
3266 }
3267
3268 if (parent && ly_mnode_addchild(parent, retval)) {
3269 goto error;
3270 }
3271
3272 return retval;
3273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003274error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003275
3276 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003277 while (root.child) {
3278 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003279 }
3280
3281 return NULL;
3282}
3283
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003284static struct ly_mnode *
3285read_yin_notif(struct ly_module *module,
3286 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02003287{
Michal Vaskoc6551b32015-06-16 10:51:43 +02003288 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02003289 struct ly_mnode *mnode = NULL;
3290 struct ly_mnode *retval;
3291 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003292 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02003293 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003294 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02003295
Michal Vaskoc6551b32015-06-16 10:51:43 +02003296 memset(&root, 0, sizeof root);
3297
Michal Vasko0ea41032015-06-16 08:53:55 +02003298 notif = calloc(1, sizeof *notif);
3299 notif->nodetype = LY_NODE_NOTIF;
3300 notif->prev = (struct ly_mnode *)notif;
3301 retval = (struct ly_mnode *)notif;
3302
3303 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3304 goto error;
3305 }
3306
3307 /* process rpc's specific children */
3308 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3309 /* data statements */
3310 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003311 !strcmp(sub->name, "leaf-list") ||
3312 !strcmp(sub->name, "leaf") ||
3313 !strcmp(sub->name, "list") ||
3314 !strcmp(sub->name, "choice") ||
3315 !strcmp(sub->name, "uses") ||
3316 !strcmp(sub->name, "grouping") ||
3317 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02003318 lyxml_unlink_elem(sub);
3319 lyxml_add_child(&root, sub);
3320
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003321 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02003322 } else if (!strcmp(sub->name, "typedef")) {
3323 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003324 } else if (!strcmp(sub->name, "if-feature")) {
3325 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003326 } else {
3327 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3328 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02003329 }
3330 }
3331
3332 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3333 if (c_tpdf) {
3334 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3335 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003336 if (c_ftrs) {
3337 notif->features = calloc(c_ftrs, sizeof *notif->features);
3338 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003339
3340 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3341 if (!strcmp(sub->name, "typedef")) {
3342 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3343 notif->tpdf_size++;
3344
3345 if (r) {
3346 goto error;
3347 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003348 } else if (!strcmp(sub->name, "typedef")) {
3349 GETVAL(value, sub, "name");
3350 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3351 if (!notif->features[notif->features_size]) {
3352 goto error;
3353 }
3354 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003355 }
3356
3357 lyxml_free_elem(module->ctx, sub);
3358 }
3359
3360 /* last part - process data nodes */
3361 LY_TREE_FOR_SAFE(root.child, next, sub) {
3362 if (!strcmp(sub->name, "container")) {
3363 mnode = read_yin_container(module, retval, sub, resolve, unres);
3364 } else if (!strcmp(sub->name, "leaf-list")) {
3365 mnode = read_yin_leaflist(module, retval, sub, resolve);
3366 } else if (!strcmp(sub->name, "leaf")) {
3367 mnode = read_yin_leaf(module, retval, sub, resolve);
3368 } else if (!strcmp(sub->name, "list")) {
3369 mnode = read_yin_list(module, retval, sub, resolve, unres);
3370 } else if (!strcmp(sub->name, "choice")) {
3371 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3372 } else if (!strcmp(sub->name, "uses")) {
3373 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3374 } else if (!strcmp(sub->name, "grouping")) {
3375 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3376 } else if (!strcmp(sub->name, "anyxml")) {
3377 mnode = read_yin_anyxml(module, retval, sub, resolve);
3378 }
3379 lyxml_free_elem(module->ctx, sub);
3380
3381 if (!mnode) {
3382 goto error;
3383 }
3384 }
3385
3386 if (parent && ly_mnode_addchild(parent, retval)) {
3387 goto error;
3388 }
3389
3390 return retval;
3391
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003392error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003393
3394 ly_mnode_free(retval);
3395 while (root.child) {
3396 lyxml_free_elem(module->ctx, root.child);
3397 }
3398
3399 return NULL;
3400}
3401
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003402static struct ly_mnode *
3403read_yin_rpc(struct ly_module *module,
3404 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003405{
Radek Krejcie0674f82015-06-15 13:58:51 +02003406 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003407 struct ly_mnode *mnode = NULL;
3408 struct ly_mnode *retval;
3409 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003410 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003411 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003412 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003413
Radek Krejcie0674f82015-06-15 13:58:51 +02003414 /* init */
3415 memset(&root, 0, sizeof root);
3416
Michal Vasko38d01f72015-06-15 09:41:06 +02003417 rpc = calloc(1, sizeof *rpc);
3418 rpc->nodetype = LY_NODE_RPC;
3419 rpc->prev = (struct ly_mnode *)rpc;
3420 retval = (struct ly_mnode *)rpc;
3421
3422 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3423 goto error;
3424 }
3425
3426 /* process rpc's specific children */
3427 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3428 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003429 if (rpc->child
3430 && (rpc->child->nodetype == LY_NODE_INPUT
3431 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003432 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3433 goto error;
3434 }
3435 lyxml_unlink_elem(sub);
3436 lyxml_add_child(&root, sub);
3437 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003438 if (rpc->child
3439 && (rpc->child->nodetype == LY_NODE_INPUT
3440 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003441 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3442 goto error;
3443 }
3444 lyxml_unlink_elem(sub);
3445 lyxml_add_child(&root, sub);
3446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003447 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003448 } else if (!strcmp(sub->name, "grouping")) {
3449 lyxml_unlink_elem(sub);
3450 lyxml_add_child(&root, sub);
3451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003452 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003453 } else if (!strcmp(sub->name, "typedef")) {
3454 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003455 } else if (!strcmp(sub->name, "if-feature")) {
3456 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003457 } else {
3458 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3459 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003460 }
3461 }
3462
3463 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3464 if (c_tpdf) {
3465 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3466 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003467 if (c_ftrs) {
3468 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3469 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003470
3471 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3472 if (!strcmp(sub->name, "typedef")) {
3473 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3474 rpc->tpdf_size++;
3475
3476 if (r) {
3477 goto error;
3478 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003479 } else if (!strcmp(sub->name, "if-feature")) {
3480 GETVAL(value, sub, "name");
3481 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3482 if (!rpc->features[rpc->features_size]) {
3483 goto error;
3484 }
3485 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003486 }
3487
3488 lyxml_free_elem(module->ctx, sub);
3489 }
3490
3491 /* last part - process data nodes */
3492 LY_TREE_FOR_SAFE(root.child, next, sub) {
3493 if (!strcmp(sub->name, "grouping")) {
3494 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3495 } else if (!strcmp(sub->name, "input")) {
3496 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3497 } else if (!strcmp(sub->name, "output")) {
3498 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3499 }
3500 lyxml_free_elem(module->ctx, sub);
3501
3502 if (!mnode) {
3503 goto error;
3504 }
3505 }
3506
3507 if (parent && ly_mnode_addchild(parent, retval)) {
3508 goto error;
3509 }
3510
3511 return retval;
3512
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003513error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003514
3515 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003516 while (root.child) {
3517 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003518 }
3519
3520 return NULL;
3521}
3522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003523static int
3524find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003525{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003526 struct ly_module *searchmod = NULL, *module = uses->module;
3527 struct ly_mnode *mnode, *mnode_aux;
3528 const char *name;
3529 int prefix_len = 0;
3530 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003531
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003532 /* get referenced grouping */
3533 name = strchr(uses->name, ':');
3534 if (!name) {
3535 /* no prefix, search in local tree */
3536 name = uses->name;
3537 } else {
3538 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003540 /* set name to correct position after colon */
3541 prefix_len = name - uses->name;
3542 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003544 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3545 /* prefix refers to the current module, ignore it */
3546 prefix_len = 0;
3547 }
3548 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003549
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003550 /* search */
3551 if (prefix_len) {
3552 /* in top-level groupings of some other module */
3553 for (i = 0; i < module->imp_size; i++) {
3554 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3555 && !module->imp[i].prefix[prefix_len]) {
3556 searchmod = module->imp[i].module;
3557 break;
3558 }
3559 }
3560 if (!searchmod) {
3561 /* uses refers unknown data model */
3562 LOGVAL(VE_INPREFIX, line, name);
3563 return EXIT_FAILURE;
3564 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003565
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003566 LY_TREE_FOR(searchmod->data, mnode) {
3567 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3568 uses->grp = (struct ly_mnode_grp *)mnode;
3569 return EXIT_SUCCESS;
3570 }
3571 }
3572 } else {
3573 /* in local tree hierarchy */
3574 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3575 LY_TREE_FOR(mnode_aux->child, mnode) {
3576 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3577 uses->grp = (struct ly_mnode_grp *)mnode;
3578 return EXIT_SUCCESS;
3579 }
3580 }
3581 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003582
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003583 /* search in top level of the current module */
3584 LY_TREE_FOR(module->data, mnode) {
3585 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3586 uses->grp = (struct ly_mnode_grp *)mnode;
3587 return EXIT_SUCCESS;
3588 }
3589 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003590
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003591 /* search in top-level of included modules */
3592 for (i = 0; i < module->inc_size; i++) {
3593 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3594 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3595 uses->grp = (struct ly_mnode_grp *)mnode;
3596 return EXIT_SUCCESS;
3597 }
3598 }
3599 }
3600 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003601
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003602 /* not found, but no explicit error occured */
3603 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003604}
3605
Radek Krejcif5be10f2015-06-16 13:29:36 +02003606static int
3607resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3608{
3609 struct lyxml_elem *yin, *next, *sub;
3610 struct ly_mnode *mnode;
3611
3612 assert(module);
3613
3614 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003615 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003616 if (!aug->target) {
3617 LOGVAL(VE_INARG, line, aug->target, "uses");
3618 return EXIT_FAILURE;
3619 }
3620
3621 if (!aug->child) {
3622 /* nothing to do */
3623 return EXIT_SUCCESS;
3624 }
3625
3626 yin = (struct lyxml_elem *)aug->child;
3627
3628 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3629 return EXIT_FAILURE;
3630 }
3631
3632 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3633 if (!strcmp(sub->name, "container")) {
3634 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3635 } else if (!strcmp(sub->name, "leaf-list")) {
3636 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3637 } else if (!strcmp(sub->name, "leaf")) {
3638 mnode = read_yin_leaf(module, aug->target, sub, 1);
3639 } else if (!strcmp(sub->name, "list")) {
3640 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3641 } else if (!strcmp(sub->name, "uses")) {
3642 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3643 } else if (!strcmp(sub->name, "choice")) {
3644 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3645 } else if (!strcmp(sub->name, "case")) {
3646 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3647 } else if (!strcmp(sub->name, "anyxml")) {
3648 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3649#if 0
3650 } else {
3651 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003652 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003653#else
3654 } else {
3655 continue;
3656#endif
3657 }
3658
3659 if (!mnode) {
3660 return EXIT_FAILURE;
3661 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003662 /* check for mandatory nodes - if the target node is in another module
3663 * the added nodes cannot be mandatory
3664 */
3665 if (check_mandatory(mnode)) {
3666 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3667 return EXIT_FAILURE;
3668 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003669
3670 lyxml_free_elem(module->ctx, sub);
3671
3672 /* the parent pointer will point to the augment node, but all
3673 * siblings pointers and possibly the child node in target does
3674 * not know about the augment and follow the standard schema tree
3675 * structure
3676 */
3677 mnode->parent = (struct ly_mnode *)aug;
3678 mnode = NULL;
3679 }
3680
3681 lyxml_free_elem(module->ctx, yin);
3682 aug->child = NULL;
3683
3684 return EXIT_SUCCESS;
3685}
3686
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003687int
3688resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003689{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003690 struct ly_ctx *ctx;
3691 struct ly_mnode *mnode = NULL, *mnode_aux;
3692 struct ly_refine *rfn;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003693 struct ly_must *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003694 int i, j;
3695 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003696
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003697 /* copy the data nodes from grouping into the uses context */
3698 LY_TREE_FOR(uses->grp->child, mnode) {
3699 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3700 if (!mnode_aux) {
3701 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3702 return EXIT_FAILURE;
3703 }
3704 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3705 ly_mnode_free(mnode_aux);
3706 return EXIT_FAILURE;
3707 }
3708 }
3709 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003711 /* apply refines */
3712 for (i = 0; i < uses->refine_size; i++) {
3713 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003714 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003715 if (!mnode) {
3716 LOGVAL(VE_INARG, line, rfn->target, "uses");
3717 return EXIT_FAILURE;
3718 }
Radek Krejci106efc02015-06-10 14:36:27 +02003719
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003720 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3721 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3722 return EXIT_FAILURE;
3723 }
Radek Krejci106efc02015-06-10 14:36:27 +02003724
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003725 /* description on any nodetype */
3726 if (rfn->dsc) {
3727 lydict_remove(ctx, mnode->dsc);
3728 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3729 }
Radek Krejci106efc02015-06-10 14:36:27 +02003730
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003731 /* reference on any nodetype */
3732 if (rfn->ref) {
3733 lydict_remove(ctx, mnode->ref);
3734 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3735 }
Radek Krejci106efc02015-06-10 14:36:27 +02003736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003737 /* config on any nodetype */
3738 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3739 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3740 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3741 }
Radek Krejci106efc02015-06-10 14:36:27 +02003742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003743 /* default value ... */
3744 if (rfn->mod.dflt) {
3745 if (mnode->nodetype == LY_NODE_LEAF) {
3746 /* leaf */
3747 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3748 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3749 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3750 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003751 ((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 +02003752 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3753 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3754 return EXIT_FAILURE;
3755 }
3756 }
3757 }
Radek Krejci106efc02015-06-10 14:36:27 +02003758
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003759 /* mandatory on leaf, anyxml or choice */
3760 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3761 if (rfn->flags & LY_NODE_MAND_FALSE) {
3762 /* erase mandatory true flag, we don't use false flag in schema nodes */
3763 mnode->flags &= ~LY_NODE_MAND_TRUE;
3764 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3765 /* set mandatory true flag */
3766 mnode->flags |= LY_NODE_MAND_TRUE;
3767 }
3768 }
Radek Krejci106efc02015-06-10 14:36:27 +02003769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003770 /* presence on container */
3771 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3772 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3773 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3774 }
Radek Krejci106efc02015-06-10 14:36:27 +02003775
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003776 /* min/max-elements on list or leaf-list */
3777 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3778 /* magic - bit 3 in flags means min set, bit 4 says max set */
3779 if (rfn->flags & 0x04) {
3780 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3781 }
3782 if (rfn->flags & 0x08) {
3783 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3784 }
3785 }
Radek Krejci106efc02015-06-10 14:36:27 +02003786
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003787 /* must in leaf, leaf-list, list, container or anyxml */
3788 if (rfn->must_size) {
3789 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3790 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3791 if (!newmust) {
3792 LOGMEM;
3793 return EXIT_FAILURE;
3794 }
3795 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
3796 newmust[j].cond = lydict_insert(ctx, rfn->must[i].cond, 0);
3797 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3798 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3799 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3800 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3801 }
Radek Krejci106efc02015-06-10 14:36:27 +02003802
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003803 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3804 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3805 }
3806 }
Radek Krejci106efc02015-06-10 14:36:27 +02003807
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003808 /* apply augments */
3809 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003810 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003811 goto error;
3812 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003813 }
Radek Krejci106efc02015-06-10 14:36:27 +02003814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003815 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003816
3817error:
3818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003819 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003820}
Radek Krejci74705112015-06-05 10:25:44 +02003821
3822/*
3823 * resolve - referenced grouping should be bounded to the namespace (resolved)
3824 * only when uses does not appear in grouping. In a case of grouping's uses,
3825 * we just get information but we do not apply augment or refine to it.
3826 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003827static struct ly_mnode *
3828read_yin_uses(struct ly_module *module,
3829 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003830{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003831 struct lyxml_elem *sub, *next;
3832 struct ly_mnode *retval;
3833 struct ly_mnode_uses *uses;
3834 struct mnode_list *unres_new;
3835 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003836 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003837 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003838
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003839 uses = calloc(1, sizeof *uses);
3840 uses->nodetype = LY_NODE_USES;
3841 uses->prev = (struct ly_mnode *)uses;
3842 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003843
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003844 GETVAL(value, node, "name");
3845 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003846
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003847 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3848 goto error;
3849 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003850
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003851 /* get other properties of uses */
3852 LY_TREE_FOR_SAFE(node->child, next, sub) {
3853 if (!strcmp(sub->name, "refine")) {
3854 c_ref++;
3855 } else if (!strcmp(sub->name, "augment")) {
3856 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003857 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02003858 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003859 } else if (!strcmp(sub->name, "when")) {
3860 if (uses->when) {
3861 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
3862 goto error;
3863 }
3864
3865 uses->when = read_yin_when(module, sub);
3866 lyxml_free_elem(module->ctx, sub);
3867
3868 if (!uses->when) {
3869 goto error;
3870 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003871 } else {
3872 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3873 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003874 }
3875 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003877 /* process properties with cardinality 0..n */
3878 if (c_ref) {
3879 uses->refine = calloc(c_ref, sizeof *uses->refine);
3880 }
3881 if (c_aug) {
3882 uses->augment = calloc(c_aug, sizeof *uses->augment);
3883 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003884 if (c_ftrs) {
3885 uses->features = calloc(c_ftrs, sizeof *uses->features);
3886 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003887
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003888 LY_TREE_FOR_SAFE(node->child, next, sub) {
3889 if (!strcmp(sub->name, "refine")) {
3890 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
3891 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003892 lyxml_free_elem(module->ctx, sub);
3893 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003894 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
3895 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003896 } else if (!strcmp(sub->name, "if-feature")) {
3897 GETVAL(value, sub, "name");
3898 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
3899 if (!uses->features[uses->features_size]) {
3900 goto error;
3901 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02003902 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003903 uses->features_size++;
3904 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003905 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003906
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003907 if (r) {
3908 goto error;
3909 }
3910 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003911
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003912 if (find_grouping(parent, uses, LOGLINE(node))) {
3913 goto error;
3914 }
3915 if (!uses->grp) {
3916 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
3917 unres_new = calloc(1, sizeof *unres_new);
3918 if (*unres) {
3919 unres_new->next = *unres;
3920 }
3921 unres_new->mnode = retval;
3922 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02003923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003924 /* put it at the beginning of the unresolved list */
3925 *unres = unres_new;
3926 }
Radek Krejci74705112015-06-05 10:25:44 +02003927
Radek Krejci368c38f2015-06-15 15:09:55 +02003928 if (parent && ly_mnode_addchild(parent, retval)) {
3929 goto error;
3930 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003931
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003932 if (resolve) {
3933 /* inherit config flag */
3934 if (parent) {
3935 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
3936 } else {
3937 /* default config is true */
3938 retval->flags |= LY_NODE_CONFIG_W;
3939 }
3940 }
Radek Krejcib388c152015-06-04 17:03:03 +02003941
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003942 if (resolve && uses->grp) {
3943 /* copy the data nodes from grouping into the uses context */
3944 if (resolve_uses(uses, LOGLINE(node))) {
3945 goto error;
3946 }
3947 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003949 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003950
3951error:
3952
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003953 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003954
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003955 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003956}
3957
Radek Krejciefaeba32015-05-27 14:30:57 +02003958/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003959static int
3960read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003961{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003962 struct ly_ctx *ctx = module->ctx;
3963 struct ly_submodule *submodule = (struct ly_submodule *)module;
3964 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
3965 struct ly_mnode *mnode = NULL;
3966 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
3967 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003968 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02003969 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003970 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003971 /* counters */
3972 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003973
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003974 /* init */
3975 memset(&root, 0, sizeof root);
3976 memset(&grps, 0, sizeof grps);
3977 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02003978 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02003979
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003980 /*
3981 * in the first run, we process elements with cardinality of 1 or 0..1 and
3982 * count elements with cardinality 0..n. Data elements (choices, containers,
3983 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
3984 * need have all top-level and groupings already prepared at that time. In
3985 * the middle loop, we process other elements with carinality of 0..n since
3986 * we need to allocate arrays to store them.
3987 */
3988 LY_TREE_FOR_SAFE(yin->child, next, node) {
3989 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
3990 lyxml_free_elem(ctx, node);
3991 continue;
3992 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003993
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003994 if (!module->type && !strcmp(node->name, "namespace")) {
3995 if (module->ns) {
3996 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3997 goto error;
3998 }
3999 GETVAL(value, node, "uri");
4000 module->ns = lydict_insert(ctx, value, strlen(value));
4001 lyxml_free_elem(ctx, node);
4002 } else if (!module->type && !strcmp(node->name, "prefix")) {
4003 if (module->prefix) {
4004 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4005 goto error;
4006 }
4007 GETVAL(value, node, "value");
4008 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4009 goto error;
4010 }
4011 module->prefix = lydict_insert(ctx, value, strlen(value));
4012 lyxml_free_elem(ctx, node);
4013 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4014 if (belongsto_flag) {
4015 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4016 goto error;
4017 }
4018 belongsto_flag = 1;
4019 GETVAL(value, node, "module");
4020 while (submodule->belongsto->type) {
4021 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4022 }
4023 if (value != submodule->belongsto->name) {
4024 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4025 goto error;
4026 }
Radek Krejcif3886932015-06-04 17:36:06 +02004027
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004028 /* get the prefix substatement, start with checks */
4029 if (!node->child) {
4030 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4031 goto error;
4032 } else if (strcmp(node->child->name, "prefix")) {
4033 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4034 goto error;
4035 } else if (node->child->next) {
4036 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4037 goto error;
4038 }
4039 /* and now finally get the value */
4040 GETVAL(value, node->child, "value");
4041 /* check here differs from a generic prefix check, since this prefix
4042 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004043 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004044 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4045 goto error;
4046 }
4047 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004048
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004049 /* we are done with belongs-to */
4050 lyxml_free_elem(ctx, node);
4051 } else if (!strcmp(node->name, "import")) {
4052 c_imp++;
4053 } else if (!strcmp(node->name, "revision")) {
4054 c_rev++;
4055 } else if (!strcmp(node->name, "typedef")) {
4056 c_tpdf++;
4057 } else if (!strcmp(node->name, "identity")) {
4058 c_ident++;
4059 } else if (!strcmp(node->name, "include")) {
4060 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004061 } else if (!strcmp(node->name, "augment")) {
4062 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004063 } else if (!strcmp(node->name, "feature")) {
4064 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004065
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004066 /* data statements */
4067 } else if (!strcmp(node->name, "container") ||
4068 !strcmp(node->name, "leaf-list") ||
4069 !strcmp(node->name, "leaf") ||
4070 !strcmp(node->name, "list") ||
4071 !strcmp(node->name, "choice") ||
4072 !strcmp(node->name, "uses") ||
4073 !strcmp(node->name, "anyxml")) {
4074 lyxml_unlink_elem(node);
4075 lyxml_add_child(&root, node);
4076 } else if (!strcmp(node->name, "grouping")) {
4077 /* keep groupings separated and process them before other data statements */
4078 lyxml_unlink_elem(node);
4079 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004081 /* optional statements */
4082 } else if (!strcmp(node->name, "description")) {
4083 if (module->dsc) {
4084 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4085 goto error;
4086 }
4087 module->dsc = read_yin_subnode(ctx, node, "text");
4088 lyxml_free_elem(ctx, node);
4089 if (!module->dsc) {
4090 goto error;
4091 }
4092 } else if (!strcmp(node->name, "reference")) {
4093 if (module->ref) {
4094 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4095 goto error;
4096 }
4097 module->ref = read_yin_subnode(ctx, node, "text");
4098 lyxml_free_elem(ctx, node);
4099 if (!module->ref) {
4100 goto error;
4101 }
4102 } else if (!strcmp(node->name, "organization")) {
4103 if (module->org) {
4104 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4105 goto error;
4106 }
4107 module->org = read_yin_subnode(ctx, node, "text");
4108 lyxml_free_elem(ctx, node);
4109 if (!module->org) {
4110 goto error;
4111 }
4112 } else if (!strcmp(node->name, "contact")) {
4113 if (module->contact) {
4114 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4115 goto error;
4116 }
4117 module->contact = read_yin_subnode(ctx, node, "text");
4118 lyxml_free_elem(ctx, node);
4119 if (!module->contact) {
4120 goto error;
4121 }
4122 } else if (!strcmp(node->name, "yang-version")) {
4123 /* TODO: support YANG 1.1 ? */
4124 if (module->version) {
4125 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4126 goto error;
4127 }
4128 GETVAL(value, node, "value");
4129 if (strcmp(value, "1")) {
4130 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
4131 goto error;
4132 }
4133 module->version = 1;
4134 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02004135
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004136 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02004137 } else if (!strcmp(node->name, "rpc")) {
4138 lyxml_unlink_elem(node);
4139 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02004140 } else if (!strcmp(node->name, "notification")) {
4141 lyxml_unlink_elem(node);
4142 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02004143#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004144 } else {
4145 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
4146 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02004147#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004148 } else {
4149 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02004150#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004151 }
4152 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004154 if (!submodule) {
4155 /* check for mandatory statements */
4156 if (!module->ns) {
4157 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
4158 goto error;
4159 }
4160 if (!module->prefix) {
4161 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
4162 goto error;
4163 }
4164 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02004165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004166 /* allocate arrays for elements with cardinality of 0..n */
4167 if (c_imp) {
4168 module->imp = calloc(c_imp, sizeof *module->imp);
4169 }
4170 if (c_rev) {
4171 module->rev = calloc(c_rev, sizeof *module->rev);
4172 }
4173 if (c_tpdf) {
4174 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
4175 }
4176 if (c_ident) {
4177 module->ident = calloc(c_ident, sizeof *module->ident);
4178 }
4179 if (c_inc) {
4180 module->inc = calloc(c_inc, sizeof *module->inc);
4181 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004182 if (c_aug) {
4183 module->augment = calloc(c_aug, sizeof *module->augment);
4184 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004185 if (c_ftrs) {
4186 module->features = calloc(c_ftrs, sizeof *module->features);
4187 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004188
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004189 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4190 LY_TREE_FOR_SAFE(yin->child, next, node) {
4191 if (!strcmp(node->name, "import")) {
4192 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
4193 module->imp_size++;
4194 if (r) {
4195 goto error;
4196 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004197
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004198 /* check duplicities in imported modules */
4199 for (i = 0; i < module->imp_size - 1; i++) {
4200 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
4201 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
4202 goto error;
4203 }
4204 }
4205 } else if (!strcmp(node->name, "include")) {
4206 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
4207 module->inc_size++;
4208 if (r) {
4209 goto error;
4210 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004211
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004212 /* check duplications in include submodules */
4213 for (i = 0; i < module->inc_size - 1; i++) {
4214 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
4215 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
4216 module->inc[i].submodule->name);
4217 goto error;
4218 }
4219 }
4220 } else if (!strcmp(node->name, "revision")) {
4221 GETVAL(value, node, "date");
4222 if (check_date(value, LOGLINE(node))) {
4223 goto error;
4224 }
4225 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4226 /* check uniqueness of the revision date - not required by RFC */
4227 for (i = 0; i < module->rev_size; i++) {
4228 if (!strcmp(value, module->rev[i].date)) {
4229 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4230 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
4231 }
4232 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004233
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004234 LY_TREE_FOR(node->child, child) {
4235 if (!strcmp(child->name, "description")) {
4236 if (module->rev[module->rev_size].dsc) {
4237 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4238 goto error;
4239 }
4240 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
4241 if (!module->rev[module->rev_size].dsc) {
4242 goto error;
4243 }
4244 } else if (!strcmp(child->name, "reference")) {
4245 if (module->rev[module->rev_size].ref) {
4246 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4247 goto error;
4248 }
4249 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
4250 if (!module->rev[module->rev_size].ref) {
4251 goto error;
4252 }
4253 } else {
4254 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
4255 goto error;
4256 }
4257 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004258
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004259 /* keep the latest revision at position 0 */
4260 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
4261 /* switch their position */
4262 value = strdup(module->rev[0].date);
4263 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
4264 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4265 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02004266
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004267 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
4268 value = module->rev[0].dsc;
4269 module->rev[0].dsc = module->rev[module->rev_size].dsc;
4270 module->rev[module->rev_size].dsc = value;
4271 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004272
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004273 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
4274 value = module->rev[0].ref;
4275 module->rev[0].ref = module->rev[module->rev_size].ref;
4276 module->rev[module->rev_size].ref = value;
4277 }
4278 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004279
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004280 module->rev_size++;
4281 } else if (!strcmp(node->name, "typedef")) {
4282 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
4283 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004284
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004285 if (r) {
4286 goto error;
4287 }
4288 } else if (!strcmp(node->name, "identity")) {
4289 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
4290 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02004291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004292 if (r) {
4293 goto error;
4294 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004295 } else if (!strcmp(node->name, "feature")) {
4296 r = fill_yin_feature(module, node, &module->features[module->features_size]);
4297 module->features_size++;
4298
4299 if (r) {
4300 goto error;
4301 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004302 } else if (!strcmp(node->name, "augment")) {
4303 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
4304 module->augment_size++;
4305
4306 if (r) {
4307 goto error;
4308 }
4309
4310 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
4311 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004312 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004314 lyxml_free_elem(ctx, node);
4315 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004316
Radek Krejcif5be10f2015-06-16 13:29:36 +02004317 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004318 * refer to them
4319 */
4320 LY_TREE_FOR_SAFE(grps.child, next, node) {
4321 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
4322 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02004323
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004324 if (!mnode) {
4325 goto error;
4326 }
Radek Krejci74705112015-06-05 10:25:44 +02004327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004328 /* include data element */
4329 if (module->data) {
4330 module->data->prev->next = mnode;
4331 mnode->prev = module->data->prev;
4332 module->data->prev = mnode;
4333 } else {
4334 module->data = mnode;
4335 }
4336 }
4337 while (unres) {
4338 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4339 goto error;
4340 }
4341 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4342 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4343 goto error;
4344 }
4345 unres_next = unres->next;
4346 free(unres);
4347 unres = unres_next;
4348 }
Radek Krejci74705112015-06-05 10:25:44 +02004349
Radek Krejcif5be10f2015-06-16 13:29:36 +02004350 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004351 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004352
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004353 if (!strcmp(node->name, "container")) {
4354 mnode = read_yin_container(module, NULL, node, 1, &unres);
4355 } else if (!strcmp(node->name, "leaf-list")) {
4356 mnode = read_yin_leaflist(module, NULL, node, 1);
4357 } else if (!strcmp(node->name, "leaf")) {
4358 mnode = read_yin_leaf(module, NULL, node, 1);
4359 } else if (!strcmp(node->name, "list")) {
4360 mnode = read_yin_list(module, NULL, node, 1, &unres);
4361 } else if (!strcmp(node->name, "choice")) {
4362 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4363 } else if (!strcmp(node->name, "uses")) {
4364 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4365 } else if (!strcmp(node->name, "anyxml")) {
4366 mnode = read_yin_anyxml(module, NULL, node, 1);
4367 }
4368 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004370 if (!mnode) {
4371 goto error;
4372 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004374 /* include data element */
4375 if (module->data) {
4376 module->data->prev->next = mnode;
4377 mnode->prev = module->data->prev;
4378 module->data->prev = mnode;
4379 } else {
4380 module->data = mnode;
4381 }
4382 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004383
4384 /* ... rpcs ... */
4385 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4386 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4387 lyxml_free_elem(ctx, node);
4388
4389 if (!mnode) {
4390 goto error;
4391 }
4392
4393 /* include rpc element */
4394 if (module->rpc) {
4395 module->rpc->prev->next = mnode;
4396 mnode->prev = module->rpc->prev;
4397 module->rpc->prev = mnode;
4398 } else {
4399 module->rpc = mnode;
4400 }
4401 }
4402
4403 /* ... and notifications */
4404 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4405 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4406 lyxml_free_elem(ctx, node);
4407
4408 if (!mnode) {
4409 goto error;
4410 }
4411
4412 /* include notification element */
4413 if (module->notif) {
4414 module->notif->prev->next = mnode;
4415 mnode->prev = module->notif->prev;
4416 module->notif->prev = mnode;
4417 } else {
4418 module->notif = mnode;
4419 }
4420 }
4421
4422 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004423 while (unres) {
4424 /* find referenced grouping */
4425 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4426 goto error;
4427 }
4428 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4429 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4430 goto error;
4431 }
Radek Krejci74705112015-06-05 10:25:44 +02004432
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004433 /* resolve uses by copying grouping content under the uses */
4434 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4435 goto error;
4436 }
Radek Krejci74705112015-06-05 10:25:44 +02004437
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004438 unres_next = unres->next;
4439 free(unres);
4440 unres = unres_next;
4441 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004442
Radek Krejcif5be10f2015-06-16 13:29:36 +02004443 /* and finally apply augments */
4444 for (i = 0; i < module->augment_size; i++) {
4445 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004446 goto error;
4447 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004448 }
4449
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004450 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004451
4452error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004453 /* cleanup */
4454 while (root.child) {
4455 lyxml_free_elem(module->ctx, root.child);
4456 }
4457 while (grps.child) {
4458 lyxml_free_elem(module->ctx, grps.child);
4459 }
4460 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004461 lyxml_free_elem(module->ctx, rpcs.child);
4462 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004464 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004465}
4466
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004467struct ly_submodule *
4468yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004469{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004470 struct lyxml_elem *yin;
4471 struct ly_submodule *submodule = NULL;
4472 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004473
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004474 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004475
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004476 yin = lyxml_read(module->ctx, data, 0);
4477 if (!yin) {
4478 return NULL;
4479 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004481 /* check root element */
4482 if (!yin->name || strcmp(yin->name, "submodule")) {
4483 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4484 goto error;
4485 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004486
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004487 GETVAL(value, yin, "name");
4488 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4489 goto error;
4490 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004491
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004492 submodule = calloc(1, sizeof *submodule);
4493 if (!submodule) {
4494 LOGMEM;
4495 goto error;
4496 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004497
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004498 submodule->ctx = module->ctx;
4499 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4500 submodule->type = 1;
4501 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004502
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004503 LOGVRB("reading submodule %s", submodule->name);
4504 if (read_sub_module((struct ly_module *)submodule, yin)) {
4505 goto error;
4506 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004508 /* cleanup */
4509 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004510
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004511 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004512
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004513 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004514
4515error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004516 /* cleanup */
4517 lyxml_free_elem(module->ctx, yin);
4518 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004519
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004520 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004521}
4522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004523struct ly_module *
4524yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004525{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004526 struct lyxml_elem *yin;
4527 struct ly_module *module = NULL, **newlist = NULL;
4528 const char *value;
4529 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004531 yin = lyxml_read(ctx, data, 0);
4532 if (!yin) {
4533 return NULL;
4534 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004536 /* check root element */
4537 if (!yin->name || strcmp(yin->name, "module")) {
4538 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4539 goto error;
4540 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004542 GETVAL(value, yin, "name");
4543 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4544 goto error;
4545 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004546
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004547 module = calloc(1, sizeof *module);
4548 if (!module) {
4549 LOGMEM;
4550 goto error;
4551 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004553 module->ctx = ctx;
4554 module->name = lydict_insert(ctx, value, strlen(value));
4555 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004557 LOGVRB("reading module %s", module->name);
4558 if (read_sub_module(module, yin)) {
4559 goto error;
4560 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004562 /* add to the context's list of modules */
4563 if (ctx->models.used == ctx->models.size) {
4564 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4565 if (!newlist) {
4566 LOGMEM;
4567 goto error;
4568 }
4569 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4570 newlist[i] = NULL;
4571 }
4572 ctx->models.size *= 2;
4573 ctx->models.list = newlist;
4574 }
4575 for (i = 0; ctx->models.list[i]; i++) {
4576 /* check name (name/revision) and namespace uniqueness */
4577 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4578 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4579 /* both data models are same, with no revision specified */
4580 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4581 module->name);
4582 goto error;
4583 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4584 /* one of the models does not have a revision, so they differs */
4585 continue;
4586 } else {
4587 /* both models have a revision statement which we have to
4588 * compare, revision at position 0 is the last revision
4589 */
4590 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4591 /* we have the same modules */
4592 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4593 module->rev[0].date);
4594 goto error;
4595 }
4596 }
4597 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4598 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4599 ctx->models.list[i]->name, module->name, module->ns);
4600 goto error;
4601 }
4602 }
4603 ctx->models.list[i] = module;
4604 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004606 /* cleanup */
4607 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004609 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004610
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004611 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004612
4613error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004614 /* cleanup */
4615 lyxml_free_elem(ctx, yin);
4616 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004618 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004619}