blob: b50ad6e7f22a6512ec40ff203e877b4231ede4ea [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 Krejcif2860132015-06-20 12:37:20 +0200832 const char *value, *delim, *name;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200833 struct lyxml_elem *next, *node;
Radek Krejcif2860132015-06-20 12:37:20 +0200834 struct ly_restr **restr;
Radek Krejci994b6f62015-06-18 16:47:27 +0200835 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200836 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200837 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200838
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200839 GETVAL(value, yin, "name")
840 delim = strchr(value, ':');
841 if (delim) {
842 type->prefix = lydict_insert(module->ctx, value, delim - value);
843 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200845 type->der = find_superior_type(value, module, parent);
846 if (!type->der) {
847 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
848 goto error;
849 }
850 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200852 switch (type->base) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200853 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200854 /* RFC 6020 9.7.4 - bit */
855
856 /* get bit specifications, at least one must be present */
857 LY_TREE_FOR_SAFE(yin->child, next, node) {
858 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200859 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200860 } else {
861 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
862 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200863 }
864 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200865 if (!type->info.bits.count) {
866 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +0200867 /* this is just a derived type with no bit specified/required */
Radek Krejci994b6f62015-06-18 16:47:27 +0200868 break;
869 }
870 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
871 goto error;
872 }
873
874 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200875 for (i = p = 0; yin->child; i++) {
876 GETVAL(value, yin->child, "name");
877 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200878 goto error;
879 }
880 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200881 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], yin->child, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200882 type->info.bits.count = i + 1;
883 goto error;
884 }
885
886 /* check the name uniqueness */
887 for (j = 0; j < i; j++) {
888 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200889 LOGVAL(VE_BITS_DUPNAME, LOGLINE(yin->child), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200890 type->info.bits.count = i + 1;
891 goto error;
892 }
893 }
894
Radek Krejci5fbc9162015-06-19 14:11:11 +0200895 node = yin->child->child;
Radek Krejci994b6f62015-06-18 16:47:27 +0200896 if (node && !strcmp(node->name, "position")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +0200897 GETVAL(value, node, "value");
Radek Krejci994b6f62015-06-18 16:47:27 +0200898 p_ = strtol(value, NULL, 10);
899
900 /* range check */
901 if (p_ < 0 || p_ > UINT32_MAX) {
902 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
903 type->info.bits.count = i + 1;
904 goto error;
905 }
906 type->info.bits.bit[i].pos = (uint32_t)p_;
907
908 /* keep the highest enum value for automatic increment */
909 if (type->info.bits.bit[i].pos > p) {
910 p = type->info.bits.bit[i].pos;
911 p++;
912 } else {
913 /* check that the value is unique */
914 for (j = 0; j < i; j++) {
915 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
916 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
917 type->info.bits.count = i + 1;
918 goto error;
919 }
920 }
921 }
922 } else {
923 /* assign value automatically */
924 if (p > UINT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200925 LOGVAL(VE_INARG, LOGLINE(yin->child), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +0200926 type->info.bits.count = i + 1;
927 goto error;
928 }
929 type->info.bits.bit[i].pos = (uint32_t)p;
930 p++;
931 }
Radek Krejci5fbc9162015-06-19 14:11:11 +0200932 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci994b6f62015-06-18 16:47:27 +0200933 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200934 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200935
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200936 case LY_TYPE_DEC64:
Radek Krejcif9401c32015-06-26 16:47:36 +0200937 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
938 LY_TREE_FOR_SAFE(yin->child, next, node) {
939 if (!strcmp(node->name, "range")) {
940 if (type->info.dec64.range) {
941 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
942 goto error;
943 }
944
945 GETVAL(value, node, "value");
946 if (check_length(value, type, LOGLINE(node))) {
947 goto error;
948 }
949 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
950 type->info.dec64.range->expr = lydict_insert(module->ctx, value, 0);
951
952 /* get possible substatements */
953 if (read_restr_substmt(module->ctx, type->info.dec64.range, node)) {
954 goto error;
955 }
956 } else if (!strcmp(node->name, "fraction-digits")) {
957 if (type->info.dec64.dig) {
958 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
959 goto error;
960 }
961 GETVAL(value, node, "value");
962 v = strtol(value, NULL, 10);
963
964 /* range check */
965 if (v < 1 || v > 18) {
966 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
967 goto error;
968 }
969 type->info.dec64.dig = (uint8_t)v;
970 } else {
971 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
972 goto error;
973 }
974 lyxml_free_elem(module->ctx, node);
975 }
976
977 /* mandatory sub-statement(s) check */
978 if (!type->info.dec64.dig && !type->der->type.der) {
979 /* decimal64 type directly derived from built-in type requires fraction-digits */
980 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "fraction-digits", "type");
981 goto error;
982 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200983 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200985 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200986 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200987
Radek Krejci994b6f62015-06-18 16:47:27 +0200988 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200989 LY_TREE_FOR_SAFE(yin->child, next, node) {
990 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200991 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200992 } else {
993 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
994 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200995 }
996 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200997 if (!type->info.enums.count) {
998 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +0200999 /* this is just a derived type with no enum specified/required */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001000 break;
1001 }
1002 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
1003 goto error;
1004 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001005
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001006 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +02001007 for (i = v = 0; yin->child; i++) {
1008 GETVAL(value, yin->child, "name");
1009 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001010 goto error;
1011 }
1012 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +02001013 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001014 type->info.enums.count = i + 1;
1015 goto error;
1016 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001017
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001018 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1019 value = type->info.enums.list[i].name;
1020 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001021 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001022 type->info.enums.count = i + 1;
1023 goto error;
1024 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001026 /* check the name uniqueness */
1027 for (j = 0; j < i; j++) {
1028 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001029 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001030 type->info.enums.count = i + 1;
1031 goto error;
1032 }
1033 }
Radek Krejci04581c62015-05-22 21:24:00 +02001034
Radek Krejci5fbc9162015-06-19 14:11:11 +02001035 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001036 if (node && !strcmp(node->name, "value")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +02001037 GETVAL(value, node, "value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001038 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001039
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001040 /* range check */
1041 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1042 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1043 type->info.enums.count = i + 1;
1044 goto error;
1045 }
1046 type->info.enums.list[i].value = v_;
1047
1048 /* keep the highest enum value for automatic increment */
1049 if (type->info.enums.list[i].value > v) {
1050 v = type->info.enums.list[i].value;
1051 v++;
1052 } else {
1053 /* check that the value is unique */
1054 for (j = 0; j < i; j++) {
1055 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001056 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 +02001057 type->info.enums.count = i + 1;
1058 goto error;
1059 }
1060 }
1061 }
1062 } else {
1063 /* assign value automatically */
1064 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001065 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001066 type->info.enums.count = i + 1;
1067 goto error;
1068 }
1069 type->info.enums.list[i].value = v;
1070 v++;
1071 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001072 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001073 }
1074 break;
1075
1076 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001077 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001078
1079 /* get base specification, exactly one must be present */
1080 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001081 if (type->der->type.der) {
1082 /* this is just a derived type with no base specified/required */
1083 break;
1084 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001085 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1086 goto error;
1087 }
1088 if (strcmp(yin->child->name, "base")) {
1089 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1090 goto error;
1091 }
1092 if (yin->child->next) {
1093 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1094 goto error;
1095 }
1096 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1097 if (!type->info.ident.ref) {
1098 return EXIT_FAILURE;
1099 }
1100 break;
1101
1102 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001103 /* RFC 6020 9.13.2 - require-instance */
1104 LY_TREE_FOR_SAFE(yin->child, next, node) {
1105 if (!strcmp(node->name, "require-instance")) {
1106 if (type->info.inst.req) {
1107 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1108 goto error;
1109 }
1110 GETVAL(value, node, "value");
1111 if (strcmp(value, "true")) {
1112 type->info.inst.req = 1;
1113 } else if (strcmp(value, "false")) {
1114 type->info.inst.req = -1;
1115 } else {
1116 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1117 goto error;
1118 }
1119 } else {
1120 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1121 goto error;
1122 }
1123 lyxml_free_elem(module->ctx, node);
1124 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001125 break;
1126
Radek Krejcif2860132015-06-20 12:37:20 +02001127 case LY_TYPE_BINARY:
1128 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001129 case LY_TYPE_INT8:
1130 case LY_TYPE_INT16:
1131 case LY_TYPE_INT32:
1132 case LY_TYPE_INT64:
1133 case LY_TYPE_UINT8:
1134 case LY_TYPE_UINT16:
1135 case LY_TYPE_UINT32:
1136 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001137 /* RFC 6020 9.2.4 - range */
1138
1139 /* length and range are actually the same restriction, so process
1140 * them by this common code, we just need to differ the name and
1141 * structure where the information will be stored
1142 */
1143 if (type->base == LY_TYPE_BINARY) {
1144 restr = &type->info.binary.length;
1145 name = "length";
1146 } else {
1147 restr = &type->info.num.range;
1148 name = "range";
1149 }
1150
1151 LY_TREE_FOR_SAFE(yin->child, next, node) {
1152 if (!strcmp(node->name, name)) {
1153 if (*restr) {
1154 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1155 goto error;
1156 }
1157
1158 GETVAL(value, node, "value");
1159 if (check_length(value, type, LOGLINE(node))) {
1160 goto error;
1161 }
1162 *restr = calloc(1, sizeof **restr);
1163 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1164
1165 /* get possible substatements */
1166 if (read_restr_substmt(module->ctx, *restr, node)) {
1167 goto error;
1168 }
1169 } else {
1170 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1171 goto error;
1172 }
1173 lyxml_free_elem(module->ctx, node);
1174 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001175 break;
1176
1177 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001178 /* RFC 6020 9.9.2 - path */
1179 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001180 if (type->der->type.der) {
1181 /* this is just a derived type with no path specified/required */
1182 break;
1183 }
Radek Krejcidc4c1412015-06-19 15:39:54 +02001184 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1185 goto error;
1186 }
1187 LY_TREE_FOR_SAFE(yin->child, next, node) {
1188 if (!strcmp(node->name, "path")) {
1189 if (type->info.lref.path) {
1190 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1191 goto error;
1192 }
1193
1194 GETVAL(value, node, "value");
1195 /* TODO
1196 * it would be nice to perform here a check that target is leaf or leaf-list,
1197 * but schema is not finnished yet and path can point almost to anywhere, so
1198 * we will have to check the path at the end of parsing the schema.
1199 */
1200 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1201 } else {
1202 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1203 goto error;
1204 }
1205 lyxml_free_elem(module->ctx, node);
1206 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001207 break;
1208
1209 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001210 /* RFC 6020 9.4.4 - length */
1211 /* RFC 6020 9.4.6 - pattern */
1212 LY_TREE_FOR_SAFE(yin->child, next, node) {
1213 if (!strcmp(node->name, "length")) {
1214 if (type->info.str.length) {
1215 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1216 goto error;
1217 }
1218
1219 GETVAL(value, node, "value");
1220 if (check_length(value, type, LOGLINE(node))) {
1221 goto error;
1222 }
1223 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1224 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1225
Radek Krejci5fbc9162015-06-19 14:11:11 +02001226 /* get possible sub-statements */
1227 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001228 goto error;
1229 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001230 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001231 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001232 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001233 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001234 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001235 goto error;
1236 }
1237 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001238 /* store patterns in array */
1239 if (type->info.str.pat_count) {
1240 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1241 for (i = 0; yin->child; i++) {
1242 GETVAL(value, yin->child, "value");
1243 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1244
1245 /* get possible sub-statements */
1246 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1247 goto error;
1248 }
1249 lyxml_free_elem(module->ctx, yin->child);
1250 }
1251 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001252 break;
1253
1254 case LY_TYPE_UNION:
1255 /* TODO type, 7.4
1256 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1257 break;
1258
1259 default:
Radek Krejci6e328cd2015-06-26 16:24:11 +02001260 /* no sub-statement allowed in:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001261 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1262 */
Radek Krejci6e328cd2015-06-26 16:24:11 +02001263 if (yin->child) {
1264 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1265 goto error;
1266 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001267 break;
1268 }
1269
1270 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001271
1272error:
1273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001274 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001275}
1276
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001277static int
1278fill_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 +02001279{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001280 const char *value;
1281 struct lyxml_elem *node, *next;
1282 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001283
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001284 GETVAL(value, yin, "name");
1285 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1286 goto error;
1287 }
1288 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001290 /* generic part - status, description, reference */
1291 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1292 goto error;
1293 }
Radek Krejcieac35532015-05-31 19:09:15 +02001294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001295 LY_TREE_FOR_SAFE(yin->child, next, node) {
1296 if (!strcmp(node->name, "type")) {
1297 if (tpdf->type.der) {
1298 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1299 goto error;
1300 }
1301 r = fill_yin_type(module, parent, node, &tpdf->type);
1302 } else if (!strcmp(node->name, "default")) {
1303 if (tpdf->dflt) {
1304 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1305 goto error;
1306 }
1307 GETVAL(value, node, "value");
1308 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1309 } else if (!strcmp(node->name, "units")) {
1310 if (tpdf->units) {
1311 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1312 goto error;
1313 }
1314 GETVAL(value, node, "name");
1315 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1316 } else {
1317 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1318 r = 1;
1319 }
1320 lyxml_free_elem(module->ctx, node);
1321 if (r) {
1322 goto error;
1323 }
1324 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001325
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001326 /* check mandatory value */
1327 if (!tpdf->type.der) {
1328 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1329 goto error;
1330 }
Radek Krejcieac35532015-05-31 19:09:15 +02001331
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001332 /* check default value */
1333 if (check_default(&tpdf->type, tpdf->dflt)) {
1334 goto error;
1335 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001336
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001337 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001338
1339error:
1340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001341 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001342}
1343
Radek Krejci3cf9e222015-06-18 11:37:50 +02001344static struct ly_feature *
1345resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1346{
1347 const char *prefix;
1348 unsigned int prefix_len = 0;
1349 int i, j, found = 0;
1350
1351 assert(name);
1352 assert(module);
1353
1354 /* check prefix */
1355 prefix = name;
1356 name = strchr(prefix, ':');
1357 if (name) {
1358 /* there is prefix */
1359 prefix_len = name - prefix;
1360 name++;
1361
1362 /* check whether the prefix points to the current module */
1363 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1364 /* then ignore prefix and works as there is no prefix */
1365 prefix_len = 0;
1366 }
1367 } else {
1368 /* no prefix, set pointers correctly */
1369 name = prefix;
1370 }
1371
1372 if (prefix_len) {
1373 /* search in imported modules */
1374 for (i = 0; i < module->imp_size; i++) {
1375 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1376 module = module->imp[i].module;
1377 found = 1;
1378 break;
1379 }
1380 }
1381 if (!found) {
1382 /* identity refers unknown data model */
1383 LOGVAL(VE_INPREFIX, line, prefix);
1384 return NULL;
1385 }
1386 } else {
1387 /* search in submodules */
1388 for (i = 0; i < module->inc_size; i++) {
1389 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1390 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1391 return &(module->inc[i].submodule->features[j]);
1392 }
1393 }
1394 }
1395 }
1396
1397 /* search in the identified module */
1398 for (j = 0; j < module->features_size; j++) {
1399 if (!strcmp(name, module->features[j].name)) {
1400 return &module->features[j];
1401 }
1402 }
1403
1404 /* not found */
1405 return NULL;
1406}
1407
1408static int
1409fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1410{
1411 const char *value;
1412 struct lyxml_elem *child, *next;
1413 int c = 0;
1414
Radek Krejcib05774c2015-06-18 13:52:59 +02001415 GETVAL(value, yin, "name");
1416 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1417 goto error;
1418 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001419 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001420
Radek Krejci7e97c352015-06-19 16:26:34 +02001421 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, OPT_MODULE)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001422 goto error;
1423 }
1424
1425 LY_TREE_FOR_SAFE(yin->child, next, child) {
1426 if (!strcmp(child->name, "if-feature")) {
1427 c++;
1428 } else {
1429 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1430 goto error;
1431 }
1432 }
1433
1434 if (c) {
1435 f->features = calloc(c, sizeof *f->features);
1436 }
1437
1438 LY_TREE_FOR_SAFE(yin->child, next, child) {
1439 GETVAL(value, child, "name");
1440 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1441 if (!f->features[f->features_size]) {
1442 goto error;
1443 }
1444 f->features_size++;
1445 }
1446
Radek Krejci3cf9e222015-06-18 11:37:50 +02001447 return EXIT_SUCCESS;
1448
1449error:
1450
1451 return EXIT_FAILURE;
1452}
1453
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001454static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001455fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001456{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001457 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001458
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001459 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001460 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001461
Radek Krejci41726f92015-06-19 13:11:05 +02001462 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001463
Radek Krejci41726f92015-06-19 13:11:05 +02001464error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001465
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001466 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001467}
1468
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001469static int
1470fill_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 +02001471{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001472 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001473 struct lyxml_elem *next, *child;
1474 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001475
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001476 GETVAL(value, yin, "target-node");
1477 aug->target_name = lydict_insert(module->ctx, value, 0);
1478 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001479
Radek Krejci3cf9e222015-06-18 11:37:50 +02001480 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1481 goto error;
1482 }
1483
1484 LY_TREE_FOR_SAFE(yin->child, next, child) {
1485 if (!strcmp(child->name, "if-feature")) {
1486 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001487 } else if (!strcmp(child->name, "when")) {
1488 if (aug->when) {
1489 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1490 goto error;
1491 }
1492
1493 aug->when = read_yin_when(module, child);
1494 lyxml_free_elem(module->ctx, child);
1495
1496 if (!aug->when) {
1497 goto error;
1498 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001499
1500 /* check allowed sub-statements */
1501 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1502 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1503 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1504 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1505 goto error;
1506 }
1507 }
1508
1509 if (c) {
1510 aug->features = calloc(c, sizeof *aug->features);
1511 }
1512
1513 LY_TREE_FOR_SAFE(yin->child, next, child) {
1514 if (!strcmp(child->name, "if-feature")) {
1515 GETVAL(value, child, "name");
1516 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1517 if (!aug->features[aug->features_size]) {
1518 goto error;
1519 }
1520 aug->features_size++;
1521 } else {
1522 /* keep the data nodes */
1523 continue;
1524 }
1525
1526 lyxml_free_elem(module->ctx, child);
1527 }
1528
1529 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001530 * when we will have the target node
1531 */
1532 lyxml_unlink_elem(yin);
1533 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001534
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001535 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001536
1537error:
1538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001539 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001540}
1541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001542static int
1543fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001544{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001545 struct lyxml_elem *sub, *next;
1546 const char *value;
1547 char *endptr;
1548 int f_mand = 0, f_min = 0, f_max = 0;
1549 int c_must = 0;
1550 int r;
1551 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001553 GETVAL(value, yin, "target-node");
1554 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001555
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001556 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1557 goto error;
1558 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001560 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1561 /* limited applicability */
1562 if (!strcmp(sub->name, "default")) {
1563 /* leaf or choice */
1564 if (rfn->mod.dflt) {
1565 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1566 goto error;
1567 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001568
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001569 /* check possibility of statements combination */
1570 if (rfn->target_type) {
1571 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1572 if (!rfn->target_type) {
1573 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1574 goto error;
1575 }
1576 } else {
1577 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1578 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001579
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001580 GETVAL(value, sub, "value");
1581 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1582 } else if (!strcmp(sub->name, "mandatory")) {
1583 /* leaf, choice or anyxml */
1584 if (f_mand) {
1585 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1586 goto error;
1587 }
1588 /* just checking the flags in leaf is not sufficient, we would allow
1589 * multiple mandatory statements with the "false" value
1590 */
1591 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001593 /* check possibility of statements combination */
1594 if (rfn->target_type) {
1595 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1596 if (!rfn->target_type) {
1597 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1598 goto error;
1599 }
1600 } else {
1601 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1602 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001603
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001604 GETVAL(value, sub, "value");
1605 if (!strcmp(value, "true")) {
1606 rfn->flags |= LY_NODE_MAND_TRUE;
1607 } else if (!strcmp(value, "false")) {
1608 rfn->flags |= LY_NODE_MAND_FALSE;
1609 } else {
1610 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1611 goto error;
1612 }
1613 } else if (!strcmp(sub->name, "min-elements")) {
1614 /* list or leaf-list */
1615 if (f_min) {
1616 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1617 goto error;
1618 }
1619 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001620
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001621 /* check possibility of statements combination */
1622 if (rfn->target_type) {
1623 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1624 if (!rfn->target_type) {
1625 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1626 goto error;
1627 }
1628 } else {
1629 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1630 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001631
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001632 GETVAL(value, sub, "value");
1633 while (isspace(value[0])) {
1634 value++;
1635 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001637 /* convert it to uint32_t */
1638 errno = 0;
1639 endptr = NULL;
1640 val = strtoul(value, &endptr, 10);
1641 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1642 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1643 goto error;
1644 }
1645 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001646
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001647 /* magic - bit 3 in flags means min set */
1648 rfn->flags |= 0x04;
1649 } else if (!strcmp(sub->name, "max-elements")) {
1650 /* list or leaf-list */
1651 if (f_max) {
1652 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1653 goto error;
1654 }
1655 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001656
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001657 /* check possibility of statements combination */
1658 if (rfn->target_type) {
1659 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1660 if (!rfn->target_type) {
1661 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1662 goto error;
1663 }
1664 } else {
1665 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1666 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001667
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001668 GETVAL(value, sub, "value");
1669 while (isspace(value[0])) {
1670 value++;
1671 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001672
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001673 /* convert it to uint32_t */
1674 errno = 0;
1675 endptr = NULL;
1676 val = strtoul(value, &endptr, 10);
1677 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1678 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1679 goto error;
1680 }
1681 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001683 /* magic - bit 4 in flags means min set */
1684 rfn->flags |= 0x08;
1685 } else if (!strcmp(sub->name, "presence")) {
1686 /* container */
1687 if (rfn->mod.presence) {
1688 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1689 goto error;
1690 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001692 /* check possibility of statements combination */
1693 if (rfn->target_type) {
1694 rfn->target_type &= LY_NODE_CONTAINER;
1695 if (!rfn->target_type) {
1696 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1697 goto error;
1698 }
1699 } else {
1700 rfn->target_type = LY_NODE_CONTAINER;
1701 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001703 GETVAL(value, sub, "value");
1704 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1705 } else if (!strcmp(sub->name, "must")) {
1706 /* leaf-list, list, container or anyxml */
1707 /* check possibility of statements combination */
1708 if (rfn->target_type) {
1709 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1710 if (!rfn->target_type) {
1711 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1712 goto error;
1713 }
1714 } else {
1715 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1716 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001717
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001718 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001719
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001720 } else {
1721 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1722 goto error;
1723 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001724
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001725 lyxml_free_elem(module->ctx, sub);
1726 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001728 /* process nodes with cardinality of 0..n */
1729 if (c_must) {
1730 rfn->must = calloc(c_must, sizeof *rfn->must);
1731 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001732
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001733 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1734 if (!strcmp(sub->name, "must")) {
1735 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1736 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001738 if (r) {
1739 goto error;
1740 }
1741 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001743 lyxml_free_elem(module->ctx, sub);
1744 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001745
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001746 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001747
1748error:
1749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001750 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001751}
1752
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001753static int
1754fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001755{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001756 struct lyxml_elem *child;
1757 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001758
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001759 LY_TREE_FOR(yin->child, child) {
1760 if (!strcmp(child->name, "prefix")) {
1761 GETVAL(value, child, "value");
1762 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1763 goto error;
1764 }
1765 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1766 } else if (!strcmp(child->name, "revision-date")) {
1767 if (imp->rev[0]) {
1768 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1769 goto error;
1770 }
1771 GETVAL(value, child, "date");
1772 if (check_date(value, LOGLINE(child))) {
1773 goto error;
1774 }
1775 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1776 } else {
1777 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1778 goto error;
1779 }
1780 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001781
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001782 /* check mandatory information */
1783 if (!imp->prefix) {
1784 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1785 goto error;
1786 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001787
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001788 GETVAL(value, yin, "module");
1789 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1790 if (!imp->module) {
1791 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1792 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1793 goto error;
1794 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001796 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001797
1798error:
1799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001800 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001801}
1802
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001803static int
1804fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001805{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001806 struct lyxml_elem *child;
1807 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001808
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001809 LY_TREE_FOR(yin->child, child) {
1810 if (!strcmp(child->name, "revision-date")) {
1811 if (inc->rev[0]) {
1812 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1813 goto error;
1814 }
1815 GETVAL(value, child, "date");
1816 if (check_date(value, LOGLINE(child))) {
1817 goto error;
1818 }
1819 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1820 } else {
1821 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1822 goto error;
1823 }
1824 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001825
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001826 GETVAL(value, yin, "module");
1827 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1828 if (!inc->submodule) {
1829 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1830 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1831 goto error;
1832 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001833
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001834 /* check that belongs-to corresponds */
1835 if (module->type) {
1836 module = ((struct ly_submodule *)module)->belongsto;
1837 }
1838 if (inc->submodule->belongsto != module) {
1839 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1840 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1841 goto error;
1842 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001843
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001844 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001845
1846error:
1847
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001848 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001849}
1850
Radek Krejcida04f4a2015-05-21 12:54:09 +02001851/*
1852 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001853 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001854 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001855 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001856static int
1857read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1858 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001859{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001860 const char *value;
1861 struct lyxml_elem *sub, *next;
1862 struct ly_ctx *const ctx = module->ctx;
1863 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001864
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001865 if (opt & OPT_MODULE) {
1866 mnode->module = module;
1867 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001868
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001869 if (opt & OPT_IDENT) {
1870 GETVAL(value, xmlnode, "name");
1871 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1872 goto error;
1873 }
1874 mnode->name = lydict_insert(ctx, value, strlen(value));
1875 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001877 /* process local parameters */
1878 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1879 if (!strcmp(sub->name, "description")) {
1880 if (mnode->dsc) {
1881 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1882 goto error;
1883 }
1884 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1885 if (!mnode->dsc) {
1886 r = 1;
1887 }
1888 } else if (!strcmp(sub->name, "reference")) {
1889 if (mnode->ref) {
1890 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1891 goto error;
1892 }
1893 mnode->ref = read_yin_subnode(ctx, sub, "text");
1894 if (!mnode->ref) {
1895 r = 1;
1896 }
1897 } else if (!strcmp(sub->name, "status")) {
1898 if (mnode->flags & LY_NODE_STATUS_MASK) {
1899 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1900 goto error;
1901 }
1902 GETVAL(value, sub, "value");
1903 if (!strcmp(value, "current")) {
1904 mnode->flags |= LY_NODE_STATUS_CURR;
1905 } else if (!strcmp(value, "deprecated")) {
1906 mnode->flags |= LY_NODE_STATUS_DEPRC;
1907 } else if (!strcmp(value, "obsolete")) {
1908 mnode->flags |= LY_NODE_STATUS_OBSLT;
1909 } else {
1910 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1911 r = 1;
1912 }
1913 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1914 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1915 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1916 goto error;
1917 }
1918 GETVAL(value, sub, "value");
1919 if (!strcmp(value, "false")) {
1920 mnode->flags |= LY_NODE_CONFIG_R;
1921 } else if (!strcmp(value, "true")) {
1922 mnode->flags |= LY_NODE_CONFIG_W;
1923 } else {
1924 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1925 r = 1;
1926 }
1927 } else {
1928 /* skip the lyxml_free_elem */
1929 continue;
1930 }
1931 lyxml_free_elem(ctx, sub);
1932 if (r) {
1933 goto error;
1934 }
1935 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001936
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001937 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1938 /* get config flag from parent */
1939 if (parent) {
1940 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1941 } else {
1942 /* default config is true */
1943 mnode->flags |= LY_NODE_CONFIG_W;
1944 }
1945 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001947 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001948
1949error:
1950
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001951 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001952}
1953
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001954static struct ly_when *
1955read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
1956{
Radek Krejci53ebfb12015-06-19 09:35:59 +02001957 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001958 struct lyxml_elem *next, *child;
1959 const char *value;
1960
1961 retval = calloc(1, sizeof *retval);
1962
1963 GETVAL(value, yin, "condition");
1964 retval->cond = lydict_insert(module->ctx, value, 0);
1965
1966 LY_TREE_FOR_SAFE(yin->child, next, child) {
1967 if (!strcmp(child->name, "description")) {
1968 if (retval->dsc) {
1969 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1970 goto error;
1971 }
1972 retval->dsc = read_yin_subnode(module->ctx, child, "text");
1973 if (!retval->dsc) {
1974 goto error;
1975 }
1976 } else if (!strcmp(child->name, "reference")) {
1977 if (retval->ref) {
1978 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1979 goto error;
1980 }
1981 retval->ref = read_yin_subnode(module->ctx, child, "text");
1982 if (!retval->ref) {
1983 goto error;
1984 }
1985 } else {
1986 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1987 goto error;
1988 }
1989
1990 lyxml_free_elem(module->ctx, child);
1991 }
1992
1993 return retval;
1994
1995error:
1996
Radek Krejci53ebfb12015-06-19 09:35:59 +02001997 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001998 return NULL;
1999}
2000
Radek Krejcib4cf2022015-06-03 14:40:05 +02002001/* additional check in case statement - the child must be unique across
2002 * all other case names and its data children
2003 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002004static int
2005check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002006{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002007 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002008
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002009 if (new->nodetype == LY_NODE_CHOICE) {
2010 /* we have nested choice in case, so we need recursion */
2011 LY_TREE_FOR(new->child, mnode) {
2012 if (mnode->nodetype == LY_NODE_CASE) {
2013 LY_TREE_FOR(mnode->child, submnode) {
2014 if (check_branch_id(parent, submnode, new, line)) {
2015 return EXIT_FAILURE;
2016 }
2017 }
2018 } else if (check_branch_id(parent, mnode, new, line)) {
2019 return EXIT_FAILURE;
2020 }
2021 }
2022 } else {
2023 LY_TREE_FOR(parent->child, mnode) {
2024 if (mnode == excl) {
2025 continue;
2026 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002027
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002028 if (!strcmp(new->name, mnode->name)) {
2029 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2030 return EXIT_FAILURE;
2031 }
2032 if (mnode->nodetype == LY_NODE_CASE) {
2033 LY_TREE_FOR(mnode->child, submnode) {
2034 if (!strcmp(new->name, submnode->name)) {
2035 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2036 return EXIT_FAILURE;
2037 }
2038 }
2039 }
2040 }
2041 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002042
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002043 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002044}
2045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002046static struct ly_mnode *
2047read_yin_case(struct ly_module *module,
2048 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002049{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002050 struct lyxml_elem *sub, *next;
2051 struct ly_mnode_case *mcase;
2052 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002053 int c_ftrs = 0;
2054 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002056 mcase = calloc(1, sizeof *mcase);
2057 mcase->nodetype = LY_NODE_CASE;
2058 mcase->prev = (struct ly_mnode *)mcase;
2059 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002061 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
2062 goto error;
2063 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002064
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002065 /* process choice's specific children */
2066 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2067 if (!strcmp(sub->name, "container")) {
2068 mnode = read_yin_container(module, retval, sub, resolve, unres);
2069 } else if (!strcmp(sub->name, "leaf-list")) {
2070 mnode = read_yin_leaflist(module, retval, sub, resolve);
2071 } else if (!strcmp(sub->name, "leaf")) {
2072 mnode = read_yin_leaf(module, retval, sub, resolve);
2073 } else if (!strcmp(sub->name, "list")) {
2074 mnode = read_yin_list(module, retval, sub, resolve, unres);
2075 } else if (!strcmp(sub->name, "uses")) {
2076 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2077 } else if (!strcmp(sub->name, "choice")) {
2078 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2079 } else if (!strcmp(sub->name, "anyxml")) {
2080 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002081 } else if (!strcmp(sub->name, "if-feature")) {
2082 c_ftrs++;
2083
2084 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
2085 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002086 } else if (!strcmp(sub->name, "when")) {
2087 if (mcase->when) {
2088 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2089 goto error;
2090 }
2091
2092 mcase->when = read_yin_when(module, sub);
2093 if (!mcase->when) {
2094 goto error;
2095 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002096 } else {
2097 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2098 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002099 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002101 if (!mnode) {
2102 goto error;
2103 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
2104 goto error;
2105 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002107 mnode = NULL;
2108 lyxml_free_elem(module->ctx, sub);
2109 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002110
Radek Krejci3cf9e222015-06-18 11:37:50 +02002111 if (c_ftrs) {
2112 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2113 }
2114 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2115 GETVAL(value, sub, "name");
2116 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2117 if (!mcase->features[mcase->features_size]) {
2118 goto error;
2119 }
2120 mcase->features_size++;
2121 lyxml_free_elem(module->ctx, sub);
2122 }
2123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002124 /* inherit config flag */
2125 if (parent) {
2126 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2127 } else {
2128 /* default config is true */
2129 retval->flags |= LY_NODE_CONFIG_W;
2130 }
Radek Krejcib388c152015-06-04 17:03:03 +02002131
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002132 /* insert the node into the schema tree */
2133 if (ly_mnode_addchild(parent, retval)) {
2134 goto error;
2135 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002137 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002138
2139error:
2140
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002141 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002142
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002143 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002144}
2145
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002146static struct ly_mnode *
2147read_yin_choice(struct ly_module *module,
2148 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002149{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002150 struct lyxml_elem *sub, *next;
2151 struct ly_ctx *const ctx = module->ctx;
2152 struct ly_mnode *retval, *mnode = NULL;
2153 struct ly_mnode_choice *choice;
2154 const char *value;
2155 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002156 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002157
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002158 choice = calloc(1, sizeof *choice);
2159 choice->nodetype = LY_NODE_CHOICE;
2160 choice->prev = (struct ly_mnode *)choice;
2161 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002163 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2164 goto error;
2165 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002166
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002167 /* process choice's specific children */
2168 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2169 if (!strcmp(sub->name, "container")) {
2170 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2171 goto error;
2172 }
2173 } else if (!strcmp(sub->name, "leaf-list")) {
2174 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2175 goto error;
2176 }
2177 } else if (!strcmp(sub->name, "leaf")) {
2178 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2179 goto error;
2180 }
2181 } else if (!strcmp(sub->name, "list")) {
2182 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2183 goto error;
2184 }
2185 } else if (!strcmp(sub->name, "case")) {
2186 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2187 goto error;
2188 }
2189 } else if (!strcmp(sub->name, "anyxml")) {
2190 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2191 goto error;
2192 }
2193 } else if (!strcmp(sub->name, "default")) {
2194 if (dflt_str) {
2195 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2196 goto error;
2197 }
2198 GETVAL(value, sub, "value");
2199 dflt_str = strdup(value);
2200 } else if (!strcmp(sub->name, "mandatory")) {
2201 if (f_mand) {
2202 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2203 goto error;
2204 }
2205 /* just checking the flags in leaf is not sufficient, we would allow
2206 * multiple mandatory statements with the "false" value
2207 */
2208 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002210 GETVAL(value, sub, "value");
2211 if (!strcmp(value, "true")) {
2212 choice->flags |= LY_NODE_MAND_TRUE;
2213 } else if (strcmp(value, "false")) {
2214 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2215 goto error;
2216 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002217 } else if (!strcmp(sub->name, "when")) {
2218 if (choice->when) {
2219 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2220 goto error;
2221 }
2222
2223 choice->when = read_yin_when(module, sub);
2224 if (!choice->when) {
2225 goto error;
2226 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002227 } else if (!strcmp(sub->name, "if-feature")) {
2228 c_ftrs++;
2229
2230 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
2231 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002232 } else {
2233 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2234 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002235 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002236
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002237 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
2238 goto error;
2239 }
2240 mnode = NULL;
2241 lyxml_free_elem(ctx, sub);
2242 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002243
Radek Krejci3cf9e222015-06-18 11:37:50 +02002244 if (c_ftrs) {
2245 choice->features = calloc(c_ftrs, sizeof *choice->features);
2246 }
2247
2248 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2249 GETVAL(value, sub, "name");
2250 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
2251 if (!choice->features[choice->features_size]) {
2252 goto error;
2253 }
2254 choice->features_size++;
2255 lyxml_free_elem(ctx, sub);
2256 }
2257
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002258 /* check - default is prohibited in combination with mandatory */
2259 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
2260 LOGVAL(VE_SPEC, LOGLINE(yin),
2261 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
2262 goto error;
2263 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002264
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002265 /* link default with the case */
2266 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02002267 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002268 if (!choice->dflt) {
2269 /* default branch not found */
2270 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
2271 goto error;
2272 }
2273 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002274
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002275 /* insert the node into the schema tree */
2276 if (parent && ly_mnode_addchild(parent, retval)) {
2277 goto error;
2278 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002279
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002280 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02002281
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002282 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002283
2284error:
2285
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002286 ly_mnode_free(retval);
2287 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002288
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002289 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002290}
2291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002292static struct ly_mnode *
2293read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02002294{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002295 struct ly_mnode *retval;
2296 struct ly_mnode_leaf *anyxml;
2297 struct lyxml_elem *sub, *next;
2298 const char *value;
2299 int r;
2300 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002301 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02002302
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002303 anyxml = calloc(1, sizeof *anyxml);
2304 anyxml->nodetype = LY_NODE_ANYXML;
2305 anyxml->prev = (struct ly_mnode *)anyxml;
2306 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02002307
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002308 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2309 goto error;
2310 }
Radek Krejci863c2852015-06-03 15:47:11 +02002311
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002312 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2313 if (!strcmp(sub->name, "mandatory")) {
2314 if (f_mand) {
2315 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2316 goto error;
2317 }
2318 /* just checking the flags in leaf is not sufficient, we would allow
2319 * multiple mandatory statements with the "false" value
2320 */
2321 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02002322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002323 GETVAL(value, sub, "value");
2324 if (!strcmp(value, "true")) {
2325 anyxml->flags |= LY_NODE_MAND_TRUE;
2326 } else if (strcmp(value, "false")) {
2327 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2328 goto error;
2329 }
2330 /* else false is the default value, so we can ignore it */
2331 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002332 } else if (!strcmp(sub->name, "when")) {
2333 if (anyxml->when) {
2334 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2335 goto error;
2336 }
2337
2338 anyxml->when = read_yin_when(module, sub);
2339 lyxml_free_elem(module->ctx, sub);
2340
2341 if (!anyxml->when) {
2342 goto error;
2343 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002344 } else if (!strcmp(sub->name, "must")) {
2345 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002346 } else if (!strcmp(sub->name, "if-feature")) {
2347 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02002348
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002349 } else {
2350 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2351 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002352 }
2353 }
Radek Krejci863c2852015-06-03 15:47:11 +02002354
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002355 /* middle part - process nodes with cardinality of 0..n */
2356 if (c_must) {
2357 anyxml->must = calloc(c_must, sizeof *anyxml->must);
2358 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002359 if (c_ftrs) {
2360 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
2361 }
Radek Krejci863c2852015-06-03 15:47:11 +02002362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002363 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2364 if (!strcmp(sub->name, "must")) {
2365 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
2366 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02002367
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002368 if (r) {
2369 goto error;
2370 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002371 } else if (!strcmp(sub->name, "must")) {
2372 GETVAL(value, sub, "name");
2373 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
2374 if (!anyxml->features[anyxml->features_size]) {
2375 goto error;
2376 }
2377 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002378 }
Radek Krejci863c2852015-06-03 15:47:11 +02002379
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002380 lyxml_free_elem(module->ctx, sub);
2381 }
Radek Krejci863c2852015-06-03 15:47:11 +02002382
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002383 if (parent && ly_mnode_addchild(parent, retval)) {
2384 goto error;
2385 }
Radek Krejci863c2852015-06-03 15:47:11 +02002386
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002387 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02002388
2389error:
2390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002391 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02002392
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002393 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02002394}
2395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002396static struct ly_mnode *
2397read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002398{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002399 struct ly_mnode *retval;
2400 struct ly_mnode_leaf *leaf;
2401 struct lyxml_elem *sub, *next;
2402 const char *value;
2403 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002404 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002405
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002406 leaf = calloc(1, sizeof *leaf);
2407 leaf->nodetype = LY_NODE_LEAF;
2408 leaf->prev = (struct ly_mnode *)leaf;
2409 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002410
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002411 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2412 goto error;
2413 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002414
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002415 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2416 if (!strcmp(sub->name, "type")) {
2417 if (leaf->type.der) {
2418 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2419 goto error;
2420 }
2421 if (fill_yin_type(module, parent, sub, &leaf->type)) {
2422 goto error;
2423 }
2424 } else if (!strcmp(sub->name, "default")) {
2425 if (leaf->dflt) {
2426 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2427 goto error;
2428 }
2429 GETVAL(value, sub, "value");
2430 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
2431 } else if (!strcmp(sub->name, "units")) {
2432 if (leaf->units) {
2433 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2434 goto error;
2435 }
2436 GETVAL(value, sub, "name");
2437 leaf->units = lydict_insert(module->ctx, value, strlen(value));
2438 } else if (!strcmp(sub->name, "mandatory")) {
2439 if (f_mand) {
2440 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2441 goto error;
2442 }
2443 /* just checking the flags in leaf is not sufficient, we would allow
2444 * multiple mandatory statements with the "false" value
2445 */
2446 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002447
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002448 GETVAL(value, sub, "value");
2449 if (!strcmp(value, "true")) {
2450 leaf->flags |= LY_NODE_MAND_TRUE;
2451 } else if (strcmp(value, "false")) {
2452 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2453 goto error;
2454 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002455 } else if (!strcmp(sub->name, "when")) {
2456 if (leaf->when) {
2457 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2458 goto error;
2459 }
2460
2461 leaf->when = read_yin_when(module, sub);
2462 if (!leaf->when) {
2463 goto error;
2464 }
2465
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002466 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002467 c_must++; /* else false is the default value, so we can ignore it */
2468 } else if (!strcmp(sub->name, "if-feature")) {
2469 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002471 /* skip element free at the end of the loop */
2472 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002473 } else {
2474 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2475 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002476 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002477
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002478 lyxml_free_elem(module->ctx, sub);
2479 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002481 /* check mandatory parameters */
2482 if (!leaf->type.der) {
2483 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2484 goto error;
2485 }
2486 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2487 goto error;
2488 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002490 /* middle part - process nodes with cardinality of 0..n */
2491 if (c_must) {
2492 leaf->must = calloc(c_must, sizeof *leaf->must);
2493 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002494 if (c_ftrs) {
2495 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2496 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002497
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002498 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2499 if (!strcmp(sub->name, "must")) {
2500 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2501 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002502
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002503 if (r) {
2504 goto error;
2505 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002506 } else if (!strcmp(sub->name, "if-feature")) {
2507 GETVAL(value, sub, "name");
2508 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2509 if (!leaf->features[leaf->features_size]) {
2510 goto error;
2511 }
2512 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002513 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002514
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002515 lyxml_free_elem(module->ctx, sub);
2516 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002518 if (parent && ly_mnode_addchild(parent, retval)) {
2519 goto error;
2520 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002521
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002522 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002523
2524error:
2525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002526 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002528 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002529}
2530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002531static struct ly_mnode *
2532read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002533{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002534 struct ly_mnode *retval;
2535 struct ly_mnode_leaflist *llist;
2536 struct lyxml_elem *sub, *next;
2537 const char *value;
2538 char *endptr;
2539 unsigned long val;
2540 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002541 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002542 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002544 llist = calloc(1, sizeof *llist);
2545 llist->nodetype = LY_NODE_LEAFLIST;
2546 llist->prev = (struct ly_mnode *)llist;
2547 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002549 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2550 goto error;
2551 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002553 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2554 if (!strcmp(sub->name, "type")) {
2555 if (llist->type.der) {
2556 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2557 goto error;
2558 }
2559 if (fill_yin_type(module, parent, sub, &llist->type)) {
2560 goto error;
2561 }
2562 } else if (!strcmp(sub->name, "units")) {
2563 if (llist->units) {
2564 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2565 goto error;
2566 }
2567 GETVAL(value, sub, "name");
2568 llist->units = lydict_insert(module->ctx, value, strlen(value));
2569 } else if (!strcmp(sub->name, "ordered-by")) {
2570 if (f_ordr) {
2571 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2572 goto error;
2573 }
2574 /* just checking the flags in llist is not sufficient, we would
2575 * allow multiple ordered-by statements with the "system" value
2576 */
2577 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002578
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002579 if (llist->flags & LY_NODE_CONFIG_R) {
2580 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2581 * state data
2582 */
2583 lyxml_free_elem(module->ctx, sub);
2584 continue;
2585 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002586
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002587 GETVAL(value, sub, "value");
2588 if (!strcmp(value, "user")) {
2589 llist->flags |= LY_NODE_USERORDERED;
2590 } else if (strcmp(value, "system")) {
2591 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2592 goto error;
2593 } /* else system is the default value, so we can ignore it */
2594 } else if (!strcmp(sub->name, "must")) {
2595 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002596 } else if (!strcmp(sub->name, "if-feature")) {
2597 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002598
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002599 /* skip element free at the end of the loop */
2600 continue;
2601 } else if (!strcmp(sub->name, "min-elements")) {
2602 if (f_min) {
2603 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2604 goto error;
2605 }
2606 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002607
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002608 GETVAL(value, sub, "value");
2609 while (isspace(value[0])) {
2610 value++;
2611 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002613 /* convert it to uint32_t */
2614 errno = 0;
2615 endptr = NULL;
2616 val = strtoul(value, &endptr, 10);
2617 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2618 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2619 goto error;
2620 }
2621 llist->min = (uint32_t) val;
2622 } else if (!strcmp(sub->name, "max-elements")) {
2623 if (f_max) {
2624 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2625 goto error;
2626 }
2627 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002628
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002629 GETVAL(value, sub, "value");
2630 while (isspace(value[0])) {
2631 value++;
2632 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002633
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002634 /* convert it to uint32_t */
2635 errno = 0;
2636 endptr = NULL;
2637 val = strtoul(value, &endptr, 10);
2638 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2639 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2640 goto error;
2641 }
2642 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002643 } else if (!strcmp(sub->name, "when")) {
2644 if (llist->when) {
2645 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2646 goto error;
2647 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002648
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002649 llist->when = read_yin_when(module, sub);
2650 if (!llist->when) {
2651 goto error;
2652 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002653 } else {
2654 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2655 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002656 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002657
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002658 lyxml_free_elem(module->ctx, sub);
2659 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002660
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002661 /* check constraints */
2662 if (!llist->type.der) {
2663 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2664 goto error;
2665 }
2666 if (llist->max && llist->min > llist->max) {
2667 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2668 goto error;
2669 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002670
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002671 /* middle part - process nodes with cardinality of 0..n */
2672 if (c_must) {
2673 llist->must = calloc(c_must, sizeof *llist->must);
2674 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002675 if (c_ftrs) {
2676 llist->features = calloc(c_ftrs, sizeof *llist->features);
2677 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002679 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2680 if (!strcmp(sub->name, "must")) {
2681 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2682 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002683
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002684 if (r) {
2685 goto error;
2686 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002687 } else if (!strcmp(sub->name, "if-feature")) {
2688 GETVAL(value, sub, "name");
2689 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2690 if (!llist->features[llist->features_size]) {
2691 goto error;
2692 }
2693 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002694 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002695
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002696 lyxml_free_elem(module->ctx, sub);
2697 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002698
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002699 if (parent && ly_mnode_addchild(parent, retval)) {
2700 goto error;
2701 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002703 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002704
2705error:
2706
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002707 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002708
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002709 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002710}
2711
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002712static struct ly_mnode *
2713read_yin_list(struct ly_module *module,
2714 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002715{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002716 struct ly_mnode *retval, *mnode;
2717 struct ly_mnode_list *list;
2718 struct ly_unique *uniq_s;
2719 struct lyxml_elem *sub, *next, root, uniq;
2720 int i, r;
2721 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002722 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002723 int f_ordr = 0, f_max = 0, f_min = 0;
2724 const char *key_str = NULL, *uniq_str, *value;
2725 char *auxs;
2726 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002728 /* init */
2729 memset(&root, 0, sizeof root);
2730 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002731
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002732 list = calloc(1, sizeof *list);
2733 list->nodetype = LY_NODE_LIST;
2734 list->prev = (struct ly_mnode *)list;
2735 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002737 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2738 goto error;
2739 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002741 /* process list's specific children */
2742 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2743 /* data statements */
2744 if (!strcmp(sub->name, "container") ||
2745 !strcmp(sub->name, "leaf-list") ||
2746 !strcmp(sub->name, "leaf") ||
2747 !strcmp(sub->name, "list") ||
2748 !strcmp(sub->name, "choice") ||
2749 !strcmp(sub->name, "uses") ||
2750 !strcmp(sub->name, "grouping") ||
2751 !strcmp(sub->name, "anyxml")) {
2752 lyxml_unlink_elem(sub);
2753 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002754
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002755 /* array counters */
2756 } else if (!strcmp(sub->name, "key")) {
2757 /* check cardinality 0..1 */
2758 if (list->keys_size) {
2759 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2760 goto error;
2761 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002762
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002763 /* count the number of keys */
2764 GETVAL(value, sub, "value");
2765 key_str = value;
2766 while ((value = strpbrk(value, " \t\n"))) {
2767 list->keys_size++;
2768 while (isspace(*value)) {
2769 value++;
2770 }
2771 }
2772 list->keys_size++;
2773 list->keys = calloc(list->keys_size, sizeof *list->keys);
2774 } else if (!strcmp(sub->name, "unique")) {
2775 c_uniq++;
2776 lyxml_unlink_elem(sub);
2777 lyxml_add_child(&uniq, sub);
2778 } else if (!strcmp(sub->name, "typedef")) {
2779 c_tpdf++;
2780 } else if (!strcmp(sub->name, "must")) {
2781 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002782 } else if (!strcmp(sub->name, "if-feature")) {
2783 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002784
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002785 /* optional stetments */
2786 } else if (!strcmp(sub->name, "ordered-by")) {
2787 if (f_ordr) {
2788 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2789 goto error;
2790 }
2791 /* just checking the flags in llist is not sufficient, we would
2792 * allow multiple ordered-by statements with the "system" value
2793 */
2794 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002796 if (list->flags & LY_NODE_CONFIG_R) {
2797 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2798 * state data
2799 */
2800 lyxml_free_elem(module->ctx, sub);
2801 continue;
2802 }
Radek Krejci345ad742015-06-03 11:04:18 +02002803
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002804 GETVAL(value, sub, "value");
2805 if (!strcmp(value, "user")) {
2806 list->flags |= LY_NODE_USERORDERED;
2807 } else if (strcmp(value, "system")) {
2808 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2809 goto error;
2810 }
2811 /* else system is the default value, so we can ignore it */
2812 lyxml_free_elem(module->ctx, sub);
2813 } else if (!strcmp(sub->name, "min-elements")) {
2814 if (f_min) {
2815 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2816 goto error;
2817 }
2818 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002819
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002820 GETVAL(value, sub, "value");
2821 while (isspace(value[0])) {
2822 value++;
2823 }
Radek Krejci345ad742015-06-03 11:04:18 +02002824
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002825 /* convert it to uint32_t */
2826 errno = 0;
2827 auxs = NULL;
2828 val = strtoul(value, &auxs, 10);
2829 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2830 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2831 goto error;
2832 }
2833 list->min = (uint32_t) val;
2834 lyxml_free_elem(module->ctx, sub);
2835 } else if (!strcmp(sub->name, "max-elements")) {
2836 if (f_max) {
2837 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2838 goto error;
2839 }
2840 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002841
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002842 GETVAL(value, sub, "value");
2843 while (isspace(value[0])) {
2844 value++;
2845 }
Radek Krejci345ad742015-06-03 11:04:18 +02002846
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002847 /* convert it to uint32_t */
2848 errno = 0;
2849 auxs = NULL;
2850 val = strtoul(value, &auxs, 10);
2851 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2852 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2853 goto error;
2854 }
2855 list->max = (uint32_t) val;
2856 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002857 } else if (!strcmp(sub->name, "when")) {
2858 if (list->when) {
2859 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2860 goto error;
2861 }
2862
2863 list->when = read_yin_when(module, sub);
2864 lyxml_free_elem(module->ctx, sub);
2865
2866 if (!list->when) {
2867 goto error;
2868 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002869 } else {
2870 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2871 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002872 }
2873 }
Radek Krejci345ad742015-06-03 11:04:18 +02002874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002875 /* check - if list is configuration, key statement is mandatory */
2876 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2877 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2878 goto error;
2879 }
2880 if (list->max && list->min > list->max) {
2881 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2882 goto error;
2883 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002884
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002885 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2886 if (c_tpdf) {
2887 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2888 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002889 if (c_must) {
2890 list->must = calloc(c_must, sizeof *list->must);
2891 }
2892 if (c_ftrs) {
2893 list->features = calloc(c_ftrs, sizeof *list->features);
2894 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002895 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2896 if (!strcmp(sub->name, "typedef")) {
2897 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2898 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002899
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002900 if (r) {
2901 goto error;
2902 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002903 } else if (!strcmp(sub->name, "if-feature")) {
2904 GETVAL(value, sub, "name");
2905 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2906 if (!list->features[list->features_size]) {
2907 goto error;
2908 }
2909 list->features_size++;
2910 } else if (!strcmp(sub->name, "must")) {
2911 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2912 list->must_size++;
2913
2914 if (r) {
2915 goto error;
2916 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002917 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002918 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002919 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002920
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002921 /* last part - process data nodes */
2922 LY_TREE_FOR_SAFE(root.child, next, sub) {
2923 if (!strcmp(sub->name, "container")) {
2924 mnode = read_yin_container(module, retval, sub, resolve, unres);
2925 } else if (!strcmp(sub->name, "leaf-list")) {
2926 mnode = read_yin_leaflist(module, retval, sub, resolve);
2927 } else if (!strcmp(sub->name, "leaf")) {
2928 mnode = read_yin_leaf(module, retval, sub, resolve);
2929 } else if (!strcmp(sub->name, "list")) {
2930 mnode = read_yin_list(module, retval, sub, resolve, unres);
2931 } else if (!strcmp(sub->name, "choice")) {
2932 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2933 } else if (!strcmp(sub->name, "uses")) {
2934 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2935 } else if (!strcmp(sub->name, "grouping")) {
2936 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2937 } else if (!strcmp(sub->name, "anyxml")) {
2938 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002939 }
2940 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002941
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002942 if (!mnode) {
2943 goto error;
2944 }
2945 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002947 if (parent && ly_mnode_addchild(parent, retval)) {
2948 goto error;
2949 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002950
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002951 if (!key_str) {
2952 /* config false list without a key */
2953 return retval;
2954 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002955
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002956 /* link key leafs into the list structure and check all constraints */
2957 for (i = 0; i < list->keys_size; i++) {
2958 /* get the key name */
2959 if ((value = strpbrk(key_str, " \t\n"))) {
2960 len = value - key_str;
2961 while (isspace(*value)) {
2962 value++;
2963 }
2964 } else {
2965 len = strlen(key_str);
2966 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002967
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002968 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002969
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002970 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2971 goto error;
2972 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002973
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002974 /* prepare for next iteration */
2975 while (value && isspace(*value)) {
2976 value++;
2977 }
2978 key_str = value;
2979 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002980
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002981 /* process unique statements */
2982 if (c_uniq) {
2983 list->unique = calloc(c_uniq, sizeof *list->unique);
2984 }
2985 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2986 /* count the number of unique values */
2987 GETVAL(value, sub, "tag");
2988 uniq_str = value;
2989 uniq_s = &list->unique[list->unique_size];
2990 while ((value = strpbrk(value, " \t\n"))) {
2991 uniq_s->leafs_size++;
2992 while (isspace(*value)) {
2993 value++;
2994 }
2995 }
2996 uniq_s->leafs_size++;
2997 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2998 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002999
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003000 /* interconnect unique values with the leafs */
3001 for (i = 0; i < uniq_s->leafs_size; i++) {
3002 if ((value = strpbrk(uniq_str, " \t\n"))) {
3003 len = value - uniq_str;
3004 while (isspace(*value)) {
3005 value++;
3006 }
3007 } else {
3008 len = strlen(uniq_str);
3009 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003011 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
3012 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
3013 goto error;
3014 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003016 /* prepare for next iteration */
3017 while (value && isspace(*value)) {
3018 value++;
3019 }
3020 uniq_str = value;
3021 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003022
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003023 lyxml_free_elem(module->ctx, sub);
3024 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003026 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003027
3028error:
3029
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003030 ly_mnode_free(retval);
3031 while (root.child) {
3032 lyxml_free_elem(module->ctx, root.child);
3033 }
3034 while (uniq.child) {
3035 lyxml_free_elem(module->ctx, uniq.child);
3036 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003037
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003038 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003039}
3040
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003041static struct ly_mnode *
3042read_yin_container(struct ly_module *module,
3043 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003044{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003045 struct lyxml_elem *sub, *next, root;
3046 struct ly_mnode *mnode = NULL;
3047 struct ly_mnode *retval;
3048 struct ly_mnode_container *cont;
3049 const char *value;
3050 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003051 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003052
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003053 /* init */
3054 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003056 cont = calloc(1, sizeof *cont);
3057 cont->nodetype = LY_NODE_CONTAINER;
3058 cont->prev = (struct ly_mnode *)cont;
3059 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003061 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3062 goto error;
3063 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003064
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003065 /* process container's specific children */
3066 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3067 if (!strcmp(sub->name, "presence")) {
3068 if (cont->presence) {
3069 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3070 goto error;
3071 }
3072 GETVAL(value, sub, "value");
3073 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02003074
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003075 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003076 } else if (!strcmp(sub->name, "when")) {
3077 if (cont->when) {
3078 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3079 goto error;
3080 }
3081
3082 cont->when = read_yin_when(module, sub);
3083 lyxml_free_elem(module->ctx, sub);
3084
3085 if (!cont->when) {
3086 goto error;
3087 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003088
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003089 /* data statements */
3090 } else if (!strcmp(sub->name, "container") ||
3091 !strcmp(sub->name, "leaf-list") ||
3092 !strcmp(sub->name, "leaf") ||
3093 !strcmp(sub->name, "list") ||
3094 !strcmp(sub->name, "choice") ||
3095 !strcmp(sub->name, "uses") ||
3096 !strcmp(sub->name, "grouping") ||
3097 !strcmp(sub->name, "anyxml")) {
3098 lyxml_unlink_elem(sub);
3099 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003101 /* array counters */
3102 } else if (!strcmp(sub->name, "typedef")) {
3103 c_tpdf++;
3104 } else if (!strcmp(sub->name, "must")) {
3105 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003106 } else if (!strcmp(sub->name, "if-feature")) {
3107 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003108 } else {
3109 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3110 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003111 }
3112 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003113
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003114 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3115 if (c_tpdf) {
3116 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3117 }
3118 if (c_must) {
3119 cont->must = calloc(c_must, sizeof *cont->must);
3120 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003121 if (c_ftrs) {
3122 cont->features = calloc(c_ftrs, sizeof *cont->features);
3123 }
Radek Krejci800af702015-06-02 13:46:01 +02003124
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003125 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3126 if (!strcmp(sub->name, "typedef")) {
3127 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
3128 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003129
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003130 if (r) {
3131 goto error;
3132 }
3133 } else if (!strcmp(sub->name, "must")) {
3134 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3135 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003137 if (r) {
3138 goto error;
3139 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003140 } else if (!strcmp(sub->name, "if-feature")) {
3141 GETVAL(value, sub, "name");
3142 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3143 if (!cont->features[cont->features_size]) {
3144 goto error;
3145 }
3146 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003147 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003149 lyxml_free_elem(module->ctx, sub);
3150 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003151
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003152 /* last part - process data nodes */
3153 LY_TREE_FOR_SAFE(root.child, next, sub) {
3154 if (!strcmp(sub->name, "container")) {
3155 mnode = read_yin_container(module, retval, sub, resolve, unres);
3156 } else if (!strcmp(sub->name, "leaf-list")) {
3157 mnode = read_yin_leaflist(module, retval, sub, resolve);
3158 } else if (!strcmp(sub->name, "leaf")) {
3159 mnode = read_yin_leaf(module, retval, sub, resolve);
3160 } else if (!strcmp(sub->name, "list")) {
3161 mnode = read_yin_list(module, retval, sub, resolve, unres);
3162 } else if (!strcmp(sub->name, "choice")) {
3163 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3164 } else if (!strcmp(sub->name, "uses")) {
3165 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3166 } else if (!strcmp(sub->name, "grouping")) {
3167 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3168 } else if (!strcmp(sub->name, "anyxml")) {
3169 mnode = read_yin_anyxml(module, retval, sub, resolve);
3170 }
3171 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003173 if (!mnode) {
3174 goto error;
3175 }
3176 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003177
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003178 if (parent && ly_mnode_addchild(parent, retval)) {
3179 goto error;
3180 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003181
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003182 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003183
3184error:
3185
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003186 ly_mnode_free(retval);
3187 while (root.child) {
3188 lyxml_free_elem(module->ctx, root.child);
3189 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003190
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003191 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003192}
3193
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003194static struct ly_mnode *
3195read_yin_grouping(struct ly_module *module,
3196 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003197{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003198 struct lyxml_elem *sub, *next, root;
3199 struct ly_mnode *mnode = NULL;
3200 struct ly_mnode *retval;
3201 struct ly_mnode_grp *grp;
3202 int r;
3203 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003204
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003205 /* init */
3206 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003207
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003208 grp = calloc(1, sizeof *grp);
3209 grp->nodetype = LY_NODE_GROUPING;
3210 grp->prev = (struct ly_mnode *)grp;
3211 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003213 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3214 goto error;
3215 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003217 LY_TREE_FOR_SAFE(node->child, next, sub) {
3218 /* data statements */
3219 if (!strcmp(sub->name, "container") ||
3220 !strcmp(sub->name, "leaf-list") ||
3221 !strcmp(sub->name, "leaf") ||
3222 !strcmp(sub->name, "list") ||
3223 !strcmp(sub->name, "choice") ||
3224 !strcmp(sub->name, "uses") ||
3225 !strcmp(sub->name, "grouping") ||
3226 !strcmp(sub->name, "anyxml")) {
3227 lyxml_unlink_elem(sub);
3228 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003230 /* array counters */
3231 } else if (!strcmp(sub->name, "typedef")) {
3232 c_tpdf++;
3233 } else {
3234 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3235 goto error;
3236 }
3237 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003238
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003239 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3240 if (c_tpdf) {
3241 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3242 }
3243 LY_TREE_FOR_SAFE(node->child, next, sub) {
3244 if (!strcmp(sub->name, "typedef")) {
3245 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3246 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003248 if (r) {
3249 goto error;
3250 }
3251 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003252
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003253 lyxml_free_elem(module->ctx, sub);
3254 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003255
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003256 /* last part - process data nodes */
3257 LY_TREE_FOR_SAFE(root.child, next, sub) {
3258 if (!strcmp(sub->name, "container")) {
3259 mnode = read_yin_container(module, retval, sub, resolve, unres);
3260 } else if (!strcmp(sub->name, "leaf-list")) {
3261 mnode = read_yin_leaflist(module, retval, sub, resolve);
3262 } else if (!strcmp(sub->name, "leaf")) {
3263 mnode = read_yin_leaf(module, retval, sub, resolve);
3264 } else if (!strcmp(sub->name, "list")) {
3265 mnode = read_yin_list(module, retval, sub, resolve, unres);
3266 } else if (!strcmp(sub->name, "choice")) {
3267 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3268 } else if (!strcmp(sub->name, "uses")) {
3269 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3270 } else if (!strcmp(sub->name, "grouping")) {
3271 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3272 } else if (!strcmp(sub->name, "anyxml")) {
3273 mnode = read_yin_anyxml(module, retval, sub, resolve);
3274 }
3275 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003276
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003277 if (!mnode) {
3278 goto error;
3279 }
3280 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003281
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003282 if (parent && ly_mnode_addchild(parent, retval)) {
3283 goto error;
3284 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003285
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003286 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003287
3288error:
3289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003290 ly_mnode_free(retval);
3291 while (root.child) {
3292 lyxml_free_elem(module->ctx, root.child);
3293 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003295 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003296}
3297
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003298static struct ly_mnode *
3299read_yin_input_output(struct ly_module *module,
3300 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003301{
Radek Krejcie0674f82015-06-15 13:58:51 +02003302 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003303 struct ly_mnode *mnode = NULL;
3304 struct ly_mnode *retval;
3305 struct ly_mnode_input_output *inout;
3306 int r;
3307 int c_tpdf = 0;
3308
Radek Krejcie0674f82015-06-15 13:58:51 +02003309 /* init */
3310 memset(&root, 0, sizeof root);
3311
Michal Vasko38d01f72015-06-15 09:41:06 +02003312 inout = calloc(1, sizeof *inout);
3313
3314 if (!strcmp(yin->name, "input")) {
3315 inout->nodetype = LY_NODE_INPUT;
3316 } else if (!strcmp(yin->name, "output")) {
3317 inout->nodetype = LY_NODE_OUTPUT;
3318 } else {
3319 assert(0);
3320 }
3321
3322 inout->prev = (struct ly_mnode *)inout;
3323 retval = (struct ly_mnode *)inout;
3324
Michal Vaskoebeac942015-06-15 12:11:50 +02003325 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
3326 goto error;
3327 }
3328
Michal Vasko38d01f72015-06-15 09:41:06 +02003329 /* data statements */
3330 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3331 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003332 !strcmp(sub->name, "leaf-list") ||
3333 !strcmp(sub->name, "leaf") ||
3334 !strcmp(sub->name, "list") ||
3335 !strcmp(sub->name, "choice") ||
3336 !strcmp(sub->name, "uses") ||
3337 !strcmp(sub->name, "grouping") ||
3338 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003339 lyxml_unlink_elem(sub);
3340 lyxml_add_child(&root, sub);
3341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003342 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003343 } else if (!strcmp(sub->name, "typedef")) {
3344 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003345#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02003346 } else {
3347 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3348 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003349#else
Michal Vasko38d01f72015-06-15 09:41:06 +02003350 } else {
3351 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003352#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02003353 }
3354 }
3355
3356 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3357 if (c_tpdf) {
3358 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
3359 }
3360
3361 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3362 if (!strcmp(sub->name, "typedef")) {
3363 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
3364 inout->tpdf_size++;
3365
3366 if (r) {
3367 goto error;
3368 }
3369 }
3370
3371 lyxml_free_elem(module->ctx, sub);
3372 }
3373
3374 /* last part - process data nodes */
3375 LY_TREE_FOR_SAFE(root.child, next, sub) {
3376 if (!strcmp(sub->name, "container")) {
3377 mnode = read_yin_container(module, retval, sub, resolve, unres);
3378 } else if (!strcmp(sub->name, "leaf-list")) {
3379 mnode = read_yin_leaflist(module, retval, sub, resolve);
3380 } else if (!strcmp(sub->name, "leaf")) {
3381 mnode = read_yin_leaf(module, retval, sub, resolve);
3382 } else if (!strcmp(sub->name, "list")) {
3383 mnode = read_yin_list(module, retval, sub, resolve, unres);
3384 } else if (!strcmp(sub->name, "choice")) {
3385 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3386 } else if (!strcmp(sub->name, "uses")) {
3387 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3388 } else if (!strcmp(sub->name, "grouping")) {
3389 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3390 } else if (!strcmp(sub->name, "anyxml")) {
3391 mnode = read_yin_anyxml(module, retval, sub, resolve);
3392 }
3393 lyxml_free_elem(module->ctx, sub);
3394
3395 if (!mnode) {
3396 goto error;
3397 }
3398 }
3399
3400 if (parent && ly_mnode_addchild(parent, retval)) {
3401 goto error;
3402 }
3403
3404 return retval;
3405
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003406error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003407
3408 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003409 while (root.child) {
3410 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003411 }
3412
3413 return NULL;
3414}
3415
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003416static struct ly_mnode *
3417read_yin_notif(struct ly_module *module,
3418 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02003419{
Michal Vaskoc6551b32015-06-16 10:51:43 +02003420 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02003421 struct ly_mnode *mnode = NULL;
3422 struct ly_mnode *retval;
3423 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003424 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02003425 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003426 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02003427
Michal Vaskoc6551b32015-06-16 10:51:43 +02003428 memset(&root, 0, sizeof root);
3429
Michal Vasko0ea41032015-06-16 08:53:55 +02003430 notif = calloc(1, sizeof *notif);
3431 notif->nodetype = LY_NODE_NOTIF;
3432 notif->prev = (struct ly_mnode *)notif;
3433 retval = (struct ly_mnode *)notif;
3434
3435 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3436 goto error;
3437 }
3438
3439 /* process rpc's specific children */
3440 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3441 /* data statements */
3442 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003443 !strcmp(sub->name, "leaf-list") ||
3444 !strcmp(sub->name, "leaf") ||
3445 !strcmp(sub->name, "list") ||
3446 !strcmp(sub->name, "choice") ||
3447 !strcmp(sub->name, "uses") ||
3448 !strcmp(sub->name, "grouping") ||
3449 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02003450 lyxml_unlink_elem(sub);
3451 lyxml_add_child(&root, sub);
3452
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003453 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02003454 } else if (!strcmp(sub->name, "typedef")) {
3455 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003456 } else if (!strcmp(sub->name, "if-feature")) {
3457 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003458 } else {
3459 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3460 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02003461 }
3462 }
3463
3464 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3465 if (c_tpdf) {
3466 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3467 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003468 if (c_ftrs) {
3469 notif->features = calloc(c_ftrs, sizeof *notif->features);
3470 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003471
3472 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3473 if (!strcmp(sub->name, "typedef")) {
3474 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3475 notif->tpdf_size++;
3476
3477 if (r) {
3478 goto error;
3479 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003480 } else if (!strcmp(sub->name, "typedef")) {
3481 GETVAL(value, sub, "name");
3482 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3483 if (!notif->features[notif->features_size]) {
3484 goto error;
3485 }
3486 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003487 }
3488
3489 lyxml_free_elem(module->ctx, sub);
3490 }
3491
3492 /* last part - process data nodes */
3493 LY_TREE_FOR_SAFE(root.child, next, sub) {
3494 if (!strcmp(sub->name, "container")) {
3495 mnode = read_yin_container(module, retval, sub, resolve, unres);
3496 } else if (!strcmp(sub->name, "leaf-list")) {
3497 mnode = read_yin_leaflist(module, retval, sub, resolve);
3498 } else if (!strcmp(sub->name, "leaf")) {
3499 mnode = read_yin_leaf(module, retval, sub, resolve);
3500 } else if (!strcmp(sub->name, "list")) {
3501 mnode = read_yin_list(module, retval, sub, resolve, unres);
3502 } else if (!strcmp(sub->name, "choice")) {
3503 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3504 } else if (!strcmp(sub->name, "uses")) {
3505 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3506 } else if (!strcmp(sub->name, "grouping")) {
3507 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3508 } else if (!strcmp(sub->name, "anyxml")) {
3509 mnode = read_yin_anyxml(module, retval, sub, resolve);
3510 }
3511 lyxml_free_elem(module->ctx, sub);
3512
3513 if (!mnode) {
3514 goto error;
3515 }
3516 }
3517
3518 if (parent && ly_mnode_addchild(parent, retval)) {
3519 goto error;
3520 }
3521
3522 return retval;
3523
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003524error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003525
3526 ly_mnode_free(retval);
3527 while (root.child) {
3528 lyxml_free_elem(module->ctx, root.child);
3529 }
3530
3531 return NULL;
3532}
3533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003534static struct ly_mnode *
3535read_yin_rpc(struct ly_module *module,
3536 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003537{
Radek Krejcie0674f82015-06-15 13:58:51 +02003538 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003539 struct ly_mnode *mnode = NULL;
3540 struct ly_mnode *retval;
3541 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003542 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003543 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003544 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003545
Radek Krejcie0674f82015-06-15 13:58:51 +02003546 /* init */
3547 memset(&root, 0, sizeof root);
3548
Michal Vasko38d01f72015-06-15 09:41:06 +02003549 rpc = calloc(1, sizeof *rpc);
3550 rpc->nodetype = LY_NODE_RPC;
3551 rpc->prev = (struct ly_mnode *)rpc;
3552 retval = (struct ly_mnode *)rpc;
3553
3554 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3555 goto error;
3556 }
3557
3558 /* process rpc's specific children */
3559 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3560 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003561 if (rpc->child
3562 && (rpc->child->nodetype == LY_NODE_INPUT
3563 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003564 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3565 goto error;
3566 }
3567 lyxml_unlink_elem(sub);
3568 lyxml_add_child(&root, sub);
3569 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003570 if (rpc->child
3571 && (rpc->child->nodetype == LY_NODE_INPUT
3572 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003573 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3574 goto error;
3575 }
3576 lyxml_unlink_elem(sub);
3577 lyxml_add_child(&root, sub);
3578
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003579 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003580 } else if (!strcmp(sub->name, "grouping")) {
3581 lyxml_unlink_elem(sub);
3582 lyxml_add_child(&root, sub);
3583
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003584 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003585 } else if (!strcmp(sub->name, "typedef")) {
3586 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003587 } else if (!strcmp(sub->name, "if-feature")) {
3588 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003589 } else {
3590 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3591 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003592 }
3593 }
3594
3595 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3596 if (c_tpdf) {
3597 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3598 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003599 if (c_ftrs) {
3600 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3601 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003602
3603 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3604 if (!strcmp(sub->name, "typedef")) {
3605 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3606 rpc->tpdf_size++;
3607
3608 if (r) {
3609 goto error;
3610 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003611 } else if (!strcmp(sub->name, "if-feature")) {
3612 GETVAL(value, sub, "name");
3613 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3614 if (!rpc->features[rpc->features_size]) {
3615 goto error;
3616 }
3617 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003618 }
3619
3620 lyxml_free_elem(module->ctx, sub);
3621 }
3622
3623 /* last part - process data nodes */
3624 LY_TREE_FOR_SAFE(root.child, next, sub) {
3625 if (!strcmp(sub->name, "grouping")) {
3626 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3627 } else if (!strcmp(sub->name, "input")) {
3628 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3629 } else if (!strcmp(sub->name, "output")) {
3630 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3631 }
3632 lyxml_free_elem(module->ctx, sub);
3633
3634 if (!mnode) {
3635 goto error;
3636 }
3637 }
3638
3639 if (parent && ly_mnode_addchild(parent, retval)) {
3640 goto error;
3641 }
3642
3643 return retval;
3644
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003645error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003646
3647 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003648 while (root.child) {
3649 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003650 }
3651
3652 return NULL;
3653}
3654
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003655static int
3656find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003657{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003658 struct ly_module *searchmod = NULL, *module = uses->module;
3659 struct ly_mnode *mnode, *mnode_aux;
3660 const char *name;
3661 int prefix_len = 0;
3662 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003664 /* get referenced grouping */
3665 name = strchr(uses->name, ':');
3666 if (!name) {
3667 /* no prefix, search in local tree */
3668 name = uses->name;
3669 } else {
3670 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003671
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003672 /* set name to correct position after colon */
3673 prefix_len = name - uses->name;
3674 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003675
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003676 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3677 /* prefix refers to the current module, ignore it */
3678 prefix_len = 0;
3679 }
3680 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003682 /* search */
3683 if (prefix_len) {
3684 /* in top-level groupings of some other module */
3685 for (i = 0; i < module->imp_size; i++) {
3686 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3687 && !module->imp[i].prefix[prefix_len]) {
3688 searchmod = module->imp[i].module;
3689 break;
3690 }
3691 }
3692 if (!searchmod) {
3693 /* uses refers unknown data model */
3694 LOGVAL(VE_INPREFIX, line, name);
3695 return EXIT_FAILURE;
3696 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003698 LY_TREE_FOR(searchmod->data, mnode) {
3699 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3700 uses->grp = (struct ly_mnode_grp *)mnode;
3701 return EXIT_SUCCESS;
3702 }
3703 }
3704 } else {
3705 /* in local tree hierarchy */
3706 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3707 LY_TREE_FOR(mnode_aux->child, mnode) {
3708 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3709 uses->grp = (struct ly_mnode_grp *)mnode;
3710 return EXIT_SUCCESS;
3711 }
3712 }
3713 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003715 /* search in top level of the current module */
3716 LY_TREE_FOR(module->data, mnode) {
3717 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3718 uses->grp = (struct ly_mnode_grp *)mnode;
3719 return EXIT_SUCCESS;
3720 }
3721 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003723 /* search in top-level of included modules */
3724 for (i = 0; i < module->inc_size; i++) {
3725 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3726 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3727 uses->grp = (struct ly_mnode_grp *)mnode;
3728 return EXIT_SUCCESS;
3729 }
3730 }
3731 }
3732 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003734 /* not found, but no explicit error occured */
3735 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003736}
3737
Radek Krejcif5be10f2015-06-16 13:29:36 +02003738static int
3739resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3740{
3741 struct lyxml_elem *yin, *next, *sub;
3742 struct ly_mnode *mnode;
3743
3744 assert(module);
3745
3746 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003747 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003748 if (!aug->target) {
3749 LOGVAL(VE_INARG, line, aug->target, "uses");
3750 return EXIT_FAILURE;
3751 }
3752
3753 if (!aug->child) {
3754 /* nothing to do */
3755 return EXIT_SUCCESS;
3756 }
3757
3758 yin = (struct lyxml_elem *)aug->child;
3759
3760 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3761 return EXIT_FAILURE;
3762 }
3763
3764 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3765 if (!strcmp(sub->name, "container")) {
3766 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3767 } else if (!strcmp(sub->name, "leaf-list")) {
3768 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3769 } else if (!strcmp(sub->name, "leaf")) {
3770 mnode = read_yin_leaf(module, aug->target, sub, 1);
3771 } else if (!strcmp(sub->name, "list")) {
3772 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3773 } else if (!strcmp(sub->name, "uses")) {
3774 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3775 } else if (!strcmp(sub->name, "choice")) {
3776 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3777 } else if (!strcmp(sub->name, "case")) {
3778 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3779 } else if (!strcmp(sub->name, "anyxml")) {
3780 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3781#if 0
3782 } else {
3783 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003784 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003785#else
3786 } else {
3787 continue;
3788#endif
3789 }
3790
3791 if (!mnode) {
3792 return EXIT_FAILURE;
3793 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003794 /* check for mandatory nodes - if the target node is in another module
3795 * the added nodes cannot be mandatory
3796 */
3797 if (check_mandatory(mnode)) {
3798 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3799 return EXIT_FAILURE;
3800 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003801
3802 lyxml_free_elem(module->ctx, sub);
3803
3804 /* the parent pointer will point to the augment node, but all
3805 * siblings pointers and possibly the child node in target does
3806 * not know about the augment and follow the standard schema tree
3807 * structure
3808 */
3809 mnode->parent = (struct ly_mnode *)aug;
3810 mnode = NULL;
3811 }
3812
3813 lyxml_free_elem(module->ctx, yin);
3814 aug->child = NULL;
3815
3816 return EXIT_SUCCESS;
3817}
3818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003819int
3820resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003821{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003822 struct ly_ctx *ctx;
3823 struct ly_mnode *mnode = NULL, *mnode_aux;
3824 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02003825 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003826 int i, j;
3827 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003828
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003829 /* copy the data nodes from grouping into the uses context */
3830 LY_TREE_FOR(uses->grp->child, mnode) {
3831 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3832 if (!mnode_aux) {
3833 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3834 return EXIT_FAILURE;
3835 }
3836 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3837 ly_mnode_free(mnode_aux);
3838 return EXIT_FAILURE;
3839 }
3840 }
3841 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003842
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003843 /* apply refines */
3844 for (i = 0; i < uses->refine_size; i++) {
3845 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003846 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003847 if (!mnode) {
3848 LOGVAL(VE_INARG, line, rfn->target, "uses");
3849 return EXIT_FAILURE;
3850 }
Radek Krejci106efc02015-06-10 14:36:27 +02003851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003852 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3853 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3854 return EXIT_FAILURE;
3855 }
Radek Krejci106efc02015-06-10 14:36:27 +02003856
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003857 /* description on any nodetype */
3858 if (rfn->dsc) {
3859 lydict_remove(ctx, mnode->dsc);
3860 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3861 }
Radek Krejci106efc02015-06-10 14:36:27 +02003862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003863 /* reference on any nodetype */
3864 if (rfn->ref) {
3865 lydict_remove(ctx, mnode->ref);
3866 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3867 }
Radek Krejci106efc02015-06-10 14:36:27 +02003868
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003869 /* config on any nodetype */
3870 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3871 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3872 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3873 }
Radek Krejci106efc02015-06-10 14:36:27 +02003874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003875 /* default value ... */
3876 if (rfn->mod.dflt) {
3877 if (mnode->nodetype == LY_NODE_LEAF) {
3878 /* leaf */
3879 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3880 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3881 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3882 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003883 ((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 +02003884 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3885 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3886 return EXIT_FAILURE;
3887 }
3888 }
3889 }
Radek Krejci106efc02015-06-10 14:36:27 +02003890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003891 /* mandatory on leaf, anyxml or choice */
3892 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3893 if (rfn->flags & LY_NODE_MAND_FALSE) {
3894 /* erase mandatory true flag, we don't use false flag in schema nodes */
3895 mnode->flags &= ~LY_NODE_MAND_TRUE;
3896 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3897 /* set mandatory true flag */
3898 mnode->flags |= LY_NODE_MAND_TRUE;
3899 }
3900 }
Radek Krejci106efc02015-06-10 14:36:27 +02003901
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003902 /* presence on container */
3903 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3904 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3905 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3906 }
Radek Krejci106efc02015-06-10 14:36:27 +02003907
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003908 /* min/max-elements on list or leaf-list */
3909 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3910 /* magic - bit 3 in flags means min set, bit 4 says max set */
3911 if (rfn->flags & 0x04) {
3912 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3913 }
3914 if (rfn->flags & 0x08) {
3915 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3916 }
3917 }
Radek Krejci106efc02015-06-10 14:36:27 +02003918
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003919 /* must in leaf, leaf-list, list, container or anyxml */
3920 if (rfn->must_size) {
3921 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3922 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3923 if (!newmust) {
3924 LOGMEM;
3925 return EXIT_FAILURE;
3926 }
3927 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02003928 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003929 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3930 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3931 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3932 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3933 }
Radek Krejci106efc02015-06-10 14:36:27 +02003934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003935 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3936 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3937 }
3938 }
Radek Krejci106efc02015-06-10 14:36:27 +02003939
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003940 /* apply augments */
3941 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003942 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003943 goto error;
3944 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003945 }
Radek Krejci106efc02015-06-10 14:36:27 +02003946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003947 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003948
3949error:
3950
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003951 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003952}
Radek Krejci74705112015-06-05 10:25:44 +02003953
3954/*
3955 * resolve - referenced grouping should be bounded to the namespace (resolved)
3956 * only when uses does not appear in grouping. In a case of grouping's uses,
3957 * we just get information but we do not apply augment or refine to it.
3958 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003959static struct ly_mnode *
3960read_yin_uses(struct ly_module *module,
3961 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003962{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003963 struct lyxml_elem *sub, *next;
3964 struct ly_mnode *retval;
3965 struct ly_mnode_uses *uses;
3966 struct mnode_list *unres_new;
3967 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003968 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003969 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003971 uses = calloc(1, sizeof *uses);
3972 uses->nodetype = LY_NODE_USES;
3973 uses->prev = (struct ly_mnode *)uses;
3974 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003976 GETVAL(value, node, "name");
3977 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003978
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003979 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3980 goto error;
3981 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003982
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003983 /* get other properties of uses */
3984 LY_TREE_FOR_SAFE(node->child, next, sub) {
3985 if (!strcmp(sub->name, "refine")) {
3986 c_ref++;
3987 } else if (!strcmp(sub->name, "augment")) {
3988 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003989 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02003990 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003991 } else if (!strcmp(sub->name, "when")) {
3992 if (uses->when) {
3993 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
3994 goto error;
3995 }
3996
3997 uses->when = read_yin_when(module, sub);
3998 lyxml_free_elem(module->ctx, sub);
3999
4000 if (!uses->when) {
4001 goto error;
4002 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004003 } else {
4004 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4005 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004006 }
4007 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004008
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004009 /* process properties with cardinality 0..n */
4010 if (c_ref) {
4011 uses->refine = calloc(c_ref, sizeof *uses->refine);
4012 }
4013 if (c_aug) {
4014 uses->augment = calloc(c_aug, sizeof *uses->augment);
4015 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004016 if (c_ftrs) {
4017 uses->features = calloc(c_ftrs, sizeof *uses->features);
4018 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004020 LY_TREE_FOR_SAFE(node->child, next, sub) {
4021 if (!strcmp(sub->name, "refine")) {
4022 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
4023 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004024 lyxml_free_elem(module->ctx, sub);
4025 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004026 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
4027 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004028 } else if (!strcmp(sub->name, "if-feature")) {
4029 GETVAL(value, sub, "name");
4030 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
4031 if (!uses->features[uses->features_size]) {
4032 goto error;
4033 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02004034 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004035 uses->features_size++;
4036 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004037 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004039 if (r) {
4040 goto error;
4041 }
4042 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004043
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004044 if (find_grouping(parent, uses, LOGLINE(node))) {
4045 goto error;
4046 }
4047 if (!uses->grp) {
4048 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
4049 unres_new = calloc(1, sizeof *unres_new);
4050 if (*unres) {
4051 unres_new->next = *unres;
4052 }
4053 unres_new->mnode = retval;
4054 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02004055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004056 /* put it at the beginning of the unresolved list */
4057 *unres = unres_new;
4058 }
Radek Krejci74705112015-06-05 10:25:44 +02004059
Radek Krejci368c38f2015-06-15 15:09:55 +02004060 if (parent && ly_mnode_addchild(parent, retval)) {
4061 goto error;
4062 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004063
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004064 if (resolve) {
4065 /* inherit config flag */
4066 if (parent) {
4067 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
4068 } else {
4069 /* default config is true */
4070 retval->flags |= LY_NODE_CONFIG_W;
4071 }
4072 }
Radek Krejcib388c152015-06-04 17:03:03 +02004073
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004074 if (resolve && uses->grp) {
4075 /* copy the data nodes from grouping into the uses context */
4076 if (resolve_uses(uses, LOGLINE(node))) {
4077 goto error;
4078 }
4079 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004081 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004082
4083error:
4084
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004085 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004086
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004087 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004088}
4089
Radek Krejciefaeba32015-05-27 14:30:57 +02004090/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004091static int
4092read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004093{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004094 struct ly_ctx *ctx = module->ctx;
4095 struct ly_submodule *submodule = (struct ly_submodule *)module;
4096 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
4097 struct ly_mnode *mnode = NULL;
4098 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
4099 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004100 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02004101 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004102 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004103 /* counters */
4104 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 +02004105
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004106 /* init */
4107 memset(&root, 0, sizeof root);
4108 memset(&grps, 0, sizeof grps);
4109 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004110 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004111
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004112 /*
4113 * in the first run, we process elements with cardinality of 1 or 0..1 and
4114 * count elements with cardinality 0..n. Data elements (choices, containers,
4115 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4116 * need have all top-level and groupings already prepared at that time. In
4117 * the middle loop, we process other elements with carinality of 0..n since
4118 * we need to allocate arrays to store them.
4119 */
4120 LY_TREE_FOR_SAFE(yin->child, next, node) {
4121 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4122 lyxml_free_elem(ctx, node);
4123 continue;
4124 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004126 if (!module->type && !strcmp(node->name, "namespace")) {
4127 if (module->ns) {
4128 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4129 goto error;
4130 }
4131 GETVAL(value, node, "uri");
4132 module->ns = lydict_insert(ctx, value, strlen(value));
4133 lyxml_free_elem(ctx, node);
4134 } else if (!module->type && !strcmp(node->name, "prefix")) {
4135 if (module->prefix) {
4136 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4137 goto error;
4138 }
4139 GETVAL(value, node, "value");
4140 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4141 goto error;
4142 }
4143 module->prefix = lydict_insert(ctx, value, strlen(value));
4144 lyxml_free_elem(ctx, node);
4145 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4146 if (belongsto_flag) {
4147 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4148 goto error;
4149 }
4150 belongsto_flag = 1;
4151 GETVAL(value, node, "module");
4152 while (submodule->belongsto->type) {
4153 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4154 }
4155 if (value != submodule->belongsto->name) {
4156 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4157 goto error;
4158 }
Radek Krejcif3886932015-06-04 17:36:06 +02004159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004160 /* get the prefix substatement, start with checks */
4161 if (!node->child) {
4162 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4163 goto error;
4164 } else if (strcmp(node->child->name, "prefix")) {
4165 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4166 goto error;
4167 } else if (node->child->next) {
4168 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4169 goto error;
4170 }
4171 /* and now finally get the value */
4172 GETVAL(value, node->child, "value");
4173 /* check here differs from a generic prefix check, since this prefix
4174 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004175 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004176 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4177 goto error;
4178 }
4179 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004180
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004181 /* we are done with belongs-to */
4182 lyxml_free_elem(ctx, node);
4183 } else if (!strcmp(node->name, "import")) {
4184 c_imp++;
4185 } else if (!strcmp(node->name, "revision")) {
4186 c_rev++;
4187 } else if (!strcmp(node->name, "typedef")) {
4188 c_tpdf++;
4189 } else if (!strcmp(node->name, "identity")) {
4190 c_ident++;
4191 } else if (!strcmp(node->name, "include")) {
4192 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004193 } else if (!strcmp(node->name, "augment")) {
4194 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004195 } else if (!strcmp(node->name, "feature")) {
4196 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004197
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004198 /* data statements */
4199 } else if (!strcmp(node->name, "container") ||
4200 !strcmp(node->name, "leaf-list") ||
4201 !strcmp(node->name, "leaf") ||
4202 !strcmp(node->name, "list") ||
4203 !strcmp(node->name, "choice") ||
4204 !strcmp(node->name, "uses") ||
4205 !strcmp(node->name, "anyxml")) {
4206 lyxml_unlink_elem(node);
4207 lyxml_add_child(&root, node);
4208 } else if (!strcmp(node->name, "grouping")) {
4209 /* keep groupings separated and process them before other data statements */
4210 lyxml_unlink_elem(node);
4211 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004213 /* optional statements */
4214 } else if (!strcmp(node->name, "description")) {
4215 if (module->dsc) {
4216 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4217 goto error;
4218 }
4219 module->dsc = read_yin_subnode(ctx, node, "text");
4220 lyxml_free_elem(ctx, node);
4221 if (!module->dsc) {
4222 goto error;
4223 }
4224 } else if (!strcmp(node->name, "reference")) {
4225 if (module->ref) {
4226 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4227 goto error;
4228 }
4229 module->ref = read_yin_subnode(ctx, node, "text");
4230 lyxml_free_elem(ctx, node);
4231 if (!module->ref) {
4232 goto error;
4233 }
4234 } else if (!strcmp(node->name, "organization")) {
4235 if (module->org) {
4236 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4237 goto error;
4238 }
4239 module->org = read_yin_subnode(ctx, node, "text");
4240 lyxml_free_elem(ctx, node);
4241 if (!module->org) {
4242 goto error;
4243 }
4244 } else if (!strcmp(node->name, "contact")) {
4245 if (module->contact) {
4246 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4247 goto error;
4248 }
4249 module->contact = read_yin_subnode(ctx, node, "text");
4250 lyxml_free_elem(ctx, node);
4251 if (!module->contact) {
4252 goto error;
4253 }
4254 } else if (!strcmp(node->name, "yang-version")) {
4255 /* TODO: support YANG 1.1 ? */
4256 if (module->version) {
4257 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4258 goto error;
4259 }
4260 GETVAL(value, node, "value");
4261 if (strcmp(value, "1")) {
4262 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
4263 goto error;
4264 }
4265 module->version = 1;
4266 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02004267
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004268 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02004269 } else if (!strcmp(node->name, "rpc")) {
4270 lyxml_unlink_elem(node);
4271 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02004272 } else if (!strcmp(node->name, "notification")) {
4273 lyxml_unlink_elem(node);
4274 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02004275#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004276 } else {
4277 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
4278 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02004279#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004280 } else {
4281 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02004282#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004283 }
4284 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004285
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004286 if (!submodule) {
4287 /* check for mandatory statements */
4288 if (!module->ns) {
4289 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
4290 goto error;
4291 }
4292 if (!module->prefix) {
4293 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
4294 goto error;
4295 }
4296 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02004297
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004298 /* allocate arrays for elements with cardinality of 0..n */
4299 if (c_imp) {
4300 module->imp = calloc(c_imp, sizeof *module->imp);
4301 }
4302 if (c_rev) {
4303 module->rev = calloc(c_rev, sizeof *module->rev);
4304 }
4305 if (c_tpdf) {
4306 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
4307 }
4308 if (c_ident) {
4309 module->ident = calloc(c_ident, sizeof *module->ident);
4310 }
4311 if (c_inc) {
4312 module->inc = calloc(c_inc, sizeof *module->inc);
4313 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004314 if (c_aug) {
4315 module->augment = calloc(c_aug, sizeof *module->augment);
4316 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004317 if (c_ftrs) {
4318 module->features = calloc(c_ftrs, sizeof *module->features);
4319 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004320
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004321 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4322 LY_TREE_FOR_SAFE(yin->child, next, node) {
4323 if (!strcmp(node->name, "import")) {
4324 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
4325 module->imp_size++;
4326 if (r) {
4327 goto error;
4328 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004330 /* check duplicities in imported modules */
4331 for (i = 0; i < module->imp_size - 1; i++) {
4332 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
4333 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
4334 goto error;
4335 }
4336 }
4337 } else if (!strcmp(node->name, "include")) {
4338 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
4339 module->inc_size++;
4340 if (r) {
4341 goto error;
4342 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004344 /* check duplications in include submodules */
4345 for (i = 0; i < module->inc_size - 1; i++) {
4346 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
4347 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
4348 module->inc[i].submodule->name);
4349 goto error;
4350 }
4351 }
4352 } else if (!strcmp(node->name, "revision")) {
4353 GETVAL(value, node, "date");
4354 if (check_date(value, LOGLINE(node))) {
4355 goto error;
4356 }
4357 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4358 /* check uniqueness of the revision date - not required by RFC */
4359 for (i = 0; i < module->rev_size; i++) {
4360 if (!strcmp(value, module->rev[i].date)) {
4361 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4362 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
4363 }
4364 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004366 LY_TREE_FOR(node->child, child) {
4367 if (!strcmp(child->name, "description")) {
4368 if (module->rev[module->rev_size].dsc) {
4369 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4370 goto error;
4371 }
4372 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
4373 if (!module->rev[module->rev_size].dsc) {
4374 goto error;
4375 }
4376 } else if (!strcmp(child->name, "reference")) {
4377 if (module->rev[module->rev_size].ref) {
4378 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4379 goto error;
4380 }
4381 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
4382 if (!module->rev[module->rev_size].ref) {
4383 goto error;
4384 }
4385 } else {
4386 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
4387 goto error;
4388 }
4389 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004391 /* keep the latest revision at position 0 */
4392 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
4393 /* switch their position */
4394 value = strdup(module->rev[0].date);
4395 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
4396 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4397 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02004398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004399 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
4400 value = module->rev[0].dsc;
4401 module->rev[0].dsc = module->rev[module->rev_size].dsc;
4402 module->rev[module->rev_size].dsc = value;
4403 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004405 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
4406 value = module->rev[0].ref;
4407 module->rev[0].ref = module->rev[module->rev_size].ref;
4408 module->rev[module->rev_size].ref = value;
4409 }
4410 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004412 module->rev_size++;
4413 } else if (!strcmp(node->name, "typedef")) {
4414 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
4415 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004416
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004417 if (r) {
4418 goto error;
4419 }
4420 } else if (!strcmp(node->name, "identity")) {
4421 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
4422 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02004423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004424 if (r) {
4425 goto error;
4426 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004427 } else if (!strcmp(node->name, "feature")) {
4428 r = fill_yin_feature(module, node, &module->features[module->features_size]);
4429 module->features_size++;
4430
4431 if (r) {
4432 goto error;
4433 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004434 } else if (!strcmp(node->name, "augment")) {
4435 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
4436 module->augment_size++;
4437
4438 if (r) {
4439 goto error;
4440 }
4441
4442 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
4443 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004444 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004445
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004446 lyxml_free_elem(ctx, node);
4447 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004448
Radek Krejcif5be10f2015-06-16 13:29:36 +02004449 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004450 * refer to them
4451 */
4452 LY_TREE_FOR_SAFE(grps.child, next, node) {
4453 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
4454 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02004455
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004456 if (!mnode) {
4457 goto error;
4458 }
Radek Krejci74705112015-06-05 10:25:44 +02004459
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004460 /* include data element */
4461 if (module->data) {
4462 module->data->prev->next = mnode;
4463 mnode->prev = module->data->prev;
4464 module->data->prev = mnode;
4465 } else {
4466 module->data = mnode;
4467 }
4468 }
4469 while (unres) {
4470 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4471 goto error;
4472 }
4473 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4474 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4475 goto error;
4476 }
4477 unres_next = unres->next;
4478 free(unres);
4479 unres = unres_next;
4480 }
Radek Krejci74705112015-06-05 10:25:44 +02004481
Radek Krejcif5be10f2015-06-16 13:29:36 +02004482 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004483 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004485 if (!strcmp(node->name, "container")) {
4486 mnode = read_yin_container(module, NULL, node, 1, &unres);
4487 } else if (!strcmp(node->name, "leaf-list")) {
4488 mnode = read_yin_leaflist(module, NULL, node, 1);
4489 } else if (!strcmp(node->name, "leaf")) {
4490 mnode = read_yin_leaf(module, NULL, node, 1);
4491 } else if (!strcmp(node->name, "list")) {
4492 mnode = read_yin_list(module, NULL, node, 1, &unres);
4493 } else if (!strcmp(node->name, "choice")) {
4494 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4495 } else if (!strcmp(node->name, "uses")) {
4496 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4497 } else if (!strcmp(node->name, "anyxml")) {
4498 mnode = read_yin_anyxml(module, NULL, node, 1);
4499 }
4500 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004502 if (!mnode) {
4503 goto error;
4504 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004505
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004506 /* include data element */
4507 if (module->data) {
4508 module->data->prev->next = mnode;
4509 mnode->prev = module->data->prev;
4510 module->data->prev = mnode;
4511 } else {
4512 module->data = mnode;
4513 }
4514 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004515
4516 /* ... rpcs ... */
4517 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4518 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4519 lyxml_free_elem(ctx, node);
4520
4521 if (!mnode) {
4522 goto error;
4523 }
4524
4525 /* include rpc element */
4526 if (module->rpc) {
4527 module->rpc->prev->next = mnode;
4528 mnode->prev = module->rpc->prev;
4529 module->rpc->prev = mnode;
4530 } else {
4531 module->rpc = mnode;
4532 }
4533 }
4534
4535 /* ... and notifications */
4536 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4537 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4538 lyxml_free_elem(ctx, node);
4539
4540 if (!mnode) {
4541 goto error;
4542 }
4543
4544 /* include notification element */
4545 if (module->notif) {
4546 module->notif->prev->next = mnode;
4547 mnode->prev = module->notif->prev;
4548 module->notif->prev = mnode;
4549 } else {
4550 module->notif = mnode;
4551 }
4552 }
4553
4554 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004555 while (unres) {
4556 /* find referenced grouping */
4557 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4558 goto error;
4559 }
4560 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4561 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4562 goto error;
4563 }
Radek Krejci74705112015-06-05 10:25:44 +02004564
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004565 /* resolve uses by copying grouping content under the uses */
4566 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4567 goto error;
4568 }
Radek Krejci74705112015-06-05 10:25:44 +02004569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004570 unres_next = unres->next;
4571 free(unres);
4572 unres = unres_next;
4573 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004574
Radek Krejcif5be10f2015-06-16 13:29:36 +02004575 /* and finally apply augments */
4576 for (i = 0; i < module->augment_size; i++) {
4577 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004578 goto error;
4579 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004580 }
4581
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004582 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004583
4584error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004585 /* cleanup */
4586 while (root.child) {
4587 lyxml_free_elem(module->ctx, root.child);
4588 }
4589 while (grps.child) {
4590 lyxml_free_elem(module->ctx, grps.child);
4591 }
4592 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004593 lyxml_free_elem(module->ctx, rpcs.child);
4594 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004596 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004597}
4598
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004599struct ly_submodule *
4600yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004601{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004602 struct lyxml_elem *yin;
4603 struct ly_submodule *submodule = NULL;
4604 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004606 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004607
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004608 yin = lyxml_read(module->ctx, data, 0);
4609 if (!yin) {
4610 return NULL;
4611 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004613 /* check root element */
4614 if (!yin->name || strcmp(yin->name, "submodule")) {
4615 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4616 goto error;
4617 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004619 GETVAL(value, yin, "name");
4620 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4621 goto error;
4622 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004623
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004624 submodule = calloc(1, sizeof *submodule);
4625 if (!submodule) {
4626 LOGMEM;
4627 goto error;
4628 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004629
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004630 submodule->ctx = module->ctx;
4631 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4632 submodule->type = 1;
4633 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004635 LOGVRB("reading submodule %s", submodule->name);
4636 if (read_sub_module((struct ly_module *)submodule, yin)) {
4637 goto error;
4638 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004639
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004640 /* cleanup */
4641 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004642
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004643 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004644
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004645 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004646
4647error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004648 /* cleanup */
4649 lyxml_free_elem(module->ctx, yin);
4650 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004652 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004653}
4654
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004655struct ly_module *
4656yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004657{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004658 struct lyxml_elem *yin;
4659 struct ly_module *module = NULL, **newlist = NULL;
4660 const char *value;
4661 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004663 yin = lyxml_read(ctx, data, 0);
4664 if (!yin) {
4665 return NULL;
4666 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004667
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004668 /* check root element */
4669 if (!yin->name || strcmp(yin->name, "module")) {
4670 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4671 goto error;
4672 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004674 GETVAL(value, yin, "name");
4675 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4676 goto error;
4677 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004679 module = calloc(1, sizeof *module);
4680 if (!module) {
4681 LOGMEM;
4682 goto error;
4683 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004684
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004685 module->ctx = ctx;
4686 module->name = lydict_insert(ctx, value, strlen(value));
4687 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004688
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004689 LOGVRB("reading module %s", module->name);
4690 if (read_sub_module(module, yin)) {
4691 goto error;
4692 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004693
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004694 /* add to the context's list of modules */
4695 if (ctx->models.used == ctx->models.size) {
4696 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4697 if (!newlist) {
4698 LOGMEM;
4699 goto error;
4700 }
4701 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4702 newlist[i] = NULL;
4703 }
4704 ctx->models.size *= 2;
4705 ctx->models.list = newlist;
4706 }
4707 for (i = 0; ctx->models.list[i]; i++) {
4708 /* check name (name/revision) and namespace uniqueness */
4709 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4710 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4711 /* both data models are same, with no revision specified */
4712 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4713 module->name);
4714 goto error;
4715 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4716 /* one of the models does not have a revision, so they differs */
4717 continue;
4718 } else {
4719 /* both models have a revision statement which we have to
4720 * compare, revision at position 0 is the last revision
4721 */
4722 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4723 /* we have the same modules */
4724 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4725 module->rev[0].date);
4726 goto error;
4727 }
4728 }
4729 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4730 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4731 ctx->models.list[i]->name, module->name, module->ns);
4732 goto error;
4733 }
4734 }
4735 ctx->models.list[i] = module;
4736 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004738 /* cleanup */
4739 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004741 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004743 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004744
4745error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004746 /* cleanup */
4747 lyxml_free_elem(ctx, yin);
4748 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004750 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004751}