blob: 1f8dc8f8fdfa722a9c9f79eacc94f43d45c96fa6 [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) {
867 /* this is just a derived type with no bit specified */
868 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:
937 /* TODO fraction-digits, 9.3.4
938 * - MUST, 1, nerekurzivni, hodnota 1-18 */
939 /* TODO range, 9.2.4
940 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
941 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200942
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200943 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200944 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200945
Radek Krejci994b6f62015-06-18 16:47:27 +0200946 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200947 LY_TREE_FOR_SAFE(yin->child, next, node) {
948 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200949 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200950 } else {
951 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
952 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200953 }
954 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200955 if (!type->info.enums.count) {
956 if (type->der->type.der) {
957 /* this is just a derived type with no enum specified */
958 break;
959 }
960 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
961 goto error;
962 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200963
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200964 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200965 for (i = v = 0; yin->child; i++) {
966 GETVAL(value, yin->child, "name");
967 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200968 goto error;
969 }
970 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200971 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200972 type->info.enums.count = i + 1;
973 goto error;
974 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200976 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
977 value = type->info.enums.list[i].name;
978 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200979 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200980 type->info.enums.count = i + 1;
981 goto error;
982 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200983
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200984 /* check the name uniqueness */
985 for (j = 0; j < i; j++) {
986 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200987 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200988 type->info.enums.count = i + 1;
989 goto error;
990 }
991 }
Radek Krejci04581c62015-05-22 21:24:00 +0200992
Radek Krejci5fbc9162015-06-19 14:11:11 +0200993 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200994 if (node && !strcmp(node->name, "value")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +0200995 GETVAL(value, node, "value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200996 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200998 /* range check */
999 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1000 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1001 type->info.enums.count = i + 1;
1002 goto error;
1003 }
1004 type->info.enums.list[i].value = v_;
1005
1006 /* keep the highest enum value for automatic increment */
1007 if (type->info.enums.list[i].value > v) {
1008 v = type->info.enums.list[i].value;
1009 v++;
1010 } else {
1011 /* check that the value is unique */
1012 for (j = 0; j < i; j++) {
1013 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001014 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 +02001015 type->info.enums.count = i + 1;
1016 goto error;
1017 }
1018 }
1019 }
1020 } else {
1021 /* assign value automatically */
1022 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001023 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001024 type->info.enums.count = i + 1;
1025 goto error;
1026 }
1027 type->info.enums.list[i].value = v;
1028 v++;
1029 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001030 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001031 }
1032 break;
1033
1034 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001035 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001036
1037 /* get base specification, exactly one must be present */
1038 if (!yin->child) {
1039 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1040 goto error;
1041 }
1042 if (strcmp(yin->child->name, "base")) {
1043 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1044 goto error;
1045 }
1046 if (yin->child->next) {
1047 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1048 goto error;
1049 }
1050 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1051 if (!type->info.ident.ref) {
1052 return EXIT_FAILURE;
1053 }
1054 break;
1055
1056 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001057 /* RFC 6020 9.13.2 - require-instance */
1058 LY_TREE_FOR_SAFE(yin->child, next, node) {
1059 if (!strcmp(node->name, "require-instance")) {
1060 if (type->info.inst.req) {
1061 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1062 goto error;
1063 }
1064 GETVAL(value, node, "value");
1065 if (strcmp(value, "true")) {
1066 type->info.inst.req = 1;
1067 } else if (strcmp(value, "false")) {
1068 type->info.inst.req = -1;
1069 } else {
1070 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1071 goto error;
1072 }
1073 } else {
1074 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1075 goto error;
1076 }
1077 lyxml_free_elem(module->ctx, node);
1078 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001079 break;
1080
Radek Krejcif2860132015-06-20 12:37:20 +02001081 case LY_TYPE_BINARY:
1082 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001083 case LY_TYPE_INT8:
1084 case LY_TYPE_INT16:
1085 case LY_TYPE_INT32:
1086 case LY_TYPE_INT64:
1087 case LY_TYPE_UINT8:
1088 case LY_TYPE_UINT16:
1089 case LY_TYPE_UINT32:
1090 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001091 /* RFC 6020 9.2.4 - range */
1092
1093 /* length and range are actually the same restriction, so process
1094 * them by this common code, we just need to differ the name and
1095 * structure where the information will be stored
1096 */
1097 if (type->base == LY_TYPE_BINARY) {
1098 restr = &type->info.binary.length;
1099 name = "length";
1100 } else {
1101 restr = &type->info.num.range;
1102 name = "range";
1103 }
1104
1105 LY_TREE_FOR_SAFE(yin->child, next, node) {
1106 if (!strcmp(node->name, name)) {
1107 if (*restr) {
1108 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1109 goto error;
1110 }
1111
1112 GETVAL(value, node, "value");
1113 if (check_length(value, type, LOGLINE(node))) {
1114 goto error;
1115 }
1116 *restr = calloc(1, sizeof **restr);
1117 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1118
1119 /* get possible substatements */
1120 if (read_restr_substmt(module->ctx, *restr, node)) {
1121 goto error;
1122 }
1123 } else {
1124 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1125 goto error;
1126 }
1127 lyxml_free_elem(module->ctx, node);
1128 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001129 break;
1130
1131 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001132 /* RFC 6020 9.9.2 - path */
1133 if (!yin->child) {
1134 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1135 goto error;
1136 }
1137 LY_TREE_FOR_SAFE(yin->child, next, node) {
1138 if (!strcmp(node->name, "path")) {
1139 if (type->info.lref.path) {
1140 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1141 goto error;
1142 }
1143
1144 GETVAL(value, node, "value");
1145 /* TODO
1146 * it would be nice to perform here a check that target is leaf or leaf-list,
1147 * but schema is not finnished yet and path can point almost to anywhere, so
1148 * we will have to check the path at the end of parsing the schema.
1149 */
1150 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1151 } else {
1152 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1153 goto error;
1154 }
1155 lyxml_free_elem(module->ctx, node);
1156 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001157 break;
1158
1159 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001160 /* RFC 6020 9.4.4 - length */
1161 /* RFC 6020 9.4.6 - pattern */
1162 LY_TREE_FOR_SAFE(yin->child, next, node) {
1163 if (!strcmp(node->name, "length")) {
1164 if (type->info.str.length) {
1165 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1166 goto error;
1167 }
1168
1169 GETVAL(value, node, "value");
1170 if (check_length(value, type, LOGLINE(node))) {
1171 goto error;
1172 }
1173 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1174 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1175
Radek Krejci5fbc9162015-06-19 14:11:11 +02001176 /* get possible sub-statements */
1177 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001178 goto error;
1179 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001180 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001181 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001182 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001183 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001184 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001185 goto error;
1186 }
1187 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001188 /* store patterns in array */
1189 if (type->info.str.pat_count) {
1190 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1191 for (i = 0; yin->child; i++) {
1192 GETVAL(value, yin->child, "value");
1193 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1194
1195 /* get possible sub-statements */
1196 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1197 goto error;
1198 }
1199 lyxml_free_elem(module->ctx, yin->child);
1200 }
1201 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001202 break;
1203
1204 case LY_TYPE_UNION:
1205 /* TODO type, 7.4
1206 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1207 break;
1208
1209 default:
1210 /* nothing needed :
1211 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1212 */
1213 break;
1214 }
1215
1216 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001217
1218error:
1219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001220 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001221}
1222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001223static int
1224fill_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 +02001225{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001226 const char *value;
1227 struct lyxml_elem *node, *next;
1228 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001230 GETVAL(value, yin, "name");
1231 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1232 goto error;
1233 }
1234 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001236 /* generic part - status, description, reference */
1237 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1238 goto error;
1239 }
Radek Krejcieac35532015-05-31 19:09:15 +02001240
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001241 LY_TREE_FOR_SAFE(yin->child, next, node) {
1242 if (!strcmp(node->name, "type")) {
1243 if (tpdf->type.der) {
1244 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1245 goto error;
1246 }
1247 r = fill_yin_type(module, parent, node, &tpdf->type);
1248 } else if (!strcmp(node->name, "default")) {
1249 if (tpdf->dflt) {
1250 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1251 goto error;
1252 }
1253 GETVAL(value, node, "value");
1254 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1255 } else if (!strcmp(node->name, "units")) {
1256 if (tpdf->units) {
1257 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1258 goto error;
1259 }
1260 GETVAL(value, node, "name");
1261 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1262 } else {
1263 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1264 r = 1;
1265 }
1266 lyxml_free_elem(module->ctx, node);
1267 if (r) {
1268 goto error;
1269 }
1270 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001271
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001272 /* check mandatory value */
1273 if (!tpdf->type.der) {
1274 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1275 goto error;
1276 }
Radek Krejcieac35532015-05-31 19:09:15 +02001277
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001278 /* check default value */
1279 if (check_default(&tpdf->type, tpdf->dflt)) {
1280 goto error;
1281 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001283 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001284
1285error:
1286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001287 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001288}
1289
Radek Krejci3cf9e222015-06-18 11:37:50 +02001290static struct ly_feature *
1291resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1292{
1293 const char *prefix;
1294 unsigned int prefix_len = 0;
1295 int i, j, found = 0;
1296
1297 assert(name);
1298 assert(module);
1299
1300 /* check prefix */
1301 prefix = name;
1302 name = strchr(prefix, ':');
1303 if (name) {
1304 /* there is prefix */
1305 prefix_len = name - prefix;
1306 name++;
1307
1308 /* check whether the prefix points to the current module */
1309 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1310 /* then ignore prefix and works as there is no prefix */
1311 prefix_len = 0;
1312 }
1313 } else {
1314 /* no prefix, set pointers correctly */
1315 name = prefix;
1316 }
1317
1318 if (prefix_len) {
1319 /* search in imported modules */
1320 for (i = 0; i < module->imp_size; i++) {
1321 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1322 module = module->imp[i].module;
1323 found = 1;
1324 break;
1325 }
1326 }
1327 if (!found) {
1328 /* identity refers unknown data model */
1329 LOGVAL(VE_INPREFIX, line, prefix);
1330 return NULL;
1331 }
1332 } else {
1333 /* search in submodules */
1334 for (i = 0; i < module->inc_size; i++) {
1335 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1336 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1337 return &(module->inc[i].submodule->features[j]);
1338 }
1339 }
1340 }
1341 }
1342
1343 /* search in the identified module */
1344 for (j = 0; j < module->features_size; j++) {
1345 if (!strcmp(name, module->features[j].name)) {
1346 return &module->features[j];
1347 }
1348 }
1349
1350 /* not found */
1351 return NULL;
1352}
1353
1354static int
1355fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1356{
1357 const char *value;
1358 struct lyxml_elem *child, *next;
1359 int c = 0;
1360
Radek Krejcib05774c2015-06-18 13:52:59 +02001361 GETVAL(value, yin, "name");
1362 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1363 goto error;
1364 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001365 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001366
Radek Krejci7e97c352015-06-19 16:26:34 +02001367 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, OPT_MODULE)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001368 goto error;
1369 }
1370
1371 LY_TREE_FOR_SAFE(yin->child, next, child) {
1372 if (!strcmp(child->name, "if-feature")) {
1373 c++;
1374 } else {
1375 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1376 goto error;
1377 }
1378 }
1379
1380 if (c) {
1381 f->features = calloc(c, sizeof *f->features);
1382 }
1383
1384 LY_TREE_FOR_SAFE(yin->child, next, child) {
1385 GETVAL(value, child, "name");
1386 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1387 if (!f->features[f->features_size]) {
1388 goto error;
1389 }
1390 f->features_size++;
1391 }
1392
Radek Krejci3cf9e222015-06-18 11:37:50 +02001393 return EXIT_SUCCESS;
1394
1395error:
1396
1397 return EXIT_FAILURE;
1398}
1399
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001400static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001401fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001402{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001403 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001405 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001406 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001407
Radek Krejci41726f92015-06-19 13:11:05 +02001408 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001409
Radek Krejci41726f92015-06-19 13:11:05 +02001410error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001412 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001413}
1414
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001415static int
1416fill_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 +02001417{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001418 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001419 struct lyxml_elem *next, *child;
1420 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001421
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001422 GETVAL(value, yin, "target-node");
1423 aug->target_name = lydict_insert(module->ctx, value, 0);
1424 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001425
Radek Krejci3cf9e222015-06-18 11:37:50 +02001426 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1427 goto error;
1428 }
1429
1430 LY_TREE_FOR_SAFE(yin->child, next, child) {
1431 if (!strcmp(child->name, "if-feature")) {
1432 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001433 } else if (!strcmp(child->name, "when")) {
1434 if (aug->when) {
1435 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1436 goto error;
1437 }
1438
1439 aug->when = read_yin_when(module, child);
1440 lyxml_free_elem(module->ctx, child);
1441
1442 if (!aug->when) {
1443 goto error;
1444 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001445
1446 /* check allowed sub-statements */
1447 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1448 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1449 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1450 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1451 goto error;
1452 }
1453 }
1454
1455 if (c) {
1456 aug->features = calloc(c, sizeof *aug->features);
1457 }
1458
1459 LY_TREE_FOR_SAFE(yin->child, next, child) {
1460 if (!strcmp(child->name, "if-feature")) {
1461 GETVAL(value, child, "name");
1462 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1463 if (!aug->features[aug->features_size]) {
1464 goto error;
1465 }
1466 aug->features_size++;
1467 } else {
1468 /* keep the data nodes */
1469 continue;
1470 }
1471
1472 lyxml_free_elem(module->ctx, child);
1473 }
1474
1475 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001476 * when we will have the target node
1477 */
1478 lyxml_unlink_elem(yin);
1479 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001481 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001482
1483error:
1484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001485 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001486}
1487
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001488static int
1489fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001490{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001491 struct lyxml_elem *sub, *next;
1492 const char *value;
1493 char *endptr;
1494 int f_mand = 0, f_min = 0, f_max = 0;
1495 int c_must = 0;
1496 int r;
1497 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001499 GETVAL(value, yin, "target-node");
1500 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001502 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1503 goto error;
1504 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001505
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001506 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1507 /* limited applicability */
1508 if (!strcmp(sub->name, "default")) {
1509 /* leaf or choice */
1510 if (rfn->mod.dflt) {
1511 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1512 goto error;
1513 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001514
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001515 /* check possibility of statements combination */
1516 if (rfn->target_type) {
1517 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1518 if (!rfn->target_type) {
1519 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1520 goto error;
1521 }
1522 } else {
1523 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1524 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001526 GETVAL(value, sub, "value");
1527 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1528 } else if (!strcmp(sub->name, "mandatory")) {
1529 /* leaf, choice or anyxml */
1530 if (f_mand) {
1531 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1532 goto error;
1533 }
1534 /* just checking the flags in leaf is not sufficient, we would allow
1535 * multiple mandatory statements with the "false" value
1536 */
1537 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001539 /* check possibility of statements combination */
1540 if (rfn->target_type) {
1541 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1542 if (!rfn->target_type) {
1543 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1544 goto error;
1545 }
1546 } else {
1547 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1548 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001549
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001550 GETVAL(value, sub, "value");
1551 if (!strcmp(value, "true")) {
1552 rfn->flags |= LY_NODE_MAND_TRUE;
1553 } else if (!strcmp(value, "false")) {
1554 rfn->flags |= LY_NODE_MAND_FALSE;
1555 } else {
1556 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1557 goto error;
1558 }
1559 } else if (!strcmp(sub->name, "min-elements")) {
1560 /* list or leaf-list */
1561 if (f_min) {
1562 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1563 goto error;
1564 }
1565 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001567 /* check possibility of statements combination */
1568 if (rfn->target_type) {
1569 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1570 if (!rfn->target_type) {
1571 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1572 goto error;
1573 }
1574 } else {
1575 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1576 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001578 GETVAL(value, sub, "value");
1579 while (isspace(value[0])) {
1580 value++;
1581 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001582
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001583 /* convert it to uint32_t */
1584 errno = 0;
1585 endptr = NULL;
1586 val = strtoul(value, &endptr, 10);
1587 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1588 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1589 goto error;
1590 }
1591 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001593 /* magic - bit 3 in flags means min set */
1594 rfn->flags |= 0x04;
1595 } else if (!strcmp(sub->name, "max-elements")) {
1596 /* list or leaf-list */
1597 if (f_max) {
1598 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1599 goto error;
1600 }
1601 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001602
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001603 /* check possibility of statements combination */
1604 if (rfn->target_type) {
1605 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1606 if (!rfn->target_type) {
1607 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1608 goto error;
1609 }
1610 } else {
1611 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1612 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001613
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001614 GETVAL(value, sub, "value");
1615 while (isspace(value[0])) {
1616 value++;
1617 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001619 /* convert it to uint32_t */
1620 errno = 0;
1621 endptr = NULL;
1622 val = strtoul(value, &endptr, 10);
1623 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1624 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1625 goto error;
1626 }
1627 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001628
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001629 /* magic - bit 4 in flags means min set */
1630 rfn->flags |= 0x08;
1631 } else if (!strcmp(sub->name, "presence")) {
1632 /* container */
1633 if (rfn->mod.presence) {
1634 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1635 goto error;
1636 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001637
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001638 /* check possibility of statements combination */
1639 if (rfn->target_type) {
1640 rfn->target_type &= LY_NODE_CONTAINER;
1641 if (!rfn->target_type) {
1642 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1643 goto error;
1644 }
1645 } else {
1646 rfn->target_type = LY_NODE_CONTAINER;
1647 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001649 GETVAL(value, sub, "value");
1650 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1651 } else if (!strcmp(sub->name, "must")) {
1652 /* leaf-list, list, container or anyxml */
1653 /* check possibility of statements combination */
1654 if (rfn->target_type) {
1655 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1656 if (!rfn->target_type) {
1657 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1658 goto error;
1659 }
1660 } else {
1661 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1662 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001664 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001665
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001666 } else {
1667 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1668 goto error;
1669 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001670
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001671 lyxml_free_elem(module->ctx, sub);
1672 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001674 /* process nodes with cardinality of 0..n */
1675 if (c_must) {
1676 rfn->must = calloc(c_must, sizeof *rfn->must);
1677 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001679 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1680 if (!strcmp(sub->name, "must")) {
1681 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1682 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001683
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001684 if (r) {
1685 goto error;
1686 }
1687 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001688
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001689 lyxml_free_elem(module->ctx, sub);
1690 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001692 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001693
1694error:
1695
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001696 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001697}
1698
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001699static int
1700fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001701{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001702 struct lyxml_elem *child;
1703 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001704
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001705 LY_TREE_FOR(yin->child, child) {
1706 if (!strcmp(child->name, "prefix")) {
1707 GETVAL(value, child, "value");
1708 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1709 goto error;
1710 }
1711 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1712 } else if (!strcmp(child->name, "revision-date")) {
1713 if (imp->rev[0]) {
1714 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1715 goto error;
1716 }
1717 GETVAL(value, child, "date");
1718 if (check_date(value, LOGLINE(child))) {
1719 goto error;
1720 }
1721 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1722 } else {
1723 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1724 goto error;
1725 }
1726 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001728 /* check mandatory information */
1729 if (!imp->prefix) {
1730 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1731 goto error;
1732 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001734 GETVAL(value, yin, "module");
1735 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1736 if (!imp->module) {
1737 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1738 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1739 goto error;
1740 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001741
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001742 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001743
1744error:
1745
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001746 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001747}
1748
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001749static int
1750fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001751{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001752 struct lyxml_elem *child;
1753 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001754
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001755 LY_TREE_FOR(yin->child, child) {
1756 if (!strcmp(child->name, "revision-date")) {
1757 if (inc->rev[0]) {
1758 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1759 goto error;
1760 }
1761 GETVAL(value, child, "date");
1762 if (check_date(value, LOGLINE(child))) {
1763 goto error;
1764 }
1765 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1766 } else {
1767 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1768 goto error;
1769 }
1770 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001771
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001772 GETVAL(value, yin, "module");
1773 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1774 if (!inc->submodule) {
1775 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1776 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1777 goto error;
1778 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001779
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001780 /* check that belongs-to corresponds */
1781 if (module->type) {
1782 module = ((struct ly_submodule *)module)->belongsto;
1783 }
1784 if (inc->submodule->belongsto != module) {
1785 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1786 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1787 goto error;
1788 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001790 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001791
1792error:
1793
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001794 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001795}
1796
Radek Krejcida04f4a2015-05-21 12:54:09 +02001797/*
1798 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001799 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001800 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001801 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001802static int
1803read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1804 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001805{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001806 const char *value;
1807 struct lyxml_elem *sub, *next;
1808 struct ly_ctx *const ctx = module->ctx;
1809 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001810
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001811 if (opt & OPT_MODULE) {
1812 mnode->module = module;
1813 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001815 if (opt & OPT_IDENT) {
1816 GETVAL(value, xmlnode, "name");
1817 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1818 goto error;
1819 }
1820 mnode->name = lydict_insert(ctx, value, strlen(value));
1821 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001822
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001823 /* process local parameters */
1824 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1825 if (!strcmp(sub->name, "description")) {
1826 if (mnode->dsc) {
1827 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1828 goto error;
1829 }
1830 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1831 if (!mnode->dsc) {
1832 r = 1;
1833 }
1834 } else if (!strcmp(sub->name, "reference")) {
1835 if (mnode->ref) {
1836 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1837 goto error;
1838 }
1839 mnode->ref = read_yin_subnode(ctx, sub, "text");
1840 if (!mnode->ref) {
1841 r = 1;
1842 }
1843 } else if (!strcmp(sub->name, "status")) {
1844 if (mnode->flags & LY_NODE_STATUS_MASK) {
1845 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1846 goto error;
1847 }
1848 GETVAL(value, sub, "value");
1849 if (!strcmp(value, "current")) {
1850 mnode->flags |= LY_NODE_STATUS_CURR;
1851 } else if (!strcmp(value, "deprecated")) {
1852 mnode->flags |= LY_NODE_STATUS_DEPRC;
1853 } else if (!strcmp(value, "obsolete")) {
1854 mnode->flags |= LY_NODE_STATUS_OBSLT;
1855 } else {
1856 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1857 r = 1;
1858 }
1859 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1860 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1861 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1862 goto error;
1863 }
1864 GETVAL(value, sub, "value");
1865 if (!strcmp(value, "false")) {
1866 mnode->flags |= LY_NODE_CONFIG_R;
1867 } else if (!strcmp(value, "true")) {
1868 mnode->flags |= LY_NODE_CONFIG_W;
1869 } else {
1870 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1871 r = 1;
1872 }
1873 } else {
1874 /* skip the lyxml_free_elem */
1875 continue;
1876 }
1877 lyxml_free_elem(ctx, sub);
1878 if (r) {
1879 goto error;
1880 }
1881 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001882
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001883 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1884 /* get config flag from parent */
1885 if (parent) {
1886 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1887 } else {
1888 /* default config is true */
1889 mnode->flags |= LY_NODE_CONFIG_W;
1890 }
1891 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001892
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001893 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001894
1895error:
1896
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001897 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001898}
1899
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001900static struct ly_when *
1901read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
1902{
Radek Krejci53ebfb12015-06-19 09:35:59 +02001903 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001904 struct lyxml_elem *next, *child;
1905 const char *value;
1906
1907 retval = calloc(1, sizeof *retval);
1908
1909 GETVAL(value, yin, "condition");
1910 retval->cond = lydict_insert(module->ctx, value, 0);
1911
1912 LY_TREE_FOR_SAFE(yin->child, next, child) {
1913 if (!strcmp(child->name, "description")) {
1914 if (retval->dsc) {
1915 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1916 goto error;
1917 }
1918 retval->dsc = read_yin_subnode(module->ctx, child, "text");
1919 if (!retval->dsc) {
1920 goto error;
1921 }
1922 } else if (!strcmp(child->name, "reference")) {
1923 if (retval->ref) {
1924 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1925 goto error;
1926 }
1927 retval->ref = read_yin_subnode(module->ctx, child, "text");
1928 if (!retval->ref) {
1929 goto error;
1930 }
1931 } else {
1932 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1933 goto error;
1934 }
1935
1936 lyxml_free_elem(module->ctx, child);
1937 }
1938
1939 return retval;
1940
1941error:
1942
Radek Krejci53ebfb12015-06-19 09:35:59 +02001943 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001944 return NULL;
1945}
1946
Radek Krejcib4cf2022015-06-03 14:40:05 +02001947/* additional check in case statement - the child must be unique across
1948 * all other case names and its data children
1949 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001950static int
1951check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001952{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001953 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001954
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001955 if (new->nodetype == LY_NODE_CHOICE) {
1956 /* we have nested choice in case, so we need recursion */
1957 LY_TREE_FOR(new->child, mnode) {
1958 if (mnode->nodetype == LY_NODE_CASE) {
1959 LY_TREE_FOR(mnode->child, submnode) {
1960 if (check_branch_id(parent, submnode, new, line)) {
1961 return EXIT_FAILURE;
1962 }
1963 }
1964 } else if (check_branch_id(parent, mnode, new, line)) {
1965 return EXIT_FAILURE;
1966 }
1967 }
1968 } else {
1969 LY_TREE_FOR(parent->child, mnode) {
1970 if (mnode == excl) {
1971 continue;
1972 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001973
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001974 if (!strcmp(new->name, mnode->name)) {
1975 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1976 return EXIT_FAILURE;
1977 }
1978 if (mnode->nodetype == LY_NODE_CASE) {
1979 LY_TREE_FOR(mnode->child, submnode) {
1980 if (!strcmp(new->name, submnode->name)) {
1981 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1982 return EXIT_FAILURE;
1983 }
1984 }
1985 }
1986 }
1987 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001989 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001990}
1991
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001992static struct ly_mnode *
1993read_yin_case(struct ly_module *module,
1994 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001995{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001996 struct lyxml_elem *sub, *next;
1997 struct ly_mnode_case *mcase;
1998 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001999 int c_ftrs = 0;
2000 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002002 mcase = calloc(1, sizeof *mcase);
2003 mcase->nodetype = LY_NODE_CASE;
2004 mcase->prev = (struct ly_mnode *)mcase;
2005 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002006
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002007 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
2008 goto error;
2009 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002011 /* process choice's specific children */
2012 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2013 if (!strcmp(sub->name, "container")) {
2014 mnode = read_yin_container(module, retval, sub, resolve, unres);
2015 } else if (!strcmp(sub->name, "leaf-list")) {
2016 mnode = read_yin_leaflist(module, retval, sub, resolve);
2017 } else if (!strcmp(sub->name, "leaf")) {
2018 mnode = read_yin_leaf(module, retval, sub, resolve);
2019 } else if (!strcmp(sub->name, "list")) {
2020 mnode = read_yin_list(module, retval, sub, resolve, unres);
2021 } else if (!strcmp(sub->name, "uses")) {
2022 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2023 } else if (!strcmp(sub->name, "choice")) {
2024 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2025 } else if (!strcmp(sub->name, "anyxml")) {
2026 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002027 } else if (!strcmp(sub->name, "if-feature")) {
2028 c_ftrs++;
2029
2030 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
2031 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002032 } else if (!strcmp(sub->name, "when")) {
2033 if (mcase->when) {
2034 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2035 goto error;
2036 }
2037
2038 mcase->when = read_yin_when(module, sub);
2039 if (!mcase->when) {
2040 goto error;
2041 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002042 } else {
2043 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2044 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002045 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002046
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002047 if (!mnode) {
2048 goto error;
2049 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
2050 goto error;
2051 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002052
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002053 mnode = NULL;
2054 lyxml_free_elem(module->ctx, sub);
2055 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002056
Radek Krejci3cf9e222015-06-18 11:37:50 +02002057 if (c_ftrs) {
2058 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2059 }
2060 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2061 GETVAL(value, sub, "name");
2062 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2063 if (!mcase->features[mcase->features_size]) {
2064 goto error;
2065 }
2066 mcase->features_size++;
2067 lyxml_free_elem(module->ctx, sub);
2068 }
2069
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002070 /* inherit config flag */
2071 if (parent) {
2072 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2073 } else {
2074 /* default config is true */
2075 retval->flags |= LY_NODE_CONFIG_W;
2076 }
Radek Krejcib388c152015-06-04 17:03:03 +02002077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002078 /* insert the node into the schema tree */
2079 if (ly_mnode_addchild(parent, retval)) {
2080 goto error;
2081 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002082
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002083 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002084
2085error:
2086
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002087 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002088
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002089 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002090}
2091
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002092static struct ly_mnode *
2093read_yin_choice(struct ly_module *module,
2094 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002095{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002096 struct lyxml_elem *sub, *next;
2097 struct ly_ctx *const ctx = module->ctx;
2098 struct ly_mnode *retval, *mnode = NULL;
2099 struct ly_mnode_choice *choice;
2100 const char *value;
2101 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002102 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002103
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002104 choice = calloc(1, sizeof *choice);
2105 choice->nodetype = LY_NODE_CHOICE;
2106 choice->prev = (struct ly_mnode *)choice;
2107 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002108
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002109 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2110 goto error;
2111 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002112
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002113 /* process choice's specific children */
2114 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2115 if (!strcmp(sub->name, "container")) {
2116 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2117 goto error;
2118 }
2119 } else if (!strcmp(sub->name, "leaf-list")) {
2120 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2121 goto error;
2122 }
2123 } else if (!strcmp(sub->name, "leaf")) {
2124 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2125 goto error;
2126 }
2127 } else if (!strcmp(sub->name, "list")) {
2128 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2129 goto error;
2130 }
2131 } else if (!strcmp(sub->name, "case")) {
2132 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2133 goto error;
2134 }
2135 } else if (!strcmp(sub->name, "anyxml")) {
2136 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2137 goto error;
2138 }
2139 } else if (!strcmp(sub->name, "default")) {
2140 if (dflt_str) {
2141 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2142 goto error;
2143 }
2144 GETVAL(value, sub, "value");
2145 dflt_str = strdup(value);
2146 } else if (!strcmp(sub->name, "mandatory")) {
2147 if (f_mand) {
2148 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2149 goto error;
2150 }
2151 /* just checking the flags in leaf is not sufficient, we would allow
2152 * multiple mandatory statements with the "false" value
2153 */
2154 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002155
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002156 GETVAL(value, sub, "value");
2157 if (!strcmp(value, "true")) {
2158 choice->flags |= LY_NODE_MAND_TRUE;
2159 } else if (strcmp(value, "false")) {
2160 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2161 goto error;
2162 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002163 } else if (!strcmp(sub->name, "when")) {
2164 if (choice->when) {
2165 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2166 goto error;
2167 }
2168
2169 choice->when = read_yin_when(module, sub);
2170 if (!choice->when) {
2171 goto error;
2172 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002173 } else if (!strcmp(sub->name, "if-feature")) {
2174 c_ftrs++;
2175
2176 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
2177 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002178 } else {
2179 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2180 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002181 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002183 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
2184 goto error;
2185 }
2186 mnode = NULL;
2187 lyxml_free_elem(ctx, sub);
2188 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002189
Radek Krejci3cf9e222015-06-18 11:37:50 +02002190 if (c_ftrs) {
2191 choice->features = calloc(c_ftrs, sizeof *choice->features);
2192 }
2193
2194 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2195 GETVAL(value, sub, "name");
2196 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
2197 if (!choice->features[choice->features_size]) {
2198 goto error;
2199 }
2200 choice->features_size++;
2201 lyxml_free_elem(ctx, sub);
2202 }
2203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002204 /* check - default is prohibited in combination with mandatory */
2205 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
2206 LOGVAL(VE_SPEC, LOGLINE(yin),
2207 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
2208 goto error;
2209 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002210
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002211 /* link default with the case */
2212 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02002213 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002214 if (!choice->dflt) {
2215 /* default branch not found */
2216 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
2217 goto error;
2218 }
2219 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002220
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002221 /* insert the node into the schema tree */
2222 if (parent && ly_mnode_addchild(parent, retval)) {
2223 goto error;
2224 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002225
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002226 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02002227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002228 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002229
2230error:
2231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002232 ly_mnode_free(retval);
2233 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002234
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002235 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002236}
2237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002238static struct ly_mnode *
2239read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02002240{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002241 struct ly_mnode *retval;
2242 struct ly_mnode_leaf *anyxml;
2243 struct lyxml_elem *sub, *next;
2244 const char *value;
2245 int r;
2246 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002247 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02002248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002249 anyxml = calloc(1, sizeof *anyxml);
2250 anyxml->nodetype = LY_NODE_ANYXML;
2251 anyxml->prev = (struct ly_mnode *)anyxml;
2252 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02002253
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002254 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2255 goto error;
2256 }
Radek Krejci863c2852015-06-03 15:47:11 +02002257
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002258 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2259 if (!strcmp(sub->name, "mandatory")) {
2260 if (f_mand) {
2261 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2262 goto error;
2263 }
2264 /* just checking the flags in leaf is not sufficient, we would allow
2265 * multiple mandatory statements with the "false" value
2266 */
2267 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02002268
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002269 GETVAL(value, sub, "value");
2270 if (!strcmp(value, "true")) {
2271 anyxml->flags |= LY_NODE_MAND_TRUE;
2272 } else if (strcmp(value, "false")) {
2273 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2274 goto error;
2275 }
2276 /* else false is the default value, so we can ignore it */
2277 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002278 } else if (!strcmp(sub->name, "when")) {
2279 if (anyxml->when) {
2280 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2281 goto error;
2282 }
2283
2284 anyxml->when = read_yin_when(module, sub);
2285 lyxml_free_elem(module->ctx, sub);
2286
2287 if (!anyxml->when) {
2288 goto error;
2289 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002290 } else if (!strcmp(sub->name, "must")) {
2291 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002292 } else if (!strcmp(sub->name, "if-feature")) {
2293 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02002294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002295 } else {
2296 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2297 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002298 }
2299 }
Radek Krejci863c2852015-06-03 15:47:11 +02002300
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002301 /* middle part - process nodes with cardinality of 0..n */
2302 if (c_must) {
2303 anyxml->must = calloc(c_must, sizeof *anyxml->must);
2304 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002305 if (c_ftrs) {
2306 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
2307 }
Radek Krejci863c2852015-06-03 15:47:11 +02002308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002309 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2310 if (!strcmp(sub->name, "must")) {
2311 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
2312 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02002313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002314 if (r) {
2315 goto error;
2316 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002317 } else if (!strcmp(sub->name, "must")) {
2318 GETVAL(value, sub, "name");
2319 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
2320 if (!anyxml->features[anyxml->features_size]) {
2321 goto error;
2322 }
2323 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002324 }
Radek Krejci863c2852015-06-03 15:47:11 +02002325
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002326 lyxml_free_elem(module->ctx, sub);
2327 }
Radek Krejci863c2852015-06-03 15:47:11 +02002328
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002329 if (parent && ly_mnode_addchild(parent, retval)) {
2330 goto error;
2331 }
Radek Krejci863c2852015-06-03 15:47:11 +02002332
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002333 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02002334
2335error:
2336
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002337 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02002338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002339 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02002340}
2341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002342static struct ly_mnode *
2343read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002344{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002345 struct ly_mnode *retval;
2346 struct ly_mnode_leaf *leaf;
2347 struct lyxml_elem *sub, *next;
2348 const char *value;
2349 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002350 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002351
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002352 leaf = calloc(1, sizeof *leaf);
2353 leaf->nodetype = LY_NODE_LEAF;
2354 leaf->prev = (struct ly_mnode *)leaf;
2355 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002356
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002357 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2358 goto error;
2359 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002360
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002361 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2362 if (!strcmp(sub->name, "type")) {
2363 if (leaf->type.der) {
2364 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2365 goto error;
2366 }
2367 if (fill_yin_type(module, parent, sub, &leaf->type)) {
2368 goto error;
2369 }
2370 } else if (!strcmp(sub->name, "default")) {
2371 if (leaf->dflt) {
2372 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2373 goto error;
2374 }
2375 GETVAL(value, sub, "value");
2376 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
2377 } else if (!strcmp(sub->name, "units")) {
2378 if (leaf->units) {
2379 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2380 goto error;
2381 }
2382 GETVAL(value, sub, "name");
2383 leaf->units = lydict_insert(module->ctx, value, strlen(value));
2384 } else if (!strcmp(sub->name, "mandatory")) {
2385 if (f_mand) {
2386 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2387 goto error;
2388 }
2389 /* just checking the flags in leaf is not sufficient, we would allow
2390 * multiple mandatory statements with the "false" value
2391 */
2392 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002393
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002394 GETVAL(value, sub, "value");
2395 if (!strcmp(value, "true")) {
2396 leaf->flags |= LY_NODE_MAND_TRUE;
2397 } else if (strcmp(value, "false")) {
2398 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2399 goto error;
2400 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002401 } else if (!strcmp(sub->name, "when")) {
2402 if (leaf->when) {
2403 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2404 goto error;
2405 }
2406
2407 leaf->when = read_yin_when(module, sub);
2408 if (!leaf->when) {
2409 goto error;
2410 }
2411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002412 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002413 c_must++; /* else false is the default value, so we can ignore it */
2414 } else if (!strcmp(sub->name, "if-feature")) {
2415 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002416
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002417 /* skip element free at the end of the loop */
2418 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002419 } else {
2420 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2421 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002422 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002424 lyxml_free_elem(module->ctx, sub);
2425 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002426
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002427 /* check mandatory parameters */
2428 if (!leaf->type.der) {
2429 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2430 goto error;
2431 }
2432 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2433 goto error;
2434 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002435
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002436 /* middle part - process nodes with cardinality of 0..n */
2437 if (c_must) {
2438 leaf->must = calloc(c_must, sizeof *leaf->must);
2439 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002440 if (c_ftrs) {
2441 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2442 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002443
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002444 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2445 if (!strcmp(sub->name, "must")) {
2446 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2447 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002449 if (r) {
2450 goto error;
2451 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002452 } else if (!strcmp(sub->name, "if-feature")) {
2453 GETVAL(value, sub, "name");
2454 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2455 if (!leaf->features[leaf->features_size]) {
2456 goto error;
2457 }
2458 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002459 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002460
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002461 lyxml_free_elem(module->ctx, sub);
2462 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002464 if (parent && ly_mnode_addchild(parent, retval)) {
2465 goto error;
2466 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002468 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002469
2470error:
2471
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002472 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002473
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002474 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002475}
2476
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002477static struct ly_mnode *
2478read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002479{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002480 struct ly_mnode *retval;
2481 struct ly_mnode_leaflist *llist;
2482 struct lyxml_elem *sub, *next;
2483 const char *value;
2484 char *endptr;
2485 unsigned long val;
2486 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002487 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002488 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002490 llist = calloc(1, sizeof *llist);
2491 llist->nodetype = LY_NODE_LEAFLIST;
2492 llist->prev = (struct ly_mnode *)llist;
2493 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002494
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002495 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2496 goto error;
2497 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002499 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2500 if (!strcmp(sub->name, "type")) {
2501 if (llist->type.der) {
2502 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2503 goto error;
2504 }
2505 if (fill_yin_type(module, parent, sub, &llist->type)) {
2506 goto error;
2507 }
2508 } else if (!strcmp(sub->name, "units")) {
2509 if (llist->units) {
2510 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2511 goto error;
2512 }
2513 GETVAL(value, sub, "name");
2514 llist->units = lydict_insert(module->ctx, value, strlen(value));
2515 } else if (!strcmp(sub->name, "ordered-by")) {
2516 if (f_ordr) {
2517 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2518 goto error;
2519 }
2520 /* just checking the flags in llist is not sufficient, we would
2521 * allow multiple ordered-by statements with the "system" value
2522 */
2523 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002525 if (llist->flags & LY_NODE_CONFIG_R) {
2526 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2527 * state data
2528 */
2529 lyxml_free_elem(module->ctx, sub);
2530 continue;
2531 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002532
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002533 GETVAL(value, sub, "value");
2534 if (!strcmp(value, "user")) {
2535 llist->flags |= LY_NODE_USERORDERED;
2536 } else if (strcmp(value, "system")) {
2537 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2538 goto error;
2539 } /* else system is the default value, so we can ignore it */
2540 } else if (!strcmp(sub->name, "must")) {
2541 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002542 } else if (!strcmp(sub->name, "if-feature")) {
2543 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002544
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002545 /* skip element free at the end of the loop */
2546 continue;
2547 } else if (!strcmp(sub->name, "min-elements")) {
2548 if (f_min) {
2549 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2550 goto error;
2551 }
2552 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002553
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002554 GETVAL(value, sub, "value");
2555 while (isspace(value[0])) {
2556 value++;
2557 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002558
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002559 /* convert it to uint32_t */
2560 errno = 0;
2561 endptr = NULL;
2562 val = strtoul(value, &endptr, 10);
2563 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2564 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2565 goto error;
2566 }
2567 llist->min = (uint32_t) val;
2568 } else if (!strcmp(sub->name, "max-elements")) {
2569 if (f_max) {
2570 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2571 goto error;
2572 }
2573 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002574
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002575 GETVAL(value, sub, "value");
2576 while (isspace(value[0])) {
2577 value++;
2578 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002579
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002580 /* convert it to uint32_t */
2581 errno = 0;
2582 endptr = NULL;
2583 val = strtoul(value, &endptr, 10);
2584 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2585 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2586 goto error;
2587 }
2588 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002589 } else if (!strcmp(sub->name, "when")) {
2590 if (llist->when) {
2591 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2592 goto error;
2593 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002594
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002595 llist->when = read_yin_when(module, sub);
2596 if (!llist->when) {
2597 goto error;
2598 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002599 } else {
2600 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2601 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002602 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002603
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002604 lyxml_free_elem(module->ctx, sub);
2605 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002607 /* check constraints */
2608 if (!llist->type.der) {
2609 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2610 goto error;
2611 }
2612 if (llist->max && llist->min > llist->max) {
2613 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2614 goto error;
2615 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002616
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002617 /* middle part - process nodes with cardinality of 0..n */
2618 if (c_must) {
2619 llist->must = calloc(c_must, sizeof *llist->must);
2620 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002621 if (c_ftrs) {
2622 llist->features = calloc(c_ftrs, sizeof *llist->features);
2623 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002624
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002625 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2626 if (!strcmp(sub->name, "must")) {
2627 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2628 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002629
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002630 if (r) {
2631 goto error;
2632 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002633 } else if (!strcmp(sub->name, "if-feature")) {
2634 GETVAL(value, sub, "name");
2635 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2636 if (!llist->features[llist->features_size]) {
2637 goto error;
2638 }
2639 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002640 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002641
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002642 lyxml_free_elem(module->ctx, sub);
2643 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002644
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002645 if (parent && ly_mnode_addchild(parent, retval)) {
2646 goto error;
2647 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002649 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002650
2651error:
2652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002653 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002654
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002655 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002656}
2657
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002658static struct ly_mnode *
2659read_yin_list(struct ly_module *module,
2660 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002661{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002662 struct ly_mnode *retval, *mnode;
2663 struct ly_mnode_list *list;
2664 struct ly_unique *uniq_s;
2665 struct lyxml_elem *sub, *next, root, uniq;
2666 int i, r;
2667 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002668 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002669 int f_ordr = 0, f_max = 0, f_min = 0;
2670 const char *key_str = NULL, *uniq_str, *value;
2671 char *auxs;
2672 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002674 /* init */
2675 memset(&root, 0, sizeof root);
2676 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002677
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002678 list = calloc(1, sizeof *list);
2679 list->nodetype = LY_NODE_LIST;
2680 list->prev = (struct ly_mnode *)list;
2681 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002683 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2684 goto error;
2685 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002686
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002687 /* process list's specific children */
2688 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2689 /* data statements */
2690 if (!strcmp(sub->name, "container") ||
2691 !strcmp(sub->name, "leaf-list") ||
2692 !strcmp(sub->name, "leaf") ||
2693 !strcmp(sub->name, "list") ||
2694 !strcmp(sub->name, "choice") ||
2695 !strcmp(sub->name, "uses") ||
2696 !strcmp(sub->name, "grouping") ||
2697 !strcmp(sub->name, "anyxml")) {
2698 lyxml_unlink_elem(sub);
2699 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002700
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002701 /* array counters */
2702 } else if (!strcmp(sub->name, "key")) {
2703 /* check cardinality 0..1 */
2704 if (list->keys_size) {
2705 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2706 goto error;
2707 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002708
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002709 /* count the number of keys */
2710 GETVAL(value, sub, "value");
2711 key_str = value;
2712 while ((value = strpbrk(value, " \t\n"))) {
2713 list->keys_size++;
2714 while (isspace(*value)) {
2715 value++;
2716 }
2717 }
2718 list->keys_size++;
2719 list->keys = calloc(list->keys_size, sizeof *list->keys);
2720 } else if (!strcmp(sub->name, "unique")) {
2721 c_uniq++;
2722 lyxml_unlink_elem(sub);
2723 lyxml_add_child(&uniq, sub);
2724 } else if (!strcmp(sub->name, "typedef")) {
2725 c_tpdf++;
2726 } else if (!strcmp(sub->name, "must")) {
2727 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002728 } else if (!strcmp(sub->name, "if-feature")) {
2729 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002730
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002731 /* optional stetments */
2732 } else if (!strcmp(sub->name, "ordered-by")) {
2733 if (f_ordr) {
2734 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2735 goto error;
2736 }
2737 /* just checking the flags in llist is not sufficient, we would
2738 * allow multiple ordered-by statements with the "system" value
2739 */
2740 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002741
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002742 if (list->flags & LY_NODE_CONFIG_R) {
2743 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2744 * state data
2745 */
2746 lyxml_free_elem(module->ctx, sub);
2747 continue;
2748 }
Radek Krejci345ad742015-06-03 11:04:18 +02002749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002750 GETVAL(value, sub, "value");
2751 if (!strcmp(value, "user")) {
2752 list->flags |= LY_NODE_USERORDERED;
2753 } else if (strcmp(value, "system")) {
2754 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2755 goto error;
2756 }
2757 /* else system is the default value, so we can ignore it */
2758 lyxml_free_elem(module->ctx, sub);
2759 } else if (!strcmp(sub->name, "min-elements")) {
2760 if (f_min) {
2761 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2762 goto error;
2763 }
2764 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002765
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002766 GETVAL(value, sub, "value");
2767 while (isspace(value[0])) {
2768 value++;
2769 }
Radek Krejci345ad742015-06-03 11:04:18 +02002770
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002771 /* convert it to uint32_t */
2772 errno = 0;
2773 auxs = NULL;
2774 val = strtoul(value, &auxs, 10);
2775 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2776 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2777 goto error;
2778 }
2779 list->min = (uint32_t) val;
2780 lyxml_free_elem(module->ctx, sub);
2781 } else if (!strcmp(sub->name, "max-elements")) {
2782 if (f_max) {
2783 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2784 goto error;
2785 }
2786 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002787
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002788 GETVAL(value, sub, "value");
2789 while (isspace(value[0])) {
2790 value++;
2791 }
Radek Krejci345ad742015-06-03 11:04:18 +02002792
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002793 /* convert it to uint32_t */
2794 errno = 0;
2795 auxs = NULL;
2796 val = strtoul(value, &auxs, 10);
2797 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2798 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2799 goto error;
2800 }
2801 list->max = (uint32_t) val;
2802 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002803 } else if (!strcmp(sub->name, "when")) {
2804 if (list->when) {
2805 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2806 goto error;
2807 }
2808
2809 list->when = read_yin_when(module, sub);
2810 lyxml_free_elem(module->ctx, sub);
2811
2812 if (!list->when) {
2813 goto error;
2814 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002815 } else {
2816 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2817 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002818 }
2819 }
Radek Krejci345ad742015-06-03 11:04:18 +02002820
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002821 /* check - if list is configuration, key statement is mandatory */
2822 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2823 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2824 goto error;
2825 }
2826 if (list->max && list->min > list->max) {
2827 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2828 goto error;
2829 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002830
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002831 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2832 if (c_tpdf) {
2833 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2834 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002835 if (c_must) {
2836 list->must = calloc(c_must, sizeof *list->must);
2837 }
2838 if (c_ftrs) {
2839 list->features = calloc(c_ftrs, sizeof *list->features);
2840 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002841 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2842 if (!strcmp(sub->name, "typedef")) {
2843 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2844 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002845
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002846 if (r) {
2847 goto error;
2848 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002849 } else if (!strcmp(sub->name, "if-feature")) {
2850 GETVAL(value, sub, "name");
2851 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2852 if (!list->features[list->features_size]) {
2853 goto error;
2854 }
2855 list->features_size++;
2856 } else if (!strcmp(sub->name, "must")) {
2857 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2858 list->must_size++;
2859
2860 if (r) {
2861 goto error;
2862 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002863 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002864 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002865 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002866
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002867 /* last part - process data nodes */
2868 LY_TREE_FOR_SAFE(root.child, next, sub) {
2869 if (!strcmp(sub->name, "container")) {
2870 mnode = read_yin_container(module, retval, sub, resolve, unres);
2871 } else if (!strcmp(sub->name, "leaf-list")) {
2872 mnode = read_yin_leaflist(module, retval, sub, resolve);
2873 } else if (!strcmp(sub->name, "leaf")) {
2874 mnode = read_yin_leaf(module, retval, sub, resolve);
2875 } else if (!strcmp(sub->name, "list")) {
2876 mnode = read_yin_list(module, retval, sub, resolve, unres);
2877 } else if (!strcmp(sub->name, "choice")) {
2878 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2879 } else if (!strcmp(sub->name, "uses")) {
2880 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2881 } else if (!strcmp(sub->name, "grouping")) {
2882 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2883 } else if (!strcmp(sub->name, "anyxml")) {
2884 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002885 }
2886 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002887
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002888 if (!mnode) {
2889 goto error;
2890 }
2891 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002892
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002893 if (parent && ly_mnode_addchild(parent, retval)) {
2894 goto error;
2895 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002896
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002897 if (!key_str) {
2898 /* config false list without a key */
2899 return retval;
2900 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002901
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002902 /* link key leafs into the list structure and check all constraints */
2903 for (i = 0; i < list->keys_size; i++) {
2904 /* get the key name */
2905 if ((value = strpbrk(key_str, " \t\n"))) {
2906 len = value - key_str;
2907 while (isspace(*value)) {
2908 value++;
2909 }
2910 } else {
2911 len = strlen(key_str);
2912 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002913
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002914 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002915
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002916 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2917 goto error;
2918 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002919
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002920 /* prepare for next iteration */
2921 while (value && isspace(*value)) {
2922 value++;
2923 }
2924 key_str = value;
2925 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002926
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002927 /* process unique statements */
2928 if (c_uniq) {
2929 list->unique = calloc(c_uniq, sizeof *list->unique);
2930 }
2931 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2932 /* count the number of unique values */
2933 GETVAL(value, sub, "tag");
2934 uniq_str = value;
2935 uniq_s = &list->unique[list->unique_size];
2936 while ((value = strpbrk(value, " \t\n"))) {
2937 uniq_s->leafs_size++;
2938 while (isspace(*value)) {
2939 value++;
2940 }
2941 }
2942 uniq_s->leafs_size++;
2943 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2944 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002945
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002946 /* interconnect unique values with the leafs */
2947 for (i = 0; i < uniq_s->leafs_size; i++) {
2948 if ((value = strpbrk(uniq_str, " \t\n"))) {
2949 len = value - uniq_str;
2950 while (isspace(*value)) {
2951 value++;
2952 }
2953 } else {
2954 len = strlen(uniq_str);
2955 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002956
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002957 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
2958 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
2959 goto error;
2960 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002961
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002962 /* prepare for next iteration */
2963 while (value && isspace(*value)) {
2964 value++;
2965 }
2966 uniq_str = value;
2967 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002968
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002969 lyxml_free_elem(module->ctx, sub);
2970 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002971
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002972 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002973
2974error:
2975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002976 ly_mnode_free(retval);
2977 while (root.child) {
2978 lyxml_free_elem(module->ctx, root.child);
2979 }
2980 while (uniq.child) {
2981 lyxml_free_elem(module->ctx, uniq.child);
2982 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002983
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002984 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002985}
2986
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002987static struct ly_mnode *
2988read_yin_container(struct ly_module *module,
2989 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002990{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002991 struct lyxml_elem *sub, *next, root;
2992 struct ly_mnode *mnode = NULL;
2993 struct ly_mnode *retval;
2994 struct ly_mnode_container *cont;
2995 const char *value;
2996 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002997 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002998
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002999 /* init */
3000 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003002 cont = calloc(1, sizeof *cont);
3003 cont->nodetype = LY_NODE_CONTAINER;
3004 cont->prev = (struct ly_mnode *)cont;
3005 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003006
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003007 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3008 goto error;
3009 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003011 /* process container's specific children */
3012 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3013 if (!strcmp(sub->name, "presence")) {
3014 if (cont->presence) {
3015 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3016 goto error;
3017 }
3018 GETVAL(value, sub, "value");
3019 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02003020
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003021 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003022 } else if (!strcmp(sub->name, "when")) {
3023 if (cont->when) {
3024 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3025 goto error;
3026 }
3027
3028 cont->when = read_yin_when(module, sub);
3029 lyxml_free_elem(module->ctx, sub);
3030
3031 if (!cont->when) {
3032 goto error;
3033 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003034
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003035 /* data statements */
3036 } else if (!strcmp(sub->name, "container") ||
3037 !strcmp(sub->name, "leaf-list") ||
3038 !strcmp(sub->name, "leaf") ||
3039 !strcmp(sub->name, "list") ||
3040 !strcmp(sub->name, "choice") ||
3041 !strcmp(sub->name, "uses") ||
3042 !strcmp(sub->name, "grouping") ||
3043 !strcmp(sub->name, "anyxml")) {
3044 lyxml_unlink_elem(sub);
3045 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003046
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003047 /* array counters */
3048 } else if (!strcmp(sub->name, "typedef")) {
3049 c_tpdf++;
3050 } else if (!strcmp(sub->name, "must")) {
3051 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003052 } else if (!strcmp(sub->name, "if-feature")) {
3053 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003054 } else {
3055 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3056 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003057 }
3058 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003059
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003060 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3061 if (c_tpdf) {
3062 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3063 }
3064 if (c_must) {
3065 cont->must = calloc(c_must, sizeof *cont->must);
3066 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003067 if (c_ftrs) {
3068 cont->features = calloc(c_ftrs, sizeof *cont->features);
3069 }
Radek Krejci800af702015-06-02 13:46:01 +02003070
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003071 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3072 if (!strcmp(sub->name, "typedef")) {
3073 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
3074 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003076 if (r) {
3077 goto error;
3078 }
3079 } else if (!strcmp(sub->name, "must")) {
3080 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3081 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003082
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003083 if (r) {
3084 goto error;
3085 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003086 } else if (!strcmp(sub->name, "if-feature")) {
3087 GETVAL(value, sub, "name");
3088 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3089 if (!cont->features[cont->features_size]) {
3090 goto error;
3091 }
3092 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003093 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003094
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003095 lyxml_free_elem(module->ctx, sub);
3096 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003097
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003098 /* last part - process data nodes */
3099 LY_TREE_FOR_SAFE(root.child, next, sub) {
3100 if (!strcmp(sub->name, "container")) {
3101 mnode = read_yin_container(module, retval, sub, resolve, unres);
3102 } else if (!strcmp(sub->name, "leaf-list")) {
3103 mnode = read_yin_leaflist(module, retval, sub, resolve);
3104 } else if (!strcmp(sub->name, "leaf")) {
3105 mnode = read_yin_leaf(module, retval, sub, resolve);
3106 } else if (!strcmp(sub->name, "list")) {
3107 mnode = read_yin_list(module, retval, sub, resolve, unres);
3108 } else if (!strcmp(sub->name, "choice")) {
3109 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3110 } else if (!strcmp(sub->name, "uses")) {
3111 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3112 } else if (!strcmp(sub->name, "grouping")) {
3113 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3114 } else if (!strcmp(sub->name, "anyxml")) {
3115 mnode = read_yin_anyxml(module, retval, sub, resolve);
3116 }
3117 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003118
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003119 if (!mnode) {
3120 goto error;
3121 }
3122 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003124 if (parent && ly_mnode_addchild(parent, retval)) {
3125 goto error;
3126 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003127
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003128 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003129
3130error:
3131
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003132 ly_mnode_free(retval);
3133 while (root.child) {
3134 lyxml_free_elem(module->ctx, root.child);
3135 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003137 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003138}
3139
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003140static struct ly_mnode *
3141read_yin_grouping(struct ly_module *module,
3142 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003143{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003144 struct lyxml_elem *sub, *next, root;
3145 struct ly_mnode *mnode = NULL;
3146 struct ly_mnode *retval;
3147 struct ly_mnode_grp *grp;
3148 int r;
3149 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003151 /* init */
3152 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003153
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003154 grp = calloc(1, sizeof *grp);
3155 grp->nodetype = LY_NODE_GROUPING;
3156 grp->prev = (struct ly_mnode *)grp;
3157 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003159 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3160 goto error;
3161 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003163 LY_TREE_FOR_SAFE(node->child, next, sub) {
3164 /* data statements */
3165 if (!strcmp(sub->name, "container") ||
3166 !strcmp(sub->name, "leaf-list") ||
3167 !strcmp(sub->name, "leaf") ||
3168 !strcmp(sub->name, "list") ||
3169 !strcmp(sub->name, "choice") ||
3170 !strcmp(sub->name, "uses") ||
3171 !strcmp(sub->name, "grouping") ||
3172 !strcmp(sub->name, "anyxml")) {
3173 lyxml_unlink_elem(sub);
3174 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003176 /* array counters */
3177 } else if (!strcmp(sub->name, "typedef")) {
3178 c_tpdf++;
3179 } else {
3180 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3181 goto error;
3182 }
3183 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003184
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003185 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3186 if (c_tpdf) {
3187 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3188 }
3189 LY_TREE_FOR_SAFE(node->child, next, sub) {
3190 if (!strcmp(sub->name, "typedef")) {
3191 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3192 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003193
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003194 if (r) {
3195 goto error;
3196 }
3197 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003198
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003199 lyxml_free_elem(module->ctx, sub);
3200 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003201
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003202 /* last part - process data nodes */
3203 LY_TREE_FOR_SAFE(root.child, next, sub) {
3204 if (!strcmp(sub->name, "container")) {
3205 mnode = read_yin_container(module, retval, sub, resolve, unres);
3206 } else if (!strcmp(sub->name, "leaf-list")) {
3207 mnode = read_yin_leaflist(module, retval, sub, resolve);
3208 } else if (!strcmp(sub->name, "leaf")) {
3209 mnode = read_yin_leaf(module, retval, sub, resolve);
3210 } else if (!strcmp(sub->name, "list")) {
3211 mnode = read_yin_list(module, retval, sub, resolve, unres);
3212 } else if (!strcmp(sub->name, "choice")) {
3213 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3214 } else if (!strcmp(sub->name, "uses")) {
3215 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3216 } else if (!strcmp(sub->name, "grouping")) {
3217 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3218 } else if (!strcmp(sub->name, "anyxml")) {
3219 mnode = read_yin_anyxml(module, retval, sub, resolve);
3220 }
3221 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003223 if (!mnode) {
3224 goto error;
3225 }
3226 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003228 if (parent && ly_mnode_addchild(parent, retval)) {
3229 goto error;
3230 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003232 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003233
3234error:
3235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003236 ly_mnode_free(retval);
3237 while (root.child) {
3238 lyxml_free_elem(module->ctx, root.child);
3239 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003240
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003241 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003242}
3243
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003244static struct ly_mnode *
3245read_yin_input_output(struct ly_module *module,
3246 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003247{
Radek Krejcie0674f82015-06-15 13:58:51 +02003248 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003249 struct ly_mnode *mnode = NULL;
3250 struct ly_mnode *retval;
3251 struct ly_mnode_input_output *inout;
3252 int r;
3253 int c_tpdf = 0;
3254
Radek Krejcie0674f82015-06-15 13:58:51 +02003255 /* init */
3256 memset(&root, 0, sizeof root);
3257
Michal Vasko38d01f72015-06-15 09:41:06 +02003258 inout = calloc(1, sizeof *inout);
3259
3260 if (!strcmp(yin->name, "input")) {
3261 inout->nodetype = LY_NODE_INPUT;
3262 } else if (!strcmp(yin->name, "output")) {
3263 inout->nodetype = LY_NODE_OUTPUT;
3264 } else {
3265 assert(0);
3266 }
3267
3268 inout->prev = (struct ly_mnode *)inout;
3269 retval = (struct ly_mnode *)inout;
3270
Michal Vaskoebeac942015-06-15 12:11:50 +02003271 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
3272 goto error;
3273 }
3274
Michal Vasko38d01f72015-06-15 09:41:06 +02003275 /* data statements */
3276 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3277 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003278 !strcmp(sub->name, "leaf-list") ||
3279 !strcmp(sub->name, "leaf") ||
3280 !strcmp(sub->name, "list") ||
3281 !strcmp(sub->name, "choice") ||
3282 !strcmp(sub->name, "uses") ||
3283 !strcmp(sub->name, "grouping") ||
3284 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003285 lyxml_unlink_elem(sub);
3286 lyxml_add_child(&root, sub);
3287
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003288 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003289 } else if (!strcmp(sub->name, "typedef")) {
3290 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003291#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02003292 } else {
3293 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3294 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003295#else
Michal Vasko38d01f72015-06-15 09:41:06 +02003296 } else {
3297 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003298#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02003299 }
3300 }
3301
3302 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3303 if (c_tpdf) {
3304 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
3305 }
3306
3307 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3308 if (!strcmp(sub->name, "typedef")) {
3309 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
3310 inout->tpdf_size++;
3311
3312 if (r) {
3313 goto error;
3314 }
3315 }
3316
3317 lyxml_free_elem(module->ctx, sub);
3318 }
3319
3320 /* last part - process data nodes */
3321 LY_TREE_FOR_SAFE(root.child, next, sub) {
3322 if (!strcmp(sub->name, "container")) {
3323 mnode = read_yin_container(module, retval, sub, resolve, unres);
3324 } else if (!strcmp(sub->name, "leaf-list")) {
3325 mnode = read_yin_leaflist(module, retval, sub, resolve);
3326 } else if (!strcmp(sub->name, "leaf")) {
3327 mnode = read_yin_leaf(module, retval, sub, resolve);
3328 } else if (!strcmp(sub->name, "list")) {
3329 mnode = read_yin_list(module, retval, sub, resolve, unres);
3330 } else if (!strcmp(sub->name, "choice")) {
3331 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3332 } else if (!strcmp(sub->name, "uses")) {
3333 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3334 } else if (!strcmp(sub->name, "grouping")) {
3335 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3336 } else if (!strcmp(sub->name, "anyxml")) {
3337 mnode = read_yin_anyxml(module, retval, sub, resolve);
3338 }
3339 lyxml_free_elem(module->ctx, sub);
3340
3341 if (!mnode) {
3342 goto error;
3343 }
3344 }
3345
3346 if (parent && ly_mnode_addchild(parent, retval)) {
3347 goto error;
3348 }
3349
3350 return retval;
3351
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003352error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003353
3354 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003355 while (root.child) {
3356 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003357 }
3358
3359 return NULL;
3360}
3361
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003362static struct ly_mnode *
3363read_yin_notif(struct ly_module *module,
3364 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02003365{
Michal Vaskoc6551b32015-06-16 10:51:43 +02003366 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02003367 struct ly_mnode *mnode = NULL;
3368 struct ly_mnode *retval;
3369 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003370 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02003371 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003372 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02003373
Michal Vaskoc6551b32015-06-16 10:51:43 +02003374 memset(&root, 0, sizeof root);
3375
Michal Vasko0ea41032015-06-16 08:53:55 +02003376 notif = calloc(1, sizeof *notif);
3377 notif->nodetype = LY_NODE_NOTIF;
3378 notif->prev = (struct ly_mnode *)notif;
3379 retval = (struct ly_mnode *)notif;
3380
3381 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3382 goto error;
3383 }
3384
3385 /* process rpc's specific children */
3386 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3387 /* data statements */
3388 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003389 !strcmp(sub->name, "leaf-list") ||
3390 !strcmp(sub->name, "leaf") ||
3391 !strcmp(sub->name, "list") ||
3392 !strcmp(sub->name, "choice") ||
3393 !strcmp(sub->name, "uses") ||
3394 !strcmp(sub->name, "grouping") ||
3395 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02003396 lyxml_unlink_elem(sub);
3397 lyxml_add_child(&root, sub);
3398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003399 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02003400 } else if (!strcmp(sub->name, "typedef")) {
3401 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003402 } else if (!strcmp(sub->name, "if-feature")) {
3403 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003404 } else {
3405 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3406 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02003407 }
3408 }
3409
3410 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3411 if (c_tpdf) {
3412 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3413 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003414 if (c_ftrs) {
3415 notif->features = calloc(c_ftrs, sizeof *notif->features);
3416 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003417
3418 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3419 if (!strcmp(sub->name, "typedef")) {
3420 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3421 notif->tpdf_size++;
3422
3423 if (r) {
3424 goto error;
3425 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003426 } else if (!strcmp(sub->name, "typedef")) {
3427 GETVAL(value, sub, "name");
3428 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3429 if (!notif->features[notif->features_size]) {
3430 goto error;
3431 }
3432 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003433 }
3434
3435 lyxml_free_elem(module->ctx, sub);
3436 }
3437
3438 /* last part - process data nodes */
3439 LY_TREE_FOR_SAFE(root.child, next, sub) {
3440 if (!strcmp(sub->name, "container")) {
3441 mnode = read_yin_container(module, retval, sub, resolve, unres);
3442 } else if (!strcmp(sub->name, "leaf-list")) {
3443 mnode = read_yin_leaflist(module, retval, sub, resolve);
3444 } else if (!strcmp(sub->name, "leaf")) {
3445 mnode = read_yin_leaf(module, retval, sub, resolve);
3446 } else if (!strcmp(sub->name, "list")) {
3447 mnode = read_yin_list(module, retval, sub, resolve, unres);
3448 } else if (!strcmp(sub->name, "choice")) {
3449 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3450 } else if (!strcmp(sub->name, "uses")) {
3451 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3452 } else if (!strcmp(sub->name, "grouping")) {
3453 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3454 } else if (!strcmp(sub->name, "anyxml")) {
3455 mnode = read_yin_anyxml(module, retval, sub, resolve);
3456 }
3457 lyxml_free_elem(module->ctx, sub);
3458
3459 if (!mnode) {
3460 goto error;
3461 }
3462 }
3463
3464 if (parent && ly_mnode_addchild(parent, retval)) {
3465 goto error;
3466 }
3467
3468 return retval;
3469
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003470error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003471
3472 ly_mnode_free(retval);
3473 while (root.child) {
3474 lyxml_free_elem(module->ctx, root.child);
3475 }
3476
3477 return NULL;
3478}
3479
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003480static struct ly_mnode *
3481read_yin_rpc(struct ly_module *module,
3482 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003483{
Radek Krejcie0674f82015-06-15 13:58:51 +02003484 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003485 struct ly_mnode *mnode = NULL;
3486 struct ly_mnode *retval;
3487 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003488 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003489 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003490 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003491
Radek Krejcie0674f82015-06-15 13:58:51 +02003492 /* init */
3493 memset(&root, 0, sizeof root);
3494
Michal Vasko38d01f72015-06-15 09:41:06 +02003495 rpc = calloc(1, sizeof *rpc);
3496 rpc->nodetype = LY_NODE_RPC;
3497 rpc->prev = (struct ly_mnode *)rpc;
3498 retval = (struct ly_mnode *)rpc;
3499
3500 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3501 goto error;
3502 }
3503
3504 /* process rpc's specific children */
3505 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3506 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003507 if (rpc->child
3508 && (rpc->child->nodetype == LY_NODE_INPUT
3509 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003510 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3511 goto error;
3512 }
3513 lyxml_unlink_elem(sub);
3514 lyxml_add_child(&root, sub);
3515 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003516 if (rpc->child
3517 && (rpc->child->nodetype == LY_NODE_INPUT
3518 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003519 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3520 goto error;
3521 }
3522 lyxml_unlink_elem(sub);
3523 lyxml_add_child(&root, sub);
3524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003525 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003526 } else if (!strcmp(sub->name, "grouping")) {
3527 lyxml_unlink_elem(sub);
3528 lyxml_add_child(&root, sub);
3529
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003530 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003531 } else if (!strcmp(sub->name, "typedef")) {
3532 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003533 } else if (!strcmp(sub->name, "if-feature")) {
3534 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003535 } else {
3536 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3537 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003538 }
3539 }
3540
3541 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3542 if (c_tpdf) {
3543 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3544 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003545 if (c_ftrs) {
3546 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3547 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003548
3549 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3550 if (!strcmp(sub->name, "typedef")) {
3551 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3552 rpc->tpdf_size++;
3553
3554 if (r) {
3555 goto error;
3556 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003557 } else if (!strcmp(sub->name, "if-feature")) {
3558 GETVAL(value, sub, "name");
3559 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3560 if (!rpc->features[rpc->features_size]) {
3561 goto error;
3562 }
3563 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003564 }
3565
3566 lyxml_free_elem(module->ctx, sub);
3567 }
3568
3569 /* last part - process data nodes */
3570 LY_TREE_FOR_SAFE(root.child, next, sub) {
3571 if (!strcmp(sub->name, "grouping")) {
3572 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3573 } else if (!strcmp(sub->name, "input")) {
3574 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3575 } else if (!strcmp(sub->name, "output")) {
3576 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3577 }
3578 lyxml_free_elem(module->ctx, sub);
3579
3580 if (!mnode) {
3581 goto error;
3582 }
3583 }
3584
3585 if (parent && ly_mnode_addchild(parent, retval)) {
3586 goto error;
3587 }
3588
3589 return retval;
3590
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003591error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003592
3593 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003594 while (root.child) {
3595 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003596 }
3597
3598 return NULL;
3599}
3600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003601static int
3602find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003603{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003604 struct ly_module *searchmod = NULL, *module = uses->module;
3605 struct ly_mnode *mnode, *mnode_aux;
3606 const char *name;
3607 int prefix_len = 0;
3608 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003609
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003610 /* get referenced grouping */
3611 name = strchr(uses->name, ':');
3612 if (!name) {
3613 /* no prefix, search in local tree */
3614 name = uses->name;
3615 } else {
3616 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003618 /* set name to correct position after colon */
3619 prefix_len = name - uses->name;
3620 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003622 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3623 /* prefix refers to the current module, ignore it */
3624 prefix_len = 0;
3625 }
3626 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003627
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003628 /* search */
3629 if (prefix_len) {
3630 /* in top-level groupings of some other module */
3631 for (i = 0; i < module->imp_size; i++) {
3632 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3633 && !module->imp[i].prefix[prefix_len]) {
3634 searchmod = module->imp[i].module;
3635 break;
3636 }
3637 }
3638 if (!searchmod) {
3639 /* uses refers unknown data model */
3640 LOGVAL(VE_INPREFIX, line, name);
3641 return EXIT_FAILURE;
3642 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003644 LY_TREE_FOR(searchmod->data, mnode) {
3645 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3646 uses->grp = (struct ly_mnode_grp *)mnode;
3647 return EXIT_SUCCESS;
3648 }
3649 }
3650 } else {
3651 /* in local tree hierarchy */
3652 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3653 LY_TREE_FOR(mnode_aux->child, mnode) {
3654 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3655 uses->grp = (struct ly_mnode_grp *)mnode;
3656 return EXIT_SUCCESS;
3657 }
3658 }
3659 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003660
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003661 /* search in top level of the current module */
3662 LY_TREE_FOR(module->data, mnode) {
3663 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3664 uses->grp = (struct ly_mnode_grp *)mnode;
3665 return EXIT_SUCCESS;
3666 }
3667 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003669 /* search in top-level of included modules */
3670 for (i = 0; i < module->inc_size; i++) {
3671 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3672 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3673 uses->grp = (struct ly_mnode_grp *)mnode;
3674 return EXIT_SUCCESS;
3675 }
3676 }
3677 }
3678 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003679
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003680 /* not found, but no explicit error occured */
3681 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003682}
3683
Radek Krejcif5be10f2015-06-16 13:29:36 +02003684static int
3685resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3686{
3687 struct lyxml_elem *yin, *next, *sub;
3688 struct ly_mnode *mnode;
3689
3690 assert(module);
3691
3692 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003693 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003694 if (!aug->target) {
3695 LOGVAL(VE_INARG, line, aug->target, "uses");
3696 return EXIT_FAILURE;
3697 }
3698
3699 if (!aug->child) {
3700 /* nothing to do */
3701 return EXIT_SUCCESS;
3702 }
3703
3704 yin = (struct lyxml_elem *)aug->child;
3705
3706 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3707 return EXIT_FAILURE;
3708 }
3709
3710 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3711 if (!strcmp(sub->name, "container")) {
3712 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3713 } else if (!strcmp(sub->name, "leaf-list")) {
3714 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3715 } else if (!strcmp(sub->name, "leaf")) {
3716 mnode = read_yin_leaf(module, aug->target, sub, 1);
3717 } else if (!strcmp(sub->name, "list")) {
3718 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3719 } else if (!strcmp(sub->name, "uses")) {
3720 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3721 } else if (!strcmp(sub->name, "choice")) {
3722 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3723 } else if (!strcmp(sub->name, "case")) {
3724 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3725 } else if (!strcmp(sub->name, "anyxml")) {
3726 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3727#if 0
3728 } else {
3729 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003730 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003731#else
3732 } else {
3733 continue;
3734#endif
3735 }
3736
3737 if (!mnode) {
3738 return EXIT_FAILURE;
3739 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003740 /* check for mandatory nodes - if the target node is in another module
3741 * the added nodes cannot be mandatory
3742 */
3743 if (check_mandatory(mnode)) {
3744 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3745 return EXIT_FAILURE;
3746 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003747
3748 lyxml_free_elem(module->ctx, sub);
3749
3750 /* the parent pointer will point to the augment node, but all
3751 * siblings pointers and possibly the child node in target does
3752 * not know about the augment and follow the standard schema tree
3753 * structure
3754 */
3755 mnode->parent = (struct ly_mnode *)aug;
3756 mnode = NULL;
3757 }
3758
3759 lyxml_free_elem(module->ctx, yin);
3760 aug->child = NULL;
3761
3762 return EXIT_SUCCESS;
3763}
3764
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003765int
3766resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003767{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003768 struct ly_ctx *ctx;
3769 struct ly_mnode *mnode = NULL, *mnode_aux;
3770 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02003771 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003772 int i, j;
3773 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003774
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003775 /* copy the data nodes from grouping into the uses context */
3776 LY_TREE_FOR(uses->grp->child, mnode) {
3777 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3778 if (!mnode_aux) {
3779 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3780 return EXIT_FAILURE;
3781 }
3782 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3783 ly_mnode_free(mnode_aux);
3784 return EXIT_FAILURE;
3785 }
3786 }
3787 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003788
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003789 /* apply refines */
3790 for (i = 0; i < uses->refine_size; i++) {
3791 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003792 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003793 if (!mnode) {
3794 LOGVAL(VE_INARG, line, rfn->target, "uses");
3795 return EXIT_FAILURE;
3796 }
Radek Krejci106efc02015-06-10 14:36:27 +02003797
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003798 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3799 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3800 return EXIT_FAILURE;
3801 }
Radek Krejci106efc02015-06-10 14:36:27 +02003802
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003803 /* description on any nodetype */
3804 if (rfn->dsc) {
3805 lydict_remove(ctx, mnode->dsc);
3806 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3807 }
Radek Krejci106efc02015-06-10 14:36:27 +02003808
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003809 /* reference on any nodetype */
3810 if (rfn->ref) {
3811 lydict_remove(ctx, mnode->ref);
3812 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3813 }
Radek Krejci106efc02015-06-10 14:36:27 +02003814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003815 /* config on any nodetype */
3816 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3817 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3818 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3819 }
Radek Krejci106efc02015-06-10 14:36:27 +02003820
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003821 /* default value ... */
3822 if (rfn->mod.dflt) {
3823 if (mnode->nodetype == LY_NODE_LEAF) {
3824 /* leaf */
3825 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3826 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3827 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3828 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003829 ((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 +02003830 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3831 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3832 return EXIT_FAILURE;
3833 }
3834 }
3835 }
Radek Krejci106efc02015-06-10 14:36:27 +02003836
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003837 /* mandatory on leaf, anyxml or choice */
3838 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3839 if (rfn->flags & LY_NODE_MAND_FALSE) {
3840 /* erase mandatory true flag, we don't use false flag in schema nodes */
3841 mnode->flags &= ~LY_NODE_MAND_TRUE;
3842 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3843 /* set mandatory true flag */
3844 mnode->flags |= LY_NODE_MAND_TRUE;
3845 }
3846 }
Radek Krejci106efc02015-06-10 14:36:27 +02003847
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003848 /* presence on container */
3849 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3850 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3851 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3852 }
Radek Krejci106efc02015-06-10 14:36:27 +02003853
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003854 /* min/max-elements on list or leaf-list */
3855 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3856 /* magic - bit 3 in flags means min set, bit 4 says max set */
3857 if (rfn->flags & 0x04) {
3858 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3859 }
3860 if (rfn->flags & 0x08) {
3861 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3862 }
3863 }
Radek Krejci106efc02015-06-10 14:36:27 +02003864
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003865 /* must in leaf, leaf-list, list, container or anyxml */
3866 if (rfn->must_size) {
3867 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3868 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3869 if (!newmust) {
3870 LOGMEM;
3871 return EXIT_FAILURE;
3872 }
3873 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02003874 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003875 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3876 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3877 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3878 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3879 }
Radek Krejci106efc02015-06-10 14:36:27 +02003880
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003881 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3882 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3883 }
3884 }
Radek Krejci106efc02015-06-10 14:36:27 +02003885
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003886 /* apply augments */
3887 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003888 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003889 goto error;
3890 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003891 }
Radek Krejci106efc02015-06-10 14:36:27 +02003892
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003893 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003894
3895error:
3896
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003897 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003898}
Radek Krejci74705112015-06-05 10:25:44 +02003899
3900/*
3901 * resolve - referenced grouping should be bounded to the namespace (resolved)
3902 * only when uses does not appear in grouping. In a case of grouping's uses,
3903 * we just get information but we do not apply augment or refine to it.
3904 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003905static struct ly_mnode *
3906read_yin_uses(struct ly_module *module,
3907 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003908{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003909 struct lyxml_elem *sub, *next;
3910 struct ly_mnode *retval;
3911 struct ly_mnode_uses *uses;
3912 struct mnode_list *unres_new;
3913 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003914 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003915 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003916
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003917 uses = calloc(1, sizeof *uses);
3918 uses->nodetype = LY_NODE_USES;
3919 uses->prev = (struct ly_mnode *)uses;
3920 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003921
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003922 GETVAL(value, node, "name");
3923 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003924
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003925 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3926 goto error;
3927 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003928
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003929 /* get other properties of uses */
3930 LY_TREE_FOR_SAFE(node->child, next, sub) {
3931 if (!strcmp(sub->name, "refine")) {
3932 c_ref++;
3933 } else if (!strcmp(sub->name, "augment")) {
3934 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003935 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02003936 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003937 } else if (!strcmp(sub->name, "when")) {
3938 if (uses->when) {
3939 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
3940 goto error;
3941 }
3942
3943 uses->when = read_yin_when(module, sub);
3944 lyxml_free_elem(module->ctx, sub);
3945
3946 if (!uses->when) {
3947 goto error;
3948 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003949 } else {
3950 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3951 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003952 }
3953 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003954
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003955 /* process properties with cardinality 0..n */
3956 if (c_ref) {
3957 uses->refine = calloc(c_ref, sizeof *uses->refine);
3958 }
3959 if (c_aug) {
3960 uses->augment = calloc(c_aug, sizeof *uses->augment);
3961 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003962 if (c_ftrs) {
3963 uses->features = calloc(c_ftrs, sizeof *uses->features);
3964 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003965
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003966 LY_TREE_FOR_SAFE(node->child, next, sub) {
3967 if (!strcmp(sub->name, "refine")) {
3968 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
3969 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003970 lyxml_free_elem(module->ctx, sub);
3971 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003972 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
3973 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003974 } else if (!strcmp(sub->name, "if-feature")) {
3975 GETVAL(value, sub, "name");
3976 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
3977 if (!uses->features[uses->features_size]) {
3978 goto error;
3979 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02003980 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003981 uses->features_size++;
3982 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003983 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003985 if (r) {
3986 goto error;
3987 }
3988 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003989
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003990 if (find_grouping(parent, uses, LOGLINE(node))) {
3991 goto error;
3992 }
3993 if (!uses->grp) {
3994 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
3995 unres_new = calloc(1, sizeof *unres_new);
3996 if (*unres) {
3997 unres_new->next = *unres;
3998 }
3999 unres_new->mnode = retval;
4000 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02004001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004002 /* put it at the beginning of the unresolved list */
4003 *unres = unres_new;
4004 }
Radek Krejci74705112015-06-05 10:25:44 +02004005
Radek Krejci368c38f2015-06-15 15:09:55 +02004006 if (parent && ly_mnode_addchild(parent, retval)) {
4007 goto error;
4008 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004010 if (resolve) {
4011 /* inherit config flag */
4012 if (parent) {
4013 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
4014 } else {
4015 /* default config is true */
4016 retval->flags |= LY_NODE_CONFIG_W;
4017 }
4018 }
Radek Krejcib388c152015-06-04 17:03:03 +02004019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004020 if (resolve && uses->grp) {
4021 /* copy the data nodes from grouping into the uses context */
4022 if (resolve_uses(uses, LOGLINE(node))) {
4023 goto error;
4024 }
4025 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004026
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004027 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004028
4029error:
4030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004031 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004032
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004033 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004034}
4035
Radek Krejciefaeba32015-05-27 14:30:57 +02004036/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004037static int
4038read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004039{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004040 struct ly_ctx *ctx = module->ctx;
4041 struct ly_submodule *submodule = (struct ly_submodule *)module;
4042 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
4043 struct ly_mnode *mnode = NULL;
4044 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
4045 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004046 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02004047 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004048 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004049 /* counters */
4050 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 +02004051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004052 /* init */
4053 memset(&root, 0, sizeof root);
4054 memset(&grps, 0, sizeof grps);
4055 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004056 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004057
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004058 /*
4059 * in the first run, we process elements with cardinality of 1 or 0..1 and
4060 * count elements with cardinality 0..n. Data elements (choices, containers,
4061 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4062 * need have all top-level and groupings already prepared at that time. In
4063 * the middle loop, we process other elements with carinality of 0..n since
4064 * we need to allocate arrays to store them.
4065 */
4066 LY_TREE_FOR_SAFE(yin->child, next, node) {
4067 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4068 lyxml_free_elem(ctx, node);
4069 continue;
4070 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004071
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004072 if (!module->type && !strcmp(node->name, "namespace")) {
4073 if (module->ns) {
4074 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4075 goto error;
4076 }
4077 GETVAL(value, node, "uri");
4078 module->ns = lydict_insert(ctx, value, strlen(value));
4079 lyxml_free_elem(ctx, node);
4080 } else if (!module->type && !strcmp(node->name, "prefix")) {
4081 if (module->prefix) {
4082 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4083 goto error;
4084 }
4085 GETVAL(value, node, "value");
4086 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4087 goto error;
4088 }
4089 module->prefix = lydict_insert(ctx, value, strlen(value));
4090 lyxml_free_elem(ctx, node);
4091 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4092 if (belongsto_flag) {
4093 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4094 goto error;
4095 }
4096 belongsto_flag = 1;
4097 GETVAL(value, node, "module");
4098 while (submodule->belongsto->type) {
4099 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4100 }
4101 if (value != submodule->belongsto->name) {
4102 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4103 goto error;
4104 }
Radek Krejcif3886932015-06-04 17:36:06 +02004105
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004106 /* get the prefix substatement, start with checks */
4107 if (!node->child) {
4108 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4109 goto error;
4110 } else if (strcmp(node->child->name, "prefix")) {
4111 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4112 goto error;
4113 } else if (node->child->next) {
4114 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4115 goto error;
4116 }
4117 /* and now finally get the value */
4118 GETVAL(value, node->child, "value");
4119 /* check here differs from a generic prefix check, since this prefix
4120 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004121 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004122 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4123 goto error;
4124 }
4125 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004126
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004127 /* we are done with belongs-to */
4128 lyxml_free_elem(ctx, node);
4129 } else if (!strcmp(node->name, "import")) {
4130 c_imp++;
4131 } else if (!strcmp(node->name, "revision")) {
4132 c_rev++;
4133 } else if (!strcmp(node->name, "typedef")) {
4134 c_tpdf++;
4135 } else if (!strcmp(node->name, "identity")) {
4136 c_ident++;
4137 } else if (!strcmp(node->name, "include")) {
4138 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004139 } else if (!strcmp(node->name, "augment")) {
4140 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004141 } else if (!strcmp(node->name, "feature")) {
4142 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004144 /* data statements */
4145 } else if (!strcmp(node->name, "container") ||
4146 !strcmp(node->name, "leaf-list") ||
4147 !strcmp(node->name, "leaf") ||
4148 !strcmp(node->name, "list") ||
4149 !strcmp(node->name, "choice") ||
4150 !strcmp(node->name, "uses") ||
4151 !strcmp(node->name, "anyxml")) {
4152 lyxml_unlink_elem(node);
4153 lyxml_add_child(&root, node);
4154 } else if (!strcmp(node->name, "grouping")) {
4155 /* keep groupings separated and process them before other data statements */
4156 lyxml_unlink_elem(node);
4157 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004159 /* optional statements */
4160 } else if (!strcmp(node->name, "description")) {
4161 if (module->dsc) {
4162 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4163 goto error;
4164 }
4165 module->dsc = read_yin_subnode(ctx, node, "text");
4166 lyxml_free_elem(ctx, node);
4167 if (!module->dsc) {
4168 goto error;
4169 }
4170 } else if (!strcmp(node->name, "reference")) {
4171 if (module->ref) {
4172 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4173 goto error;
4174 }
4175 module->ref = read_yin_subnode(ctx, node, "text");
4176 lyxml_free_elem(ctx, node);
4177 if (!module->ref) {
4178 goto error;
4179 }
4180 } else if (!strcmp(node->name, "organization")) {
4181 if (module->org) {
4182 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4183 goto error;
4184 }
4185 module->org = read_yin_subnode(ctx, node, "text");
4186 lyxml_free_elem(ctx, node);
4187 if (!module->org) {
4188 goto error;
4189 }
4190 } else if (!strcmp(node->name, "contact")) {
4191 if (module->contact) {
4192 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4193 goto error;
4194 }
4195 module->contact = read_yin_subnode(ctx, node, "text");
4196 lyxml_free_elem(ctx, node);
4197 if (!module->contact) {
4198 goto error;
4199 }
4200 } else if (!strcmp(node->name, "yang-version")) {
4201 /* TODO: support YANG 1.1 ? */
4202 if (module->version) {
4203 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4204 goto error;
4205 }
4206 GETVAL(value, node, "value");
4207 if (strcmp(value, "1")) {
4208 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
4209 goto error;
4210 }
4211 module->version = 1;
4212 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02004213
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004214 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02004215 } else if (!strcmp(node->name, "rpc")) {
4216 lyxml_unlink_elem(node);
4217 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02004218 } else if (!strcmp(node->name, "notification")) {
4219 lyxml_unlink_elem(node);
4220 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02004221#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004222 } else {
4223 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
4224 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02004225#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004226 } else {
4227 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02004228#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004229 }
4230 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004232 if (!submodule) {
4233 /* check for mandatory statements */
4234 if (!module->ns) {
4235 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
4236 goto error;
4237 }
4238 if (!module->prefix) {
4239 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
4240 goto error;
4241 }
4242 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02004243
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004244 /* allocate arrays for elements with cardinality of 0..n */
4245 if (c_imp) {
4246 module->imp = calloc(c_imp, sizeof *module->imp);
4247 }
4248 if (c_rev) {
4249 module->rev = calloc(c_rev, sizeof *module->rev);
4250 }
4251 if (c_tpdf) {
4252 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
4253 }
4254 if (c_ident) {
4255 module->ident = calloc(c_ident, sizeof *module->ident);
4256 }
4257 if (c_inc) {
4258 module->inc = calloc(c_inc, sizeof *module->inc);
4259 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004260 if (c_aug) {
4261 module->augment = calloc(c_aug, sizeof *module->augment);
4262 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004263 if (c_ftrs) {
4264 module->features = calloc(c_ftrs, sizeof *module->features);
4265 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004266
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004267 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4268 LY_TREE_FOR_SAFE(yin->child, next, node) {
4269 if (!strcmp(node->name, "import")) {
4270 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
4271 module->imp_size++;
4272 if (r) {
4273 goto error;
4274 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004275
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004276 /* check duplicities in imported modules */
4277 for (i = 0; i < module->imp_size - 1; i++) {
4278 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
4279 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
4280 goto error;
4281 }
4282 }
4283 } else if (!strcmp(node->name, "include")) {
4284 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
4285 module->inc_size++;
4286 if (r) {
4287 goto error;
4288 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004290 /* check duplications in include submodules */
4291 for (i = 0; i < module->inc_size - 1; i++) {
4292 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
4293 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
4294 module->inc[i].submodule->name);
4295 goto error;
4296 }
4297 }
4298 } else if (!strcmp(node->name, "revision")) {
4299 GETVAL(value, node, "date");
4300 if (check_date(value, LOGLINE(node))) {
4301 goto error;
4302 }
4303 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4304 /* check uniqueness of the revision date - not required by RFC */
4305 for (i = 0; i < module->rev_size; i++) {
4306 if (!strcmp(value, module->rev[i].date)) {
4307 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4308 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
4309 }
4310 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004311
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004312 LY_TREE_FOR(node->child, child) {
4313 if (!strcmp(child->name, "description")) {
4314 if (module->rev[module->rev_size].dsc) {
4315 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4316 goto error;
4317 }
4318 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
4319 if (!module->rev[module->rev_size].dsc) {
4320 goto error;
4321 }
4322 } else if (!strcmp(child->name, "reference")) {
4323 if (module->rev[module->rev_size].ref) {
4324 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4325 goto error;
4326 }
4327 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
4328 if (!module->rev[module->rev_size].ref) {
4329 goto error;
4330 }
4331 } else {
4332 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
4333 goto error;
4334 }
4335 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004336
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004337 /* keep the latest revision at position 0 */
4338 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
4339 /* switch their position */
4340 value = strdup(module->rev[0].date);
4341 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
4342 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4343 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02004344
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004345 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
4346 value = module->rev[0].dsc;
4347 module->rev[0].dsc = module->rev[module->rev_size].dsc;
4348 module->rev[module->rev_size].dsc = value;
4349 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004350
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004351 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
4352 value = module->rev[0].ref;
4353 module->rev[0].ref = module->rev[module->rev_size].ref;
4354 module->rev[module->rev_size].ref = value;
4355 }
4356 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004357
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004358 module->rev_size++;
4359 } else if (!strcmp(node->name, "typedef")) {
4360 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
4361 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004363 if (r) {
4364 goto error;
4365 }
4366 } else if (!strcmp(node->name, "identity")) {
4367 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
4368 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02004369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004370 if (r) {
4371 goto error;
4372 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004373 } else if (!strcmp(node->name, "feature")) {
4374 r = fill_yin_feature(module, node, &module->features[module->features_size]);
4375 module->features_size++;
4376
4377 if (r) {
4378 goto error;
4379 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004380 } else if (!strcmp(node->name, "augment")) {
4381 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
4382 module->augment_size++;
4383
4384 if (r) {
4385 goto error;
4386 }
4387
4388 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
4389 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004390 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004391
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004392 lyxml_free_elem(ctx, node);
4393 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004394
Radek Krejcif5be10f2015-06-16 13:29:36 +02004395 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004396 * refer to them
4397 */
4398 LY_TREE_FOR_SAFE(grps.child, next, node) {
4399 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
4400 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02004401
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004402 if (!mnode) {
4403 goto error;
4404 }
Radek Krejci74705112015-06-05 10:25:44 +02004405
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004406 /* include data element */
4407 if (module->data) {
4408 module->data->prev->next = mnode;
4409 mnode->prev = module->data->prev;
4410 module->data->prev = mnode;
4411 } else {
4412 module->data = mnode;
4413 }
4414 }
4415 while (unres) {
4416 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4417 goto error;
4418 }
4419 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4420 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4421 goto error;
4422 }
4423 unres_next = unres->next;
4424 free(unres);
4425 unres = unres_next;
4426 }
Radek Krejci74705112015-06-05 10:25:44 +02004427
Radek Krejcif5be10f2015-06-16 13:29:36 +02004428 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004429 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004430
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004431 if (!strcmp(node->name, "container")) {
4432 mnode = read_yin_container(module, NULL, node, 1, &unres);
4433 } else if (!strcmp(node->name, "leaf-list")) {
4434 mnode = read_yin_leaflist(module, NULL, node, 1);
4435 } else if (!strcmp(node->name, "leaf")) {
4436 mnode = read_yin_leaf(module, NULL, node, 1);
4437 } else if (!strcmp(node->name, "list")) {
4438 mnode = read_yin_list(module, NULL, node, 1, &unres);
4439 } else if (!strcmp(node->name, "choice")) {
4440 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4441 } else if (!strcmp(node->name, "uses")) {
4442 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4443 } else if (!strcmp(node->name, "anyxml")) {
4444 mnode = read_yin_anyxml(module, NULL, node, 1);
4445 }
4446 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004447
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004448 if (!mnode) {
4449 goto error;
4450 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004452 /* include data element */
4453 if (module->data) {
4454 module->data->prev->next = mnode;
4455 mnode->prev = module->data->prev;
4456 module->data->prev = mnode;
4457 } else {
4458 module->data = mnode;
4459 }
4460 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004461
4462 /* ... rpcs ... */
4463 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4464 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4465 lyxml_free_elem(ctx, node);
4466
4467 if (!mnode) {
4468 goto error;
4469 }
4470
4471 /* include rpc element */
4472 if (module->rpc) {
4473 module->rpc->prev->next = mnode;
4474 mnode->prev = module->rpc->prev;
4475 module->rpc->prev = mnode;
4476 } else {
4477 module->rpc = mnode;
4478 }
4479 }
4480
4481 /* ... and notifications */
4482 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4483 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4484 lyxml_free_elem(ctx, node);
4485
4486 if (!mnode) {
4487 goto error;
4488 }
4489
4490 /* include notification element */
4491 if (module->notif) {
4492 module->notif->prev->next = mnode;
4493 mnode->prev = module->notif->prev;
4494 module->notif->prev = mnode;
4495 } else {
4496 module->notif = mnode;
4497 }
4498 }
4499
4500 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004501 while (unres) {
4502 /* find referenced grouping */
4503 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4504 goto error;
4505 }
4506 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4507 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4508 goto error;
4509 }
Radek Krejci74705112015-06-05 10:25:44 +02004510
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004511 /* resolve uses by copying grouping content under the uses */
4512 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4513 goto error;
4514 }
Radek Krejci74705112015-06-05 10:25:44 +02004515
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004516 unres_next = unres->next;
4517 free(unres);
4518 unres = unres_next;
4519 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004520
Radek Krejcif5be10f2015-06-16 13:29:36 +02004521 /* and finally apply augments */
4522 for (i = 0; i < module->augment_size; i++) {
4523 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004524 goto error;
4525 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004526 }
4527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004528 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004529
4530error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004531 /* cleanup */
4532 while (root.child) {
4533 lyxml_free_elem(module->ctx, root.child);
4534 }
4535 while (grps.child) {
4536 lyxml_free_elem(module->ctx, grps.child);
4537 }
4538 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004539 lyxml_free_elem(module->ctx, rpcs.child);
4540 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004542 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004543}
4544
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004545struct ly_submodule *
4546yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004547{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004548 struct lyxml_elem *yin;
4549 struct ly_submodule *submodule = NULL;
4550 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004551
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004552 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004553
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004554 yin = lyxml_read(module->ctx, data, 0);
4555 if (!yin) {
4556 return NULL;
4557 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004558
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004559 /* check root element */
4560 if (!yin->name || strcmp(yin->name, "submodule")) {
4561 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4562 goto error;
4563 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004564
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004565 GETVAL(value, yin, "name");
4566 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4567 goto error;
4568 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004570 submodule = calloc(1, sizeof *submodule);
4571 if (!submodule) {
4572 LOGMEM;
4573 goto error;
4574 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004576 submodule->ctx = module->ctx;
4577 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4578 submodule->type = 1;
4579 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004581 LOGVRB("reading submodule %s", submodule->name);
4582 if (read_sub_module((struct ly_module *)submodule, yin)) {
4583 goto error;
4584 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004585
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004586 /* cleanup */
4587 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004588
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004589 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004590
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004591 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004592
4593error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004594 /* cleanup */
4595 lyxml_free_elem(module->ctx, yin);
4596 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004597
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004598 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004599}
4600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004601struct ly_module *
4602yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004603{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004604 struct lyxml_elem *yin;
4605 struct ly_module *module = NULL, **newlist = NULL;
4606 const char *value;
4607 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004609 yin = lyxml_read(ctx, data, 0);
4610 if (!yin) {
4611 return NULL;
4612 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004613
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004614 /* check root element */
4615 if (!yin->name || strcmp(yin->name, "module")) {
4616 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4617 goto error;
4618 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004619
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004620 GETVAL(value, yin, "name");
4621 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4622 goto error;
4623 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004624
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004625 module = calloc(1, sizeof *module);
4626 if (!module) {
4627 LOGMEM;
4628 goto error;
4629 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004631 module->ctx = ctx;
4632 module->name = lydict_insert(ctx, value, strlen(value));
4633 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004635 LOGVRB("reading module %s", module->name);
4636 if (read_sub_module(module, yin)) {
4637 goto error;
4638 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004639
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004640 /* add to the context's list of modules */
4641 if (ctx->models.used == ctx->models.size) {
4642 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4643 if (!newlist) {
4644 LOGMEM;
4645 goto error;
4646 }
4647 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4648 newlist[i] = NULL;
4649 }
4650 ctx->models.size *= 2;
4651 ctx->models.list = newlist;
4652 }
4653 for (i = 0; ctx->models.list[i]; i++) {
4654 /* check name (name/revision) and namespace uniqueness */
4655 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4656 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4657 /* both data models are same, with no revision specified */
4658 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4659 module->name);
4660 goto error;
4661 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4662 /* one of the models does not have a revision, so they differs */
4663 continue;
4664 } else {
4665 /* both models have a revision statement which we have to
4666 * compare, revision at position 0 is the last revision
4667 */
4668 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4669 /* we have the same modules */
4670 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4671 module->rev[0].date);
4672 goto error;
4673 }
4674 }
4675 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4676 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4677 ctx->models.list[i]->name, module->name, module->ns);
4678 goto error;
4679 }
4680 }
4681 ctx->models.list[i] = module;
4682 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004683
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004684 /* cleanup */
4685 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004686
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004687 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004688
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004689 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004690
4691error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004692 /* cleanup */
4693 lyxml_free_elem(ctx, yin);
4694 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004695
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004696 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004697}