blob: 09630e79c7fc18cc642cf8b26f31f695e12d7e8a [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file yin.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief YIN parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Radek Krejci812b10a2015-05-28 16:48:25 +020022#include <assert.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020023#include <ctype.h>
Radek Krejci8b4f23c2015-06-02 16:09:25 +020024#include <errno.h>
25#include <limits.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020026#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020027#include <stdlib.h>
28#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020029#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020030
Radek Krejciefdd0ce2015-05-26 16:48:29 +020031#include "../libyang.h"
32#include "../common.h"
33#include "../context.h"
34#include "../dict.h"
35#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020036
Radek Krejciefdd0ce2015-05-26 16:48:29 +020037#include "../tree_internal.h"
38#include "../xml.h"
39
Radek Krejcice7fb782015-05-29 16:52:34 +020040enum LY_IDENT {
Radek Krejci994b6f62015-06-18 16:47:27 +020041 LY_IDENT_SIMPLE, /* only syntax rules */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020042 LY_IDENT_FEATURE,
43 LY_IDENT_IDENTITY,
44 LY_IDENT_TYPE,
45 LY_IDENT_NODE,
Radek Krejci994b6f62015-06-18 16:47:27 +020046 LY_IDENT_NAME, /* uniqueness across the siblings */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020047 LY_IDENT_PREFIX
Radek Krejcice7fb782015-05-29 16:52:34 +020048};
49
Radek Krejciefdd0ce2015-05-26 16:48:29 +020050#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020051
Radek Krejcice7fb782015-05-29 16:52:34 +020052#define GETVAL(value, node, arg) \
53 value = lyxml_get_attr(node, arg, NULL); \
54 if (!value) { \
55 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
56 goto error; \
57 }
58
Radek Krejcib388c152015-06-04 17:03:03 +020059#define OPT_IDENT 0x01
60#define OPT_CONFIG 0x02
61#define OPT_MODULE 0x04
62#define OPT_INHERIT 0x08
63static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
64
Radek Krejci74705112015-06-05 10:25:44 +020065struct mnode_list {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020066 struct ly_mnode *mnode;
67 struct mnode_list *next;
68 unsigned int line;
Radek Krejci74705112015-06-05 10:25:44 +020069};
70
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020071static struct ly_mnode *read_yin_choice(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
72 int resolve, struct mnode_list **unres);
73static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
74 int resolve, struct mnode_list **unres);
75static struct ly_mnode *read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
76 int resolve);
77static struct ly_mnode *read_yin_container(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
78 int resolve, struct mnode_list **unres);
79static struct ly_mnode *read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
80 int resolve);
81static struct ly_mnode *read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
82 int resolve);
83static struct ly_mnode *read_yin_list(struct ly_module *module,struct ly_mnode *parent, struct lyxml_elem *yin,
84 int resolve, struct mnode_list **unres);
85static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
86 int resolve, struct mnode_list **unres);
87static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
88 int resolve, struct mnode_list **unres);
Radek Krejcib0af6ba2015-06-18 15:01:03 +020089static struct ly_when *read_yin_when(struct ly_module *module,struct lyxml_elem *yin);
Radek Krejci74705112015-06-05 10:25:44 +020090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091static int
92dup_typedef_check(const char *type, struct ly_tpdf *tpdf, int size)
Radek Krejcieac35532015-05-31 19:09:15 +020093{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020095
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020096 for (i = 0; i < size; i++) {
97 if (!strcmp(type, tpdf[i].name)) {
98 /* name collision */
99 return EXIT_FAILURE;
100 }
101 }
Radek Krejcieac35532015-05-31 19:09:15 +0200102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200104}
105
Radek Krejcib05774c2015-06-18 13:52:59 +0200106
107static int
108dup_feature_check(const char *id, struct ly_module *module)
109{
110 int i;
111
112 for (i = 0; i < module->features_size; i++) {
113 if (!strcmp(id, module->features[i].name)) {
114 return EXIT_FAILURE;
115 }
116 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +0200117
118 return EXIT_SUCCESS;
Radek Krejcib05774c2015-06-18 13:52:59 +0200119}
120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200121static int
122dup_prefix_check(const char *prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200123{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200124 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
127 return EXIT_FAILURE;
128 }
129 for (i = 0; i < module->imp_size; i++) {
130 if (!strcmp(module->imp[i].prefix, prefix)) {
131 return EXIT_FAILURE;
132 }
133 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200134
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200135 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200136}
137
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200138static int
139check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
140 struct ly_module *module, struct ly_mnode *parent)
Radek Krejcice7fb782015-05-29 16:52:34 +0200141{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200142 int i;
143 int size;
144 struct ly_tpdf *tpdf;
145 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200147 assert(id);
Radek Krejcice7fb782015-05-29 16:52:34 +0200148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200149 /* check id syntax */
150 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
151 LOGVAL(VE_INID, line, id, "invalid start character");
152 return EXIT_FAILURE;
153 }
154 for (i = 1; id[i]; i++) {
155 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
156 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
157 LOGVAL(VE_INID, line, id, "invalid character");
158 return EXIT_FAILURE;
159 }
160 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200162 if (i > 64) {
163 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
164 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 switch (type) {
167 case LY_IDENT_NAME:
168 /* check uniqueness of the node within its siblings */
169 if (!parent) {
170 break;
171 }
Radek Krejcib4cf2022015-06-03 14:40:05 +0200172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200173 LY_TREE_FOR(parent->child, mnode) {
174 if (mnode->name == id) {
175 LOGVAL(VE_INID, line, id, "name duplication");
176 return EXIT_FAILURE;
177 }
178 }
179 break;
180 case LY_IDENT_TYPE:
181 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200183 /* check collision with the built-in types */
184 if (!strcmp(id, "binary") || !strcmp(id, "bits") ||
185 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
186 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
187 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
188 !strcmp(id, "int8") || !strcmp(id, "int16") ||
189 !strcmp(id, "int32") || !strcmp(id, "int64") ||
190 !strcmp(id, "leafref") || !strcmp(id, "string") ||
191 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
192 !strcmp(id, "uint32") || !strcmp(id, "uint64") || !strcmp(id, "union")) {
193 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
194 return EXIT_FAILURE;
195 }
Radek Krejcieac35532015-05-31 19:09:15 +0200196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200197 /* check locally scoped typedefs (avoid name shadowing) */
198 for (; parent; parent = parent->parent) {
199 switch (parent->nodetype) {
200 case LY_NODE_CONTAINER:
201 size = ((struct ly_mnode_container *)parent)->tpdf_size;
202 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
203 break;
204 case LY_NODE_LIST:
205 size = ((struct ly_mnode_list *)parent)->tpdf_size;
206 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
207 break;
208 case LY_NODE_GROUPING:
209 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
210 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
211 break;
212 default:
213 continue;
214 }
Radek Krejcieac35532015-05-31 19:09:15 +0200215
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200216 if (dup_typedef_check(id, tpdf, size)) {
217 LOGVAL(VE_DUPID, line, "typedef", id);
218 return EXIT_FAILURE;
219 }
220 }
Radek Krejcieac35532015-05-31 19:09:15 +0200221
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200222 /* check top-level names */
223 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
224 LOGVAL(VE_DUPID, line, "typedef", id);
225 return EXIT_FAILURE;
226 }
Radek Krejcieac35532015-05-31 19:09:15 +0200227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200228 /* check submodule's top-level names */
229 for (i = 0; i < module->inc_size; i++) {
230 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
231 LOGVAL(VE_DUPID, line, "typedef", id);
232 return EXIT_FAILURE;
233 }
234 }
Radek Krejcieac35532015-05-31 19:09:15 +0200235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200236 /* check top-level names in the main module */
237 if (module->type) {
238 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
239 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
240 LOGVAL(VE_DUPID, line, "typedef", id);
241 return EXIT_FAILURE;
242 }
243 }
Radek Krejcieac35532015-05-31 19:09:15 +0200244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200245 break;
246 case LY_IDENT_PREFIX:
247 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200249 if (module->type) {
250 /* go to the main module */
251 module = ((struct ly_submodule *)module)->belongsto;
252 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200253
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200254 /* check the main module itself */
255 if (dup_prefix_check(id, module)) {
256 LOGVAL(VE_DUPID, line, "prefix", id);
257 return EXIT_FAILURE;
258 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200260 /* and all its submodules */
261 for (i = 0; i < module->inc_size; i++) {
262 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
263 LOGVAL(VE_DUPID, line, "prefix", id);
264 return EXIT_FAILURE;
265 }
266 }
267 break;
Radek Krejcib05774c2015-06-18 13:52:59 +0200268 case LY_IDENT_FEATURE:
269 assert(module);
270
271 /* check feature name uniqness*/
Radek Krejci49babf32015-06-18 13:56:17 +0200272 /* check features in the current module */
Radek Krejcib05774c2015-06-18 13:52:59 +0200273 if (dup_feature_check(id, module)) {
274 LOGVAL(VE_DUPID, line, "feature", id);
275 return EXIT_FAILURE;
276 }
277
278 /* and all its submodules */
279 for (i = 0; i < module->inc_size; i++) {
280 if (dup_feature_check(id, (struct ly_module *)module->inc[i].submodule)) {
281 LOGVAL(VE_DUPID, line, "feature", id);
282 return EXIT_FAILURE;
283 }
284 }
285 break;
286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200287 default:
288 /* no check required */
289 break;
290 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200292 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200293}
294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200295static int
296check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
297 const char *name, int len)
Radek Krejci345ad742015-06-03 11:04:18 +0200298{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200299 char *dup = NULL;
300 int j;
Radek Krejci345ad742015-06-03 11:04:18 +0200301
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200302 /* existence */
303 if (!key) {
304 if (name[len] != '\0') {
305 dup = strdup(name);
306 dup[len] = '\0';
307 name = dup;
308 }
309 LOGVAL(VE_KEY_MISS, line, name);
310 free(dup);
311 return EXIT_FAILURE;
312 }
Radek Krejci345ad742015-06-03 11:04:18 +0200313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200314 /* uniqueness */
315 for (j = index - 1; j >= 0; j--) {
316 if (list[index] == list[j]) {
317 LOGVAL(VE_KEY_DUP, line, key->name);
318 return EXIT_FAILURE;
319 }
320 }
Radek Krejci345ad742015-06-03 11:04:18 +0200321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200322 /* key is a leaf */
323 if (key->nodetype != LY_NODE_LEAF) {
324 LOGVAL(VE_KEY_NLEAF, line, key->name);
325 return EXIT_FAILURE;
326 }
Radek Krejci345ad742015-06-03 11:04:18 +0200327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200328 /* type of the leaf is not built-in empty */
329 if (key->type.base == LY_TYPE_EMPTY) {
330 LOGVAL(VE_KEY_TYPE, line, key->name);
331 return EXIT_FAILURE;
332 }
Radek Krejci345ad742015-06-03 11:04:18 +0200333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200334 /* config attribute is the same as of the list */
335 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
336 LOGVAL(VE_KEY_CONFIG, line, key->name);
337 return EXIT_FAILURE;
338 }
Radek Krejci345ad742015-06-03 11:04:18 +0200339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200340 return EXIT_SUCCESS;
Radek Krejci345ad742015-06-03 11:04:18 +0200341}
342
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200343static int
Radek Krejci3de29a72015-06-16 15:23:03 +0200344check_mandatory(struct ly_mnode *mnode)
345{
346 struct ly_mnode *child;
347
348 assert(mnode);
349
350 if (mnode->flags & LY_NODE_MAND_TRUE) {
351 return EXIT_FAILURE;
352 }
353
Radek Krejcifd0bb0a2015-06-18 13:18:24 +0200354 if (mnode->nodetype == LY_NODE_CASE || mnode->nodetype == LY_NODE_CHOICE) {
355 LY_TREE_FOR(mnode->child, child) {
356 if (check_mandatory(child)) {
357 return EXIT_FAILURE;
358 }
Radek Krejci3de29a72015-06-16 15:23:03 +0200359 }
360 }
361
362 return EXIT_SUCCESS;
363}
364
365static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200366check_default(struct ly_type *type, const char *value)
Radek Krejcieac35532015-05-31 19:09:15 +0200367{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200368 /* TODO - RFC 6020, sec. 7.3.4 */
369 (void)type;
370 (void)value;
371 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200372}
373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200374static int
375check_date(const char *date, unsigned int line)
Radek Krejcice7fb782015-05-29 16:52:34 +0200376{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200377 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200378
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200379 assert(date);
Radek Krejcice7fb782015-05-29 16:52:34 +0200380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200381 if (strlen(date) != LY_REV_SIZE - 1) {
382 goto error;
383 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200385 for (i = 0; i < LY_REV_SIZE - 1; i++) {
386 if (i == 4 || i == 7) {
387 if (date[i] != '-') {
388 goto error;
389 }
390 } else if (!isdigit(date[i])) {
391 goto error;
392 }
393 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200394
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200395 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200396
397error:
398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200399 LOGVAL(VE_INDATE, line, date);
400 return EXIT_FAILURE;
Radek Krejcice7fb782015-05-29 16:52:34 +0200401}
402
Radek Krejci41726f92015-06-19 13:11:05 +0200403static int
404check_length(const char *expr, struct ly_type *type, unsigned int line)
405{
406 const char *c = expr;
407 char *tail;
408 uint64_t limit = 0, n;
409 int flg = 1; /* first run flag */
410
411 assert(expr);
412
413 /* TODO check compatibility with the restriction defined on type from which this type is derived,
414 * it will be the same function to check that the value from instance data respect the restriction */
415 (void)type;
416
417lengthpart:
418
419 while (isspace(*c)) {
420 c++;
421 }
422
423 /* lower boundary or explicit number */
424 if (!strncmp(c, "max", 3)) {
425max:
426 c += 3;
427 while (isspace(*c)) {
428 c++;
429 }
430 if (*c != '\0') {
431 goto error;
432 }
433
434 return EXIT_SUCCESS;
435
436 } else if (!strncmp(c, "min", 3)) {
437 if (!flg) {
438 /* min cannot be used elsewhere than in the first length-part */
439 goto error;
440 } else {
441 flg = 0;
442 /* remember value/lower boundary */
443 limit = 0;
444 }
445 c += 3;
446 while (isspace(*c)) {
447 c++;
448 }
449
450 if (*c == '|') {
451 c++;
452 /* process next length-parth */
453 goto lengthpart;
454 } else if (*c == '\0') {
455 return EXIT_SUCCESS;
456 } else if (!strncmp(c, "..", 2)) {
457upper:
458 c += 2;
459 while (isspace(*c)) {
460 c++;
461 }
462 if (*c == '\0') {
463 goto error;
464 }
465
466 /* upper boundary */
467 if (!strncmp(c, "max", 3)) {
468 goto max;
469 }
470
471 if (!isdigit(*c)) {
472 goto error;
473 }
474
475 n = strtol(c, &tail, 10);
476 c = tail;
477 while (isspace(*c)) {
478 c++;
479 }
480 if (n <= limit) {
481 goto error;
482 }
483 if (*c == '\0') {
484 return EXIT_SUCCESS;
485 } else if (*c == '|') {
486 c++;
487 /* remember the uppre boundary for check in next part */
488 limit = n;
489 /* process next length-parth */
490 goto lengthpart;
491 } else {
492 goto error;
493 }
494 } else {
495 goto error;
496 }
497
498 } else if (isdigit(*c)) {
499 /* number */
500 n = strtol(c, &tail, 10);
501 c = tail;
502 while (isspace(*c)) {
503 c++;
504 }
505 /* skip limit check in first length-part check */
506 if (!flg && n <= limit) {
507 goto error;
508 }
509 flg = 0;
510 limit = n;
511
512 if (*c == '|') {
513 c++;
514 /* process next length-parth */
515 goto lengthpart;
516 } else if (*c == '\0') {
517 return EXIT_SUCCESS;
518 } else if (!strncmp(c, "..", 2)) {
519 goto upper;
520 }
521 } /* else error */
522
523error:
524
525 LOGVAL(VE_INARG, line, expr, "length");
526 return EXIT_FAILURE;
527}
528
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200529static const char *
530read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200531{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200532 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200534 /* there should be <text> child */
535 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
536 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
537 } else if (node->child->content) {
538 len = strlen(node->child->content);
539 return lydict_insert(ctx, node->child->content, len);
540 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200542 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
543 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200544}
545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200546static struct ly_tpdf *
547find_superior_type(const char *name, struct ly_module *module, struct ly_mnode *parent)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200548{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200549 int i, j, found = 0;
550 int prefix_len = 0;
551 const char *qname;
552 struct ly_tpdf *tpdf;
553 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200555 qname = strchr(name, ':');
Radek Krejcida04f4a2015-05-21 12:54:09 +0200556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200557 if (!qname) {
558 /* no prefix, try built-in types */
559 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
560 if (!strcmp(ly_types[i].def->name, name)) {
561 return ly_types[i].def;
562 }
563 }
564 qname = name;
565 } else {
566 /* set qname to correct position after colon */
567 prefix_len = qname - name;
568 qname++;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200570 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
571 /* prefix refers to the current module, ignore it */
572 prefix_len = 0;
573 }
574 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200576 if (!prefix_len && parent) {
577 /* search in local typedefs */
578 while (parent) {
579 switch (parent->nodetype) {
580 case LY_NODE_CONTAINER:
581 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
582 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
583 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200584
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200585 case LY_NODE_LIST:
586 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
587 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
588 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200589
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200590 case LY_NODE_GROUPING:
591 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
592 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
593 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200594
Radek Krejci3cf9e222015-06-18 11:37:50 +0200595 /* TODO add rpc, notification, input, output */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200596 default:
597 parent = parent->parent;
598 continue;
599 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200601 for (i = 0; i < tpdf_size; i++) {
602 if (!strcmp(tpdf[i].name, qname)) {
603 return &tpdf[i];
604 }
605 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200607 parent = parent->parent;
608 }
609 } else if (prefix_len) {
610 /* get module where to search */
611 for (i = 0; i < module->imp_size; i++) {
612 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
613 module = module->imp[i].module;
614 found = 1;
615 break;
616 }
617 }
618 if (!found) {
619 return NULL;
620 }
621 }
622
623 /* search in top level typedefs */
624 for (i = 0; i < module->tpdf_size; i++) {
625 if (!strcmp(module->tpdf[i].name, qname)) {
626 return &module->tpdf[i];
627 }
628 }
629
630 /* search in submodules */
631 for (i = 0; i < module->inc_size; i++) {
632 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
633 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
634 return &module->inc[i].submodule->tpdf[j];
635 }
636 }
637 }
638
639 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200640}
641
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200642static struct ly_ident *
643find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
Radek Krejciefaeba32015-05-27 14:30:57 +0200644{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200645 unsigned int i;
646 struct ly_ident *base_iter;
647 struct ly_ident_der *der;
Radek Krejciefaeba32015-05-27 14:30:57 +0200648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200649 for (i = 0; i < module->ident_size; i++) {
650 if (!strcmp(basename, module->ident[i].name)) {
651 /* we are done */
Radek Krejciefaeba32015-05-27 14:30:57 +0200652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200653 if (!ident) {
654 /* just search for type, so do not modify anything, just return
655 * the base identity pointer
656 */
657 return &module->ident[i];
658 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200660 /* we are resolving identity definition, so now update structures */
661 ident->base = base_iter = &module->ident[i];
Radek Krejciefaeba32015-05-27 14:30:57 +0200662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200663 while (base_iter) {
664 for (der = base_iter->der; der && der->next; der = der->next);
665 if (der) {
666 der->next = malloc(sizeof *der);
667 der = der->next;
668 } else {
669 ident->base->der = der = malloc(sizeof *der);
670 }
671 der->next = NULL;
672 der->ident = ident;
Radek Krejciefaeba32015-05-27 14:30:57 +0200673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200674 base_iter = base_iter->base;
675 }
676 return ident->base;
677 }
678 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200679
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200680 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200681}
682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200683static struct ly_ident *
684find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200685{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200686 const char *name;
687 int prefix_len = 0;
688 int i, found = 0;
689 struct ly_ident *result;
690 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200692 basename = lyxml_get_attr(node, "name", NULL);
693 if (!basename) {
694 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
695 return NULL;
696 }
Radek Krejci04581c62015-05-22 21:24:00 +0200697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200698 /* search for the base identity */
699 name = strchr(basename, ':');
700 if (name) {
701 /* set name to correct position after colon */
702 prefix_len = name - basename;
703 name++;
Radek Krejci04581c62015-05-22 21:24:00 +0200704
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200705 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
706 /* prefix refers to the current module, ignore it */
707 prefix_len = 0;
708 }
709 } else {
710 name = basename;
711 }
Radek Krejci04581c62015-05-22 21:24:00 +0200712
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200713 if (prefix_len) {
714 /* get module where to search */
715 for (i = 0; i < module->imp_size; i++) {
716 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
717 && !module->imp[i].prefix[prefix_len]) {
718 module = module->imp[i].module;
719 found = 1;
720 break;
721 }
722 }
723 if (!found) {
724 /* identity refers unknown data model */
725 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
726 return NULL;
727 }
728 } else {
729 /* search in submodules */
730 for (i = 0; i < module->inc_size; i++) {
731 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
732 if (result) {
733 return result;
734 }
735 }
736 }
Radek Krejci04581c62015-05-22 21:24:00 +0200737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200738 /* search in the identified module */
739 result = find_base_ident_sub(module, ident, name);
740 if (!result) {
741 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
742 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200743
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200744 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200745}
746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200747static int
748fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
Radek Krejci04581c62015-05-22 21:24:00 +0200749{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200750 struct lyxml_elem *node, *next;
Radek Krejci04581c62015-05-22 21:24:00 +0200751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200752 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
753 return EXIT_FAILURE;
754 }
Radek Krejci04581c62015-05-22 21:24:00 +0200755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200756 LY_TREE_FOR_SAFE(yin->child, next, node) {
757 if (!strcmp(node->name, "base")) {
758 if (ident->base) {
759 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
760 return EXIT_FAILURE;
761 }
762 if (!find_base_ident(module, ident, node)) {
763 return EXIT_FAILURE;
764 }
765 } else {
766 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
767 return EXIT_FAILURE;
768 }
Radek Krejci04581c62015-05-22 21:24:00 +0200769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200770 lyxml_free_elem(module->ctx, node);
771 }
Radek Krejci04581c62015-05-22 21:24:00 +0200772
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200773 return EXIT_SUCCESS;
Radek Krejci04581c62015-05-22 21:24:00 +0200774}
775
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200776static int
Radek Krejci0bd5db42015-06-19 13:30:07 +0200777read_restr_substmt(struct ly_ctx *ctx, struct ly_restr *restr, struct lyxml_elem *yin)
Radek Krejci41726f92015-06-19 13:11:05 +0200778{
779 struct lyxml_elem *next, *child;
780
781 LY_TREE_FOR_SAFE(yin->child, next, child) {
782 if (!strcmp(child->name, "description")) {
783 if (restr->dsc) {
784 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
785 return EXIT_FAILURE;
786 }
787 restr->dsc = read_yin_subnode(ctx, child, "text");
788 if (!restr->dsc) {
789 return EXIT_FAILURE;
790 }
791 } else if (!strcmp(child->name, "reference")) {
792 if (restr->ref) {
793 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
794 return EXIT_FAILURE;
795 }
796 restr->ref = read_yin_subnode(ctx, child, "text");
797 if (!restr->ref) {
798 return EXIT_FAILURE;
799 }
800 } else if (!strcmp(child->name, "error-app-tag")) {
801 if (restr->eapptag) {
802 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
803 return EXIT_FAILURE;
804 }
805 restr->eapptag = read_yin_subnode(ctx, child, "value");
806 if (!restr->eapptag) {
807 return EXIT_FAILURE;
808 }
809 } else if (!strcmp(child->name, "error-message")) {
810 if (restr->emsg) {
811 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
812 return EXIT_FAILURE;
813 }
814 restr->emsg = read_yin_subnode(ctx, child, "value");
815 if (!restr->emsg) {
816 return EXIT_FAILURE;
817 }
818 } else {
819 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
820 return EXIT_FAILURE;
821 }
822
823 lyxml_free_elem(ctx, child);
824 }
825
826 return EXIT_SUCCESS;
827}
828
829static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200830fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200831{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200832 const char *value, *delim;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200833 struct lyxml_elem *next, *node;
Radek Krejci994b6f62015-06-18 16:47:27 +0200834 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200835 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200836 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200837
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200838 GETVAL(value, yin, "name")
839 delim = strchr(value, ':');
840 if (delim) {
841 type->prefix = lydict_insert(module->ctx, value, delim - value);
842 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200843
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200844 type->der = find_superior_type(value, module, parent);
845 if (!type->der) {
846 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
847 goto error;
848 }
849 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200850
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200851 switch (type->base) {
852 case LY_TYPE_BINARY:
Radek Krejci41726f92015-06-19 13:11:05 +0200853 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
854 LY_TREE_FOR_SAFE(yin->child, next, node) {
855 if (!strcmp(node->name, "length")) {
856 if (type->info.binary.length) {
857 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
858 goto error;
859 }
860
861 GETVAL(value, node, "value");
862 if (check_length(value, type, LOGLINE(node))) {
863 goto error;
864 }
865 type->info.binary.length = calloc(1, sizeof *type->info.binary.length);
866 type->info.binary.length->expr = lydict_insert(module->ctx, value, 0);
867
868 /* get possible substatements */
Radek Krejci0bd5db42015-06-19 13:30:07 +0200869 if (read_restr_substmt(module->ctx, (struct ly_restr *)type->info.binary.length, node)) {
Radek Krejci41726f92015-06-19 13:11:05 +0200870 goto error;
871 }
872 } else {
873 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
874 goto error;
875 }
876 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200877 break;
Radek Krejci04581c62015-05-22 21:24:00 +0200878
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200879 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200880 /* RFC 6020 9.7.4 - bit */
881
882 /* get bit specifications, at least one must be present */
883 LY_TREE_FOR_SAFE(yin->child, next, node) {
884 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200885 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200886 } else {
887 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
888 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200889 }
890 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200891 if (!type->info.bits.count) {
892 if (type->der->type.der) {
893 /* this is just a derived type with no bit specified */
894 break;
895 }
896 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
897 goto error;
898 }
899
900 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200901 for (i = p = 0; yin->child; i++) {
902 GETVAL(value, yin->child, "name");
903 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200904 goto error;
905 }
906 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200907 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], yin->child, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200908 type->info.bits.count = i + 1;
909 goto error;
910 }
911
912 /* check the name uniqueness */
913 for (j = 0; j < i; j++) {
914 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200915 LOGVAL(VE_BITS_DUPNAME, LOGLINE(yin->child), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200916 type->info.bits.count = i + 1;
917 goto error;
918 }
919 }
920
Radek Krejci5fbc9162015-06-19 14:11:11 +0200921 node = yin->child->child;
Radek Krejci994b6f62015-06-18 16:47:27 +0200922 if (node && !strcmp(node->name, "position")) {
923 value = lyxml_get_attr(node, "value", NULL);
924 p_ = strtol(value, NULL, 10);
925
926 /* range check */
927 if (p_ < 0 || p_ > UINT32_MAX) {
928 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
929 type->info.bits.count = i + 1;
930 goto error;
931 }
932 type->info.bits.bit[i].pos = (uint32_t)p_;
933
934 /* keep the highest enum value for automatic increment */
935 if (type->info.bits.bit[i].pos > p) {
936 p = type->info.bits.bit[i].pos;
937 p++;
938 } else {
939 /* check that the value is unique */
940 for (j = 0; j < i; j++) {
941 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
942 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
943 type->info.bits.count = i + 1;
944 goto error;
945 }
946 }
947 }
948 } else {
949 /* assign value automatically */
950 if (p > UINT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200951 LOGVAL(VE_INARG, LOGLINE(yin->child), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +0200952 type->info.bits.count = i + 1;
953 goto error;
954 }
955 type->info.bits.bit[i].pos = (uint32_t)p;
956 p++;
957 }
Radek Krejci5fbc9162015-06-19 14:11:11 +0200958 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci994b6f62015-06-18 16:47:27 +0200959 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200960 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200961
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200962 case LY_TYPE_DEC64:
963 /* TODO fraction-digits, 9.3.4
964 * - MUST, 1, nerekurzivni, hodnota 1-18 */
965 /* TODO range, 9.2.4
966 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
967 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200968
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200969 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200970 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200971
Radek Krejci994b6f62015-06-18 16:47:27 +0200972 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200973 LY_TREE_FOR_SAFE(yin->child, next, node) {
974 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200975 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200976 } else {
977 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
978 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200979 }
980 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200981 if (!type->info.enums.count) {
982 if (type->der->type.der) {
983 /* this is just a derived type with no enum specified */
984 break;
985 }
986 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
987 goto error;
988 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200989
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200990 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200991 for (i = v = 0; yin->child; i++) {
992 GETVAL(value, yin->child, "name");
993 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200994 goto error;
995 }
996 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200997 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200998 type->info.enums.count = i + 1;
999 goto error;
1000 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001001
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001002 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1003 value = type->info.enums.list[i].name;
1004 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001005 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001006 type->info.enums.count = i + 1;
1007 goto error;
1008 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001010 /* check the name uniqueness */
1011 for (j = 0; j < i; j++) {
1012 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001013 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001014 type->info.enums.count = i + 1;
1015 goto error;
1016 }
1017 }
Radek Krejci04581c62015-05-22 21:24:00 +02001018
Radek Krejci5fbc9162015-06-19 14:11:11 +02001019 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001020 if (node && !strcmp(node->name, "value")) {
1021 value = lyxml_get_attr(node, "value", NULL);
1022 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001023
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001024 /* range check */
1025 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1026 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1027 type->info.enums.count = i + 1;
1028 goto error;
1029 }
1030 type->info.enums.list[i].value = v_;
1031
1032 /* keep the highest enum value for automatic increment */
1033 if (type->info.enums.list[i].value > v) {
1034 v = type->info.enums.list[i].value;
1035 v++;
1036 } else {
1037 /* check that the value is unique */
1038 for (j = 0; j < i; j++) {
1039 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001040 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 +02001041 type->info.enums.count = i + 1;
1042 goto error;
1043 }
1044 }
1045 }
1046 } else {
1047 /* assign value automatically */
1048 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001049 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001050 type->info.enums.count = i + 1;
1051 goto error;
1052 }
1053 type->info.enums.list[i].value = v;
1054 v++;
1055 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001056 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001057 }
1058 break;
1059
1060 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001061 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001062
1063 /* get base specification, exactly one must be present */
1064 if (!yin->child) {
1065 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1066 goto error;
1067 }
1068 if (strcmp(yin->child->name, "base")) {
1069 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1070 goto error;
1071 }
1072 if (yin->child->next) {
1073 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1074 goto error;
1075 }
1076 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1077 if (!type->info.ident.ref) {
1078 return EXIT_FAILURE;
1079 }
1080 break;
1081
1082 case LY_TYPE_INST:
1083 /* TODO require-instance, 9.13.2
1084 * - 0..1, true/false */
1085 break;
1086
1087 case LY_TYPE_INT8:
1088 case LY_TYPE_INT16:
1089 case LY_TYPE_INT32:
1090 case LY_TYPE_INT64:
1091 case LY_TYPE_UINT8:
1092 case LY_TYPE_UINT16:
1093 case LY_TYPE_UINT32:
1094 case LY_TYPE_UINT64:
1095 /* TODO range, 9.2.4
1096 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
1097 break;
1098
1099 case LY_TYPE_LEAFREF:
1100 /* TODO path, 9.9.2
1101 * - 1, nerekurzivni, string */
1102 break;
1103
1104 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001105 /* RFC 6020 9.4.4 - length */
1106 /* RFC 6020 9.4.6 - pattern */
1107 LY_TREE_FOR_SAFE(yin->child, next, node) {
1108 if (!strcmp(node->name, "length")) {
1109 if (type->info.str.length) {
1110 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1111 goto error;
1112 }
1113
1114 GETVAL(value, node, "value");
1115 if (check_length(value, type, LOGLINE(node))) {
1116 goto error;
1117 }
1118 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1119 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1120
Radek Krejci5fbc9162015-06-19 14:11:11 +02001121 /* get possible sub-statements */
1122 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001123 goto error;
1124 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001125 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci3733a802015-06-19 13:43:21 +02001126 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001127 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001128 } else {
1129 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1130 goto error;
1131 }
1132 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001133 /* store patterns in array */
1134 if (type->info.str.pat_count) {
1135 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1136 for (i = 0; yin->child; i++) {
1137 GETVAL(value, yin->child, "value");
1138 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1139
1140 /* get possible sub-statements */
1141 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1142 goto error;
1143 }
1144 lyxml_free_elem(module->ctx, yin->child);
1145 }
1146 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001147 break;
1148
1149 case LY_TYPE_UNION:
1150 /* TODO type, 7.4
1151 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1152 break;
1153
1154 default:
1155 /* nothing needed :
1156 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1157 */
1158 break;
1159 }
1160
1161 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001162
1163error:
1164
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001165 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001166}
1167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001168static int
1169fill_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 +02001170{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001171 const char *value;
1172 struct lyxml_elem *node, *next;
1173 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001174
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001175 GETVAL(value, yin, "name");
1176 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1177 goto error;
1178 }
1179 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001180
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001181 /* generic part - status, description, reference */
1182 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1183 goto error;
1184 }
Radek Krejcieac35532015-05-31 19:09:15 +02001185
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001186 LY_TREE_FOR_SAFE(yin->child, next, node) {
1187 if (!strcmp(node->name, "type")) {
1188 if (tpdf->type.der) {
1189 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1190 goto error;
1191 }
1192 r = fill_yin_type(module, parent, node, &tpdf->type);
1193 } else if (!strcmp(node->name, "default")) {
1194 if (tpdf->dflt) {
1195 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1196 goto error;
1197 }
1198 GETVAL(value, node, "value");
1199 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1200 } else if (!strcmp(node->name, "units")) {
1201 if (tpdf->units) {
1202 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1203 goto error;
1204 }
1205 GETVAL(value, node, "name");
1206 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1207 } else {
1208 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1209 r = 1;
1210 }
1211 lyxml_free_elem(module->ctx, node);
1212 if (r) {
1213 goto error;
1214 }
1215 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001217 /* check mandatory value */
1218 if (!tpdf->type.der) {
1219 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1220 goto error;
1221 }
Radek Krejcieac35532015-05-31 19:09:15 +02001222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001223 /* check default value */
1224 if (check_default(&tpdf->type, tpdf->dflt)) {
1225 goto error;
1226 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001228 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001229
1230error:
1231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001232 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001233}
1234
Radek Krejci3cf9e222015-06-18 11:37:50 +02001235static struct ly_feature *
1236resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1237{
1238 const char *prefix;
1239 unsigned int prefix_len = 0;
1240 int i, j, found = 0;
1241
1242 assert(name);
1243 assert(module);
1244
1245 /* check prefix */
1246 prefix = name;
1247 name = strchr(prefix, ':');
1248 if (name) {
1249 /* there is prefix */
1250 prefix_len = name - prefix;
1251 name++;
1252
1253 /* check whether the prefix points to the current module */
1254 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1255 /* then ignore prefix and works as there is no prefix */
1256 prefix_len = 0;
1257 }
1258 } else {
1259 /* no prefix, set pointers correctly */
1260 name = prefix;
1261 }
1262
1263 if (prefix_len) {
1264 /* search in imported modules */
1265 for (i = 0; i < module->imp_size; i++) {
1266 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1267 module = module->imp[i].module;
1268 found = 1;
1269 break;
1270 }
1271 }
1272 if (!found) {
1273 /* identity refers unknown data model */
1274 LOGVAL(VE_INPREFIX, line, prefix);
1275 return NULL;
1276 }
1277 } else {
1278 /* search in submodules */
1279 for (i = 0; i < module->inc_size; i++) {
1280 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1281 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1282 return &(module->inc[i].submodule->features[j]);
1283 }
1284 }
1285 }
1286 }
1287
1288 /* search in the identified module */
1289 for (j = 0; j < module->features_size; j++) {
1290 if (!strcmp(name, module->features[j].name)) {
1291 return &module->features[j];
1292 }
1293 }
1294
1295 /* not found */
1296 return NULL;
1297}
1298
1299static int
1300fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1301{
1302 const char *value;
1303 struct lyxml_elem *child, *next;
1304 int c = 0;
1305
Radek Krejcib05774c2015-06-18 13:52:59 +02001306 GETVAL(value, yin, "name");
1307 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1308 goto error;
1309 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001310 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001311
1312 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001313 goto error;
1314 }
1315
1316 LY_TREE_FOR_SAFE(yin->child, next, child) {
1317 if (!strcmp(child->name, "if-feature")) {
1318 c++;
1319 } else {
1320 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1321 goto error;
1322 }
1323 }
1324
1325 if (c) {
1326 f->features = calloc(c, sizeof *f->features);
1327 }
1328
1329 LY_TREE_FOR_SAFE(yin->child, next, child) {
1330 GETVAL(value, child, "name");
1331 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1332 if (!f->features[f->features_size]) {
1333 goto error;
1334 }
1335 f->features_size++;
1336 }
1337
1338 /* tmp TODO remove */
1339 f->flags |= LY_NODE_FENABLED;
1340
1341 return EXIT_SUCCESS;
1342
1343error:
1344
1345 return EXIT_FAILURE;
1346}
1347
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001348static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001349fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001350{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001351 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001352
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001353 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001354 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001355
Radek Krejci41726f92015-06-19 13:11:05 +02001356 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001357
Radek Krejci41726f92015-06-19 13:11:05 +02001358error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001359
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001360 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001361}
1362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001363static int
1364fill_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 +02001365{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001366 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001367 struct lyxml_elem *next, *child;
1368 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001370 GETVAL(value, yin, "target-node");
1371 aug->target_name = lydict_insert(module->ctx, value, 0);
1372 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001373
Radek Krejci3cf9e222015-06-18 11:37:50 +02001374 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1375 goto error;
1376 }
1377
1378 LY_TREE_FOR_SAFE(yin->child, next, child) {
1379 if (!strcmp(child->name, "if-feature")) {
1380 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001381 } else if (!strcmp(child->name, "when")) {
1382 if (aug->when) {
1383 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1384 goto error;
1385 }
1386
1387 aug->when = read_yin_when(module, child);
1388 lyxml_free_elem(module->ctx, child);
1389
1390 if (!aug->when) {
1391 goto error;
1392 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001393
1394 /* check allowed sub-statements */
1395 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1396 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1397 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1398 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1399 goto error;
1400 }
1401 }
1402
1403 if (c) {
1404 aug->features = calloc(c, sizeof *aug->features);
1405 }
1406
1407 LY_TREE_FOR_SAFE(yin->child, next, child) {
1408 if (!strcmp(child->name, "if-feature")) {
1409 GETVAL(value, child, "name");
1410 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1411 if (!aug->features[aug->features_size]) {
1412 goto error;
1413 }
1414 aug->features_size++;
1415 } else {
1416 /* keep the data nodes */
1417 continue;
1418 }
1419
1420 lyxml_free_elem(module->ctx, child);
1421 }
1422
1423 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001424 * when we will have the target node
1425 */
1426 lyxml_unlink_elem(yin);
1427 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001428
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001429 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001430
1431error:
1432
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001433 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001434}
1435
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001436static int
1437fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001438{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001439 struct lyxml_elem *sub, *next;
1440 const char *value;
1441 char *endptr;
1442 int f_mand = 0, f_min = 0, f_max = 0;
1443 int c_must = 0;
1444 int r;
1445 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001447 GETVAL(value, yin, "target-node");
1448 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001449
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001450 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1451 goto error;
1452 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001453
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001454 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1455 /* limited applicability */
1456 if (!strcmp(sub->name, "default")) {
1457 /* leaf or choice */
1458 if (rfn->mod.dflt) {
1459 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1460 goto error;
1461 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001462
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001463 /* check possibility of statements combination */
1464 if (rfn->target_type) {
1465 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1466 if (!rfn->target_type) {
1467 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1468 goto error;
1469 }
1470 } else {
1471 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1472 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001473
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001474 GETVAL(value, sub, "value");
1475 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1476 } else if (!strcmp(sub->name, "mandatory")) {
1477 /* leaf, choice or anyxml */
1478 if (f_mand) {
1479 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1480 goto error;
1481 }
1482 /* just checking the flags in leaf is not sufficient, we would allow
1483 * multiple mandatory statements with the "false" value
1484 */
1485 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001486
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001487 /* check possibility of statements combination */
1488 if (rfn->target_type) {
1489 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1490 if (!rfn->target_type) {
1491 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1492 goto error;
1493 }
1494 } else {
1495 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1496 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001497
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001498 GETVAL(value, sub, "value");
1499 if (!strcmp(value, "true")) {
1500 rfn->flags |= LY_NODE_MAND_TRUE;
1501 } else if (!strcmp(value, "false")) {
1502 rfn->flags |= LY_NODE_MAND_FALSE;
1503 } else {
1504 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1505 goto error;
1506 }
1507 } else if (!strcmp(sub->name, "min-elements")) {
1508 /* list or leaf-list */
1509 if (f_min) {
1510 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1511 goto error;
1512 }
1513 f_min = 1;
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_LIST | LY_NODE_LEAFLIST);
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_LIST | LY_NODE_LEAFLIST;
1524 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001526 GETVAL(value, sub, "value");
1527 while (isspace(value[0])) {
1528 value++;
1529 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001531 /* convert it to uint32_t */
1532 errno = 0;
1533 endptr = NULL;
1534 val = strtoul(value, &endptr, 10);
1535 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1536 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1537 goto error;
1538 }
1539 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001540
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001541 /* magic - bit 3 in flags means min set */
1542 rfn->flags |= 0x04;
1543 } else if (!strcmp(sub->name, "max-elements")) {
1544 /* list or leaf-list */
1545 if (f_max) {
1546 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1547 goto error;
1548 }
1549 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001550
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001551 /* check possibility of statements combination */
1552 if (rfn->target_type) {
1553 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1554 if (!rfn->target_type) {
1555 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1556 goto error;
1557 }
1558 } else {
1559 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1560 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001562 GETVAL(value, sub, "value");
1563 while (isspace(value[0])) {
1564 value++;
1565 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001567 /* convert it to uint32_t */
1568 errno = 0;
1569 endptr = NULL;
1570 val = strtoul(value, &endptr, 10);
1571 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1572 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1573 goto error;
1574 }
1575 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001577 /* magic - bit 4 in flags means min set */
1578 rfn->flags |= 0x08;
1579 } else if (!strcmp(sub->name, "presence")) {
1580 /* container */
1581 if (rfn->mod.presence) {
1582 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1583 goto error;
1584 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001585
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001586 /* check possibility of statements combination */
1587 if (rfn->target_type) {
1588 rfn->target_type &= LY_NODE_CONTAINER;
1589 if (!rfn->target_type) {
1590 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1591 goto error;
1592 }
1593 } else {
1594 rfn->target_type = LY_NODE_CONTAINER;
1595 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001596
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001597 GETVAL(value, sub, "value");
1598 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1599 } else if (!strcmp(sub->name, "must")) {
1600 /* leaf-list, list, container or anyxml */
1601 /* check possibility of statements combination */
1602 if (rfn->target_type) {
1603 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1604 if (!rfn->target_type) {
1605 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1606 goto error;
1607 }
1608 } else {
1609 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1610 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001611
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001612 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001613
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001614 } else {
1615 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1616 goto error;
1617 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001619 lyxml_free_elem(module->ctx, sub);
1620 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001622 /* process nodes with cardinality of 0..n */
1623 if (c_must) {
1624 rfn->must = calloc(c_must, sizeof *rfn->must);
1625 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001626
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001627 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1628 if (!strcmp(sub->name, "must")) {
1629 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1630 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001631
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001632 if (r) {
1633 goto error;
1634 }
1635 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001637 lyxml_free_elem(module->ctx, sub);
1638 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001639
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001640 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001641
1642error:
1643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001644 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001645}
1646
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001647static int
1648fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001649{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001650 struct lyxml_elem *child;
1651 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001653 LY_TREE_FOR(yin->child, child) {
1654 if (!strcmp(child->name, "prefix")) {
1655 GETVAL(value, child, "value");
1656 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1657 goto error;
1658 }
1659 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1660 } else if (!strcmp(child->name, "revision-date")) {
1661 if (imp->rev[0]) {
1662 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1663 goto error;
1664 }
1665 GETVAL(value, child, "date");
1666 if (check_date(value, LOGLINE(child))) {
1667 goto error;
1668 }
1669 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1670 } else {
1671 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1672 goto error;
1673 }
1674 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001675
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001676 /* check mandatory information */
1677 if (!imp->prefix) {
1678 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1679 goto error;
1680 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001682 GETVAL(value, yin, "module");
1683 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1684 if (!imp->module) {
1685 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1686 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1687 goto error;
1688 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001689
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001690 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001691
1692error:
1693
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001694 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001695}
1696
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001697static int
1698fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001699{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001700 struct lyxml_elem *child;
1701 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001703 LY_TREE_FOR(yin->child, child) {
1704 if (!strcmp(child->name, "revision-date")) {
1705 if (inc->rev[0]) {
1706 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1707 goto error;
1708 }
1709 GETVAL(value, child, "date");
1710 if (check_date(value, LOGLINE(child))) {
1711 goto error;
1712 }
1713 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1714 } else {
1715 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1716 goto error;
1717 }
1718 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001719
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001720 GETVAL(value, yin, "module");
1721 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1722 if (!inc->submodule) {
1723 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1724 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1725 goto error;
1726 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001728 /* check that belongs-to corresponds */
1729 if (module->type) {
1730 module = ((struct ly_submodule *)module)->belongsto;
1731 }
1732 if (inc->submodule->belongsto != module) {
1733 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1734 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1735 goto error;
1736 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001738 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001739
1740error:
1741
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001742 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001743}
1744
Radek Krejcida04f4a2015-05-21 12:54:09 +02001745/*
1746 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001747 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001748 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001749 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001750static int
1751read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1752 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001753{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001754 const char *value;
1755 struct lyxml_elem *sub, *next;
1756 struct ly_ctx *const ctx = module->ctx;
1757 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001758
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001759 if (opt & OPT_MODULE) {
1760 mnode->module = module;
1761 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001762
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001763 if (opt & OPT_IDENT) {
1764 GETVAL(value, xmlnode, "name");
1765 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1766 goto error;
1767 }
1768 mnode->name = lydict_insert(ctx, value, strlen(value));
1769 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001770
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001771 /* process local parameters */
1772 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1773 if (!strcmp(sub->name, "description")) {
1774 if (mnode->dsc) {
1775 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1776 goto error;
1777 }
1778 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1779 if (!mnode->dsc) {
1780 r = 1;
1781 }
1782 } else if (!strcmp(sub->name, "reference")) {
1783 if (mnode->ref) {
1784 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1785 goto error;
1786 }
1787 mnode->ref = read_yin_subnode(ctx, sub, "text");
1788 if (!mnode->ref) {
1789 r = 1;
1790 }
1791 } else if (!strcmp(sub->name, "status")) {
1792 if (mnode->flags & LY_NODE_STATUS_MASK) {
1793 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1794 goto error;
1795 }
1796 GETVAL(value, sub, "value");
1797 if (!strcmp(value, "current")) {
1798 mnode->flags |= LY_NODE_STATUS_CURR;
1799 } else if (!strcmp(value, "deprecated")) {
1800 mnode->flags |= LY_NODE_STATUS_DEPRC;
1801 } else if (!strcmp(value, "obsolete")) {
1802 mnode->flags |= LY_NODE_STATUS_OBSLT;
1803 } else {
1804 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1805 r = 1;
1806 }
1807 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1808 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1809 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1810 goto error;
1811 }
1812 GETVAL(value, sub, "value");
1813 if (!strcmp(value, "false")) {
1814 mnode->flags |= LY_NODE_CONFIG_R;
1815 } else if (!strcmp(value, "true")) {
1816 mnode->flags |= LY_NODE_CONFIG_W;
1817 } else {
1818 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1819 r = 1;
1820 }
1821 } else {
1822 /* skip the lyxml_free_elem */
1823 continue;
1824 }
1825 lyxml_free_elem(ctx, sub);
1826 if (r) {
1827 goto error;
1828 }
1829 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001830
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001831 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1832 /* get config flag from parent */
1833 if (parent) {
1834 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1835 } else {
1836 /* default config is true */
1837 mnode->flags |= LY_NODE_CONFIG_W;
1838 }
1839 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001840
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001841 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001842
1843error:
1844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001845 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001846}
1847
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001848static struct ly_when *
1849read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
1850{
Radek Krejci53ebfb12015-06-19 09:35:59 +02001851 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001852 struct lyxml_elem *next, *child;
1853 const char *value;
1854
1855 retval = calloc(1, sizeof *retval);
1856
1857 GETVAL(value, yin, "condition");
1858 retval->cond = lydict_insert(module->ctx, value, 0);
1859
1860 LY_TREE_FOR_SAFE(yin->child, next, child) {
1861 if (!strcmp(child->name, "description")) {
1862 if (retval->dsc) {
1863 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1864 goto error;
1865 }
1866 retval->dsc = read_yin_subnode(module->ctx, child, "text");
1867 if (!retval->dsc) {
1868 goto error;
1869 }
1870 } else if (!strcmp(child->name, "reference")) {
1871 if (retval->ref) {
1872 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1873 goto error;
1874 }
1875 retval->ref = read_yin_subnode(module->ctx, child, "text");
1876 if (!retval->ref) {
1877 goto error;
1878 }
1879 } else {
1880 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1881 goto error;
1882 }
1883
1884 lyxml_free_elem(module->ctx, child);
1885 }
1886
1887 return retval;
1888
1889error:
1890
Radek Krejci53ebfb12015-06-19 09:35:59 +02001891 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001892 return NULL;
1893}
1894
Radek Krejcib4cf2022015-06-03 14:40:05 +02001895/* additional check in case statement - the child must be unique across
1896 * all other case names and its data children
1897 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001898static int
1899check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001900{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001901 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001902
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001903 if (new->nodetype == LY_NODE_CHOICE) {
1904 /* we have nested choice in case, so we need recursion */
1905 LY_TREE_FOR(new->child, mnode) {
1906 if (mnode->nodetype == LY_NODE_CASE) {
1907 LY_TREE_FOR(mnode->child, submnode) {
1908 if (check_branch_id(parent, submnode, new, line)) {
1909 return EXIT_FAILURE;
1910 }
1911 }
1912 } else if (check_branch_id(parent, mnode, new, line)) {
1913 return EXIT_FAILURE;
1914 }
1915 }
1916 } else {
1917 LY_TREE_FOR(parent->child, mnode) {
1918 if (mnode == excl) {
1919 continue;
1920 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001921
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001922 if (!strcmp(new->name, mnode->name)) {
1923 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1924 return EXIT_FAILURE;
1925 }
1926 if (mnode->nodetype == LY_NODE_CASE) {
1927 LY_TREE_FOR(mnode->child, submnode) {
1928 if (!strcmp(new->name, submnode->name)) {
1929 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1930 return EXIT_FAILURE;
1931 }
1932 }
1933 }
1934 }
1935 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001936
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001937 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001938}
1939
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001940static struct ly_mnode *
1941read_yin_case(struct ly_module *module,
1942 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001943{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001944 struct lyxml_elem *sub, *next;
1945 struct ly_mnode_case *mcase;
1946 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001947 int c_ftrs = 0;
1948 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001949
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001950 mcase = calloc(1, sizeof *mcase);
1951 mcase->nodetype = LY_NODE_CASE;
1952 mcase->prev = (struct ly_mnode *)mcase;
1953 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001954
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001955 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
1956 goto error;
1957 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001959 /* process choice's specific children */
1960 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1961 if (!strcmp(sub->name, "container")) {
1962 mnode = read_yin_container(module, retval, sub, resolve, unres);
1963 } else if (!strcmp(sub->name, "leaf-list")) {
1964 mnode = read_yin_leaflist(module, retval, sub, resolve);
1965 } else if (!strcmp(sub->name, "leaf")) {
1966 mnode = read_yin_leaf(module, retval, sub, resolve);
1967 } else if (!strcmp(sub->name, "list")) {
1968 mnode = read_yin_list(module, retval, sub, resolve, unres);
1969 } else if (!strcmp(sub->name, "uses")) {
1970 mnode = read_yin_uses(module, retval, sub, resolve, unres);
1971 } else if (!strcmp(sub->name, "choice")) {
1972 mnode = read_yin_choice(module, retval, sub, resolve, unres);
1973 } else if (!strcmp(sub->name, "anyxml")) {
1974 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02001975 } else if (!strcmp(sub->name, "if-feature")) {
1976 c_ftrs++;
1977
1978 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
1979 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001980 } else if (!strcmp(sub->name, "when")) {
1981 if (mcase->when) {
1982 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1983 goto error;
1984 }
1985
1986 mcase->when = read_yin_when(module, sub);
1987 if (!mcase->when) {
1988 goto error;
1989 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001990 } else {
1991 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1992 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001993 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001994
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001995 if (!mnode) {
1996 goto error;
1997 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
1998 goto error;
1999 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002000
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002001 mnode = NULL;
2002 lyxml_free_elem(module->ctx, sub);
2003 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002004
Radek Krejci3cf9e222015-06-18 11:37:50 +02002005 if (c_ftrs) {
2006 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2007 }
2008 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2009 GETVAL(value, sub, "name");
2010 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2011 if (!mcase->features[mcase->features_size]) {
2012 goto error;
2013 }
2014 mcase->features_size++;
2015 lyxml_free_elem(module->ctx, sub);
2016 }
2017
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002018 /* inherit config flag */
2019 if (parent) {
2020 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2021 } else {
2022 /* default config is true */
2023 retval->flags |= LY_NODE_CONFIG_W;
2024 }
Radek Krejcib388c152015-06-04 17:03:03 +02002025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002026 /* insert the node into the schema tree */
2027 if (ly_mnode_addchild(parent, retval)) {
2028 goto error;
2029 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002031 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002032
2033error:
2034
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002035 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002036
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002037 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002038}
2039
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002040static struct ly_mnode *
2041read_yin_choice(struct ly_module *module,
2042 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002043{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002044 struct lyxml_elem *sub, *next;
2045 struct ly_ctx *const ctx = module->ctx;
2046 struct ly_mnode *retval, *mnode = NULL;
2047 struct ly_mnode_choice *choice;
2048 const char *value;
2049 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002050 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002052 choice = calloc(1, sizeof *choice);
2053 choice->nodetype = LY_NODE_CHOICE;
2054 choice->prev = (struct ly_mnode *)choice;
2055 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002056
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002057 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2058 goto error;
2059 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002061 /* process choice's specific children */
2062 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2063 if (!strcmp(sub->name, "container")) {
2064 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2065 goto error;
2066 }
2067 } else if (!strcmp(sub->name, "leaf-list")) {
2068 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2069 goto error;
2070 }
2071 } else if (!strcmp(sub->name, "leaf")) {
2072 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2073 goto error;
2074 }
2075 } else if (!strcmp(sub->name, "list")) {
2076 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2077 goto error;
2078 }
2079 } else if (!strcmp(sub->name, "case")) {
2080 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2081 goto error;
2082 }
2083 } else if (!strcmp(sub->name, "anyxml")) {
2084 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2085 goto error;
2086 }
2087 } else if (!strcmp(sub->name, "default")) {
2088 if (dflt_str) {
2089 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2090 goto error;
2091 }
2092 GETVAL(value, sub, "value");
2093 dflt_str = strdup(value);
2094 } else if (!strcmp(sub->name, "mandatory")) {
2095 if (f_mand) {
2096 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2097 goto error;
2098 }
2099 /* just checking the flags in leaf is not sufficient, we would allow
2100 * multiple mandatory statements with the "false" value
2101 */
2102 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002103
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002104 GETVAL(value, sub, "value");
2105 if (!strcmp(value, "true")) {
2106 choice->flags |= LY_NODE_MAND_TRUE;
2107 } else if (strcmp(value, "false")) {
2108 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2109 goto error;
2110 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002111 } else if (!strcmp(sub->name, "when")) {
2112 if (choice->when) {
2113 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2114 goto error;
2115 }
2116
2117 choice->when = read_yin_when(module, sub);
2118 if (!choice->when) {
2119 goto error;
2120 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002121 } else if (!strcmp(sub->name, "if-feature")) {
2122 c_ftrs++;
2123
2124 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
2125 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002126 } else {
2127 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2128 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002129 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002131 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
2132 goto error;
2133 }
2134 mnode = NULL;
2135 lyxml_free_elem(ctx, sub);
2136 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002137
Radek Krejci3cf9e222015-06-18 11:37:50 +02002138 if (c_ftrs) {
2139 choice->features = calloc(c_ftrs, sizeof *choice->features);
2140 }
2141
2142 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2143 GETVAL(value, sub, "name");
2144 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
2145 if (!choice->features[choice->features_size]) {
2146 goto error;
2147 }
2148 choice->features_size++;
2149 lyxml_free_elem(ctx, sub);
2150 }
2151
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002152 /* check - default is prohibited in combination with mandatory */
2153 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
2154 LOGVAL(VE_SPEC, LOGLINE(yin),
2155 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
2156 goto error;
2157 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002159 /* link default with the case */
2160 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02002161 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002162 if (!choice->dflt) {
2163 /* default branch not found */
2164 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
2165 goto error;
2166 }
2167 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002168
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002169 /* insert the node into the schema tree */
2170 if (parent && ly_mnode_addchild(parent, retval)) {
2171 goto error;
2172 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002173
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002174 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02002175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002176 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002177
2178error:
2179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002180 ly_mnode_free(retval);
2181 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002183 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002184}
2185
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002186static struct ly_mnode *
2187read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02002188{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002189 struct ly_mnode *retval;
2190 struct ly_mnode_leaf *anyxml;
2191 struct lyxml_elem *sub, *next;
2192 const char *value;
2193 int r;
2194 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002195 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02002196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002197 anyxml = calloc(1, sizeof *anyxml);
2198 anyxml->nodetype = LY_NODE_ANYXML;
2199 anyxml->prev = (struct ly_mnode *)anyxml;
2200 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02002201
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002202 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2203 goto error;
2204 }
Radek Krejci863c2852015-06-03 15:47:11 +02002205
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002206 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2207 if (!strcmp(sub->name, "mandatory")) {
2208 if (f_mand) {
2209 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2210 goto error;
2211 }
2212 /* just checking the flags in leaf is not sufficient, we would allow
2213 * multiple mandatory statements with the "false" value
2214 */
2215 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02002216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002217 GETVAL(value, sub, "value");
2218 if (!strcmp(value, "true")) {
2219 anyxml->flags |= LY_NODE_MAND_TRUE;
2220 } else if (strcmp(value, "false")) {
2221 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2222 goto error;
2223 }
2224 /* else false is the default value, so we can ignore it */
2225 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002226 } else if (!strcmp(sub->name, "when")) {
2227 if (anyxml->when) {
2228 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2229 goto error;
2230 }
2231
2232 anyxml->when = read_yin_when(module, sub);
2233 lyxml_free_elem(module->ctx, sub);
2234
2235 if (!anyxml->when) {
2236 goto error;
2237 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002238 } else if (!strcmp(sub->name, "must")) {
2239 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002240 } else if (!strcmp(sub->name, "if-feature")) {
2241 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02002242
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002243 } else {
2244 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2245 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002246 }
2247 }
Radek Krejci863c2852015-06-03 15:47:11 +02002248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002249 /* middle part - process nodes with cardinality of 0..n */
2250 if (c_must) {
2251 anyxml->must = calloc(c_must, sizeof *anyxml->must);
2252 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002253 if (c_ftrs) {
2254 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
2255 }
Radek Krejci863c2852015-06-03 15:47:11 +02002256
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002257 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2258 if (!strcmp(sub->name, "must")) {
2259 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
2260 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02002261
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002262 if (r) {
2263 goto error;
2264 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002265 } else if (!strcmp(sub->name, "must")) {
2266 GETVAL(value, sub, "name");
2267 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
2268 if (!anyxml->features[anyxml->features_size]) {
2269 goto error;
2270 }
2271 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002272 }
Radek Krejci863c2852015-06-03 15:47:11 +02002273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002274 lyxml_free_elem(module->ctx, sub);
2275 }
Radek Krejci863c2852015-06-03 15:47:11 +02002276
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002277 if (parent && ly_mnode_addchild(parent, retval)) {
2278 goto error;
2279 }
Radek Krejci863c2852015-06-03 15:47:11 +02002280
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002281 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02002282
2283error:
2284
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002285 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02002286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002287 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02002288}
2289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002290static struct ly_mnode *
2291read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002292{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002293 struct ly_mnode *retval;
2294 struct ly_mnode_leaf *leaf;
2295 struct lyxml_elem *sub, *next;
2296 const char *value;
2297 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002298 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002300 leaf = calloc(1, sizeof *leaf);
2301 leaf->nodetype = LY_NODE_LEAF;
2302 leaf->prev = (struct ly_mnode *)leaf;
2303 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002304
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002305 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2306 goto error;
2307 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002309 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2310 if (!strcmp(sub->name, "type")) {
2311 if (leaf->type.der) {
2312 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2313 goto error;
2314 }
2315 if (fill_yin_type(module, parent, sub, &leaf->type)) {
2316 goto error;
2317 }
2318 } else if (!strcmp(sub->name, "default")) {
2319 if (leaf->dflt) {
2320 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2321 goto error;
2322 }
2323 GETVAL(value, sub, "value");
2324 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
2325 } else if (!strcmp(sub->name, "units")) {
2326 if (leaf->units) {
2327 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2328 goto error;
2329 }
2330 GETVAL(value, sub, "name");
2331 leaf->units = lydict_insert(module->ctx, value, strlen(value));
2332 } else if (!strcmp(sub->name, "mandatory")) {
2333 if (f_mand) {
2334 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2335 goto error;
2336 }
2337 /* just checking the flags in leaf is not sufficient, we would allow
2338 * multiple mandatory statements with the "false" value
2339 */
2340 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002342 GETVAL(value, sub, "value");
2343 if (!strcmp(value, "true")) {
2344 leaf->flags |= LY_NODE_MAND_TRUE;
2345 } else if (strcmp(value, "false")) {
2346 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2347 goto error;
2348 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002349 } else if (!strcmp(sub->name, "when")) {
2350 if (leaf->when) {
2351 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2352 goto error;
2353 }
2354
2355 leaf->when = read_yin_when(module, sub);
2356 if (!leaf->when) {
2357 goto error;
2358 }
2359
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002360 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002361 c_must++; /* else false is the default value, so we can ignore it */
2362 } else if (!strcmp(sub->name, "if-feature")) {
2363 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002364
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002365 /* skip element free at the end of the loop */
2366 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002367 } else {
2368 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2369 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002370 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002371
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002372 lyxml_free_elem(module->ctx, sub);
2373 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002374
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002375 /* check mandatory parameters */
2376 if (!leaf->type.der) {
2377 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2378 goto error;
2379 }
2380 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2381 goto error;
2382 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002383
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002384 /* middle part - process nodes with cardinality of 0..n */
2385 if (c_must) {
2386 leaf->must = calloc(c_must, sizeof *leaf->must);
2387 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002388 if (c_ftrs) {
2389 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2390 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002391
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002392 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2393 if (!strcmp(sub->name, "must")) {
2394 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2395 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002396
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002397 if (r) {
2398 goto error;
2399 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002400 } else if (!strcmp(sub->name, "if-feature")) {
2401 GETVAL(value, sub, "name");
2402 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2403 if (!leaf->features[leaf->features_size]) {
2404 goto error;
2405 }
2406 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002407 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002408
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002409 lyxml_free_elem(module->ctx, sub);
2410 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002412 if (parent && ly_mnode_addchild(parent, retval)) {
2413 goto error;
2414 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002415
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002416 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002417
2418error:
2419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002420 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002421
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002422 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002423}
2424
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002425static struct ly_mnode *
2426read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002427{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002428 struct ly_mnode *retval;
2429 struct ly_mnode_leaflist *llist;
2430 struct lyxml_elem *sub, *next;
2431 const char *value;
2432 char *endptr;
2433 unsigned long val;
2434 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002435 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002436 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002437
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002438 llist = calloc(1, sizeof *llist);
2439 llist->nodetype = LY_NODE_LEAFLIST;
2440 llist->prev = (struct ly_mnode *)llist;
2441 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002442
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002443 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2444 goto error;
2445 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002447 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2448 if (!strcmp(sub->name, "type")) {
2449 if (llist->type.der) {
2450 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2451 goto error;
2452 }
2453 if (fill_yin_type(module, parent, sub, &llist->type)) {
2454 goto error;
2455 }
2456 } else if (!strcmp(sub->name, "units")) {
2457 if (llist->units) {
2458 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2459 goto error;
2460 }
2461 GETVAL(value, sub, "name");
2462 llist->units = lydict_insert(module->ctx, value, strlen(value));
2463 } else if (!strcmp(sub->name, "ordered-by")) {
2464 if (f_ordr) {
2465 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2466 goto error;
2467 }
2468 /* just checking the flags in llist is not sufficient, we would
2469 * allow multiple ordered-by statements with the "system" value
2470 */
2471 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002472
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002473 if (llist->flags & LY_NODE_CONFIG_R) {
2474 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2475 * state data
2476 */
2477 lyxml_free_elem(module->ctx, sub);
2478 continue;
2479 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002481 GETVAL(value, sub, "value");
2482 if (!strcmp(value, "user")) {
2483 llist->flags |= LY_NODE_USERORDERED;
2484 } else if (strcmp(value, "system")) {
2485 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2486 goto error;
2487 } /* else system is the default value, so we can ignore it */
2488 } else if (!strcmp(sub->name, "must")) {
2489 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002490 } else if (!strcmp(sub->name, "if-feature")) {
2491 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002492
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002493 /* skip element free at the end of the loop */
2494 continue;
2495 } else if (!strcmp(sub->name, "min-elements")) {
2496 if (f_min) {
2497 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2498 goto error;
2499 }
2500 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002502 GETVAL(value, sub, "value");
2503 while (isspace(value[0])) {
2504 value++;
2505 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002506
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002507 /* convert it to uint32_t */
2508 errno = 0;
2509 endptr = NULL;
2510 val = strtoul(value, &endptr, 10);
2511 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2512 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2513 goto error;
2514 }
2515 llist->min = (uint32_t) val;
2516 } else if (!strcmp(sub->name, "max-elements")) {
2517 if (f_max) {
2518 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2519 goto error;
2520 }
2521 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002523 GETVAL(value, sub, "value");
2524 while (isspace(value[0])) {
2525 value++;
2526 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002528 /* convert it to uint32_t */
2529 errno = 0;
2530 endptr = NULL;
2531 val = strtoul(value, &endptr, 10);
2532 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2533 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2534 goto error;
2535 }
2536 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002537 } else if (!strcmp(sub->name, "when")) {
2538 if (llist->when) {
2539 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2540 goto error;
2541 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002542
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002543 llist->when = read_yin_when(module, sub);
2544 if (!llist->when) {
2545 goto error;
2546 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002547 } else {
2548 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2549 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002550 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002551
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002552 lyxml_free_elem(module->ctx, sub);
2553 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002555 /* check constraints */
2556 if (!llist->type.der) {
2557 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2558 goto error;
2559 }
2560 if (llist->max && llist->min > llist->max) {
2561 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2562 goto error;
2563 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002564
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002565 /* middle part - process nodes with cardinality of 0..n */
2566 if (c_must) {
2567 llist->must = calloc(c_must, sizeof *llist->must);
2568 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002569 if (c_ftrs) {
2570 llist->features = calloc(c_ftrs, sizeof *llist->features);
2571 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002573 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2574 if (!strcmp(sub->name, "must")) {
2575 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2576 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002578 if (r) {
2579 goto error;
2580 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002581 } else if (!strcmp(sub->name, "if-feature")) {
2582 GETVAL(value, sub, "name");
2583 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2584 if (!llist->features[llist->features_size]) {
2585 goto error;
2586 }
2587 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002588 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002589
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002590 lyxml_free_elem(module->ctx, sub);
2591 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002593 if (parent && ly_mnode_addchild(parent, retval)) {
2594 goto error;
2595 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002596
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002597 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002598
2599error:
2600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002601 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002602
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002603 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002604}
2605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002606static struct ly_mnode *
2607read_yin_list(struct ly_module *module,
2608 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002609{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002610 struct ly_mnode *retval, *mnode;
2611 struct ly_mnode_list *list;
2612 struct ly_unique *uniq_s;
2613 struct lyxml_elem *sub, *next, root, uniq;
2614 int i, r;
2615 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002616 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002617 int f_ordr = 0, f_max = 0, f_min = 0;
2618 const char *key_str = NULL, *uniq_str, *value;
2619 char *auxs;
2620 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002622 /* init */
2623 memset(&root, 0, sizeof root);
2624 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002625
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002626 list = calloc(1, sizeof *list);
2627 list->nodetype = LY_NODE_LIST;
2628 list->prev = (struct ly_mnode *)list;
2629 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002631 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2632 goto error;
2633 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002635 /* process list's specific children */
2636 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2637 /* data statements */
2638 if (!strcmp(sub->name, "container") ||
2639 !strcmp(sub->name, "leaf-list") ||
2640 !strcmp(sub->name, "leaf") ||
2641 !strcmp(sub->name, "list") ||
2642 !strcmp(sub->name, "choice") ||
2643 !strcmp(sub->name, "uses") ||
2644 !strcmp(sub->name, "grouping") ||
2645 !strcmp(sub->name, "anyxml")) {
2646 lyxml_unlink_elem(sub);
2647 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002649 /* array counters */
2650 } else if (!strcmp(sub->name, "key")) {
2651 /* check cardinality 0..1 */
2652 if (list->keys_size) {
2653 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2654 goto error;
2655 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002656
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002657 /* count the number of keys */
2658 GETVAL(value, sub, "value");
2659 key_str = value;
2660 while ((value = strpbrk(value, " \t\n"))) {
2661 list->keys_size++;
2662 while (isspace(*value)) {
2663 value++;
2664 }
2665 }
2666 list->keys_size++;
2667 list->keys = calloc(list->keys_size, sizeof *list->keys);
2668 } else if (!strcmp(sub->name, "unique")) {
2669 c_uniq++;
2670 lyxml_unlink_elem(sub);
2671 lyxml_add_child(&uniq, sub);
2672 } else if (!strcmp(sub->name, "typedef")) {
2673 c_tpdf++;
2674 } else if (!strcmp(sub->name, "must")) {
2675 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002676 } else if (!strcmp(sub->name, "if-feature")) {
2677 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002679 /* optional stetments */
2680 } else if (!strcmp(sub->name, "ordered-by")) {
2681 if (f_ordr) {
2682 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2683 goto error;
2684 }
2685 /* just checking the flags in llist is not sufficient, we would
2686 * allow multiple ordered-by statements with the "system" value
2687 */
2688 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002689
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002690 if (list->flags & LY_NODE_CONFIG_R) {
2691 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2692 * state data
2693 */
2694 lyxml_free_elem(module->ctx, sub);
2695 continue;
2696 }
Radek Krejci345ad742015-06-03 11:04:18 +02002697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002698 GETVAL(value, sub, "value");
2699 if (!strcmp(value, "user")) {
2700 list->flags |= LY_NODE_USERORDERED;
2701 } else if (strcmp(value, "system")) {
2702 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2703 goto error;
2704 }
2705 /* else system is the default value, so we can ignore it */
2706 lyxml_free_elem(module->ctx, sub);
2707 } else if (!strcmp(sub->name, "min-elements")) {
2708 if (f_min) {
2709 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2710 goto error;
2711 }
2712 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002713
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002714 GETVAL(value, sub, "value");
2715 while (isspace(value[0])) {
2716 value++;
2717 }
Radek Krejci345ad742015-06-03 11:04:18 +02002718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002719 /* convert it to uint32_t */
2720 errno = 0;
2721 auxs = NULL;
2722 val = strtoul(value, &auxs, 10);
2723 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2724 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2725 goto error;
2726 }
2727 list->min = (uint32_t) val;
2728 lyxml_free_elem(module->ctx, sub);
2729 } else if (!strcmp(sub->name, "max-elements")) {
2730 if (f_max) {
2731 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2732 goto error;
2733 }
2734 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002735
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002736 GETVAL(value, sub, "value");
2737 while (isspace(value[0])) {
2738 value++;
2739 }
Radek Krejci345ad742015-06-03 11:04:18 +02002740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002741 /* convert it to uint32_t */
2742 errno = 0;
2743 auxs = NULL;
2744 val = strtoul(value, &auxs, 10);
2745 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2746 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2747 goto error;
2748 }
2749 list->max = (uint32_t) val;
2750 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002751 } else if (!strcmp(sub->name, "when")) {
2752 if (list->when) {
2753 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2754 goto error;
2755 }
2756
2757 list->when = read_yin_when(module, sub);
2758 lyxml_free_elem(module->ctx, sub);
2759
2760 if (!list->when) {
2761 goto error;
2762 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002763 } else {
2764 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2765 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002766 }
2767 }
Radek Krejci345ad742015-06-03 11:04:18 +02002768
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002769 /* check - if list is configuration, key statement is mandatory */
2770 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2771 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2772 goto error;
2773 }
2774 if (list->max && list->min > list->max) {
2775 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2776 goto error;
2777 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002778
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002779 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2780 if (c_tpdf) {
2781 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2782 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002783 if (c_must) {
2784 list->must = calloc(c_must, sizeof *list->must);
2785 }
2786 if (c_ftrs) {
2787 list->features = calloc(c_ftrs, sizeof *list->features);
2788 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002789 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2790 if (!strcmp(sub->name, "typedef")) {
2791 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2792 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002793
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002794 if (r) {
2795 goto error;
2796 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002797 } else if (!strcmp(sub->name, "if-feature")) {
2798 GETVAL(value, sub, "name");
2799 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2800 if (!list->features[list->features_size]) {
2801 goto error;
2802 }
2803 list->features_size++;
2804 } else if (!strcmp(sub->name, "must")) {
2805 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2806 list->must_size++;
2807
2808 if (r) {
2809 goto error;
2810 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002811 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002812 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002813 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002815 /* last part - process data nodes */
2816 LY_TREE_FOR_SAFE(root.child, next, sub) {
2817 if (!strcmp(sub->name, "container")) {
2818 mnode = read_yin_container(module, retval, sub, resolve, unres);
2819 } else if (!strcmp(sub->name, "leaf-list")) {
2820 mnode = read_yin_leaflist(module, retval, sub, resolve);
2821 } else if (!strcmp(sub->name, "leaf")) {
2822 mnode = read_yin_leaf(module, retval, sub, resolve);
2823 } else if (!strcmp(sub->name, "list")) {
2824 mnode = read_yin_list(module, retval, sub, resolve, unres);
2825 } else if (!strcmp(sub->name, "choice")) {
2826 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2827 } else if (!strcmp(sub->name, "uses")) {
2828 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2829 } else if (!strcmp(sub->name, "grouping")) {
2830 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2831 } else if (!strcmp(sub->name, "anyxml")) {
2832 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002833 }
2834 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002835
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002836 if (!mnode) {
2837 goto error;
2838 }
2839 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002840
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002841 if (parent && ly_mnode_addchild(parent, retval)) {
2842 goto error;
2843 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002845 if (!key_str) {
2846 /* config false list without a key */
2847 return retval;
2848 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002849
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002850 /* link key leafs into the list structure and check all constraints */
2851 for (i = 0; i < list->keys_size; i++) {
2852 /* get the key name */
2853 if ((value = strpbrk(key_str, " \t\n"))) {
2854 len = value - key_str;
2855 while (isspace(*value)) {
2856 value++;
2857 }
2858 } else {
2859 len = strlen(key_str);
2860 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002861
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002862 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002863
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002864 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2865 goto error;
2866 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002867
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002868 /* prepare for next iteration */
2869 while (value && isspace(*value)) {
2870 value++;
2871 }
2872 key_str = value;
2873 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002875 /* process unique statements */
2876 if (c_uniq) {
2877 list->unique = calloc(c_uniq, sizeof *list->unique);
2878 }
2879 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2880 /* count the number of unique values */
2881 GETVAL(value, sub, "tag");
2882 uniq_str = value;
2883 uniq_s = &list->unique[list->unique_size];
2884 while ((value = strpbrk(value, " \t\n"))) {
2885 uniq_s->leafs_size++;
2886 while (isspace(*value)) {
2887 value++;
2888 }
2889 }
2890 uniq_s->leafs_size++;
2891 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2892 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002893
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002894 /* interconnect unique values with the leafs */
2895 for (i = 0; i < uniq_s->leafs_size; i++) {
2896 if ((value = strpbrk(uniq_str, " \t\n"))) {
2897 len = value - uniq_str;
2898 while (isspace(*value)) {
2899 value++;
2900 }
2901 } else {
2902 len = strlen(uniq_str);
2903 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002904
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002905 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
2906 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
2907 goto error;
2908 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002909
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002910 /* prepare for next iteration */
2911 while (value && isspace(*value)) {
2912 value++;
2913 }
2914 uniq_str = value;
2915 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002916
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002917 lyxml_free_elem(module->ctx, sub);
2918 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002919
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002920 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002921
2922error:
2923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002924 ly_mnode_free(retval);
2925 while (root.child) {
2926 lyxml_free_elem(module->ctx, root.child);
2927 }
2928 while (uniq.child) {
2929 lyxml_free_elem(module->ctx, uniq.child);
2930 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002931
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002932 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002933}
2934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002935static struct ly_mnode *
2936read_yin_container(struct ly_module *module,
2937 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002938{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002939 struct lyxml_elem *sub, *next, root;
2940 struct ly_mnode *mnode = NULL;
2941 struct ly_mnode *retval;
2942 struct ly_mnode_container *cont;
2943 const char *value;
2944 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002945 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002947 /* init */
2948 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02002949
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002950 cont = calloc(1, sizeof *cont);
2951 cont->nodetype = LY_NODE_CONTAINER;
2952 cont->prev = (struct ly_mnode *)cont;
2953 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002954
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002955 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2956 goto error;
2957 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002958
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002959 /* process container's specific children */
2960 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2961 if (!strcmp(sub->name, "presence")) {
2962 if (cont->presence) {
2963 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2964 goto error;
2965 }
2966 GETVAL(value, sub, "value");
2967 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02002968
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002969 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002970 } else if (!strcmp(sub->name, "when")) {
2971 if (cont->when) {
2972 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2973 goto error;
2974 }
2975
2976 cont->when = read_yin_when(module, sub);
2977 lyxml_free_elem(module->ctx, sub);
2978
2979 if (!cont->when) {
2980 goto error;
2981 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002982
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002983 /* data statements */
2984 } else if (!strcmp(sub->name, "container") ||
2985 !strcmp(sub->name, "leaf-list") ||
2986 !strcmp(sub->name, "leaf") ||
2987 !strcmp(sub->name, "list") ||
2988 !strcmp(sub->name, "choice") ||
2989 !strcmp(sub->name, "uses") ||
2990 !strcmp(sub->name, "grouping") ||
2991 !strcmp(sub->name, "anyxml")) {
2992 lyxml_unlink_elem(sub);
2993 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002994
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002995 /* array counters */
2996 } else if (!strcmp(sub->name, "typedef")) {
2997 c_tpdf++;
2998 } else if (!strcmp(sub->name, "must")) {
2999 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003000 } else if (!strcmp(sub->name, "if-feature")) {
3001 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003002 } else {
3003 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3004 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003005 }
3006 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003007
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003008 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3009 if (c_tpdf) {
3010 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3011 }
3012 if (c_must) {
3013 cont->must = calloc(c_must, sizeof *cont->must);
3014 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003015 if (c_ftrs) {
3016 cont->features = calloc(c_ftrs, sizeof *cont->features);
3017 }
Radek Krejci800af702015-06-02 13:46:01 +02003018
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003019 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3020 if (!strcmp(sub->name, "typedef")) {
3021 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
3022 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003023
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003024 if (r) {
3025 goto error;
3026 }
3027 } else if (!strcmp(sub->name, "must")) {
3028 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3029 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003031 if (r) {
3032 goto error;
3033 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003034 } else if (!strcmp(sub->name, "if-feature")) {
3035 GETVAL(value, sub, "name");
3036 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3037 if (!cont->features[cont->features_size]) {
3038 goto error;
3039 }
3040 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003041 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003042
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003043 lyxml_free_elem(module->ctx, sub);
3044 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003046 /* last part - process data nodes */
3047 LY_TREE_FOR_SAFE(root.child, next, sub) {
3048 if (!strcmp(sub->name, "container")) {
3049 mnode = read_yin_container(module, retval, sub, resolve, unres);
3050 } else if (!strcmp(sub->name, "leaf-list")) {
3051 mnode = read_yin_leaflist(module, retval, sub, resolve);
3052 } else if (!strcmp(sub->name, "leaf")) {
3053 mnode = read_yin_leaf(module, retval, sub, resolve);
3054 } else if (!strcmp(sub->name, "list")) {
3055 mnode = read_yin_list(module, retval, sub, resolve, unres);
3056 } else if (!strcmp(sub->name, "choice")) {
3057 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3058 } else if (!strcmp(sub->name, "uses")) {
3059 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3060 } else if (!strcmp(sub->name, "grouping")) {
3061 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3062 } else if (!strcmp(sub->name, "anyxml")) {
3063 mnode = read_yin_anyxml(module, retval, sub, resolve);
3064 }
3065 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003066
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003067 if (!mnode) {
3068 goto error;
3069 }
3070 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003071
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003072 if (parent && ly_mnode_addchild(parent, retval)) {
3073 goto error;
3074 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003076 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003077
3078error:
3079
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003080 ly_mnode_free(retval);
3081 while (root.child) {
3082 lyxml_free_elem(module->ctx, root.child);
3083 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003084
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003085 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003086}
3087
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003088static struct ly_mnode *
3089read_yin_grouping(struct ly_module *module,
3090 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003091{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003092 struct lyxml_elem *sub, *next, root;
3093 struct ly_mnode *mnode = NULL;
3094 struct ly_mnode *retval;
3095 struct ly_mnode_grp *grp;
3096 int r;
3097 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003098
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003099 /* init */
3100 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003101
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003102 grp = calloc(1, sizeof *grp);
3103 grp->nodetype = LY_NODE_GROUPING;
3104 grp->prev = (struct ly_mnode *)grp;
3105 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003107 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3108 goto error;
3109 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003110
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003111 LY_TREE_FOR_SAFE(node->child, next, sub) {
3112 /* data statements */
3113 if (!strcmp(sub->name, "container") ||
3114 !strcmp(sub->name, "leaf-list") ||
3115 !strcmp(sub->name, "leaf") ||
3116 !strcmp(sub->name, "list") ||
3117 !strcmp(sub->name, "choice") ||
3118 !strcmp(sub->name, "uses") ||
3119 !strcmp(sub->name, "grouping") ||
3120 !strcmp(sub->name, "anyxml")) {
3121 lyxml_unlink_elem(sub);
3122 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003124 /* array counters */
3125 } else if (!strcmp(sub->name, "typedef")) {
3126 c_tpdf++;
3127 } else {
3128 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3129 goto error;
3130 }
3131 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003132
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003133 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3134 if (c_tpdf) {
3135 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3136 }
3137 LY_TREE_FOR_SAFE(node->child, next, sub) {
3138 if (!strcmp(sub->name, "typedef")) {
3139 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3140 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003141
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003142 if (r) {
3143 goto error;
3144 }
3145 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003147 lyxml_free_elem(module->ctx, sub);
3148 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003149
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003150 /* last part - process data nodes */
3151 LY_TREE_FOR_SAFE(root.child, next, sub) {
3152 if (!strcmp(sub->name, "container")) {
3153 mnode = read_yin_container(module, retval, sub, resolve, unres);
3154 } else if (!strcmp(sub->name, "leaf-list")) {
3155 mnode = read_yin_leaflist(module, retval, sub, resolve);
3156 } else if (!strcmp(sub->name, "leaf")) {
3157 mnode = read_yin_leaf(module, retval, sub, resolve);
3158 } else if (!strcmp(sub->name, "list")) {
3159 mnode = read_yin_list(module, retval, sub, resolve, unres);
3160 } else if (!strcmp(sub->name, "choice")) {
3161 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3162 } else if (!strcmp(sub->name, "uses")) {
3163 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3164 } else if (!strcmp(sub->name, "grouping")) {
3165 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3166 } else if (!strcmp(sub->name, "anyxml")) {
3167 mnode = read_yin_anyxml(module, retval, sub, resolve);
3168 }
3169 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003170
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003171 if (!mnode) {
3172 goto error;
3173 }
3174 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003176 if (parent && ly_mnode_addchild(parent, retval)) {
3177 goto error;
3178 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003180 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003181
3182error:
3183
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003184 ly_mnode_free(retval);
3185 while (root.child) {
3186 lyxml_free_elem(module->ctx, root.child);
3187 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003188
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003189 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003190}
3191
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003192static struct ly_mnode *
3193read_yin_input_output(struct ly_module *module,
3194 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003195{
Radek Krejcie0674f82015-06-15 13:58:51 +02003196 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003197 struct ly_mnode *mnode = NULL;
3198 struct ly_mnode *retval;
3199 struct ly_mnode_input_output *inout;
3200 int r;
3201 int c_tpdf = 0;
3202
Radek Krejcie0674f82015-06-15 13:58:51 +02003203 /* init */
3204 memset(&root, 0, sizeof root);
3205
Michal Vasko38d01f72015-06-15 09:41:06 +02003206 inout = calloc(1, sizeof *inout);
3207
3208 if (!strcmp(yin->name, "input")) {
3209 inout->nodetype = LY_NODE_INPUT;
3210 } else if (!strcmp(yin->name, "output")) {
3211 inout->nodetype = LY_NODE_OUTPUT;
3212 } else {
3213 assert(0);
3214 }
3215
3216 inout->prev = (struct ly_mnode *)inout;
3217 retval = (struct ly_mnode *)inout;
3218
Michal Vaskoebeac942015-06-15 12:11:50 +02003219 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
3220 goto error;
3221 }
3222
Michal Vasko38d01f72015-06-15 09:41:06 +02003223 /* data statements */
3224 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3225 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003226 !strcmp(sub->name, "leaf-list") ||
3227 !strcmp(sub->name, "leaf") ||
3228 !strcmp(sub->name, "list") ||
3229 !strcmp(sub->name, "choice") ||
3230 !strcmp(sub->name, "uses") ||
3231 !strcmp(sub->name, "grouping") ||
3232 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003233 lyxml_unlink_elem(sub);
3234 lyxml_add_child(&root, sub);
3235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003236 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003237 } else if (!strcmp(sub->name, "typedef")) {
3238 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003239#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02003240 } else {
3241 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3242 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003243#else
Michal Vasko38d01f72015-06-15 09:41:06 +02003244 } else {
3245 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003246#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02003247 }
3248 }
3249
3250 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3251 if (c_tpdf) {
3252 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
3253 }
3254
3255 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3256 if (!strcmp(sub->name, "typedef")) {
3257 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
3258 inout->tpdf_size++;
3259
3260 if (r) {
3261 goto error;
3262 }
3263 }
3264
3265 lyxml_free_elem(module->ctx, sub);
3266 }
3267
3268 /* last part - process data nodes */
3269 LY_TREE_FOR_SAFE(root.child, next, sub) {
3270 if (!strcmp(sub->name, "container")) {
3271 mnode = read_yin_container(module, retval, sub, resolve, unres);
3272 } else if (!strcmp(sub->name, "leaf-list")) {
3273 mnode = read_yin_leaflist(module, retval, sub, resolve);
3274 } else if (!strcmp(sub->name, "leaf")) {
3275 mnode = read_yin_leaf(module, retval, sub, resolve);
3276 } else if (!strcmp(sub->name, "list")) {
3277 mnode = read_yin_list(module, retval, sub, resolve, unres);
3278 } else if (!strcmp(sub->name, "choice")) {
3279 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3280 } else if (!strcmp(sub->name, "uses")) {
3281 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3282 } else if (!strcmp(sub->name, "grouping")) {
3283 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3284 } else if (!strcmp(sub->name, "anyxml")) {
3285 mnode = read_yin_anyxml(module, retval, sub, resolve);
3286 }
3287 lyxml_free_elem(module->ctx, sub);
3288
3289 if (!mnode) {
3290 goto error;
3291 }
3292 }
3293
3294 if (parent && ly_mnode_addchild(parent, retval)) {
3295 goto error;
3296 }
3297
3298 return retval;
3299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003300error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003301
3302 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003303 while (root.child) {
3304 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003305 }
3306
3307 return NULL;
3308}
3309
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003310static struct ly_mnode *
3311read_yin_notif(struct ly_module *module,
3312 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02003313{
Michal Vaskoc6551b32015-06-16 10:51:43 +02003314 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02003315 struct ly_mnode *mnode = NULL;
3316 struct ly_mnode *retval;
3317 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003318 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02003319 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003320 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02003321
Michal Vaskoc6551b32015-06-16 10:51:43 +02003322 memset(&root, 0, sizeof root);
3323
Michal Vasko0ea41032015-06-16 08:53:55 +02003324 notif = calloc(1, sizeof *notif);
3325 notif->nodetype = LY_NODE_NOTIF;
3326 notif->prev = (struct ly_mnode *)notif;
3327 retval = (struct ly_mnode *)notif;
3328
3329 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3330 goto error;
3331 }
3332
3333 /* process rpc's specific children */
3334 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3335 /* data statements */
3336 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003337 !strcmp(sub->name, "leaf-list") ||
3338 !strcmp(sub->name, "leaf") ||
3339 !strcmp(sub->name, "list") ||
3340 !strcmp(sub->name, "choice") ||
3341 !strcmp(sub->name, "uses") ||
3342 !strcmp(sub->name, "grouping") ||
3343 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02003344 lyxml_unlink_elem(sub);
3345 lyxml_add_child(&root, sub);
3346
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003347 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02003348 } else if (!strcmp(sub->name, "typedef")) {
3349 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003350 } else if (!strcmp(sub->name, "if-feature")) {
3351 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003352 } else {
3353 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3354 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02003355 }
3356 }
3357
3358 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3359 if (c_tpdf) {
3360 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3361 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003362 if (c_ftrs) {
3363 notif->features = calloc(c_ftrs, sizeof *notif->features);
3364 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003365
3366 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3367 if (!strcmp(sub->name, "typedef")) {
3368 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3369 notif->tpdf_size++;
3370
3371 if (r) {
3372 goto error;
3373 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003374 } else if (!strcmp(sub->name, "typedef")) {
3375 GETVAL(value, sub, "name");
3376 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3377 if (!notif->features[notif->features_size]) {
3378 goto error;
3379 }
3380 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003381 }
3382
3383 lyxml_free_elem(module->ctx, sub);
3384 }
3385
3386 /* last part - process data nodes */
3387 LY_TREE_FOR_SAFE(root.child, next, sub) {
3388 if (!strcmp(sub->name, "container")) {
3389 mnode = read_yin_container(module, retval, sub, resolve, unres);
3390 } else if (!strcmp(sub->name, "leaf-list")) {
3391 mnode = read_yin_leaflist(module, retval, sub, resolve);
3392 } else if (!strcmp(sub->name, "leaf")) {
3393 mnode = read_yin_leaf(module, retval, sub, resolve);
3394 } else if (!strcmp(sub->name, "list")) {
3395 mnode = read_yin_list(module, retval, sub, resolve, unres);
3396 } else if (!strcmp(sub->name, "choice")) {
3397 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3398 } else if (!strcmp(sub->name, "uses")) {
3399 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3400 } else if (!strcmp(sub->name, "grouping")) {
3401 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3402 } else if (!strcmp(sub->name, "anyxml")) {
3403 mnode = read_yin_anyxml(module, retval, sub, resolve);
3404 }
3405 lyxml_free_elem(module->ctx, sub);
3406
3407 if (!mnode) {
3408 goto error;
3409 }
3410 }
3411
3412 if (parent && ly_mnode_addchild(parent, retval)) {
3413 goto error;
3414 }
3415
3416 return retval;
3417
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003418error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003419
3420 ly_mnode_free(retval);
3421 while (root.child) {
3422 lyxml_free_elem(module->ctx, root.child);
3423 }
3424
3425 return NULL;
3426}
3427
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003428static struct ly_mnode *
3429read_yin_rpc(struct ly_module *module,
3430 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003431{
Radek Krejcie0674f82015-06-15 13:58:51 +02003432 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003433 struct ly_mnode *mnode = NULL;
3434 struct ly_mnode *retval;
3435 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003436 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003437 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003438 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003439
Radek Krejcie0674f82015-06-15 13:58:51 +02003440 /* init */
3441 memset(&root, 0, sizeof root);
3442
Michal Vasko38d01f72015-06-15 09:41:06 +02003443 rpc = calloc(1, sizeof *rpc);
3444 rpc->nodetype = LY_NODE_RPC;
3445 rpc->prev = (struct ly_mnode *)rpc;
3446 retval = (struct ly_mnode *)rpc;
3447
3448 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3449 goto error;
3450 }
3451
3452 /* process rpc's specific children */
3453 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3454 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003455 if (rpc->child
3456 && (rpc->child->nodetype == LY_NODE_INPUT
3457 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003458 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3459 goto error;
3460 }
3461 lyxml_unlink_elem(sub);
3462 lyxml_add_child(&root, sub);
3463 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003464 if (rpc->child
3465 && (rpc->child->nodetype == LY_NODE_INPUT
3466 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003467 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3468 goto error;
3469 }
3470 lyxml_unlink_elem(sub);
3471 lyxml_add_child(&root, sub);
3472
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003473 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003474 } else if (!strcmp(sub->name, "grouping")) {
3475 lyxml_unlink_elem(sub);
3476 lyxml_add_child(&root, sub);
3477
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003478 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003479 } else if (!strcmp(sub->name, "typedef")) {
3480 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003481 } else if (!strcmp(sub->name, "if-feature")) {
3482 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003483 } else {
3484 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3485 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003486 }
3487 }
3488
3489 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3490 if (c_tpdf) {
3491 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3492 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003493 if (c_ftrs) {
3494 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3495 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003496
3497 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3498 if (!strcmp(sub->name, "typedef")) {
3499 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3500 rpc->tpdf_size++;
3501
3502 if (r) {
3503 goto error;
3504 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003505 } else if (!strcmp(sub->name, "if-feature")) {
3506 GETVAL(value, sub, "name");
3507 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3508 if (!rpc->features[rpc->features_size]) {
3509 goto error;
3510 }
3511 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003512 }
3513
3514 lyxml_free_elem(module->ctx, sub);
3515 }
3516
3517 /* last part - process data nodes */
3518 LY_TREE_FOR_SAFE(root.child, next, sub) {
3519 if (!strcmp(sub->name, "grouping")) {
3520 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3521 } else if (!strcmp(sub->name, "input")) {
3522 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3523 } else if (!strcmp(sub->name, "output")) {
3524 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3525 }
3526 lyxml_free_elem(module->ctx, sub);
3527
3528 if (!mnode) {
3529 goto error;
3530 }
3531 }
3532
3533 if (parent && ly_mnode_addchild(parent, retval)) {
3534 goto error;
3535 }
3536
3537 return retval;
3538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003539error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003540
3541 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003542 while (root.child) {
3543 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003544 }
3545
3546 return NULL;
3547}
3548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003549static int
3550find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003551{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003552 struct ly_module *searchmod = NULL, *module = uses->module;
3553 struct ly_mnode *mnode, *mnode_aux;
3554 const char *name;
3555 int prefix_len = 0;
3556 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003557
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003558 /* get referenced grouping */
3559 name = strchr(uses->name, ':');
3560 if (!name) {
3561 /* no prefix, search in local tree */
3562 name = uses->name;
3563 } else {
3564 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003565
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003566 /* set name to correct position after colon */
3567 prefix_len = name - uses->name;
3568 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003570 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3571 /* prefix refers to the current module, ignore it */
3572 prefix_len = 0;
3573 }
3574 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003576 /* search */
3577 if (prefix_len) {
3578 /* in top-level groupings of some other module */
3579 for (i = 0; i < module->imp_size; i++) {
3580 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3581 && !module->imp[i].prefix[prefix_len]) {
3582 searchmod = module->imp[i].module;
3583 break;
3584 }
3585 }
3586 if (!searchmod) {
3587 /* uses refers unknown data model */
3588 LOGVAL(VE_INPREFIX, line, name);
3589 return EXIT_FAILURE;
3590 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003591
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003592 LY_TREE_FOR(searchmod->data, mnode) {
3593 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3594 uses->grp = (struct ly_mnode_grp *)mnode;
3595 return EXIT_SUCCESS;
3596 }
3597 }
3598 } else {
3599 /* in local tree hierarchy */
3600 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3601 LY_TREE_FOR(mnode_aux->child, mnode) {
3602 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3603 uses->grp = (struct ly_mnode_grp *)mnode;
3604 return EXIT_SUCCESS;
3605 }
3606 }
3607 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003609 /* search in top level of the current module */
3610 LY_TREE_FOR(module->data, mnode) {
3611 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3612 uses->grp = (struct ly_mnode_grp *)mnode;
3613 return EXIT_SUCCESS;
3614 }
3615 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003616
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003617 /* search in top-level of included modules */
3618 for (i = 0; i < module->inc_size; i++) {
3619 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3620 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3621 uses->grp = (struct ly_mnode_grp *)mnode;
3622 return EXIT_SUCCESS;
3623 }
3624 }
3625 }
3626 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003627
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003628 /* not found, but no explicit error occured */
3629 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003630}
3631
Radek Krejcif5be10f2015-06-16 13:29:36 +02003632static int
3633resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3634{
3635 struct lyxml_elem *yin, *next, *sub;
3636 struct ly_mnode *mnode;
3637
3638 assert(module);
3639
3640 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003641 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003642 if (!aug->target) {
3643 LOGVAL(VE_INARG, line, aug->target, "uses");
3644 return EXIT_FAILURE;
3645 }
3646
3647 if (!aug->child) {
3648 /* nothing to do */
3649 return EXIT_SUCCESS;
3650 }
3651
3652 yin = (struct lyxml_elem *)aug->child;
3653
3654 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3655 return EXIT_FAILURE;
3656 }
3657
3658 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3659 if (!strcmp(sub->name, "container")) {
3660 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3661 } else if (!strcmp(sub->name, "leaf-list")) {
3662 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3663 } else if (!strcmp(sub->name, "leaf")) {
3664 mnode = read_yin_leaf(module, aug->target, sub, 1);
3665 } else if (!strcmp(sub->name, "list")) {
3666 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3667 } else if (!strcmp(sub->name, "uses")) {
3668 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3669 } else if (!strcmp(sub->name, "choice")) {
3670 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3671 } else if (!strcmp(sub->name, "case")) {
3672 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3673 } else if (!strcmp(sub->name, "anyxml")) {
3674 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3675#if 0
3676 } else {
3677 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003678 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003679#else
3680 } else {
3681 continue;
3682#endif
3683 }
3684
3685 if (!mnode) {
3686 return EXIT_FAILURE;
3687 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003688 /* check for mandatory nodes - if the target node is in another module
3689 * the added nodes cannot be mandatory
3690 */
3691 if (check_mandatory(mnode)) {
3692 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3693 return EXIT_FAILURE;
3694 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003695
3696 lyxml_free_elem(module->ctx, sub);
3697
3698 /* the parent pointer will point to the augment node, but all
3699 * siblings pointers and possibly the child node in target does
3700 * not know about the augment and follow the standard schema tree
3701 * structure
3702 */
3703 mnode->parent = (struct ly_mnode *)aug;
3704 mnode = NULL;
3705 }
3706
3707 lyxml_free_elem(module->ctx, yin);
3708 aug->child = NULL;
3709
3710 return EXIT_SUCCESS;
3711}
3712
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003713int
3714resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003715{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003716 struct ly_ctx *ctx;
3717 struct ly_mnode *mnode = NULL, *mnode_aux;
3718 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02003719 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003720 int i, j;
3721 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003723 /* copy the data nodes from grouping into the uses context */
3724 LY_TREE_FOR(uses->grp->child, mnode) {
3725 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3726 if (!mnode_aux) {
3727 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3728 return EXIT_FAILURE;
3729 }
3730 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3731 ly_mnode_free(mnode_aux);
3732 return EXIT_FAILURE;
3733 }
3734 }
3735 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003737 /* apply refines */
3738 for (i = 0; i < uses->refine_size; i++) {
3739 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003740 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003741 if (!mnode) {
3742 LOGVAL(VE_INARG, line, rfn->target, "uses");
3743 return EXIT_FAILURE;
3744 }
Radek Krejci106efc02015-06-10 14:36:27 +02003745
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003746 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3747 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3748 return EXIT_FAILURE;
3749 }
Radek Krejci106efc02015-06-10 14:36:27 +02003750
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003751 /* description on any nodetype */
3752 if (rfn->dsc) {
3753 lydict_remove(ctx, mnode->dsc);
3754 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3755 }
Radek Krejci106efc02015-06-10 14:36:27 +02003756
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003757 /* reference on any nodetype */
3758 if (rfn->ref) {
3759 lydict_remove(ctx, mnode->ref);
3760 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3761 }
Radek Krejci106efc02015-06-10 14:36:27 +02003762
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003763 /* config on any nodetype */
3764 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3765 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3766 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3767 }
Radek Krejci106efc02015-06-10 14:36:27 +02003768
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003769 /* default value ... */
3770 if (rfn->mod.dflt) {
3771 if (mnode->nodetype == LY_NODE_LEAF) {
3772 /* leaf */
3773 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3774 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3775 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3776 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003777 ((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 +02003778 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3779 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3780 return EXIT_FAILURE;
3781 }
3782 }
3783 }
Radek Krejci106efc02015-06-10 14:36:27 +02003784
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003785 /* mandatory on leaf, anyxml or choice */
3786 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3787 if (rfn->flags & LY_NODE_MAND_FALSE) {
3788 /* erase mandatory true flag, we don't use false flag in schema nodes */
3789 mnode->flags &= ~LY_NODE_MAND_TRUE;
3790 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3791 /* set mandatory true flag */
3792 mnode->flags |= LY_NODE_MAND_TRUE;
3793 }
3794 }
Radek Krejci106efc02015-06-10 14:36:27 +02003795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003796 /* presence on container */
3797 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3798 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3799 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3800 }
Radek Krejci106efc02015-06-10 14:36:27 +02003801
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003802 /* min/max-elements on list or leaf-list */
3803 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3804 /* magic - bit 3 in flags means min set, bit 4 says max set */
3805 if (rfn->flags & 0x04) {
3806 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3807 }
3808 if (rfn->flags & 0x08) {
3809 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3810 }
3811 }
Radek Krejci106efc02015-06-10 14:36:27 +02003812
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003813 /* must in leaf, leaf-list, list, container or anyxml */
3814 if (rfn->must_size) {
3815 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3816 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3817 if (!newmust) {
3818 LOGMEM;
3819 return EXIT_FAILURE;
3820 }
3821 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02003822 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003823 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3824 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3825 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3826 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3827 }
Radek Krejci106efc02015-06-10 14:36:27 +02003828
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003829 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3830 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3831 }
3832 }
Radek Krejci106efc02015-06-10 14:36:27 +02003833
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003834 /* apply augments */
3835 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003836 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003837 goto error;
3838 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003839 }
Radek Krejci106efc02015-06-10 14:36:27 +02003840
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003841 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003842
3843error:
3844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003845 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003846}
Radek Krejci74705112015-06-05 10:25:44 +02003847
3848/*
3849 * resolve - referenced grouping should be bounded to the namespace (resolved)
3850 * only when uses does not appear in grouping. In a case of grouping's uses,
3851 * we just get information but we do not apply augment or refine to it.
3852 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003853static struct ly_mnode *
3854read_yin_uses(struct ly_module *module,
3855 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003856{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003857 struct lyxml_elem *sub, *next;
3858 struct ly_mnode *retval;
3859 struct ly_mnode_uses *uses;
3860 struct mnode_list *unres_new;
3861 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003862 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003863 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003864
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003865 uses = calloc(1, sizeof *uses);
3866 uses->nodetype = LY_NODE_USES;
3867 uses->prev = (struct ly_mnode *)uses;
3868 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003869
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003870 GETVAL(value, node, "name");
3871 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003872
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003873 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3874 goto error;
3875 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003877 /* get other properties of uses */
3878 LY_TREE_FOR_SAFE(node->child, next, sub) {
3879 if (!strcmp(sub->name, "refine")) {
3880 c_ref++;
3881 } else if (!strcmp(sub->name, "augment")) {
3882 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003883 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02003884 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003885 } else if (!strcmp(sub->name, "when")) {
3886 if (uses->when) {
3887 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
3888 goto error;
3889 }
3890
3891 uses->when = read_yin_when(module, sub);
3892 lyxml_free_elem(module->ctx, sub);
3893
3894 if (!uses->when) {
3895 goto error;
3896 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003897 } else {
3898 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3899 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003900 }
3901 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003902
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003903 /* process properties with cardinality 0..n */
3904 if (c_ref) {
3905 uses->refine = calloc(c_ref, sizeof *uses->refine);
3906 }
3907 if (c_aug) {
3908 uses->augment = calloc(c_aug, sizeof *uses->augment);
3909 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003910 if (c_ftrs) {
3911 uses->features = calloc(c_ftrs, sizeof *uses->features);
3912 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003913
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003914 LY_TREE_FOR_SAFE(node->child, next, sub) {
3915 if (!strcmp(sub->name, "refine")) {
3916 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
3917 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003918 lyxml_free_elem(module->ctx, sub);
3919 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003920 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
3921 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003922 } else if (!strcmp(sub->name, "if-feature")) {
3923 GETVAL(value, sub, "name");
3924 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
3925 if (!uses->features[uses->features_size]) {
3926 goto error;
3927 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02003928 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003929 uses->features_size++;
3930 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003931 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003932
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003933 if (r) {
3934 goto error;
3935 }
3936 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003937
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003938 if (find_grouping(parent, uses, LOGLINE(node))) {
3939 goto error;
3940 }
3941 if (!uses->grp) {
3942 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
3943 unres_new = calloc(1, sizeof *unres_new);
3944 if (*unres) {
3945 unres_new->next = *unres;
3946 }
3947 unres_new->mnode = retval;
3948 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02003949
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003950 /* put it at the beginning of the unresolved list */
3951 *unres = unres_new;
3952 }
Radek Krejci74705112015-06-05 10:25:44 +02003953
Radek Krejci368c38f2015-06-15 15:09:55 +02003954 if (parent && ly_mnode_addchild(parent, retval)) {
3955 goto error;
3956 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003957
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003958 if (resolve) {
3959 /* inherit config flag */
3960 if (parent) {
3961 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
3962 } else {
3963 /* default config is true */
3964 retval->flags |= LY_NODE_CONFIG_W;
3965 }
3966 }
Radek Krejcib388c152015-06-04 17:03:03 +02003967
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003968 if (resolve && uses->grp) {
3969 /* copy the data nodes from grouping into the uses context */
3970 if (resolve_uses(uses, LOGLINE(node))) {
3971 goto error;
3972 }
3973 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003974
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003975 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003976
3977error:
3978
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003979 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003980
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003981 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003982}
3983
Radek Krejciefaeba32015-05-27 14:30:57 +02003984/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003985static int
3986read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003987{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003988 struct ly_ctx *ctx = module->ctx;
3989 struct ly_submodule *submodule = (struct ly_submodule *)module;
3990 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
3991 struct ly_mnode *mnode = NULL;
3992 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
3993 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003994 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02003995 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003996 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003997 /* counters */
3998 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 +02003999
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004000 /* init */
4001 memset(&root, 0, sizeof root);
4002 memset(&grps, 0, sizeof grps);
4003 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004004 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004005
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004006 /*
4007 * in the first run, we process elements with cardinality of 1 or 0..1 and
4008 * count elements with cardinality 0..n. Data elements (choices, containers,
4009 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4010 * need have all top-level and groupings already prepared at that time. In
4011 * the middle loop, we process other elements with carinality of 0..n since
4012 * we need to allocate arrays to store them.
4013 */
4014 LY_TREE_FOR_SAFE(yin->child, next, node) {
4015 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4016 lyxml_free_elem(ctx, node);
4017 continue;
4018 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004020 if (!module->type && !strcmp(node->name, "namespace")) {
4021 if (module->ns) {
4022 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4023 goto error;
4024 }
4025 GETVAL(value, node, "uri");
4026 module->ns = lydict_insert(ctx, value, strlen(value));
4027 lyxml_free_elem(ctx, node);
4028 } else if (!module->type && !strcmp(node->name, "prefix")) {
4029 if (module->prefix) {
4030 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4031 goto error;
4032 }
4033 GETVAL(value, node, "value");
4034 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4035 goto error;
4036 }
4037 module->prefix = lydict_insert(ctx, value, strlen(value));
4038 lyxml_free_elem(ctx, node);
4039 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4040 if (belongsto_flag) {
4041 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4042 goto error;
4043 }
4044 belongsto_flag = 1;
4045 GETVAL(value, node, "module");
4046 while (submodule->belongsto->type) {
4047 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4048 }
4049 if (value != submodule->belongsto->name) {
4050 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4051 goto error;
4052 }
Radek Krejcif3886932015-06-04 17:36:06 +02004053
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004054 /* get the prefix substatement, start with checks */
4055 if (!node->child) {
4056 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4057 goto error;
4058 } else if (strcmp(node->child->name, "prefix")) {
4059 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4060 goto error;
4061 } else if (node->child->next) {
4062 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4063 goto error;
4064 }
4065 /* and now finally get the value */
4066 GETVAL(value, node->child, "value");
4067 /* check here differs from a generic prefix check, since this prefix
4068 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004069 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004070 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4071 goto error;
4072 }
4073 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004074
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004075 /* we are done with belongs-to */
4076 lyxml_free_elem(ctx, node);
4077 } else if (!strcmp(node->name, "import")) {
4078 c_imp++;
4079 } else if (!strcmp(node->name, "revision")) {
4080 c_rev++;
4081 } else if (!strcmp(node->name, "typedef")) {
4082 c_tpdf++;
4083 } else if (!strcmp(node->name, "identity")) {
4084 c_ident++;
4085 } else if (!strcmp(node->name, "include")) {
4086 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004087 } else if (!strcmp(node->name, "augment")) {
4088 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004089 } else if (!strcmp(node->name, "feature")) {
4090 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004091
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004092 /* data statements */
4093 } else if (!strcmp(node->name, "container") ||
4094 !strcmp(node->name, "leaf-list") ||
4095 !strcmp(node->name, "leaf") ||
4096 !strcmp(node->name, "list") ||
4097 !strcmp(node->name, "choice") ||
4098 !strcmp(node->name, "uses") ||
4099 !strcmp(node->name, "anyxml")) {
4100 lyxml_unlink_elem(node);
4101 lyxml_add_child(&root, node);
4102 } else if (!strcmp(node->name, "grouping")) {
4103 /* keep groupings separated and process them before other data statements */
4104 lyxml_unlink_elem(node);
4105 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004107 /* optional statements */
4108 } else if (!strcmp(node->name, "description")) {
4109 if (module->dsc) {
4110 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4111 goto error;
4112 }
4113 module->dsc = read_yin_subnode(ctx, node, "text");
4114 lyxml_free_elem(ctx, node);
4115 if (!module->dsc) {
4116 goto error;
4117 }
4118 } else if (!strcmp(node->name, "reference")) {
4119 if (module->ref) {
4120 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4121 goto error;
4122 }
4123 module->ref = read_yin_subnode(ctx, node, "text");
4124 lyxml_free_elem(ctx, node);
4125 if (!module->ref) {
4126 goto error;
4127 }
4128 } else if (!strcmp(node->name, "organization")) {
4129 if (module->org) {
4130 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4131 goto error;
4132 }
4133 module->org = read_yin_subnode(ctx, node, "text");
4134 lyxml_free_elem(ctx, node);
4135 if (!module->org) {
4136 goto error;
4137 }
4138 } else if (!strcmp(node->name, "contact")) {
4139 if (module->contact) {
4140 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4141 goto error;
4142 }
4143 module->contact = read_yin_subnode(ctx, node, "text");
4144 lyxml_free_elem(ctx, node);
4145 if (!module->contact) {
4146 goto error;
4147 }
4148 } else if (!strcmp(node->name, "yang-version")) {
4149 /* TODO: support YANG 1.1 ? */
4150 if (module->version) {
4151 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4152 goto error;
4153 }
4154 GETVAL(value, node, "value");
4155 if (strcmp(value, "1")) {
4156 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
4157 goto error;
4158 }
4159 module->version = 1;
4160 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02004161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004162 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02004163 } else if (!strcmp(node->name, "rpc")) {
4164 lyxml_unlink_elem(node);
4165 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02004166 } else if (!strcmp(node->name, "notification")) {
4167 lyxml_unlink_elem(node);
4168 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02004169#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004170 } else {
4171 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
4172 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02004173#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004174 } else {
4175 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02004176#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004177 }
4178 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004180 if (!submodule) {
4181 /* check for mandatory statements */
4182 if (!module->ns) {
4183 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
4184 goto error;
4185 }
4186 if (!module->prefix) {
4187 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
4188 goto error;
4189 }
4190 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02004191
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004192 /* allocate arrays for elements with cardinality of 0..n */
4193 if (c_imp) {
4194 module->imp = calloc(c_imp, sizeof *module->imp);
4195 }
4196 if (c_rev) {
4197 module->rev = calloc(c_rev, sizeof *module->rev);
4198 }
4199 if (c_tpdf) {
4200 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
4201 }
4202 if (c_ident) {
4203 module->ident = calloc(c_ident, sizeof *module->ident);
4204 }
4205 if (c_inc) {
4206 module->inc = calloc(c_inc, sizeof *module->inc);
4207 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004208 if (c_aug) {
4209 module->augment = calloc(c_aug, sizeof *module->augment);
4210 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004211 if (c_ftrs) {
4212 module->features = calloc(c_ftrs, sizeof *module->features);
4213 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004214
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004215 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4216 LY_TREE_FOR_SAFE(yin->child, next, node) {
4217 if (!strcmp(node->name, "import")) {
4218 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
4219 module->imp_size++;
4220 if (r) {
4221 goto error;
4222 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004223
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004224 /* check duplicities in imported modules */
4225 for (i = 0; i < module->imp_size - 1; i++) {
4226 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
4227 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
4228 goto error;
4229 }
4230 }
4231 } else if (!strcmp(node->name, "include")) {
4232 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
4233 module->inc_size++;
4234 if (r) {
4235 goto error;
4236 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004238 /* check duplications in include submodules */
4239 for (i = 0; i < module->inc_size - 1; i++) {
4240 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
4241 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
4242 module->inc[i].submodule->name);
4243 goto error;
4244 }
4245 }
4246 } else if (!strcmp(node->name, "revision")) {
4247 GETVAL(value, node, "date");
4248 if (check_date(value, LOGLINE(node))) {
4249 goto error;
4250 }
4251 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4252 /* check uniqueness of the revision date - not required by RFC */
4253 for (i = 0; i < module->rev_size; i++) {
4254 if (!strcmp(value, module->rev[i].date)) {
4255 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4256 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
4257 }
4258 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004260 LY_TREE_FOR(node->child, child) {
4261 if (!strcmp(child->name, "description")) {
4262 if (module->rev[module->rev_size].dsc) {
4263 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4264 goto error;
4265 }
4266 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
4267 if (!module->rev[module->rev_size].dsc) {
4268 goto error;
4269 }
4270 } else if (!strcmp(child->name, "reference")) {
4271 if (module->rev[module->rev_size].ref) {
4272 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
4273 goto error;
4274 }
4275 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
4276 if (!module->rev[module->rev_size].ref) {
4277 goto error;
4278 }
4279 } else {
4280 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
4281 goto error;
4282 }
4283 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004284
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004285 /* keep the latest revision at position 0 */
4286 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
4287 /* switch their position */
4288 value = strdup(module->rev[0].date);
4289 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
4290 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
4291 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02004292
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004293 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
4294 value = module->rev[0].dsc;
4295 module->rev[0].dsc = module->rev[module->rev_size].dsc;
4296 module->rev[module->rev_size].dsc = value;
4297 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004298
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004299 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
4300 value = module->rev[0].ref;
4301 module->rev[0].ref = module->rev[module->rev_size].ref;
4302 module->rev[module->rev_size].ref = value;
4303 }
4304 }
Radek Krejcice7fb782015-05-29 16:52:34 +02004305
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004306 module->rev_size++;
4307 } else if (!strcmp(node->name, "typedef")) {
4308 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
4309 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004310
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004311 if (r) {
4312 goto error;
4313 }
4314 } else if (!strcmp(node->name, "identity")) {
4315 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
4316 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02004317
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004318 if (r) {
4319 goto error;
4320 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004321 } else if (!strcmp(node->name, "feature")) {
4322 r = fill_yin_feature(module, node, &module->features[module->features_size]);
4323 module->features_size++;
4324
4325 if (r) {
4326 goto error;
4327 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004328 } else if (!strcmp(node->name, "augment")) {
4329 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
4330 module->augment_size++;
4331
4332 if (r) {
4333 goto error;
4334 }
4335
4336 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
4337 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004338 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004340 lyxml_free_elem(ctx, node);
4341 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004342
Radek Krejcif5be10f2015-06-16 13:29:36 +02004343 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004344 * refer to them
4345 */
4346 LY_TREE_FOR_SAFE(grps.child, next, node) {
4347 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
4348 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02004349
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004350 if (!mnode) {
4351 goto error;
4352 }
Radek Krejci74705112015-06-05 10:25:44 +02004353
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004354 /* include data element */
4355 if (module->data) {
4356 module->data->prev->next = mnode;
4357 mnode->prev = module->data->prev;
4358 module->data->prev = mnode;
4359 } else {
4360 module->data = mnode;
4361 }
4362 }
4363 while (unres) {
4364 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4365 goto error;
4366 }
4367 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4368 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4369 goto error;
4370 }
4371 unres_next = unres->next;
4372 free(unres);
4373 unres = unres_next;
4374 }
Radek Krejci74705112015-06-05 10:25:44 +02004375
Radek Krejcif5be10f2015-06-16 13:29:36 +02004376 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004377 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004378
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004379 if (!strcmp(node->name, "container")) {
4380 mnode = read_yin_container(module, NULL, node, 1, &unres);
4381 } else if (!strcmp(node->name, "leaf-list")) {
4382 mnode = read_yin_leaflist(module, NULL, node, 1);
4383 } else if (!strcmp(node->name, "leaf")) {
4384 mnode = read_yin_leaf(module, NULL, node, 1);
4385 } else if (!strcmp(node->name, "list")) {
4386 mnode = read_yin_list(module, NULL, node, 1, &unres);
4387 } else if (!strcmp(node->name, "choice")) {
4388 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4389 } else if (!strcmp(node->name, "uses")) {
4390 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4391 } else if (!strcmp(node->name, "anyxml")) {
4392 mnode = read_yin_anyxml(module, NULL, node, 1);
4393 }
4394 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004396 if (!mnode) {
4397 goto error;
4398 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004399
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004400 /* include data element */
4401 if (module->data) {
4402 module->data->prev->next = mnode;
4403 mnode->prev = module->data->prev;
4404 module->data->prev = mnode;
4405 } else {
4406 module->data = mnode;
4407 }
4408 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004409
4410 /* ... rpcs ... */
4411 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4412 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4413 lyxml_free_elem(ctx, node);
4414
4415 if (!mnode) {
4416 goto error;
4417 }
4418
4419 /* include rpc element */
4420 if (module->rpc) {
4421 module->rpc->prev->next = mnode;
4422 mnode->prev = module->rpc->prev;
4423 module->rpc->prev = mnode;
4424 } else {
4425 module->rpc = mnode;
4426 }
4427 }
4428
4429 /* ... and notifications */
4430 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4431 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4432 lyxml_free_elem(ctx, node);
4433
4434 if (!mnode) {
4435 goto error;
4436 }
4437
4438 /* include notification element */
4439 if (module->notif) {
4440 module->notif->prev->next = mnode;
4441 mnode->prev = module->notif->prev;
4442 module->notif->prev = mnode;
4443 } else {
4444 module->notif = mnode;
4445 }
4446 }
4447
4448 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004449 while (unres) {
4450 /* find referenced grouping */
4451 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4452 goto error;
4453 }
4454 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4455 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4456 goto error;
4457 }
Radek Krejci74705112015-06-05 10:25:44 +02004458
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004459 /* resolve uses by copying grouping content under the uses */
4460 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4461 goto error;
4462 }
Radek Krejci74705112015-06-05 10:25:44 +02004463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004464 unres_next = unres->next;
4465 free(unres);
4466 unres = unres_next;
4467 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004468
Radek Krejcif5be10f2015-06-16 13:29:36 +02004469 /* and finally apply augments */
4470 for (i = 0; i < module->augment_size; i++) {
4471 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004472 goto error;
4473 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004474 }
4475
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004476 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004477
4478error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004479 /* cleanup */
4480 while (root.child) {
4481 lyxml_free_elem(module->ctx, root.child);
4482 }
4483 while (grps.child) {
4484 lyxml_free_elem(module->ctx, grps.child);
4485 }
4486 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004487 lyxml_free_elem(module->ctx, rpcs.child);
4488 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004490 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004491}
4492
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004493struct ly_submodule *
4494yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004495{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004496 struct lyxml_elem *yin;
4497 struct ly_submodule *submodule = NULL;
4498 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004499
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004500 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004502 yin = lyxml_read(module->ctx, data, 0);
4503 if (!yin) {
4504 return NULL;
4505 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004506
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004507 /* check root element */
4508 if (!yin->name || strcmp(yin->name, "submodule")) {
4509 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4510 goto error;
4511 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004512
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004513 GETVAL(value, yin, "name");
4514 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4515 goto error;
4516 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004518 submodule = calloc(1, sizeof *submodule);
4519 if (!submodule) {
4520 LOGMEM;
4521 goto error;
4522 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004523
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004524 submodule->ctx = module->ctx;
4525 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4526 submodule->type = 1;
4527 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004528
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004529 LOGVRB("reading submodule %s", submodule->name);
4530 if (read_sub_module((struct ly_module *)submodule, yin)) {
4531 goto error;
4532 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004534 /* cleanup */
4535 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004536
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004537 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004539 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004540
4541error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004542 /* cleanup */
4543 lyxml_free_elem(module->ctx, yin);
4544 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004546 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004547}
4548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004549struct ly_module *
4550yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004551{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004552 struct lyxml_elem *yin;
4553 struct ly_module *module = NULL, **newlist = NULL;
4554 const char *value;
4555 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004557 yin = lyxml_read(ctx, data, 0);
4558 if (!yin) {
4559 return NULL;
4560 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004562 /* check root element */
4563 if (!yin->name || strcmp(yin->name, "module")) {
4564 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4565 goto error;
4566 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004567
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004568 GETVAL(value, yin, "name");
4569 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4570 goto error;
4571 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004573 module = calloc(1, sizeof *module);
4574 if (!module) {
4575 LOGMEM;
4576 goto error;
4577 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004578
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004579 module->ctx = ctx;
4580 module->name = lydict_insert(ctx, value, strlen(value));
4581 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004582
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004583 LOGVRB("reading module %s", module->name);
4584 if (read_sub_module(module, yin)) {
4585 goto error;
4586 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004588 /* add to the context's list of modules */
4589 if (ctx->models.used == ctx->models.size) {
4590 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4591 if (!newlist) {
4592 LOGMEM;
4593 goto error;
4594 }
4595 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4596 newlist[i] = NULL;
4597 }
4598 ctx->models.size *= 2;
4599 ctx->models.list = newlist;
4600 }
4601 for (i = 0; ctx->models.list[i]; i++) {
4602 /* check name (name/revision) and namespace uniqueness */
4603 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4604 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4605 /* both data models are same, with no revision specified */
4606 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4607 module->name);
4608 goto error;
4609 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4610 /* one of the models does not have a revision, so they differs */
4611 continue;
4612 } else {
4613 /* both models have a revision statement which we have to
4614 * compare, revision at position 0 is the last revision
4615 */
4616 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4617 /* we have the same modules */
4618 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4619 module->rev[0].date);
4620 goto error;
4621 }
4622 }
4623 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4624 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4625 ctx->models.list[i]->name, module->name, module->ns);
4626 goto error;
4627 }
4628 }
4629 ctx->models.list[i] = module;
4630 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004631
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004632 /* cleanup */
4633 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004635 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004637 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004638
4639error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004640 /* cleanup */
4641 lyxml_free_elem(ctx, yin);
4642 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004644 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004645}