blob: c11e67bc8b43c042eb23e0e61138a8f1ff3e1e58 [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 Krejci0bd5db42015-06-19 13:30:07 +0200777read_restr_substmt(struct ly_ctx *ctx, struct ly_restr *restr, struct lyxml_elem *yin)
Radek Krejci41726f92015-06-19 13:11:05 +0200778{
779 struct lyxml_elem *next, *child;
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;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200833 struct lyxml_elem *next, *node;
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 GETVAL(value, yin, "name")
839 delim = strchr(value, ':');
840 if (delim) {
841 type->prefix = lydict_insert(module->ctx, value, delim - value);
842 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200843
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200844 type->der = find_superior_type(value, module, parent);
845 if (!type->der) {
846 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
847 goto error;
848 }
849 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200850
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200851 switch (type->base) {
852 case LY_TYPE_BINARY:
Radek Krejci41726f92015-06-19 13:11:05 +0200853 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
854 LY_TREE_FOR_SAFE(yin->child, next, node) {
855 if (!strcmp(node->name, "length")) {
856 if (type->info.binary.length) {
857 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
858 goto error;
859 }
860
861 GETVAL(value, node, "value");
862 if (check_length(value, type, LOGLINE(node))) {
863 goto error;
864 }
865 type->info.binary.length = calloc(1, sizeof *type->info.binary.length);
866 type->info.binary.length->expr = lydict_insert(module->ctx, value, 0);
867
868 /* get possible substatements */
Radek Krejci0bd5db42015-06-19 13:30:07 +0200869 if (read_restr_substmt(module->ctx, (struct ly_restr *)type->info.binary.length, node)) {
Radek Krejci41726f92015-06-19 13:11:05 +0200870 goto error;
871 }
872 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +0200873 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci41726f92015-06-19 13:11:05 +0200874 goto error;
875 }
Radek Krejci82d971d2015-06-19 14:20:50 +0200876 lyxml_free_elem(module->ctx, node);
Radek Krejci41726f92015-06-19 13:11:05 +0200877 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200878 break;
Radek Krejci04581c62015-05-22 21:24:00 +0200879
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200880 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200881 /* RFC 6020 9.7.4 - bit */
882
883 /* get bit specifications, at least one must be present */
884 LY_TREE_FOR_SAFE(yin->child, next, node) {
885 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200886 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200887 } else {
888 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
889 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200890 }
891 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200892 if (!type->info.bits.count) {
893 if (type->der->type.der) {
894 /* this is just a derived type with no bit specified */
895 break;
896 }
897 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
898 goto error;
899 }
900
901 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200902 for (i = p = 0; yin->child; i++) {
903 GETVAL(value, yin->child, "name");
904 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200905 goto error;
906 }
907 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200908 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], yin->child, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200909 type->info.bits.count = i + 1;
910 goto error;
911 }
912
913 /* check the name uniqueness */
914 for (j = 0; j < i; j++) {
915 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200916 LOGVAL(VE_BITS_DUPNAME, LOGLINE(yin->child), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200917 type->info.bits.count = i + 1;
918 goto error;
919 }
920 }
921
Radek Krejci5fbc9162015-06-19 14:11:11 +0200922 node = yin->child->child;
Radek Krejci994b6f62015-06-18 16:47:27 +0200923 if (node && !strcmp(node->name, "position")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +0200924 GETVAL(value, node, "value");
Radek Krejci994b6f62015-06-18 16:47:27 +0200925 p_ = strtol(value, NULL, 10);
926
927 /* range check */
928 if (p_ < 0 || p_ > UINT32_MAX) {
929 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
930 type->info.bits.count = i + 1;
931 goto error;
932 }
933 type->info.bits.bit[i].pos = (uint32_t)p_;
934
935 /* keep the highest enum value for automatic increment */
936 if (type->info.bits.bit[i].pos > p) {
937 p = type->info.bits.bit[i].pos;
938 p++;
939 } else {
940 /* check that the value is unique */
941 for (j = 0; j < i; j++) {
942 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
943 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
944 type->info.bits.count = i + 1;
945 goto error;
946 }
947 }
948 }
949 } else {
950 /* assign value automatically */
951 if (p > UINT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200952 LOGVAL(VE_INARG, LOGLINE(yin->child), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +0200953 type->info.bits.count = i + 1;
954 goto error;
955 }
956 type->info.bits.bit[i].pos = (uint32_t)p;
957 p++;
958 }
Radek Krejci5fbc9162015-06-19 14:11:11 +0200959 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci994b6f62015-06-18 16:47:27 +0200960 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200961 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200962
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200963 case LY_TYPE_DEC64:
964 /* TODO fraction-digits, 9.3.4
965 * - MUST, 1, nerekurzivni, hodnota 1-18 */
966 /* TODO range, 9.2.4
967 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
968 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200969
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200970 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200971 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200972
Radek Krejci994b6f62015-06-18 16:47:27 +0200973 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200974 LY_TREE_FOR_SAFE(yin->child, next, node) {
975 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200976 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200977 } else {
978 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
979 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200980 }
981 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200982 if (!type->info.enums.count) {
983 if (type->der->type.der) {
984 /* this is just a derived type with no enum specified */
985 break;
986 }
987 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
988 goto error;
989 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200990
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200991 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200992 for (i = v = 0; yin->child; i++) {
993 GETVAL(value, yin->child, "name");
994 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200995 goto error;
996 }
997 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200998 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200999 type->info.enums.count = i + 1;
1000 goto error;
1001 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001002
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001003 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1004 value = type->info.enums.list[i].name;
1005 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001006 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001007 type->info.enums.count = i + 1;
1008 goto error;
1009 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001011 /* check the name uniqueness */
1012 for (j = 0; j < i; j++) {
1013 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001014 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001015 type->info.enums.count = i + 1;
1016 goto error;
1017 }
1018 }
Radek Krejci04581c62015-05-22 21:24:00 +02001019
Radek Krejci5fbc9162015-06-19 14:11:11 +02001020 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001021 if (node && !strcmp(node->name, "value")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +02001022 GETVAL(value, node, "value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001023 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001024
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001025 /* range check */
1026 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1027 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1028 type->info.enums.count = i + 1;
1029 goto error;
1030 }
1031 type->info.enums.list[i].value = v_;
1032
1033 /* keep the highest enum value for automatic increment */
1034 if (type->info.enums.list[i].value > v) {
1035 v = type->info.enums.list[i].value;
1036 v++;
1037 } else {
1038 /* check that the value is unique */
1039 for (j = 0; j < i; j++) {
1040 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001041 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 +02001042 type->info.enums.count = i + 1;
1043 goto error;
1044 }
1045 }
1046 }
1047 } else {
1048 /* assign value automatically */
1049 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001050 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001051 type->info.enums.count = i + 1;
1052 goto error;
1053 }
1054 type->info.enums.list[i].value = v;
1055 v++;
1056 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001057 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001058 }
1059 break;
1060
1061 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001062 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001063
1064 /* get base specification, exactly one must be present */
1065 if (!yin->child) {
1066 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1067 goto error;
1068 }
1069 if (strcmp(yin->child->name, "base")) {
1070 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1071 goto error;
1072 }
1073 if (yin->child->next) {
1074 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1075 goto error;
1076 }
1077 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1078 if (!type->info.ident.ref) {
1079 return EXIT_FAILURE;
1080 }
1081 break;
1082
1083 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001084 /* RFC 6020 9.13.2 - require-instance */
1085 LY_TREE_FOR_SAFE(yin->child, next, node) {
1086 if (!strcmp(node->name, "require-instance")) {
1087 if (type->info.inst.req) {
1088 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1089 goto error;
1090 }
1091 GETVAL(value, node, "value");
1092 if (strcmp(value, "true")) {
1093 type->info.inst.req = 1;
1094 } else if (strcmp(value, "false")) {
1095 type->info.inst.req = -1;
1096 } else {
1097 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1098 goto error;
1099 }
1100 } else {
1101 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1102 goto error;
1103 }
1104 lyxml_free_elem(module->ctx, node);
1105 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001106 break;
1107
1108 case LY_TYPE_INT8:
1109 case LY_TYPE_INT16:
1110 case LY_TYPE_INT32:
1111 case LY_TYPE_INT64:
1112 case LY_TYPE_UINT8:
1113 case LY_TYPE_UINT16:
1114 case LY_TYPE_UINT32:
1115 case LY_TYPE_UINT64:
1116 /* TODO range, 9.2.4
1117 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
1118 break;
1119
1120 case LY_TYPE_LEAFREF:
1121 /* TODO path, 9.9.2
1122 * - 1, nerekurzivni, string */
1123 break;
1124
1125 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001126 /* RFC 6020 9.4.4 - length */
1127 /* RFC 6020 9.4.6 - pattern */
1128 LY_TREE_FOR_SAFE(yin->child, next, node) {
1129 if (!strcmp(node->name, "length")) {
1130 if (type->info.str.length) {
1131 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1132 goto error;
1133 }
1134
1135 GETVAL(value, node, "value");
1136 if (check_length(value, type, LOGLINE(node))) {
1137 goto error;
1138 }
1139 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1140 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1141
Radek Krejci5fbc9162015-06-19 14:11:11 +02001142 /* get possible sub-statements */
1143 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001144 goto error;
1145 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001146 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001147 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001148 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001149 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001150 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001151 goto error;
1152 }
1153 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001154 /* store patterns in array */
1155 if (type->info.str.pat_count) {
1156 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1157 for (i = 0; yin->child; i++) {
1158 GETVAL(value, yin->child, "value");
1159 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1160
1161 /* get possible sub-statements */
1162 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1163 goto error;
1164 }
1165 lyxml_free_elem(module->ctx, yin->child);
1166 }
1167 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001168 break;
1169
1170 case LY_TYPE_UNION:
1171 /* TODO type, 7.4
1172 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1173 break;
1174
1175 default:
1176 /* nothing needed :
1177 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1178 */
1179 break;
1180 }
1181
1182 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001183
1184error:
1185
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001186 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001187}
1188
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001189static int
1190fill_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 +02001191{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001192 const char *value;
1193 struct lyxml_elem *node, *next;
1194 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001195
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001196 GETVAL(value, yin, "name");
1197 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1198 goto error;
1199 }
1200 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001201
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001202 /* generic part - status, description, reference */
1203 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1204 goto error;
1205 }
Radek Krejcieac35532015-05-31 19:09:15 +02001206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001207 LY_TREE_FOR_SAFE(yin->child, next, node) {
1208 if (!strcmp(node->name, "type")) {
1209 if (tpdf->type.der) {
1210 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1211 goto error;
1212 }
1213 r = fill_yin_type(module, parent, node, &tpdf->type);
1214 } else if (!strcmp(node->name, "default")) {
1215 if (tpdf->dflt) {
1216 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1217 goto error;
1218 }
1219 GETVAL(value, node, "value");
1220 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1221 } else if (!strcmp(node->name, "units")) {
1222 if (tpdf->units) {
1223 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1224 goto error;
1225 }
1226 GETVAL(value, node, "name");
1227 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1228 } else {
1229 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1230 r = 1;
1231 }
1232 lyxml_free_elem(module->ctx, node);
1233 if (r) {
1234 goto error;
1235 }
1236 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001238 /* check mandatory value */
1239 if (!tpdf->type.der) {
1240 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1241 goto error;
1242 }
Radek Krejcieac35532015-05-31 19:09:15 +02001243
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001244 /* check default value */
1245 if (check_default(&tpdf->type, tpdf->dflt)) {
1246 goto error;
1247 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001249 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001250
1251error:
1252
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001253 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001254}
1255
Radek Krejci3cf9e222015-06-18 11:37:50 +02001256static struct ly_feature *
1257resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1258{
1259 const char *prefix;
1260 unsigned int prefix_len = 0;
1261 int i, j, found = 0;
1262
1263 assert(name);
1264 assert(module);
1265
1266 /* check prefix */
1267 prefix = name;
1268 name = strchr(prefix, ':');
1269 if (name) {
1270 /* there is prefix */
1271 prefix_len = name - prefix;
1272 name++;
1273
1274 /* check whether the prefix points to the current module */
1275 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1276 /* then ignore prefix and works as there is no prefix */
1277 prefix_len = 0;
1278 }
1279 } else {
1280 /* no prefix, set pointers correctly */
1281 name = prefix;
1282 }
1283
1284 if (prefix_len) {
1285 /* search in imported modules */
1286 for (i = 0; i < module->imp_size; i++) {
1287 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1288 module = module->imp[i].module;
1289 found = 1;
1290 break;
1291 }
1292 }
1293 if (!found) {
1294 /* identity refers unknown data model */
1295 LOGVAL(VE_INPREFIX, line, prefix);
1296 return NULL;
1297 }
1298 } else {
1299 /* search in submodules */
1300 for (i = 0; i < module->inc_size; i++) {
1301 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1302 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1303 return &(module->inc[i].submodule->features[j]);
1304 }
1305 }
1306 }
1307 }
1308
1309 /* search in the identified module */
1310 for (j = 0; j < module->features_size; j++) {
1311 if (!strcmp(name, module->features[j].name)) {
1312 return &module->features[j];
1313 }
1314 }
1315
1316 /* not found */
1317 return NULL;
1318}
1319
1320static int
1321fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1322{
1323 const char *value;
1324 struct lyxml_elem *child, *next;
1325 int c = 0;
1326
Radek Krejcib05774c2015-06-18 13:52:59 +02001327 GETVAL(value, yin, "name");
1328 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1329 goto error;
1330 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001331 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001332
1333 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001334 goto error;
1335 }
1336
1337 LY_TREE_FOR_SAFE(yin->child, next, child) {
1338 if (!strcmp(child->name, "if-feature")) {
1339 c++;
1340 } else {
1341 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1342 goto error;
1343 }
1344 }
1345
1346 if (c) {
1347 f->features = calloc(c, sizeof *f->features);
1348 }
1349
1350 LY_TREE_FOR_SAFE(yin->child, next, child) {
1351 GETVAL(value, child, "name");
1352 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1353 if (!f->features[f->features_size]) {
1354 goto error;
1355 }
1356 f->features_size++;
1357 }
1358
1359 /* tmp TODO remove */
1360 f->flags |= LY_NODE_FENABLED;
1361
1362 return EXIT_SUCCESS;
1363
1364error:
1365
1366 return EXIT_FAILURE;
1367}
1368
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001369static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001370fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001371{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001372 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001374 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001375 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001376
Radek Krejci41726f92015-06-19 13:11:05 +02001377 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001378
Radek Krejci41726f92015-06-19 13:11:05 +02001379error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001381 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001382}
1383
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001384static int
1385fill_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 +02001386{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001387 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001388 struct lyxml_elem *next, *child;
1389 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001391 GETVAL(value, yin, "target-node");
1392 aug->target_name = lydict_insert(module->ctx, value, 0);
1393 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001394
Radek Krejci3cf9e222015-06-18 11:37:50 +02001395 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1396 goto error;
1397 }
1398
1399 LY_TREE_FOR_SAFE(yin->child, next, child) {
1400 if (!strcmp(child->name, "if-feature")) {
1401 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001402 } else if (!strcmp(child->name, "when")) {
1403 if (aug->when) {
1404 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1405 goto error;
1406 }
1407
1408 aug->when = read_yin_when(module, child);
1409 lyxml_free_elem(module->ctx, child);
1410
1411 if (!aug->when) {
1412 goto error;
1413 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001414
1415 /* check allowed sub-statements */
1416 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1417 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1418 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1419 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1420 goto error;
1421 }
1422 }
1423
1424 if (c) {
1425 aug->features = calloc(c, sizeof *aug->features);
1426 }
1427
1428 LY_TREE_FOR_SAFE(yin->child, next, child) {
1429 if (!strcmp(child->name, "if-feature")) {
1430 GETVAL(value, child, "name");
1431 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1432 if (!aug->features[aug->features_size]) {
1433 goto error;
1434 }
1435 aug->features_size++;
1436 } else {
1437 /* keep the data nodes */
1438 continue;
1439 }
1440
1441 lyxml_free_elem(module->ctx, child);
1442 }
1443
1444 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001445 * when we will have the target node
1446 */
1447 lyxml_unlink_elem(yin);
1448 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001449
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001450 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001451
1452error:
1453
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001454 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001455}
1456
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001457static int
1458fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001459{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001460 struct lyxml_elem *sub, *next;
1461 const char *value;
1462 char *endptr;
1463 int f_mand = 0, f_min = 0, f_max = 0;
1464 int c_must = 0;
1465 int r;
1466 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001468 GETVAL(value, yin, "target-node");
1469 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001471 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1472 goto error;
1473 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001475 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1476 /* limited applicability */
1477 if (!strcmp(sub->name, "default")) {
1478 /* leaf or choice */
1479 if (rfn->mod.dflt) {
1480 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1481 goto error;
1482 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001483
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001484 /* check possibility of statements combination */
1485 if (rfn->target_type) {
1486 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1487 if (!rfn->target_type) {
1488 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1489 goto error;
1490 }
1491 } else {
1492 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1493 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001494
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001495 GETVAL(value, sub, "value");
1496 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1497 } else if (!strcmp(sub->name, "mandatory")) {
1498 /* leaf, choice or anyxml */
1499 if (f_mand) {
1500 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1501 goto error;
1502 }
1503 /* just checking the flags in leaf is not sufficient, we would allow
1504 * multiple mandatory statements with the "false" value
1505 */
1506 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001508 /* check possibility of statements combination */
1509 if (rfn->target_type) {
1510 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1511 if (!rfn->target_type) {
1512 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1513 goto error;
1514 }
1515 } else {
1516 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1517 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001519 GETVAL(value, sub, "value");
1520 if (!strcmp(value, "true")) {
1521 rfn->flags |= LY_NODE_MAND_TRUE;
1522 } else if (!strcmp(value, "false")) {
1523 rfn->flags |= LY_NODE_MAND_FALSE;
1524 } else {
1525 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1526 goto error;
1527 }
1528 } else if (!strcmp(sub->name, "min-elements")) {
1529 /* list or leaf-list */
1530 if (f_min) {
1531 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1532 goto error;
1533 }
1534 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001536 /* check possibility of statements combination */
1537 if (rfn->target_type) {
1538 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1539 if (!rfn->target_type) {
1540 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1541 goto error;
1542 }
1543 } else {
1544 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1545 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001546
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001547 GETVAL(value, sub, "value");
1548 while (isspace(value[0])) {
1549 value++;
1550 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001551
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001552 /* convert it to uint32_t */
1553 errno = 0;
1554 endptr = NULL;
1555 val = strtoul(value, &endptr, 10);
1556 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1557 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1558 goto error;
1559 }
1560 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001562 /* magic - bit 3 in flags means min set */
1563 rfn->flags |= 0x04;
1564 } else if (!strcmp(sub->name, "max-elements")) {
1565 /* list or leaf-list */
1566 if (f_max) {
1567 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1568 goto error;
1569 }
1570 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001571
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001572 /* check possibility of statements combination */
1573 if (rfn->target_type) {
1574 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1575 if (!rfn->target_type) {
1576 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1577 goto error;
1578 }
1579 } else {
1580 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1581 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001582
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001583 GETVAL(value, sub, "value");
1584 while (isspace(value[0])) {
1585 value++;
1586 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001588 /* convert it to uint32_t */
1589 errno = 0;
1590 endptr = NULL;
1591 val = strtoul(value, &endptr, 10);
1592 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1593 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1594 goto error;
1595 }
1596 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001597
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001598 /* magic - bit 4 in flags means min set */
1599 rfn->flags |= 0x08;
1600 } else if (!strcmp(sub->name, "presence")) {
1601 /* container */
1602 if (rfn->mod.presence) {
1603 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1604 goto error;
1605 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001607 /* check possibility of statements combination */
1608 if (rfn->target_type) {
1609 rfn->target_type &= LY_NODE_CONTAINER;
1610 if (!rfn->target_type) {
1611 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1612 goto error;
1613 }
1614 } else {
1615 rfn->target_type = LY_NODE_CONTAINER;
1616 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001618 GETVAL(value, sub, "value");
1619 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1620 } else if (!strcmp(sub->name, "must")) {
1621 /* leaf-list, list, container or anyxml */
1622 /* check possibility of statements combination */
1623 if (rfn->target_type) {
1624 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1625 if (!rfn->target_type) {
1626 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1627 goto error;
1628 }
1629 } else {
1630 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1631 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001632
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001633 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001635 } else {
1636 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1637 goto error;
1638 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001639
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001640 lyxml_free_elem(module->ctx, sub);
1641 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001642
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001643 /* process nodes with cardinality of 0..n */
1644 if (c_must) {
1645 rfn->must = calloc(c_must, sizeof *rfn->must);
1646 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001647
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001648 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1649 if (!strcmp(sub->name, "must")) {
1650 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1651 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001653 if (r) {
1654 goto error;
1655 }
1656 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001657
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001658 lyxml_free_elem(module->ctx, sub);
1659 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001660
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001661 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001662
1663error:
1664
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001665 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001666}
1667
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001668static int
1669fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001670{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001671 struct lyxml_elem *child;
1672 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001674 LY_TREE_FOR(yin->child, child) {
1675 if (!strcmp(child->name, "prefix")) {
1676 GETVAL(value, child, "value");
1677 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1678 goto error;
1679 }
1680 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1681 } else if (!strcmp(child->name, "revision-date")) {
1682 if (imp->rev[0]) {
1683 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1684 goto error;
1685 }
1686 GETVAL(value, child, "date");
1687 if (check_date(value, LOGLINE(child))) {
1688 goto error;
1689 }
1690 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1691 } else {
1692 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1693 goto error;
1694 }
1695 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001696
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001697 /* check mandatory information */
1698 if (!imp->prefix) {
1699 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1700 goto error;
1701 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001703 GETVAL(value, yin, "module");
1704 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1705 if (!imp->module) {
1706 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1707 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1708 goto error;
1709 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001711 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001712
1713error:
1714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001715 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001716}
1717
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001718static int
1719fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001720{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001721 struct lyxml_elem *child;
1722 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001723
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001724 LY_TREE_FOR(yin->child, child) {
1725 if (!strcmp(child->name, "revision-date")) {
1726 if (inc->rev[0]) {
1727 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1728 goto error;
1729 }
1730 GETVAL(value, child, "date");
1731 if (check_date(value, LOGLINE(child))) {
1732 goto error;
1733 }
1734 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1735 } else {
1736 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1737 goto error;
1738 }
1739 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001741 GETVAL(value, yin, "module");
1742 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1743 if (!inc->submodule) {
1744 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1745 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1746 goto error;
1747 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001748
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001749 /* check that belongs-to corresponds */
1750 if (module->type) {
1751 module = ((struct ly_submodule *)module)->belongsto;
1752 }
1753 if (inc->submodule->belongsto != module) {
1754 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1755 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1756 goto error;
1757 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001758
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001759 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001760
1761error:
1762
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001763 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001764}
1765
Radek Krejcida04f4a2015-05-21 12:54:09 +02001766/*
1767 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001768 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001769 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001770 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001771static int
1772read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1773 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001774{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001775 const char *value;
1776 struct lyxml_elem *sub, *next;
1777 struct ly_ctx *const ctx = module->ctx;
1778 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001779
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001780 if (opt & OPT_MODULE) {
1781 mnode->module = module;
1782 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001783
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001784 if (opt & OPT_IDENT) {
1785 GETVAL(value, xmlnode, "name");
1786 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1787 goto error;
1788 }
1789 mnode->name = lydict_insert(ctx, value, strlen(value));
1790 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001791
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001792 /* process local parameters */
1793 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1794 if (!strcmp(sub->name, "description")) {
1795 if (mnode->dsc) {
1796 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1797 goto error;
1798 }
1799 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1800 if (!mnode->dsc) {
1801 r = 1;
1802 }
1803 } else if (!strcmp(sub->name, "reference")) {
1804 if (mnode->ref) {
1805 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1806 goto error;
1807 }
1808 mnode->ref = read_yin_subnode(ctx, sub, "text");
1809 if (!mnode->ref) {
1810 r = 1;
1811 }
1812 } else if (!strcmp(sub->name, "status")) {
1813 if (mnode->flags & LY_NODE_STATUS_MASK) {
1814 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1815 goto error;
1816 }
1817 GETVAL(value, sub, "value");
1818 if (!strcmp(value, "current")) {
1819 mnode->flags |= LY_NODE_STATUS_CURR;
1820 } else if (!strcmp(value, "deprecated")) {
1821 mnode->flags |= LY_NODE_STATUS_DEPRC;
1822 } else if (!strcmp(value, "obsolete")) {
1823 mnode->flags |= LY_NODE_STATUS_OBSLT;
1824 } else {
1825 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1826 r = 1;
1827 }
1828 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1829 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1830 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1831 goto error;
1832 }
1833 GETVAL(value, sub, "value");
1834 if (!strcmp(value, "false")) {
1835 mnode->flags |= LY_NODE_CONFIG_R;
1836 } else if (!strcmp(value, "true")) {
1837 mnode->flags |= LY_NODE_CONFIG_W;
1838 } else {
1839 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1840 r = 1;
1841 }
1842 } else {
1843 /* skip the lyxml_free_elem */
1844 continue;
1845 }
1846 lyxml_free_elem(ctx, sub);
1847 if (r) {
1848 goto error;
1849 }
1850 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001852 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1853 /* get config flag from parent */
1854 if (parent) {
1855 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1856 } else {
1857 /* default config is true */
1858 mnode->flags |= LY_NODE_CONFIG_W;
1859 }
1860 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001861
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001862 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001863
1864error:
1865
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001866 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001867}
1868
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001869static struct ly_when *
1870read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
1871{
Radek Krejci53ebfb12015-06-19 09:35:59 +02001872 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001873 struct lyxml_elem *next, *child;
1874 const char *value;
1875
1876 retval = calloc(1, sizeof *retval);
1877
1878 GETVAL(value, yin, "condition");
1879 retval->cond = lydict_insert(module->ctx, value, 0);
1880
1881 LY_TREE_FOR_SAFE(yin->child, next, child) {
1882 if (!strcmp(child->name, "description")) {
1883 if (retval->dsc) {
1884 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1885 goto error;
1886 }
1887 retval->dsc = read_yin_subnode(module->ctx, child, "text");
1888 if (!retval->dsc) {
1889 goto error;
1890 }
1891 } else if (!strcmp(child->name, "reference")) {
1892 if (retval->ref) {
1893 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1894 goto error;
1895 }
1896 retval->ref = read_yin_subnode(module->ctx, child, "text");
1897 if (!retval->ref) {
1898 goto error;
1899 }
1900 } else {
1901 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1902 goto error;
1903 }
1904
1905 lyxml_free_elem(module->ctx, child);
1906 }
1907
1908 return retval;
1909
1910error:
1911
Radek Krejci53ebfb12015-06-19 09:35:59 +02001912 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001913 return NULL;
1914}
1915
Radek Krejcib4cf2022015-06-03 14:40:05 +02001916/* additional check in case statement - the child must be unique across
1917 * all other case names and its data children
1918 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001919static int
1920check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001921{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001922 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001924 if (new->nodetype == LY_NODE_CHOICE) {
1925 /* we have nested choice in case, so we need recursion */
1926 LY_TREE_FOR(new->child, mnode) {
1927 if (mnode->nodetype == LY_NODE_CASE) {
1928 LY_TREE_FOR(mnode->child, submnode) {
1929 if (check_branch_id(parent, submnode, new, line)) {
1930 return EXIT_FAILURE;
1931 }
1932 }
1933 } else if (check_branch_id(parent, mnode, new, line)) {
1934 return EXIT_FAILURE;
1935 }
1936 }
1937 } else {
1938 LY_TREE_FOR(parent->child, mnode) {
1939 if (mnode == excl) {
1940 continue;
1941 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001942
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001943 if (!strcmp(new->name, mnode->name)) {
1944 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1945 return EXIT_FAILURE;
1946 }
1947 if (mnode->nodetype == LY_NODE_CASE) {
1948 LY_TREE_FOR(mnode->child, submnode) {
1949 if (!strcmp(new->name, submnode->name)) {
1950 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1951 return EXIT_FAILURE;
1952 }
1953 }
1954 }
1955 }
1956 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001957
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001958 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001959}
1960
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001961static struct ly_mnode *
1962read_yin_case(struct ly_module *module,
1963 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001964{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001965 struct lyxml_elem *sub, *next;
1966 struct ly_mnode_case *mcase;
1967 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001968 int c_ftrs = 0;
1969 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001971 mcase = calloc(1, sizeof *mcase);
1972 mcase->nodetype = LY_NODE_CASE;
1973 mcase->prev = (struct ly_mnode *)mcase;
1974 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001976 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
1977 goto error;
1978 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001979
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001980 /* process choice's specific children */
1981 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1982 if (!strcmp(sub->name, "container")) {
1983 mnode = read_yin_container(module, retval, sub, resolve, unres);
1984 } else if (!strcmp(sub->name, "leaf-list")) {
1985 mnode = read_yin_leaflist(module, retval, sub, resolve);
1986 } else if (!strcmp(sub->name, "leaf")) {
1987 mnode = read_yin_leaf(module, retval, sub, resolve);
1988 } else if (!strcmp(sub->name, "list")) {
1989 mnode = read_yin_list(module, retval, sub, resolve, unres);
1990 } else if (!strcmp(sub->name, "uses")) {
1991 mnode = read_yin_uses(module, retval, sub, resolve, unres);
1992 } else if (!strcmp(sub->name, "choice")) {
1993 mnode = read_yin_choice(module, retval, sub, resolve, unres);
1994 } else if (!strcmp(sub->name, "anyxml")) {
1995 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02001996 } else if (!strcmp(sub->name, "if-feature")) {
1997 c_ftrs++;
1998
1999 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
2000 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002001 } else if (!strcmp(sub->name, "when")) {
2002 if (mcase->when) {
2003 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2004 goto error;
2005 }
2006
2007 mcase->when = read_yin_when(module, sub);
2008 if (!mcase->when) {
2009 goto error;
2010 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002011 } else {
2012 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2013 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002014 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002016 if (!mnode) {
2017 goto error;
2018 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
2019 goto error;
2020 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002021
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002022 mnode = NULL;
2023 lyxml_free_elem(module->ctx, sub);
2024 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002025
Radek Krejci3cf9e222015-06-18 11:37:50 +02002026 if (c_ftrs) {
2027 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2028 }
2029 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2030 GETVAL(value, sub, "name");
2031 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2032 if (!mcase->features[mcase->features_size]) {
2033 goto error;
2034 }
2035 mcase->features_size++;
2036 lyxml_free_elem(module->ctx, sub);
2037 }
2038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002039 /* inherit config flag */
2040 if (parent) {
2041 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2042 } else {
2043 /* default config is true */
2044 retval->flags |= LY_NODE_CONFIG_W;
2045 }
Radek Krejcib388c152015-06-04 17:03:03 +02002046
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002047 /* insert the node into the schema tree */
2048 if (ly_mnode_addchild(parent, retval)) {
2049 goto error;
2050 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002052 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002053
2054error:
2055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002056 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002057
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002058 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002059}
2060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002061static struct ly_mnode *
2062read_yin_choice(struct ly_module *module,
2063 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002064{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002065 struct lyxml_elem *sub, *next;
2066 struct ly_ctx *const ctx = module->ctx;
2067 struct ly_mnode *retval, *mnode = NULL;
2068 struct ly_mnode_choice *choice;
2069 const char *value;
2070 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002071 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002072
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002073 choice = calloc(1, sizeof *choice);
2074 choice->nodetype = LY_NODE_CHOICE;
2075 choice->prev = (struct ly_mnode *)choice;
2076 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002078 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2079 goto error;
2080 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002081
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002082 /* process choice's specific children */
2083 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2084 if (!strcmp(sub->name, "container")) {
2085 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2086 goto error;
2087 }
2088 } else if (!strcmp(sub->name, "leaf-list")) {
2089 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2090 goto error;
2091 }
2092 } else if (!strcmp(sub->name, "leaf")) {
2093 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2094 goto error;
2095 }
2096 } else if (!strcmp(sub->name, "list")) {
2097 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2098 goto error;
2099 }
2100 } else if (!strcmp(sub->name, "case")) {
2101 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2102 goto error;
2103 }
2104 } else if (!strcmp(sub->name, "anyxml")) {
2105 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2106 goto error;
2107 }
2108 } else if (!strcmp(sub->name, "default")) {
2109 if (dflt_str) {
2110 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2111 goto error;
2112 }
2113 GETVAL(value, sub, "value");
2114 dflt_str = strdup(value);
2115 } else if (!strcmp(sub->name, "mandatory")) {
2116 if (f_mand) {
2117 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2118 goto error;
2119 }
2120 /* just checking the flags in leaf is not sufficient, we would allow
2121 * multiple mandatory statements with the "false" value
2122 */
2123 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002124
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002125 GETVAL(value, sub, "value");
2126 if (!strcmp(value, "true")) {
2127 choice->flags |= LY_NODE_MAND_TRUE;
2128 } else if (strcmp(value, "false")) {
2129 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2130 goto error;
2131 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002132 } else if (!strcmp(sub->name, "when")) {
2133 if (choice->when) {
2134 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2135 goto error;
2136 }
2137
2138 choice->when = read_yin_when(module, sub);
2139 if (!choice->when) {
2140 goto error;
2141 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002142 } else if (!strcmp(sub->name, "if-feature")) {
2143 c_ftrs++;
2144
2145 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
2146 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002147 } else {
2148 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2149 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002150 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002151
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002152 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
2153 goto error;
2154 }
2155 mnode = NULL;
2156 lyxml_free_elem(ctx, sub);
2157 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002158
Radek Krejci3cf9e222015-06-18 11:37:50 +02002159 if (c_ftrs) {
2160 choice->features = calloc(c_ftrs, sizeof *choice->features);
2161 }
2162
2163 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2164 GETVAL(value, sub, "name");
2165 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
2166 if (!choice->features[choice->features_size]) {
2167 goto error;
2168 }
2169 choice->features_size++;
2170 lyxml_free_elem(ctx, sub);
2171 }
2172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002173 /* check - default is prohibited in combination with mandatory */
2174 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
2175 LOGVAL(VE_SPEC, LOGLINE(yin),
2176 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
2177 goto error;
2178 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002180 /* link default with the case */
2181 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02002182 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002183 if (!choice->dflt) {
2184 /* default branch not found */
2185 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
2186 goto error;
2187 }
2188 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002189
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002190 /* insert the node into the schema tree */
2191 if (parent && ly_mnode_addchild(parent, retval)) {
2192 goto error;
2193 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002194
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002195 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02002196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002197 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002198
2199error:
2200
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002201 ly_mnode_free(retval);
2202 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002204 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002205}
2206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002207static struct ly_mnode *
2208read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02002209{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002210 struct ly_mnode *retval;
2211 struct ly_mnode_leaf *anyxml;
2212 struct lyxml_elem *sub, *next;
2213 const char *value;
2214 int r;
2215 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002216 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02002217
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002218 anyxml = calloc(1, sizeof *anyxml);
2219 anyxml->nodetype = LY_NODE_ANYXML;
2220 anyxml->prev = (struct ly_mnode *)anyxml;
2221 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02002222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002223 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2224 goto error;
2225 }
Radek Krejci863c2852015-06-03 15:47:11 +02002226
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002227 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2228 if (!strcmp(sub->name, "mandatory")) {
2229 if (f_mand) {
2230 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2231 goto error;
2232 }
2233 /* just checking the flags in leaf is not sufficient, we would allow
2234 * multiple mandatory statements with the "false" value
2235 */
2236 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02002237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002238 GETVAL(value, sub, "value");
2239 if (!strcmp(value, "true")) {
2240 anyxml->flags |= LY_NODE_MAND_TRUE;
2241 } else if (strcmp(value, "false")) {
2242 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2243 goto error;
2244 }
2245 /* else false is the default value, so we can ignore it */
2246 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002247 } else if (!strcmp(sub->name, "when")) {
2248 if (anyxml->when) {
2249 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2250 goto error;
2251 }
2252
2253 anyxml->when = read_yin_when(module, sub);
2254 lyxml_free_elem(module->ctx, sub);
2255
2256 if (!anyxml->when) {
2257 goto error;
2258 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002259 } else if (!strcmp(sub->name, "must")) {
2260 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002261 } else if (!strcmp(sub->name, "if-feature")) {
2262 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02002263
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002264 } else {
2265 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2266 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002267 }
2268 }
Radek Krejci863c2852015-06-03 15:47:11 +02002269
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002270 /* middle part - process nodes with cardinality of 0..n */
2271 if (c_must) {
2272 anyxml->must = calloc(c_must, sizeof *anyxml->must);
2273 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002274 if (c_ftrs) {
2275 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
2276 }
Radek Krejci863c2852015-06-03 15:47:11 +02002277
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002278 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2279 if (!strcmp(sub->name, "must")) {
2280 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
2281 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02002282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002283 if (r) {
2284 goto error;
2285 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002286 } else if (!strcmp(sub->name, "must")) {
2287 GETVAL(value, sub, "name");
2288 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
2289 if (!anyxml->features[anyxml->features_size]) {
2290 goto error;
2291 }
2292 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002293 }
Radek Krejci863c2852015-06-03 15:47:11 +02002294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002295 lyxml_free_elem(module->ctx, sub);
2296 }
Radek Krejci863c2852015-06-03 15:47:11 +02002297
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002298 if (parent && ly_mnode_addchild(parent, retval)) {
2299 goto error;
2300 }
Radek Krejci863c2852015-06-03 15:47:11 +02002301
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002302 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02002303
2304error:
2305
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002306 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02002307
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002308 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02002309}
2310
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002311static struct ly_mnode *
2312read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002313{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002314 struct ly_mnode *retval;
2315 struct ly_mnode_leaf *leaf;
2316 struct lyxml_elem *sub, *next;
2317 const char *value;
2318 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002319 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002320
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002321 leaf = calloc(1, sizeof *leaf);
2322 leaf->nodetype = LY_NODE_LEAF;
2323 leaf->prev = (struct ly_mnode *)leaf;
2324 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002325
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002326 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2327 goto error;
2328 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002330 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2331 if (!strcmp(sub->name, "type")) {
2332 if (leaf->type.der) {
2333 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2334 goto error;
2335 }
2336 if (fill_yin_type(module, parent, sub, &leaf->type)) {
2337 goto error;
2338 }
2339 } else if (!strcmp(sub->name, "default")) {
2340 if (leaf->dflt) {
2341 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2342 goto error;
2343 }
2344 GETVAL(value, sub, "value");
2345 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
2346 } else if (!strcmp(sub->name, "units")) {
2347 if (leaf->units) {
2348 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2349 goto error;
2350 }
2351 GETVAL(value, sub, "name");
2352 leaf->units = lydict_insert(module->ctx, value, strlen(value));
2353 } else if (!strcmp(sub->name, "mandatory")) {
2354 if (f_mand) {
2355 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2356 goto error;
2357 }
2358 /* just checking the flags in leaf is not sufficient, we would allow
2359 * multiple mandatory statements with the "false" value
2360 */
2361 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002363 GETVAL(value, sub, "value");
2364 if (!strcmp(value, "true")) {
2365 leaf->flags |= LY_NODE_MAND_TRUE;
2366 } else if (strcmp(value, "false")) {
2367 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2368 goto error;
2369 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002370 } else if (!strcmp(sub->name, "when")) {
2371 if (leaf->when) {
2372 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2373 goto error;
2374 }
2375
2376 leaf->when = read_yin_when(module, sub);
2377 if (!leaf->when) {
2378 goto error;
2379 }
2380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002381 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002382 c_must++; /* else false is the default value, so we can ignore it */
2383 } else if (!strcmp(sub->name, "if-feature")) {
2384 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002385
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002386 /* skip element free at the end of the loop */
2387 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002388 } else {
2389 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2390 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002391 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002392
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002393 lyxml_free_elem(module->ctx, sub);
2394 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002396 /* check mandatory parameters */
2397 if (!leaf->type.der) {
2398 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2399 goto error;
2400 }
2401 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2402 goto error;
2403 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002405 /* middle part - process nodes with cardinality of 0..n */
2406 if (c_must) {
2407 leaf->must = calloc(c_must, sizeof *leaf->must);
2408 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002409 if (c_ftrs) {
2410 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2411 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002412
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002413 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2414 if (!strcmp(sub->name, "must")) {
2415 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2416 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002417
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002418 if (r) {
2419 goto error;
2420 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002421 } else if (!strcmp(sub->name, "if-feature")) {
2422 GETVAL(value, sub, "name");
2423 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2424 if (!leaf->features[leaf->features_size]) {
2425 goto error;
2426 }
2427 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002428 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002429
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002430 lyxml_free_elem(module->ctx, sub);
2431 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002432
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002433 if (parent && ly_mnode_addchild(parent, retval)) {
2434 goto error;
2435 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002436
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002437 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002438
2439error:
2440
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002441 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002442
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002443 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002444}
2445
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002446static struct ly_mnode *
2447read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002448{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002449 struct ly_mnode *retval;
2450 struct ly_mnode_leaflist *llist;
2451 struct lyxml_elem *sub, *next;
2452 const char *value;
2453 char *endptr;
2454 unsigned long val;
2455 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002456 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002457 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002458
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002459 llist = calloc(1, sizeof *llist);
2460 llist->nodetype = LY_NODE_LEAFLIST;
2461 llist->prev = (struct ly_mnode *)llist;
2462 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002464 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2465 goto error;
2466 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002468 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2469 if (!strcmp(sub->name, "type")) {
2470 if (llist->type.der) {
2471 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2472 goto error;
2473 }
2474 if (fill_yin_type(module, parent, sub, &llist->type)) {
2475 goto error;
2476 }
2477 } else if (!strcmp(sub->name, "units")) {
2478 if (llist->units) {
2479 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2480 goto error;
2481 }
2482 GETVAL(value, sub, "name");
2483 llist->units = lydict_insert(module->ctx, value, strlen(value));
2484 } else if (!strcmp(sub->name, "ordered-by")) {
2485 if (f_ordr) {
2486 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2487 goto error;
2488 }
2489 /* just checking the flags in llist is not sufficient, we would
2490 * allow multiple ordered-by statements with the "system" value
2491 */
2492 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002493
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002494 if (llist->flags & LY_NODE_CONFIG_R) {
2495 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2496 * state data
2497 */
2498 lyxml_free_elem(module->ctx, sub);
2499 continue;
2500 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002502 GETVAL(value, sub, "value");
2503 if (!strcmp(value, "user")) {
2504 llist->flags |= LY_NODE_USERORDERED;
2505 } else if (strcmp(value, "system")) {
2506 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2507 goto error;
2508 } /* else system is the default value, so we can ignore it */
2509 } else if (!strcmp(sub->name, "must")) {
2510 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002511 } else if (!strcmp(sub->name, "if-feature")) {
2512 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002513
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002514 /* skip element free at the end of the loop */
2515 continue;
2516 } else if (!strcmp(sub->name, "min-elements")) {
2517 if (f_min) {
2518 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2519 goto error;
2520 }
2521 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002523 GETVAL(value, sub, "value");
2524 while (isspace(value[0])) {
2525 value++;
2526 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002528 /* convert it to uint32_t */
2529 errno = 0;
2530 endptr = NULL;
2531 val = strtoul(value, &endptr, 10);
2532 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2533 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2534 goto error;
2535 }
2536 llist->min = (uint32_t) val;
2537 } else if (!strcmp(sub->name, "max-elements")) {
2538 if (f_max) {
2539 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2540 goto error;
2541 }
2542 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002544 GETVAL(value, sub, "value");
2545 while (isspace(value[0])) {
2546 value++;
2547 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002549 /* convert it to uint32_t */
2550 errno = 0;
2551 endptr = NULL;
2552 val = strtoul(value, &endptr, 10);
2553 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2554 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2555 goto error;
2556 }
2557 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002558 } else if (!strcmp(sub->name, "when")) {
2559 if (llist->when) {
2560 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2561 goto error;
2562 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002563
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002564 llist->when = read_yin_when(module, sub);
2565 if (!llist->when) {
2566 goto error;
2567 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002568 } else {
2569 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2570 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002571 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002573 lyxml_free_elem(module->ctx, sub);
2574 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002576 /* check constraints */
2577 if (!llist->type.der) {
2578 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2579 goto error;
2580 }
2581 if (llist->max && llist->min > llist->max) {
2582 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2583 goto error;
2584 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002585
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002586 /* middle part - process nodes with cardinality of 0..n */
2587 if (c_must) {
2588 llist->must = calloc(c_must, sizeof *llist->must);
2589 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002590 if (c_ftrs) {
2591 llist->features = calloc(c_ftrs, sizeof *llist->features);
2592 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002593
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002594 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2595 if (!strcmp(sub->name, "must")) {
2596 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2597 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002598
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002599 if (r) {
2600 goto error;
2601 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002602 } else if (!strcmp(sub->name, "if-feature")) {
2603 GETVAL(value, sub, "name");
2604 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2605 if (!llist->features[llist->features_size]) {
2606 goto error;
2607 }
2608 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002609 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002610
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002611 lyxml_free_elem(module->ctx, sub);
2612 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002613
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002614 if (parent && ly_mnode_addchild(parent, retval)) {
2615 goto error;
2616 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002618 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002619
2620error:
2621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002622 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002623
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002624 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002625}
2626
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002627static struct ly_mnode *
2628read_yin_list(struct ly_module *module,
2629 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002630{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002631 struct ly_mnode *retval, *mnode;
2632 struct ly_mnode_list *list;
2633 struct ly_unique *uniq_s;
2634 struct lyxml_elem *sub, *next, root, uniq;
2635 int i, r;
2636 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002637 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002638 int f_ordr = 0, f_max = 0, f_min = 0;
2639 const char *key_str = NULL, *uniq_str, *value;
2640 char *auxs;
2641 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002642
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002643 /* init */
2644 memset(&root, 0, sizeof root);
2645 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002646
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002647 list = calloc(1, sizeof *list);
2648 list->nodetype = LY_NODE_LIST;
2649 list->prev = (struct ly_mnode *)list;
2650 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002652 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2653 goto error;
2654 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002655
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002656 /* process list's specific children */
2657 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2658 /* data statements */
2659 if (!strcmp(sub->name, "container") ||
2660 !strcmp(sub->name, "leaf-list") ||
2661 !strcmp(sub->name, "leaf") ||
2662 !strcmp(sub->name, "list") ||
2663 !strcmp(sub->name, "choice") ||
2664 !strcmp(sub->name, "uses") ||
2665 !strcmp(sub->name, "grouping") ||
2666 !strcmp(sub->name, "anyxml")) {
2667 lyxml_unlink_elem(sub);
2668 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002669
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002670 /* array counters */
2671 } else if (!strcmp(sub->name, "key")) {
2672 /* check cardinality 0..1 */
2673 if (list->keys_size) {
2674 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2675 goto error;
2676 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002677
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002678 /* count the number of keys */
2679 GETVAL(value, sub, "value");
2680 key_str = value;
2681 while ((value = strpbrk(value, " \t\n"))) {
2682 list->keys_size++;
2683 while (isspace(*value)) {
2684 value++;
2685 }
2686 }
2687 list->keys_size++;
2688 list->keys = calloc(list->keys_size, sizeof *list->keys);
2689 } else if (!strcmp(sub->name, "unique")) {
2690 c_uniq++;
2691 lyxml_unlink_elem(sub);
2692 lyxml_add_child(&uniq, sub);
2693 } else if (!strcmp(sub->name, "typedef")) {
2694 c_tpdf++;
2695 } else if (!strcmp(sub->name, "must")) {
2696 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002697 } else if (!strcmp(sub->name, "if-feature")) {
2698 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002699
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002700 /* optional stetments */
2701 } else if (!strcmp(sub->name, "ordered-by")) {
2702 if (f_ordr) {
2703 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2704 goto error;
2705 }
2706 /* just checking the flags in llist is not sufficient, we would
2707 * allow multiple ordered-by statements with the "system" value
2708 */
2709 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002711 if (list->flags & LY_NODE_CONFIG_R) {
2712 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2713 * state data
2714 */
2715 lyxml_free_elem(module->ctx, sub);
2716 continue;
2717 }
Radek Krejci345ad742015-06-03 11:04:18 +02002718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002719 GETVAL(value, sub, "value");
2720 if (!strcmp(value, "user")) {
2721 list->flags |= LY_NODE_USERORDERED;
2722 } else if (strcmp(value, "system")) {
2723 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2724 goto error;
2725 }
2726 /* else system is the default value, so we can ignore it */
2727 lyxml_free_elem(module->ctx, sub);
2728 } else if (!strcmp(sub->name, "min-elements")) {
2729 if (f_min) {
2730 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2731 goto error;
2732 }
2733 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002734
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002735 GETVAL(value, sub, "value");
2736 while (isspace(value[0])) {
2737 value++;
2738 }
Radek Krejci345ad742015-06-03 11:04:18 +02002739
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002740 /* convert it to uint32_t */
2741 errno = 0;
2742 auxs = NULL;
2743 val = strtoul(value, &auxs, 10);
2744 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2745 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2746 goto error;
2747 }
2748 list->min = (uint32_t) val;
2749 lyxml_free_elem(module->ctx, sub);
2750 } else if (!strcmp(sub->name, "max-elements")) {
2751 if (f_max) {
2752 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2753 goto error;
2754 }
2755 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002756
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002757 GETVAL(value, sub, "value");
2758 while (isspace(value[0])) {
2759 value++;
2760 }
Radek Krejci345ad742015-06-03 11:04:18 +02002761
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002762 /* convert it to uint32_t */
2763 errno = 0;
2764 auxs = NULL;
2765 val = strtoul(value, &auxs, 10);
2766 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2767 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2768 goto error;
2769 }
2770 list->max = (uint32_t) val;
2771 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002772 } else if (!strcmp(sub->name, "when")) {
2773 if (list->when) {
2774 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2775 goto error;
2776 }
2777
2778 list->when = read_yin_when(module, sub);
2779 lyxml_free_elem(module->ctx, sub);
2780
2781 if (!list->when) {
2782 goto error;
2783 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002784 } else {
2785 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2786 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002787 }
2788 }
Radek Krejci345ad742015-06-03 11:04:18 +02002789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002790 /* check - if list is configuration, key statement is mandatory */
2791 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2792 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2793 goto error;
2794 }
2795 if (list->max && list->min > list->max) {
2796 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2797 goto error;
2798 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002800 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2801 if (c_tpdf) {
2802 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2803 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002804 if (c_must) {
2805 list->must = calloc(c_must, sizeof *list->must);
2806 }
2807 if (c_ftrs) {
2808 list->features = calloc(c_ftrs, sizeof *list->features);
2809 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002810 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2811 if (!strcmp(sub->name, "typedef")) {
2812 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2813 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002815 if (r) {
2816 goto error;
2817 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002818 } else if (!strcmp(sub->name, "if-feature")) {
2819 GETVAL(value, sub, "name");
2820 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2821 if (!list->features[list->features_size]) {
2822 goto error;
2823 }
2824 list->features_size++;
2825 } else if (!strcmp(sub->name, "must")) {
2826 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2827 list->must_size++;
2828
2829 if (r) {
2830 goto error;
2831 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002832 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002833 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002834 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002835
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002836 /* last part - process data nodes */
2837 LY_TREE_FOR_SAFE(root.child, next, sub) {
2838 if (!strcmp(sub->name, "container")) {
2839 mnode = read_yin_container(module, retval, sub, resolve, unres);
2840 } else if (!strcmp(sub->name, "leaf-list")) {
2841 mnode = read_yin_leaflist(module, retval, sub, resolve);
2842 } else if (!strcmp(sub->name, "leaf")) {
2843 mnode = read_yin_leaf(module, retval, sub, resolve);
2844 } else if (!strcmp(sub->name, "list")) {
2845 mnode = read_yin_list(module, retval, sub, resolve, unres);
2846 } else if (!strcmp(sub->name, "choice")) {
2847 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2848 } else if (!strcmp(sub->name, "uses")) {
2849 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2850 } else if (!strcmp(sub->name, "grouping")) {
2851 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2852 } else if (!strcmp(sub->name, "anyxml")) {
2853 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002854 }
2855 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002856
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002857 if (!mnode) {
2858 goto error;
2859 }
2860 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002861
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002862 if (parent && ly_mnode_addchild(parent, retval)) {
2863 goto error;
2864 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002865
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002866 if (!key_str) {
2867 /* config false list without a key */
2868 return retval;
2869 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002870
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002871 /* link key leafs into the list structure and check all constraints */
2872 for (i = 0; i < list->keys_size; i++) {
2873 /* get the key name */
2874 if ((value = strpbrk(key_str, " \t\n"))) {
2875 len = value - key_str;
2876 while (isspace(*value)) {
2877 value++;
2878 }
2879 } else {
2880 len = strlen(key_str);
2881 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002882
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002883 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002884
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002885 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2886 goto error;
2887 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002888
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002889 /* prepare for next iteration */
2890 while (value && isspace(*value)) {
2891 value++;
2892 }
2893 key_str = value;
2894 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002896 /* process unique statements */
2897 if (c_uniq) {
2898 list->unique = calloc(c_uniq, sizeof *list->unique);
2899 }
2900 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2901 /* count the number of unique values */
2902 GETVAL(value, sub, "tag");
2903 uniq_str = value;
2904 uniq_s = &list->unique[list->unique_size];
2905 while ((value = strpbrk(value, " \t\n"))) {
2906 uniq_s->leafs_size++;
2907 while (isspace(*value)) {
2908 value++;
2909 }
2910 }
2911 uniq_s->leafs_size++;
2912 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2913 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002914
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002915 /* interconnect unique values with the leafs */
2916 for (i = 0; i < uniq_s->leafs_size; i++) {
2917 if ((value = strpbrk(uniq_str, " \t\n"))) {
2918 len = value - uniq_str;
2919 while (isspace(*value)) {
2920 value++;
2921 }
2922 } else {
2923 len = strlen(uniq_str);
2924 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002925
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002926 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
2927 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
2928 goto error;
2929 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002930
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002931 /* prepare for next iteration */
2932 while (value && isspace(*value)) {
2933 value++;
2934 }
2935 uniq_str = value;
2936 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002937
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002938 lyxml_free_elem(module->ctx, sub);
2939 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002940
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002941 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002942
2943error:
2944
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002945 ly_mnode_free(retval);
2946 while (root.child) {
2947 lyxml_free_elem(module->ctx, root.child);
2948 }
2949 while (uniq.child) {
2950 lyxml_free_elem(module->ctx, uniq.child);
2951 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002952
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002953 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002954}
2955
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002956static struct ly_mnode *
2957read_yin_container(struct ly_module *module,
2958 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002959{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002960 struct lyxml_elem *sub, *next, root;
2961 struct ly_mnode *mnode = NULL;
2962 struct ly_mnode *retval;
2963 struct ly_mnode_container *cont;
2964 const char *value;
2965 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002966 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002967
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002968 /* init */
2969 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02002970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002971 cont = calloc(1, sizeof *cont);
2972 cont->nodetype = LY_NODE_CONTAINER;
2973 cont->prev = (struct ly_mnode *)cont;
2974 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002976 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2977 goto error;
2978 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002979
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002980 /* process container's specific children */
2981 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2982 if (!strcmp(sub->name, "presence")) {
2983 if (cont->presence) {
2984 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2985 goto error;
2986 }
2987 GETVAL(value, sub, "value");
2988 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02002989
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002990 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002991 } else if (!strcmp(sub->name, "when")) {
2992 if (cont->when) {
2993 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2994 goto error;
2995 }
2996
2997 cont->when = read_yin_when(module, sub);
2998 lyxml_free_elem(module->ctx, sub);
2999
3000 if (!cont->when) {
3001 goto error;
3002 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003003
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003004 /* data statements */
3005 } else if (!strcmp(sub->name, "container") ||
3006 !strcmp(sub->name, "leaf-list") ||
3007 !strcmp(sub->name, "leaf") ||
3008 !strcmp(sub->name, "list") ||
3009 !strcmp(sub->name, "choice") ||
3010 !strcmp(sub->name, "uses") ||
3011 !strcmp(sub->name, "grouping") ||
3012 !strcmp(sub->name, "anyxml")) {
3013 lyxml_unlink_elem(sub);
3014 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003016 /* array counters */
3017 } else if (!strcmp(sub->name, "typedef")) {
3018 c_tpdf++;
3019 } else if (!strcmp(sub->name, "must")) {
3020 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003021 } else if (!strcmp(sub->name, "if-feature")) {
3022 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003023 } else {
3024 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3025 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003026 }
3027 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003028
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003029 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3030 if (c_tpdf) {
3031 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3032 }
3033 if (c_must) {
3034 cont->must = calloc(c_must, sizeof *cont->must);
3035 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003036 if (c_ftrs) {
3037 cont->features = calloc(c_ftrs, sizeof *cont->features);
3038 }
Radek Krejci800af702015-06-02 13:46:01 +02003039
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003040 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3041 if (!strcmp(sub->name, "typedef")) {
3042 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
3043 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003044
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003045 if (r) {
3046 goto error;
3047 }
3048 } else if (!strcmp(sub->name, "must")) {
3049 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3050 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003052 if (r) {
3053 goto error;
3054 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003055 } else if (!strcmp(sub->name, "if-feature")) {
3056 GETVAL(value, sub, "name");
3057 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3058 if (!cont->features[cont->features_size]) {
3059 goto error;
3060 }
3061 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003062 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003063
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003064 lyxml_free_elem(module->ctx, sub);
3065 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003066
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003067 /* last part - process data nodes */
3068 LY_TREE_FOR_SAFE(root.child, next, sub) {
3069 if (!strcmp(sub->name, "container")) {
3070 mnode = read_yin_container(module, retval, sub, resolve, unres);
3071 } else if (!strcmp(sub->name, "leaf-list")) {
3072 mnode = read_yin_leaflist(module, retval, sub, resolve);
3073 } else if (!strcmp(sub->name, "leaf")) {
3074 mnode = read_yin_leaf(module, retval, sub, resolve);
3075 } else if (!strcmp(sub->name, "list")) {
3076 mnode = read_yin_list(module, retval, sub, resolve, unres);
3077 } else if (!strcmp(sub->name, "choice")) {
3078 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3079 } else if (!strcmp(sub->name, "uses")) {
3080 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3081 } else if (!strcmp(sub->name, "grouping")) {
3082 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3083 } else if (!strcmp(sub->name, "anyxml")) {
3084 mnode = read_yin_anyxml(module, retval, sub, resolve);
3085 }
3086 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003087
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003088 if (!mnode) {
3089 goto error;
3090 }
3091 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003092
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003093 if (parent && ly_mnode_addchild(parent, retval)) {
3094 goto error;
3095 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003097 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003098
3099error:
3100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003101 ly_mnode_free(retval);
3102 while (root.child) {
3103 lyxml_free_elem(module->ctx, root.child);
3104 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003105
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003106 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003107}
3108
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003109static struct ly_mnode *
3110read_yin_grouping(struct ly_module *module,
3111 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003112{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003113 struct lyxml_elem *sub, *next, root;
3114 struct ly_mnode *mnode = NULL;
3115 struct ly_mnode *retval;
3116 struct ly_mnode_grp *grp;
3117 int r;
3118 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003119
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003120 /* init */
3121 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003122
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003123 grp = calloc(1, sizeof *grp);
3124 grp->nodetype = LY_NODE_GROUPING;
3125 grp->prev = (struct ly_mnode *)grp;
3126 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003127
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003128 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3129 goto error;
3130 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003131
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003132 LY_TREE_FOR_SAFE(node->child, next, sub) {
3133 /* data statements */
3134 if (!strcmp(sub->name, "container") ||
3135 !strcmp(sub->name, "leaf-list") ||
3136 !strcmp(sub->name, "leaf") ||
3137 !strcmp(sub->name, "list") ||
3138 !strcmp(sub->name, "choice") ||
3139 !strcmp(sub->name, "uses") ||
3140 !strcmp(sub->name, "grouping") ||
3141 !strcmp(sub->name, "anyxml")) {
3142 lyxml_unlink_elem(sub);
3143 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003145 /* array counters */
3146 } else if (!strcmp(sub->name, "typedef")) {
3147 c_tpdf++;
3148 } else {
3149 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3150 goto error;
3151 }
3152 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003154 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3155 if (c_tpdf) {
3156 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3157 }
3158 LY_TREE_FOR_SAFE(node->child, next, sub) {
3159 if (!strcmp(sub->name, "typedef")) {
3160 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3161 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003163 if (r) {
3164 goto error;
3165 }
3166 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003168 lyxml_free_elem(module->ctx, sub);
3169 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003170
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003171 /* last part - process data nodes */
3172 LY_TREE_FOR_SAFE(root.child, next, sub) {
3173 if (!strcmp(sub->name, "container")) {
3174 mnode = read_yin_container(module, retval, sub, resolve, unres);
3175 } else if (!strcmp(sub->name, "leaf-list")) {
3176 mnode = read_yin_leaflist(module, retval, sub, resolve);
3177 } else if (!strcmp(sub->name, "leaf")) {
3178 mnode = read_yin_leaf(module, retval, sub, resolve);
3179 } else if (!strcmp(sub->name, "list")) {
3180 mnode = read_yin_list(module, retval, sub, resolve, unres);
3181 } else if (!strcmp(sub->name, "choice")) {
3182 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3183 } else if (!strcmp(sub->name, "uses")) {
3184 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3185 } else if (!strcmp(sub->name, "grouping")) {
3186 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3187 } else if (!strcmp(sub->name, "anyxml")) {
3188 mnode = read_yin_anyxml(module, retval, sub, resolve);
3189 }
3190 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003191
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003192 if (!mnode) {
3193 goto error;
3194 }
3195 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003197 if (parent && ly_mnode_addchild(parent, retval)) {
3198 goto error;
3199 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003200
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003201 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003202
3203error:
3204
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003205 ly_mnode_free(retval);
3206 while (root.child) {
3207 lyxml_free_elem(module->ctx, root.child);
3208 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003210 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003211}
3212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003213static struct ly_mnode *
3214read_yin_input_output(struct ly_module *module,
3215 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003216{
Radek Krejcie0674f82015-06-15 13:58:51 +02003217 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003218 struct ly_mnode *mnode = NULL;
3219 struct ly_mnode *retval;
3220 struct ly_mnode_input_output *inout;
3221 int r;
3222 int c_tpdf = 0;
3223
Radek Krejcie0674f82015-06-15 13:58:51 +02003224 /* init */
3225 memset(&root, 0, sizeof root);
3226
Michal Vasko38d01f72015-06-15 09:41:06 +02003227 inout = calloc(1, sizeof *inout);
3228
3229 if (!strcmp(yin->name, "input")) {
3230 inout->nodetype = LY_NODE_INPUT;
3231 } else if (!strcmp(yin->name, "output")) {
3232 inout->nodetype = LY_NODE_OUTPUT;
3233 } else {
3234 assert(0);
3235 }
3236
3237 inout->prev = (struct ly_mnode *)inout;
3238 retval = (struct ly_mnode *)inout;
3239
Michal Vaskoebeac942015-06-15 12:11:50 +02003240 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
3241 goto error;
3242 }
3243
Michal Vasko38d01f72015-06-15 09:41:06 +02003244 /* data statements */
3245 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3246 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003247 !strcmp(sub->name, "leaf-list") ||
3248 !strcmp(sub->name, "leaf") ||
3249 !strcmp(sub->name, "list") ||
3250 !strcmp(sub->name, "choice") ||
3251 !strcmp(sub->name, "uses") ||
3252 !strcmp(sub->name, "grouping") ||
3253 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003254 lyxml_unlink_elem(sub);
3255 lyxml_add_child(&root, sub);
3256
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003257 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003258 } else if (!strcmp(sub->name, "typedef")) {
3259 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003260#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02003261 } else {
3262 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3263 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003264#else
Michal Vasko38d01f72015-06-15 09:41:06 +02003265 } else {
3266 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003267#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02003268 }
3269 }
3270
3271 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3272 if (c_tpdf) {
3273 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
3274 }
3275
3276 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3277 if (!strcmp(sub->name, "typedef")) {
3278 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
3279 inout->tpdf_size++;
3280
3281 if (r) {
3282 goto error;
3283 }
3284 }
3285
3286 lyxml_free_elem(module->ctx, sub);
3287 }
3288
3289 /* last part - process data nodes */
3290 LY_TREE_FOR_SAFE(root.child, next, sub) {
3291 if (!strcmp(sub->name, "container")) {
3292 mnode = read_yin_container(module, retval, sub, resolve, unres);
3293 } else if (!strcmp(sub->name, "leaf-list")) {
3294 mnode = read_yin_leaflist(module, retval, sub, resolve);
3295 } else if (!strcmp(sub->name, "leaf")) {
3296 mnode = read_yin_leaf(module, retval, sub, resolve);
3297 } else if (!strcmp(sub->name, "list")) {
3298 mnode = read_yin_list(module, retval, sub, resolve, unres);
3299 } else if (!strcmp(sub->name, "choice")) {
3300 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3301 } else if (!strcmp(sub->name, "uses")) {
3302 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3303 } else if (!strcmp(sub->name, "grouping")) {
3304 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3305 } else if (!strcmp(sub->name, "anyxml")) {
3306 mnode = read_yin_anyxml(module, retval, sub, resolve);
3307 }
3308 lyxml_free_elem(module->ctx, sub);
3309
3310 if (!mnode) {
3311 goto error;
3312 }
3313 }
3314
3315 if (parent && ly_mnode_addchild(parent, retval)) {
3316 goto error;
3317 }
3318
3319 return retval;
3320
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003321error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003322
3323 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003324 while (root.child) {
3325 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003326 }
3327
3328 return NULL;
3329}
3330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003331static struct ly_mnode *
3332read_yin_notif(struct ly_module *module,
3333 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02003334{
Michal Vaskoc6551b32015-06-16 10:51:43 +02003335 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02003336 struct ly_mnode *mnode = NULL;
3337 struct ly_mnode *retval;
3338 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003339 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02003340 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003341 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02003342
Michal Vaskoc6551b32015-06-16 10:51:43 +02003343 memset(&root, 0, sizeof root);
3344
Michal Vasko0ea41032015-06-16 08:53:55 +02003345 notif = calloc(1, sizeof *notif);
3346 notif->nodetype = LY_NODE_NOTIF;
3347 notif->prev = (struct ly_mnode *)notif;
3348 retval = (struct ly_mnode *)notif;
3349
3350 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3351 goto error;
3352 }
3353
3354 /* process rpc's specific children */
3355 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3356 /* data statements */
3357 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003358 !strcmp(sub->name, "leaf-list") ||
3359 !strcmp(sub->name, "leaf") ||
3360 !strcmp(sub->name, "list") ||
3361 !strcmp(sub->name, "choice") ||
3362 !strcmp(sub->name, "uses") ||
3363 !strcmp(sub->name, "grouping") ||
3364 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02003365 lyxml_unlink_elem(sub);
3366 lyxml_add_child(&root, sub);
3367
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003368 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02003369 } else if (!strcmp(sub->name, "typedef")) {
3370 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003371 } else if (!strcmp(sub->name, "if-feature")) {
3372 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003373 } else {
3374 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3375 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02003376 }
3377 }
3378
3379 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3380 if (c_tpdf) {
3381 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3382 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003383 if (c_ftrs) {
3384 notif->features = calloc(c_ftrs, sizeof *notif->features);
3385 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003386
3387 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3388 if (!strcmp(sub->name, "typedef")) {
3389 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3390 notif->tpdf_size++;
3391
3392 if (r) {
3393 goto error;
3394 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003395 } else if (!strcmp(sub->name, "typedef")) {
3396 GETVAL(value, sub, "name");
3397 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3398 if (!notif->features[notif->features_size]) {
3399 goto error;
3400 }
3401 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003402 }
3403
3404 lyxml_free_elem(module->ctx, sub);
3405 }
3406
3407 /* last part - process data nodes */
3408 LY_TREE_FOR_SAFE(root.child, next, sub) {
3409 if (!strcmp(sub->name, "container")) {
3410 mnode = read_yin_container(module, retval, sub, resolve, unres);
3411 } else if (!strcmp(sub->name, "leaf-list")) {
3412 mnode = read_yin_leaflist(module, retval, sub, resolve);
3413 } else if (!strcmp(sub->name, "leaf")) {
3414 mnode = read_yin_leaf(module, retval, sub, resolve);
3415 } else if (!strcmp(sub->name, "list")) {
3416 mnode = read_yin_list(module, retval, sub, resolve, unres);
3417 } else if (!strcmp(sub->name, "choice")) {
3418 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3419 } else if (!strcmp(sub->name, "uses")) {
3420 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3421 } else if (!strcmp(sub->name, "grouping")) {
3422 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3423 } else if (!strcmp(sub->name, "anyxml")) {
3424 mnode = read_yin_anyxml(module, retval, sub, resolve);
3425 }
3426 lyxml_free_elem(module->ctx, sub);
3427
3428 if (!mnode) {
3429 goto error;
3430 }
3431 }
3432
3433 if (parent && ly_mnode_addchild(parent, retval)) {
3434 goto error;
3435 }
3436
3437 return retval;
3438
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003439error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003440
3441 ly_mnode_free(retval);
3442 while (root.child) {
3443 lyxml_free_elem(module->ctx, root.child);
3444 }
3445
3446 return NULL;
3447}
3448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003449static struct ly_mnode *
3450read_yin_rpc(struct ly_module *module,
3451 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003452{
Radek Krejcie0674f82015-06-15 13:58:51 +02003453 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003454 struct ly_mnode *mnode = NULL;
3455 struct ly_mnode *retval;
3456 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003457 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003458 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003459 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003460
Radek Krejcie0674f82015-06-15 13:58:51 +02003461 /* init */
3462 memset(&root, 0, sizeof root);
3463
Michal Vasko38d01f72015-06-15 09:41:06 +02003464 rpc = calloc(1, sizeof *rpc);
3465 rpc->nodetype = LY_NODE_RPC;
3466 rpc->prev = (struct ly_mnode *)rpc;
3467 retval = (struct ly_mnode *)rpc;
3468
3469 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3470 goto error;
3471 }
3472
3473 /* process rpc's specific children */
3474 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3475 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003476 if (rpc->child
3477 && (rpc->child->nodetype == LY_NODE_INPUT
3478 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003479 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3480 goto error;
3481 }
3482 lyxml_unlink_elem(sub);
3483 lyxml_add_child(&root, sub);
3484 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003485 if (rpc->child
3486 && (rpc->child->nodetype == LY_NODE_INPUT
3487 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003488 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3489 goto error;
3490 }
3491 lyxml_unlink_elem(sub);
3492 lyxml_add_child(&root, sub);
3493
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003494 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003495 } else if (!strcmp(sub->name, "grouping")) {
3496 lyxml_unlink_elem(sub);
3497 lyxml_add_child(&root, sub);
3498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003499 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003500 } else if (!strcmp(sub->name, "typedef")) {
3501 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003502 } else if (!strcmp(sub->name, "if-feature")) {
3503 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003504 } else {
3505 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3506 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003507 }
3508 }
3509
3510 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3511 if (c_tpdf) {
3512 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3513 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003514 if (c_ftrs) {
3515 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3516 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003517
3518 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3519 if (!strcmp(sub->name, "typedef")) {
3520 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3521 rpc->tpdf_size++;
3522
3523 if (r) {
3524 goto error;
3525 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003526 } else if (!strcmp(sub->name, "if-feature")) {
3527 GETVAL(value, sub, "name");
3528 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3529 if (!rpc->features[rpc->features_size]) {
3530 goto error;
3531 }
3532 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003533 }
3534
3535 lyxml_free_elem(module->ctx, sub);
3536 }
3537
3538 /* last part - process data nodes */
3539 LY_TREE_FOR_SAFE(root.child, next, sub) {
3540 if (!strcmp(sub->name, "grouping")) {
3541 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3542 } else if (!strcmp(sub->name, "input")) {
3543 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3544 } else if (!strcmp(sub->name, "output")) {
3545 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3546 }
3547 lyxml_free_elem(module->ctx, sub);
3548
3549 if (!mnode) {
3550 goto error;
3551 }
3552 }
3553
3554 if (parent && ly_mnode_addchild(parent, retval)) {
3555 goto error;
3556 }
3557
3558 return retval;
3559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003560error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003561
3562 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003563 while (root.child) {
3564 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003565 }
3566
3567 return NULL;
3568}
3569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003570static int
3571find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003572{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003573 struct ly_module *searchmod = NULL, *module = uses->module;
3574 struct ly_mnode *mnode, *mnode_aux;
3575 const char *name;
3576 int prefix_len = 0;
3577 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003578
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003579 /* get referenced grouping */
3580 name = strchr(uses->name, ':');
3581 if (!name) {
3582 /* no prefix, search in local tree */
3583 name = uses->name;
3584 } else {
3585 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003586
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003587 /* set name to correct position after colon */
3588 prefix_len = name - uses->name;
3589 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003590
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003591 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3592 /* prefix refers to the current module, ignore it */
3593 prefix_len = 0;
3594 }
3595 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003596
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003597 /* search */
3598 if (prefix_len) {
3599 /* in top-level groupings of some other module */
3600 for (i = 0; i < module->imp_size; i++) {
3601 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3602 && !module->imp[i].prefix[prefix_len]) {
3603 searchmod = module->imp[i].module;
3604 break;
3605 }
3606 }
3607 if (!searchmod) {
3608 /* uses refers unknown data model */
3609 LOGVAL(VE_INPREFIX, line, name);
3610 return EXIT_FAILURE;
3611 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003613 LY_TREE_FOR(searchmod->data, mnode) {
3614 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3615 uses->grp = (struct ly_mnode_grp *)mnode;
3616 return EXIT_SUCCESS;
3617 }
3618 }
3619 } else {
3620 /* in local tree hierarchy */
3621 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3622 LY_TREE_FOR(mnode_aux->child, mnode) {
3623 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3624 uses->grp = (struct ly_mnode_grp *)mnode;
3625 return EXIT_SUCCESS;
3626 }
3627 }
3628 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003629
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003630 /* search in top level of the current module */
3631 LY_TREE_FOR(module->data, mnode) {
3632 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3633 uses->grp = (struct ly_mnode_grp *)mnode;
3634 return EXIT_SUCCESS;
3635 }
3636 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003637
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003638 /* search in top-level of included modules */
3639 for (i = 0; i < module->inc_size; i++) {
3640 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3641 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3642 uses->grp = (struct ly_mnode_grp *)mnode;
3643 return EXIT_SUCCESS;
3644 }
3645 }
3646 }
3647 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003649 /* not found, but no explicit error occured */
3650 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003651}
3652
Radek Krejcif5be10f2015-06-16 13:29:36 +02003653static int
3654resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3655{
3656 struct lyxml_elem *yin, *next, *sub;
3657 struct ly_mnode *mnode;
3658
3659 assert(module);
3660
3661 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003662 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003663 if (!aug->target) {
3664 LOGVAL(VE_INARG, line, aug->target, "uses");
3665 return EXIT_FAILURE;
3666 }
3667
3668 if (!aug->child) {
3669 /* nothing to do */
3670 return EXIT_SUCCESS;
3671 }
3672
3673 yin = (struct lyxml_elem *)aug->child;
3674
3675 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3676 return EXIT_FAILURE;
3677 }
3678
3679 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3680 if (!strcmp(sub->name, "container")) {
3681 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3682 } else if (!strcmp(sub->name, "leaf-list")) {
3683 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3684 } else if (!strcmp(sub->name, "leaf")) {
3685 mnode = read_yin_leaf(module, aug->target, sub, 1);
3686 } else if (!strcmp(sub->name, "list")) {
3687 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3688 } else if (!strcmp(sub->name, "uses")) {
3689 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3690 } else if (!strcmp(sub->name, "choice")) {
3691 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3692 } else if (!strcmp(sub->name, "case")) {
3693 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3694 } else if (!strcmp(sub->name, "anyxml")) {
3695 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3696#if 0
3697 } else {
3698 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003699 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003700#else
3701 } else {
3702 continue;
3703#endif
3704 }
3705
3706 if (!mnode) {
3707 return EXIT_FAILURE;
3708 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003709 /* check for mandatory nodes - if the target node is in another module
3710 * the added nodes cannot be mandatory
3711 */
3712 if (check_mandatory(mnode)) {
3713 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3714 return EXIT_FAILURE;
3715 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003716
3717 lyxml_free_elem(module->ctx, sub);
3718
3719 /* the parent pointer will point to the augment node, but all
3720 * siblings pointers and possibly the child node in target does
3721 * not know about the augment and follow the standard schema tree
3722 * structure
3723 */
3724 mnode->parent = (struct ly_mnode *)aug;
3725 mnode = NULL;
3726 }
3727
3728 lyxml_free_elem(module->ctx, yin);
3729 aug->child = NULL;
3730
3731 return EXIT_SUCCESS;
3732}
3733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003734int
3735resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003736{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003737 struct ly_ctx *ctx;
3738 struct ly_mnode *mnode = NULL, *mnode_aux;
3739 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02003740 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003741 int i, j;
3742 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003743
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003744 /* copy the data nodes from grouping into the uses context */
3745 LY_TREE_FOR(uses->grp->child, mnode) {
3746 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3747 if (!mnode_aux) {
3748 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3749 return EXIT_FAILURE;
3750 }
3751 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3752 ly_mnode_free(mnode_aux);
3753 return EXIT_FAILURE;
3754 }
3755 }
3756 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003757
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003758 /* apply refines */
3759 for (i = 0; i < uses->refine_size; i++) {
3760 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003761 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003762 if (!mnode) {
3763 LOGVAL(VE_INARG, line, rfn->target, "uses");
3764 return EXIT_FAILURE;
3765 }
Radek Krejci106efc02015-06-10 14:36:27 +02003766
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003767 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3768 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3769 return EXIT_FAILURE;
3770 }
Radek Krejci106efc02015-06-10 14:36:27 +02003771
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003772 /* description on any nodetype */
3773 if (rfn->dsc) {
3774 lydict_remove(ctx, mnode->dsc);
3775 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3776 }
Radek Krejci106efc02015-06-10 14:36:27 +02003777
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003778 /* reference on any nodetype */
3779 if (rfn->ref) {
3780 lydict_remove(ctx, mnode->ref);
3781 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3782 }
Radek Krejci106efc02015-06-10 14:36:27 +02003783
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003784 /* config on any nodetype */
3785 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3786 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3787 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3788 }
Radek Krejci106efc02015-06-10 14:36:27 +02003789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003790 /* default value ... */
3791 if (rfn->mod.dflt) {
3792 if (mnode->nodetype == LY_NODE_LEAF) {
3793 /* leaf */
3794 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3795 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3796 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3797 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003798 ((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 +02003799 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3800 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3801 return EXIT_FAILURE;
3802 }
3803 }
3804 }
Radek Krejci106efc02015-06-10 14:36:27 +02003805
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003806 /* mandatory on leaf, anyxml or choice */
3807 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3808 if (rfn->flags & LY_NODE_MAND_FALSE) {
3809 /* erase mandatory true flag, we don't use false flag in schema nodes */
3810 mnode->flags &= ~LY_NODE_MAND_TRUE;
3811 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3812 /* set mandatory true flag */
3813 mnode->flags |= LY_NODE_MAND_TRUE;
3814 }
3815 }
Radek Krejci106efc02015-06-10 14:36:27 +02003816
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003817 /* presence on container */
3818 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3819 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3820 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3821 }
Radek Krejci106efc02015-06-10 14:36:27 +02003822
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003823 /* min/max-elements on list or leaf-list */
3824 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3825 /* magic - bit 3 in flags means min set, bit 4 says max set */
3826 if (rfn->flags & 0x04) {
3827 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3828 }
3829 if (rfn->flags & 0x08) {
3830 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3831 }
3832 }
Radek Krejci106efc02015-06-10 14:36:27 +02003833
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003834 /* must in leaf, leaf-list, list, container or anyxml */
3835 if (rfn->must_size) {
3836 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3837 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3838 if (!newmust) {
3839 LOGMEM;
3840 return EXIT_FAILURE;
3841 }
3842 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02003843 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003844 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3845 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3846 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3847 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3848 }
Radek Krejci106efc02015-06-10 14:36:27 +02003849
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003850 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3851 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3852 }
3853 }
Radek Krejci106efc02015-06-10 14:36:27 +02003854
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003855 /* apply augments */
3856 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003857 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003858 goto error;
3859 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003860 }
Radek Krejci106efc02015-06-10 14:36:27 +02003861
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003862 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003863
3864error:
3865
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003866 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003867}
Radek Krejci74705112015-06-05 10:25:44 +02003868
3869/*
3870 * resolve - referenced grouping should be bounded to the namespace (resolved)
3871 * only when uses does not appear in grouping. In a case of grouping's uses,
3872 * we just get information but we do not apply augment or refine to it.
3873 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003874static struct ly_mnode *
3875read_yin_uses(struct ly_module *module,
3876 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003877{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003878 struct lyxml_elem *sub, *next;
3879 struct ly_mnode *retval;
3880 struct ly_mnode_uses *uses;
3881 struct mnode_list *unres_new;
3882 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003883 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003884 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003885
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003886 uses = calloc(1, sizeof *uses);
3887 uses->nodetype = LY_NODE_USES;
3888 uses->prev = (struct ly_mnode *)uses;
3889 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003891 GETVAL(value, node, "name");
3892 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003893
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003894 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3895 goto error;
3896 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003897
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003898 /* get other properties of uses */
3899 LY_TREE_FOR_SAFE(node->child, next, sub) {
3900 if (!strcmp(sub->name, "refine")) {
3901 c_ref++;
3902 } else if (!strcmp(sub->name, "augment")) {
3903 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003904 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02003905 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003906 } else if (!strcmp(sub->name, "when")) {
3907 if (uses->when) {
3908 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
3909 goto error;
3910 }
3911
3912 uses->when = read_yin_when(module, sub);
3913 lyxml_free_elem(module->ctx, sub);
3914
3915 if (!uses->when) {
3916 goto error;
3917 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003918 } else {
3919 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3920 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003921 }
3922 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003924 /* process properties with cardinality 0..n */
3925 if (c_ref) {
3926 uses->refine = calloc(c_ref, sizeof *uses->refine);
3927 }
3928 if (c_aug) {
3929 uses->augment = calloc(c_aug, sizeof *uses->augment);
3930 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003931 if (c_ftrs) {
3932 uses->features = calloc(c_ftrs, sizeof *uses->features);
3933 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003935 LY_TREE_FOR_SAFE(node->child, next, sub) {
3936 if (!strcmp(sub->name, "refine")) {
3937 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
3938 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003939 lyxml_free_elem(module->ctx, sub);
3940 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003941 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
3942 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003943 } else if (!strcmp(sub->name, "if-feature")) {
3944 GETVAL(value, sub, "name");
3945 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
3946 if (!uses->features[uses->features_size]) {
3947 goto error;
3948 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02003949 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003950 uses->features_size++;
3951 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003952 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003953
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003954 if (r) {
3955 goto error;
3956 }
3957 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003959 if (find_grouping(parent, uses, LOGLINE(node))) {
3960 goto error;
3961 }
3962 if (!uses->grp) {
3963 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
3964 unres_new = calloc(1, sizeof *unres_new);
3965 if (*unres) {
3966 unres_new->next = *unres;
3967 }
3968 unres_new->mnode = retval;
3969 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02003970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003971 /* put it at the beginning of the unresolved list */
3972 *unres = unres_new;
3973 }
Radek Krejci74705112015-06-05 10:25:44 +02003974
Radek Krejci368c38f2015-06-15 15:09:55 +02003975 if (parent && ly_mnode_addchild(parent, retval)) {
3976 goto error;
3977 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003978
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003979 if (resolve) {
3980 /* inherit config flag */
3981 if (parent) {
3982 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
3983 } else {
3984 /* default config is true */
3985 retval->flags |= LY_NODE_CONFIG_W;
3986 }
3987 }
Radek Krejcib388c152015-06-04 17:03:03 +02003988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003989 if (resolve && uses->grp) {
3990 /* copy the data nodes from grouping into the uses context */
3991 if (resolve_uses(uses, LOGLINE(node))) {
3992 goto error;
3993 }
3994 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003995
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003996 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003997
3998error:
3999
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004000 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004002 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004003}
4004
Radek Krejciefaeba32015-05-27 14:30:57 +02004005/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004006static int
4007read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004008{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004009 struct ly_ctx *ctx = module->ctx;
4010 struct ly_submodule *submodule = (struct ly_submodule *)module;
4011 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
4012 struct ly_mnode *mnode = NULL;
4013 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
4014 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004015 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02004016 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004017 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004018 /* counters */
4019 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 +02004020
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004021 /* init */
4022 memset(&root, 0, sizeof root);
4023 memset(&grps, 0, sizeof grps);
4024 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004025 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004026
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004027 /*
4028 * in the first run, we process elements with cardinality of 1 or 0..1 and
4029 * count elements with cardinality 0..n. Data elements (choices, containers,
4030 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4031 * need have all top-level and groupings already prepared at that time. In
4032 * the middle loop, we process other elements with carinality of 0..n since
4033 * we need to allocate arrays to store them.
4034 */
4035 LY_TREE_FOR_SAFE(yin->child, next, node) {
4036 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4037 lyxml_free_elem(ctx, node);
4038 continue;
4039 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004040
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004041 if (!module->type && !strcmp(node->name, "namespace")) {
4042 if (module->ns) {
4043 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4044 goto error;
4045 }
4046 GETVAL(value, node, "uri");
4047 module->ns = lydict_insert(ctx, value, strlen(value));
4048 lyxml_free_elem(ctx, node);
4049 } else if (!module->type && !strcmp(node->name, "prefix")) {
4050 if (module->prefix) {
4051 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4052 goto error;
4053 }
4054 GETVAL(value, node, "value");
4055 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4056 goto error;
4057 }
4058 module->prefix = lydict_insert(ctx, value, strlen(value));
4059 lyxml_free_elem(ctx, node);
4060 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4061 if (belongsto_flag) {
4062 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4063 goto error;
4064 }
4065 belongsto_flag = 1;
4066 GETVAL(value, node, "module");
4067 while (submodule->belongsto->type) {
4068 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4069 }
4070 if (value != submodule->belongsto->name) {
4071 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4072 goto error;
4073 }
Radek Krejcif3886932015-06-04 17:36:06 +02004074
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004075 /* get the prefix substatement, start with checks */
4076 if (!node->child) {
4077 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4078 goto error;
4079 } else if (strcmp(node->child->name, "prefix")) {
4080 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4081 goto error;
4082 } else if (node->child->next) {
4083 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4084 goto error;
4085 }
4086 /* and now finally get the value */
4087 GETVAL(value, node->child, "value");
4088 /* check here differs from a generic prefix check, since this prefix
4089 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004090 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004091 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4092 goto error;
4093 }
4094 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004095
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004096 /* we are done with belongs-to */
4097 lyxml_free_elem(ctx, node);
4098 } else if (!strcmp(node->name, "import")) {
4099 c_imp++;
4100 } else if (!strcmp(node->name, "revision")) {
4101 c_rev++;
4102 } else if (!strcmp(node->name, "typedef")) {
4103 c_tpdf++;
4104 } else if (!strcmp(node->name, "identity")) {
4105 c_ident++;
4106 } else if (!strcmp(node->name, "include")) {
4107 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004108 } else if (!strcmp(node->name, "augment")) {
4109 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004110 } else if (!strcmp(node->name, "feature")) {
4111 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004112
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004113 /* data statements */
4114 } else if (!strcmp(node->name, "container") ||
4115 !strcmp(node->name, "leaf-list") ||
4116 !strcmp(node->name, "leaf") ||
4117 !strcmp(node->name, "list") ||
4118 !strcmp(node->name, "choice") ||
4119 !strcmp(node->name, "uses") ||
4120 !strcmp(node->name, "anyxml")) {
4121 lyxml_unlink_elem(node);
4122 lyxml_add_child(&root, node);
4123 } else if (!strcmp(node->name, "grouping")) {
4124 /* keep groupings separated and process them before other data statements */
4125 lyxml_unlink_elem(node);
4126 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004127
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004128 /* optional statements */
4129 } else if (!strcmp(node->name, "description")) {
4130 if (module->dsc) {
4131 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4132 goto error;
4133 }
4134 module->dsc = read_yin_subnode(ctx, node, "text");
4135 lyxml_free_elem(ctx, node);
4136 if (!module->dsc) {
4137 goto error;
4138 }
4139 } else if (!strcmp(node->name, "reference")) {
4140 if (module->ref) {
4141 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4142 goto error;
4143 }
4144 module->ref = read_yin_subnode(ctx, node, "text");
4145 lyxml_free_elem(ctx, node);
4146 if (!module->ref) {
4147 goto error;
4148 }
4149 } else if (!strcmp(node->name, "organization")) {
4150 if (module->org) {
4151 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4152 goto error;
4153 }
4154 module->org = read_yin_subnode(ctx, node, "text");
4155 lyxml_free_elem(ctx, node);
4156 if (!module->org) {
4157 goto error;
4158 }
4159 } else if (!strcmp(node->name, "contact")) {
4160 if (module->contact) {
4161 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4162 goto error;
4163 }
4164 module->contact = read_yin_subnode(ctx, node, "text");
4165 lyxml_free_elem(ctx, node);
4166 if (!module->contact) {
4167 goto error;
4168 }
4169 } else if (!strcmp(node->name, "yang-version")) {
4170 /* TODO: support YANG 1.1 ? */
4171 if (module->version) {
4172 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4173 goto error;
4174 }
4175 GETVAL(value, node, "value");
4176 if (strcmp(value, "1")) {
4177 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
4178 goto error;
4179 }
4180 module->version = 1;
4181 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02004182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004183 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02004184 } else if (!strcmp(node->name, "rpc")) {
4185 lyxml_unlink_elem(node);
4186 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02004187 } else if (!strcmp(node->name, "notification")) {
4188 lyxml_unlink_elem(node);
4189 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02004190#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004191 } else {
4192 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
4193 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02004194#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004195 } else {
4196 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02004197#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004198 }
4199 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004200
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004201 if (!submodule) {
4202 /* check for mandatory statements */
4203 if (!module->ns) {
4204 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
4205 goto error;
4206 }
4207 if (!module->prefix) {
4208 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
4209 goto error;
4210 }
4211 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02004212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004213 /* allocate arrays for elements with cardinality of 0..n */
4214 if (c_imp) {
4215 module->imp = calloc(c_imp, sizeof *module->imp);
4216 }
4217 if (c_rev) {
4218 module->rev = calloc(c_rev, sizeof *module->rev);
4219 }
4220 if (c_tpdf) {
4221 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
4222 }
4223 if (c_ident) {
4224 module->ident = calloc(c_ident, sizeof *module->ident);
4225 }
4226 if (c_inc) {
4227 module->inc = calloc(c_inc, sizeof *module->inc);
4228 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004229 if (c_aug) {
4230 module->augment = calloc(c_aug, sizeof *module->augment);
4231 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004232 if (c_ftrs) {
4233 module->features = calloc(c_ftrs, sizeof *module->features);
4234 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004236 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4237 LY_TREE_FOR_SAFE(yin->child, next, node) {
4238 if (!strcmp(node->name, "import")) {
4239 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
4240 module->imp_size++;
4241 if (r) {
4242 goto error;
4243 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004245 /* check duplicities in imported modules */
4246 for (i = 0; i < module->imp_size - 1; i++) {
4247 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
4248 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
4249 goto error;
4250 }
4251 }
4252 } else if (!strcmp(node->name, "include")) {
4253 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
4254 module->inc_size++;
4255 if (r) {
4256 goto error;
4257 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004258
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004259 /* check duplications in include submodules */
4260 for (i = 0; i < module->inc_size - 1; i++) {
4261 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
4262 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
4263 module->inc[i].submodule->name);
4264 goto error;
4265 }
4266 }
4267 } else if (!strcmp(node->name, "revision")) {
4268 GETVAL(value, node, "date");
4269 if (check_date(value, LOGLINE(node))) {
4270 goto error;
4271 }
4272 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4273 /* check uniqueness of the revision date - not required by RFC */
4274 for (i = 0; i < module->rev_size; i++) {
4275 if (!strcmp(value, module->rev[i].date)) {
4276 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4277 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
4278 }
4279 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004280
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004281 LY_TREE_FOR(node->child, child) {
4282 if (!strcmp(child->name, "description")) {
4283 if (module->rev[module->rev_size].dsc) {
4284 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4285 goto error;
4286 }
4287 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
4288 if (!module->rev[module->rev_size].dsc) {
4289 goto error;
4290 }
4291 } else if (!strcmp(child->name, "reference")) {
4292 if (module->rev[module->rev_size].ref) {
4293 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4294 goto error;
4295 }
4296 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
4297 if (!module->rev[module->rev_size].ref) {
4298 goto error;
4299 }
4300 } else {
4301 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
4302 goto error;
4303 }
4304 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004305
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004306 /* keep the latest revision at position 0 */
4307 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
4308 /* switch their position */
4309 value = strdup(module->rev[0].date);
4310 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
4311 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4312 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02004313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004314 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
4315 value = module->rev[0].dsc;
4316 module->rev[0].dsc = module->rev[module->rev_size].dsc;
4317 module->rev[module->rev_size].dsc = value;
4318 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004319
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004320 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
4321 value = module->rev[0].ref;
4322 module->rev[0].ref = module->rev[module->rev_size].ref;
4323 module->rev[module->rev_size].ref = value;
4324 }
4325 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004327 module->rev_size++;
4328 } else if (!strcmp(node->name, "typedef")) {
4329 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
4330 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004331
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004332 if (r) {
4333 goto error;
4334 }
4335 } else if (!strcmp(node->name, "identity")) {
4336 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
4337 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02004338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004339 if (r) {
4340 goto error;
4341 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004342 } else if (!strcmp(node->name, "feature")) {
4343 r = fill_yin_feature(module, node, &module->features[module->features_size]);
4344 module->features_size++;
4345
4346 if (r) {
4347 goto error;
4348 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004349 } else if (!strcmp(node->name, "augment")) {
4350 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
4351 module->augment_size++;
4352
4353 if (r) {
4354 goto error;
4355 }
4356
4357 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
4358 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004359 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004360
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004361 lyxml_free_elem(ctx, node);
4362 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004363
Radek Krejcif5be10f2015-06-16 13:29:36 +02004364 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004365 * refer to them
4366 */
4367 LY_TREE_FOR_SAFE(grps.child, next, node) {
4368 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
4369 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02004370
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004371 if (!mnode) {
4372 goto error;
4373 }
Radek Krejci74705112015-06-05 10:25:44 +02004374
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004375 /* include data element */
4376 if (module->data) {
4377 module->data->prev->next = mnode;
4378 mnode->prev = module->data->prev;
4379 module->data->prev = mnode;
4380 } else {
4381 module->data = mnode;
4382 }
4383 }
4384 while (unres) {
4385 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4386 goto error;
4387 }
4388 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4389 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4390 goto error;
4391 }
4392 unres_next = unres->next;
4393 free(unres);
4394 unres = unres_next;
4395 }
Radek Krejci74705112015-06-05 10:25:44 +02004396
Radek Krejcif5be10f2015-06-16 13:29:36 +02004397 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004398 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004399
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004400 if (!strcmp(node->name, "container")) {
4401 mnode = read_yin_container(module, NULL, node, 1, &unres);
4402 } else if (!strcmp(node->name, "leaf-list")) {
4403 mnode = read_yin_leaflist(module, NULL, node, 1);
4404 } else if (!strcmp(node->name, "leaf")) {
4405 mnode = read_yin_leaf(module, NULL, node, 1);
4406 } else if (!strcmp(node->name, "list")) {
4407 mnode = read_yin_list(module, NULL, node, 1, &unres);
4408 } else if (!strcmp(node->name, "choice")) {
4409 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4410 } else if (!strcmp(node->name, "uses")) {
4411 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4412 } else if (!strcmp(node->name, "anyxml")) {
4413 mnode = read_yin_anyxml(module, NULL, node, 1);
4414 }
4415 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004416
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004417 if (!mnode) {
4418 goto error;
4419 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004421 /* include data element */
4422 if (module->data) {
4423 module->data->prev->next = mnode;
4424 mnode->prev = module->data->prev;
4425 module->data->prev = mnode;
4426 } else {
4427 module->data = mnode;
4428 }
4429 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004430
4431 /* ... rpcs ... */
4432 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4433 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4434 lyxml_free_elem(ctx, node);
4435
4436 if (!mnode) {
4437 goto error;
4438 }
4439
4440 /* include rpc element */
4441 if (module->rpc) {
4442 module->rpc->prev->next = mnode;
4443 mnode->prev = module->rpc->prev;
4444 module->rpc->prev = mnode;
4445 } else {
4446 module->rpc = mnode;
4447 }
4448 }
4449
4450 /* ... and notifications */
4451 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4452 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4453 lyxml_free_elem(ctx, node);
4454
4455 if (!mnode) {
4456 goto error;
4457 }
4458
4459 /* include notification element */
4460 if (module->notif) {
4461 module->notif->prev->next = mnode;
4462 mnode->prev = module->notif->prev;
4463 module->notif->prev = mnode;
4464 } else {
4465 module->notif = mnode;
4466 }
4467 }
4468
4469 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004470 while (unres) {
4471 /* find referenced grouping */
4472 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4473 goto error;
4474 }
4475 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4476 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4477 goto error;
4478 }
Radek Krejci74705112015-06-05 10:25:44 +02004479
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004480 /* resolve uses by copying grouping content under the uses */
4481 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4482 goto error;
4483 }
Radek Krejci74705112015-06-05 10:25:44 +02004484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004485 unres_next = unres->next;
4486 free(unres);
4487 unres = unres_next;
4488 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004489
Radek Krejcif5be10f2015-06-16 13:29:36 +02004490 /* and finally apply augments */
4491 for (i = 0; i < module->augment_size; i++) {
4492 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004493 goto error;
4494 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004495 }
4496
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004497 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004498
4499error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004500 /* cleanup */
4501 while (root.child) {
4502 lyxml_free_elem(module->ctx, root.child);
4503 }
4504 while (grps.child) {
4505 lyxml_free_elem(module->ctx, grps.child);
4506 }
4507 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004508 lyxml_free_elem(module->ctx, rpcs.child);
4509 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004510
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004511 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004512}
4513
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004514struct ly_submodule *
4515yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004516{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004517 struct lyxml_elem *yin;
4518 struct ly_submodule *submodule = NULL;
4519 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004520
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004521 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004523 yin = lyxml_read(module->ctx, data, 0);
4524 if (!yin) {
4525 return NULL;
4526 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004528 /* check root element */
4529 if (!yin->name || strcmp(yin->name, "submodule")) {
4530 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4531 goto error;
4532 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004534 GETVAL(value, yin, "name");
4535 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4536 goto error;
4537 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004539 submodule = calloc(1, sizeof *submodule);
4540 if (!submodule) {
4541 LOGMEM;
4542 goto error;
4543 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004544
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004545 submodule->ctx = module->ctx;
4546 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4547 submodule->type = 1;
4548 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004549
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004550 LOGVRB("reading submodule %s", submodule->name);
4551 if (read_sub_module((struct ly_module *)submodule, yin)) {
4552 goto error;
4553 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004555 /* cleanup */
4556 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004557
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004558 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004560 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004561
4562error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004563 /* cleanup */
4564 lyxml_free_elem(module->ctx, yin);
4565 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004567 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004568}
4569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004570struct ly_module *
4571yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004572{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004573 struct lyxml_elem *yin;
4574 struct ly_module *module = NULL, **newlist = NULL;
4575 const char *value;
4576 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004578 yin = lyxml_read(ctx, data, 0);
4579 if (!yin) {
4580 return NULL;
4581 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004582
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004583 /* check root element */
4584 if (!yin->name || strcmp(yin->name, "module")) {
4585 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4586 goto error;
4587 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004588
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004589 GETVAL(value, yin, "name");
4590 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4591 goto error;
4592 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004593
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004594 module = calloc(1, sizeof *module);
4595 if (!module) {
4596 LOGMEM;
4597 goto error;
4598 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004599
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004600 module->ctx = ctx;
4601 module->name = lydict_insert(ctx, value, strlen(value));
4602 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004603
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004604 LOGVRB("reading module %s", module->name);
4605 if (read_sub_module(module, yin)) {
4606 goto error;
4607 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004609 /* add to the context's list of modules */
4610 if (ctx->models.used == ctx->models.size) {
4611 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4612 if (!newlist) {
4613 LOGMEM;
4614 goto error;
4615 }
4616 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4617 newlist[i] = NULL;
4618 }
4619 ctx->models.size *= 2;
4620 ctx->models.list = newlist;
4621 }
4622 for (i = 0; ctx->models.list[i]; i++) {
4623 /* check name (name/revision) and namespace uniqueness */
4624 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4625 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4626 /* both data models are same, with no revision specified */
4627 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4628 module->name);
4629 goto error;
4630 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4631 /* one of the models does not have a revision, so they differs */
4632 continue;
4633 } else {
4634 /* both models have a revision statement which we have to
4635 * compare, revision at position 0 is the last revision
4636 */
4637 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4638 /* we have the same modules */
4639 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4640 module->rev[0].date);
4641 goto error;
4642 }
4643 }
4644 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4645 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4646 ctx->models.list[i]->name, module->name, module->ns);
4647 goto error;
4648 }
4649 }
4650 ctx->models.list[i] = module;
4651 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004653 /* cleanup */
4654 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004655
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004656 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004657
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004658 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004659
4660error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004661 /* cleanup */
4662 lyxml_free_elem(ctx, yin);
4663 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004664
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004665 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004666}