blob: 54e62df8e4744eaf5b874e9c982ee87bc04c15ff [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 {
41 LY_IDENT_FEATURE,
42 LY_IDENT_IDENTITY,
43 LY_IDENT_TYPE,
44 LY_IDENT_NODE,
Radek Krejci0af13872015-05-30 11:50:52 +020045 LY_IDENT_NAME,
Radek Krejcice7fb782015-05-29 16:52:34 +020046 LY_IDENT_PREFIX
47};
48
Radek Krejciefdd0ce2015-05-26 16:48:29 +020049#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020050
Radek Krejcice7fb782015-05-29 16:52:34 +020051#define GETVAL(value, node, arg) \
52 value = lyxml_get_attr(node, arg, NULL); \
53 if (!value) { \
54 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
55 goto error; \
56 }
57
Radek Krejcib388c152015-06-04 17:03:03 +020058#define OPT_IDENT 0x01
59#define OPT_CONFIG 0x02
60#define OPT_MODULE 0x04
61#define OPT_INHERIT 0x08
62static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
63
Radek Krejci8bc9ca02015-06-04 15:52:46 +020064static struct ly_mnode *read_yin_choice(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
65static struct ly_mnode *read_yin_case(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcib388c152015-06-04 17:03:03 +020066static struct ly_mnode *read_yin_anyxml(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejci8bc9ca02015-06-04 15:52:46 +020067static struct ly_mnode *read_yin_container(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcib388c152015-06-04 17:03:03 +020068static struct ly_mnode *read_yin_leaf(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
69static struct ly_mnode *read_yin_leaflist(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejci8bc9ca02015-06-04 15:52:46 +020070static struct ly_mnode *read_yin_list(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +020071static struct ly_mnode *read_yin_uses(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejci8bc9ca02015-06-04 15:52:46 +020072static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcida04f4a2015-05-21 12:54:09 +020073
Radek Krejcieac35532015-05-31 19:09:15 +020074static int dup_typedef_check(const char* type, struct ly_tpdf *tpdf, int size)
75{
76 int i;
77
78 for (i = 0; i < size; i++) {
79 if (!strcmp(type, tpdf[i].name)) {
80 /* name collision */
81 return EXIT_FAILURE;
82 }
83 }
84
85 return EXIT_SUCCESS;
86}
87
Radek Krejcice7fb782015-05-29 16:52:34 +020088static int dup_prefix_check(const char* prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +020089{
Radek Krejcice7fb782015-05-29 16:52:34 +020090 int i;
91
92 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
93 return EXIT_FAILURE;
94 }
95 for (i = 0; i < module->imp_size; i++) {
96 if (!strcmp(module->imp[i].prefix, prefix)) {
97 return EXIT_FAILURE;
98 }
99 }
100
101 return EXIT_SUCCESS;
102}
103
104static int check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
105 struct ly_module *module, struct ly_mnode *parent)
106{
107 int i;
Radek Krejcieac35532015-05-31 19:09:15 +0200108 int size;
109 struct ly_tpdf *tpdf;
Radek Krejcib4cf2022015-06-03 14:40:05 +0200110 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200111
112 assert(id);
113
114 /* check id syntax */
115 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
116 LOGVAL(VE_INID, line, id, "invalid start character");
117 return EXIT_FAILURE;
118 }
119 for (i = 1; id[i]; i++) {
120 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
121 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
Radek Krejcid47904a2015-06-03 11:33:06 +0200122 LOGVAL(VE_INID, line, id, "invalid character");
Radek Krejcice7fb782015-05-29 16:52:34 +0200123 return EXIT_FAILURE;
124 }
125 }
126
127 if (i > 64) {
128 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
129 }
130
131 switch(type) {
Radek Krejcib4cf2022015-06-03 14:40:05 +0200132 case LY_IDENT_NAME:
133 /* check uniqueness of the node within its siblings */
134 if (!parent) {
135 break;
136 }
137
138 LY_TREE_FOR(parent->child, mnode) {
139 if (mnode->name == id) {
140 LOGVAL(VE_INID, line, id, "name duplication");
141 return EXIT_FAILURE;
142 }
143 }
144 break;
Radek Krejcieac35532015-05-31 19:09:15 +0200145 case LY_IDENT_TYPE:
146 assert(module);
147
148 /* check collision with the built-in types */
149 if (!strcmp(id, "binary") || !strcmp(id,"bits") ||
150 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
151 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
152 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
153 !strcmp(id, "int8") || !strcmp(id, "int16") ||
154 !strcmp(id, "int32") || !strcmp(id, "int64") ||
155 !strcmp(id, "leafref") || !strcmp(id, "string") ||
156 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
157 !strcmp(id, "uint32") || !strcmp(id, "uint64") ||
158 !strcmp(id, "union")) {
159 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
160 return EXIT_FAILURE;
161 }
162
163 /* check locally scoped typedefs (avoid name shadowing) */
164 for ( ; parent; parent = parent->parent) {
165 switch(parent->nodetype) {
166 case LY_NODE_CONTAINER:
167 size = ((struct ly_mnode_container *)parent)->tpdf_size;
168 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
169 break;
170 case LY_NODE_LIST:
171 size = ((struct ly_mnode_list *)parent)->tpdf_size;
172 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
173 break;
174 case LY_NODE_GROUPING:
175 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
176 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
177 break;
178 default:
179 continue;
180 }
181
182 if (dup_typedef_check(id, tpdf, size)) {
183 LOGVAL(VE_DUPID, line, "typedef", id);
184 return EXIT_FAILURE;
185 }
186 }
187
188 /* check top-level names */
189 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
190 LOGVAL(VE_DUPID, line, "typedef", id);
191 return EXIT_FAILURE;
192 }
193
194 /* check submodule's top-level names */
195 for (i = 0; i < module->inc_size; i++) {
196 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
197 LOGVAL(VE_DUPID, line, "typedef", id);
198 return EXIT_FAILURE;
199 }
200 }
201
202 /* check top-level names in the main module */
203 if (module->type) {
204 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
205 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
206 LOGVAL(VE_DUPID, line, "typedef", id);
207 return EXIT_FAILURE;
208 }
209 }
210
211 break;
Radek Krejcice7fb782015-05-29 16:52:34 +0200212 case LY_IDENT_PREFIX:
Radek Krejcieac35532015-05-31 19:09:15 +0200213 assert(module);
214
Radek Krejcice7fb782015-05-29 16:52:34 +0200215 if (module->type) {
216 /* go to the main module */
217 module = ((struct ly_submodule *)module)->belongsto;
218 }
219
220 /* check the main module itself */
221 if (dup_prefix_check(id, module)) {
222 LOGVAL(VE_DUPID, line, "prefix", id);
223 return EXIT_FAILURE;
224 }
225
226 /* and all its submodules */
227 for (i = 0; i < module->inc_size; i++) {
228 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
229 LOGVAL(VE_DUPID, line, "prefix", id);
230 return EXIT_FAILURE;
231 }
232 }
233 break;
234 default:
235 /* no check required */
236 break;
237 }
238
239 return EXIT_SUCCESS;
240}
241
Radek Krejci345ad742015-06-03 11:04:18 +0200242static int check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line, const char *name, int len)
243{
244 char *dup = NULL;
245 int j;
246
247 /* existence */
248 if (!key) {
249 if (name[len] != '\0') {
250 dup = strdup(name);
251 dup[len] = '\0';
252 name = dup;
253 }
254 LOGVAL(VE_KEY_MISS, line, name);
255 free(dup);
256 return EXIT_FAILURE;
257 }
258
259 /* uniqueness */
260 for (j = index - 1; j >= 0; j--) {
261 if (list[index] == list[j]) {
262 LOGVAL(VE_KEY_DUP, line, key->name);
263 return EXIT_FAILURE;
264 }
265 }
266
267 /* key is a leaf */
268 if (key->nodetype != LY_NODE_LEAF) {
269 LOGVAL(VE_KEY_NLEAF, line, key->name);
270 return EXIT_FAILURE;
271 }
272
273 /* type of the leaf is not built-in empty */
274 if (key->type.base == LY_TYPE_EMPTY) {
275 LOGVAL(VE_KEY_TYPE, line, key->name);
276 return EXIT_FAILURE;
277 }
278
279 /* config attribute is the same as of the list */
280 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
281 LOGVAL(VE_KEY_CONFIG, line, key->name);
282 return EXIT_FAILURE;
283 }
284
285 return EXIT_SUCCESS;
286}
287
Radek Krejci4c31f122015-06-02 14:51:22 +0200288static int check_default(struct ly_type *type, const char* value)
Radek Krejcieac35532015-05-31 19:09:15 +0200289{
290 /* TODO - RFC 6020, sec. 7.3.4 */
Radek Krejci4c31f122015-06-02 14:51:22 +0200291 (void)type;
292 (void)value;
Radek Krejcieac35532015-05-31 19:09:15 +0200293 return EXIT_SUCCESS;
294}
295
Radek Krejcice7fb782015-05-29 16:52:34 +0200296static int check_date(const char* date, unsigned int line)
297{
298 int i;
299
300 assert(date);
301
302 if (strlen(date) != LY_REV_SIZE - 1) {
303 goto error;
304 }
305
306 for (i = 0; i < LY_REV_SIZE - 1; i++) {
307 if (i == 4 || i == 7) {
308 if (date[i] != '-') {
309 goto error;
310 }
311 } else if (!isdigit(date[i])) {
312 goto error;
313 }
314 }
315
316 return EXIT_SUCCESS;
317
318error:
319
320 LOGVAL(VE_INDATE, line, date);
321 return EXIT_FAILURE;
322}
323
Radek Krejcib8329282015-06-04 11:04:08 +0200324static const char *read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200325{
326 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200327
328 /* there should be <text> child */
329 if (!node->child || !node->child->name
Radek Krejcib8329282015-06-04 11:04:08 +0200330 || strcmp(node->child->name, name)) {
331 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200332 } else if (node->child->content) {
333 len = strlen(node->child->content);
334 return lydict_insert(ctx, node->child->content, len);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200335 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200336
Radek Krejcib8329282015-06-04 11:04:08 +0200337 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200338 return NULL;
339}
340
341static struct ly_tpdf *find_superior_type(const char *name,
342 struct ly_module *module,
343 struct ly_mnode *parent)
344{
Radek Krejciefaeba32015-05-27 14:30:57 +0200345 int i, j, found = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200346 int prefix_len = 0;
347 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +0200348 struct ly_tpdf *tpdf;
349 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200350
351 qname = strchr(name, ':');
352
353 if (!qname) {
354 /* no prefix, try built-in types */
355 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
356 if (!strcmp(ly_types[i].def->name, name)) {
357 return ly_types[i].def;
358 }
359 }
360 qname = name;
361 } else {
362 /* set qname to correct position after colon */
363 prefix_len = qname - name;
364 qname++;
365
366 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
367 /* prefix refers to the current module, ignore it */
368 prefix_len = 0;
369 }
370 }
371
372 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200373 /* search in local typedefs */
374 while (parent) {
375 switch (parent->nodetype) {
376 case LY_NODE_CONTAINER:
377 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
378 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
379 break;
380 case LY_NODE_LIST:
381 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
382 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
383 break;
384 case LY_NODE_GROUPING:
385 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
386 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
387 break;
388 default:
389 parent = parent->parent;
390 continue;
391 }
392
393 for (i = 0; i < tpdf_size; i++) {
394 if (!strcmp(tpdf[i].name, qname)) {
395 return &tpdf[i];
396 }
397 }
398
399 parent = parent->parent;
400 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200401 } else if (prefix_len) {
402 /* get module where to search */
403 for (i = 0; i < module->imp_size; i++) {
404 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
405 module = module->imp[i].module;
406 found = 1;
407 break;
408 }
409 }
410 if (!found) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200411 return NULL;
412 }
413 }
414
415 /* search in top level typedefs */
416 for (i = 0; i < module->tpdf_size; i++) {
417 if (!strcmp(module->tpdf[i].name, qname)) {
418 return &module->tpdf[i];
419 }
420 }
421
Radek Krejciefaeba32015-05-27 14:30:57 +0200422 /* search in submodules */
423 for (i = 0; i < module->inc_size; i++) {
424 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
425 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
426 return &module->inc[i].submodule->tpdf[j];
427 }
428 }
429 }
430
431 return NULL;
432}
433
434static struct ly_ident *find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
435{
Radek Krejcice7fb782015-05-29 16:52:34 +0200436 unsigned int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200437 struct ly_ident *base_iter;
438 struct ly_ident_der *der;
439
440 for (i = 0; i < module->ident_size; i++) {
441 if (!strcmp(basename, module->ident[i].name)) {
442 /* we are done */
443
444 if (!ident) {
445 /* just search for type, so do not modify anything, just return
446 * the base identity pointer
447 */
448 return &module->ident[i];
449 }
450
451 /* we are resolving identity definition, so now update structures */
452 ident->base = base_iter = &module->ident[i];
453
454 while (base_iter) {
455 for (der = base_iter->der; der && der->next; der = der->next);
456 if (der) {
457 der->next = malloc(sizeof *der);
458 der = der->next;
459 } else {
460 ident->base->der = der = malloc(sizeof *der);
461 }
462 der->next = NULL;
463 der->ident = ident;
464
465 base_iter = base_iter->base;
466 }
467 return ident->base;
468 }
469 }
470
Radek Krejcida04f4a2015-05-21 12:54:09 +0200471 return NULL;
472}
473
Radek Krejci3045cf32015-05-28 10:58:52 +0200474static struct ly_ident *find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200475{
476 const char *name;
477 int prefix_len = 0;
478 int i, found = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200479 struct ly_ident *result;
Radek Krejci3045cf32015-05-28 10:58:52 +0200480 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200481
Radek Krejci3045cf32015-05-28 10:58:52 +0200482 basename = lyxml_get_attr(node, "name", NULL);
Radek Krejci04581c62015-05-22 21:24:00 +0200483 if (!basename) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200484 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
Radek Krejci04581c62015-05-22 21:24:00 +0200485 return NULL;
486 }
487
488 /* search for the base identity */
489 name = strchr(basename, ':');
490 if (name) {
491 /* set name to correct position after colon */
492 prefix_len = name - basename;
493 name++;
494
495 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
496 /* prefix refers to the current module, ignore it */
497 prefix_len = 0;
498 }
499 } else {
500 name = basename;
501 }
502
503 if (prefix_len) {
504 /* get module where to search */
505 for (i = 0; i < module->imp_size; i++) {
506 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
507 && !module->imp[i].prefix[prefix_len]) {
508 module = module->imp[i].module;
509 found = 1;
510 break;
511 }
512 }
513 if (!found) {
514 /* identity refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +0200515 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
Radek Krejci04581c62015-05-22 21:24:00 +0200516 return NULL;
517 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200518 } else {
519 /* search in submodules */
520 for (i = 0; i < module->inc_size; i++) {
521 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
522 if (result) {
523 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200524 }
Radek Krejci04581c62015-05-22 21:24:00 +0200525 }
526 }
527
Radek Krejciefaeba32015-05-27 14:30:57 +0200528 /* search in the identified module */
529 result = find_base_ident_sub(module, ident, name);
530 if (!result) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200531 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
Radek Krejciefaeba32015-05-27 14:30:57 +0200532 }
533
534 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200535}
536
537static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
538{
539 struct lyxml_elem *node, *next;
540
Radek Krejcib388c152015-06-04 17:03:03 +0200541 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
Radek Krejci04581c62015-05-22 21:24:00 +0200542 return EXIT_FAILURE;
543 }
Radek Krejci04581c62015-05-22 21:24:00 +0200544
545 LY_TREE_FOR_SAFE(yin->child, next, node) {
546 if (!strcmp(node->name, "base")) {
547 if (ident->base) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200548 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200549 return EXIT_FAILURE;
550 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200551 if (!find_base_ident(module, ident, node)) {
Radek Krejci04581c62015-05-22 21:24:00 +0200552 return EXIT_FAILURE;
553 }
554 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200555 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200556 return EXIT_FAILURE;
557 }
558
559 lyxml_free_elem(module->ctx, node);
560 }
561
562 return EXIT_SUCCESS;
563}
564
Radek Krejcida04f4a2015-05-21 12:54:09 +0200565static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
566 struct lyxml_elem *yin, struct ly_type *type)
567{
Radek Krejci25d782a2015-05-22 15:03:23 +0200568 const char *value, *delim;
569 struct lyxml_elem *next, *node, root = {0};
570 int i, j, r;
571 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200572
Radek Krejci800af702015-06-02 13:46:01 +0200573 GETVAL(value, yin, "name")
Radek Krejci25d782a2015-05-22 15:03:23 +0200574 delim = strchr(value, ':');
575 if (delim) {
576 type->prefix = lydict_insert(module->ctx, value, delim - value);
577 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200578
Radek Krejcida04f4a2015-05-21 12:54:09 +0200579 type->der = find_superior_type(value, module, parent);
Radek Krejci3045cf32015-05-28 10:58:52 +0200580 if (!type->der) {
581 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +0200582 goto error;
Radek Krejci3045cf32015-05-28 10:58:52 +0200583 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200584 type->base = type->der->type.base;
585
586 switch (type->base) {
587 case LY_TYPE_BINARY:
Radek Krejci800af702015-06-02 13:46:01 +0200588 /* TODO length, 9.4.4
Radek Krejci04581c62015-05-22 21:24:00 +0200589 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
590 * hodnoty se musi vejit do 64b, podelementy
Radek Krejci25d782a2015-05-22 15:03:23 +0200591 */
592 break;
593 case LY_TYPE_BITS:
Radek Krejci800af702015-06-02 13:46:01 +0200594 /* TODO bit, 9.7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200595 * 1..n, nerekurzivni, stringy s podelementy */
596 break;
597 case LY_TYPE_DEC64:
Radek Krejci800af702015-06-02 13:46:01 +0200598 /* TODO fraction-digits, 9.3.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200599 * - MUST, 1, nerekurzivni, hodnota 1-18 */
Radek Krejci800af702015-06-02 13:46:01 +0200600 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200601 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
602 break;
603 case LY_TYPE_ENUM:
Radek Krejci6793db02015-05-22 17:49:54 +0200604 /* RFC 6020 9.6 */
Radek Krejci04581c62015-05-22 21:24:00 +0200605
Radek Krejci25d782a2015-05-22 15:03:23 +0200606 /* get enum specification, at least one must be present */
607 LY_TREE_FOR_SAFE(yin->child, next, node) {
608 if (!strcmp(node->name, "enum")) {
609 lyxml_unlink_elem(node);
610 lyxml_add_child(&root, node);
611 type->info.enums.count++;
612 }
613 }
614 if (yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200615 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200616 goto error;
617 }
618 if (!type->info.enums.count) {
619 if (type->der->type.der) {
620 /* this is just a derived type with no enum specified */
621 break;
622 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200623 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
Radek Krejci25d782a2015-05-22 15:03:23 +0200624 goto error;
625 }
626
627 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
628 for (i = v = 0; root.child; i++) {
Radek Krejcib388c152015-06-04 17:03:03 +0200629 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, OPT_IDENT);
Radek Krejci25d782a2015-05-22 15:03:23 +0200630 if (r) {
631 type->info.enums.count = i + 1;
632 goto error;
633 }
634 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
635 value = type->info.enums.list[i].name;
636 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200637 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
Radek Krejci25d782a2015-05-22 15:03:23 +0200638 type->info.enums.count = i + 1;
639 goto error;
640 }
641
642 /* check the name uniqueness */
643 for (j = 0; j < i; j++) {
644 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200645 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200646 type->info.enums.count = i + 1;
647 goto error;
648 }
649 }
650
651 node = root.child->child;
652 if (node && !strcmp(node->name, "value")) {
653 value = lyxml_get_attr(node, "value", NULL);
654 v_ = strtol(value, NULL, 10);
655
656 /* range check */
657 if (v_ < INT32_MIN || v_ > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200658 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200659 type->info.enums.count = i + 1;
660 goto error;
661 }
662 type->info.enums.list[i].value = v_;
663
664 /* keep the highest enum value for automatic increment */
665 if (type->info.enums.list[i].value > v) {
666 v = type->info.enums.list[i].value;
667 v++;
668 } else {
669 /* check that the value is unique */
670 for (j = 0; j < i; j++) {
671 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200672 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value, type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200673 type->info.enums.count = i + 1;
674 goto error;
675 }
676 }
677 }
678 } else {
679 /* assign value automatically */
680 if (v > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200681 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200682 type->info.enums.count = i + 1;
683 goto error;
684 }
685 type->info.enums.list[i].value = v;
686 v++;
687 }
688 lyxml_free_elem(module->ctx, root.child);
689 }
690 break;
691 case LY_TYPE_IDENT:
Radek Krejci04581c62015-05-22 21:24:00 +0200692 /* RFC 6020 9.10 */
693
694 /* get base specification, exactly one must be present */
695 if (!yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200696 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
Radek Krejci04581c62015-05-22 21:24:00 +0200697 goto error;
698 }
699 if (strcmp(yin->child->name, "base")) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200700 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200701 goto error;
702 }
703 if (yin->child->next) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200704 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200705 goto error;
706 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200707 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
Radek Krejci04581c62015-05-22 21:24:00 +0200708 if (!type->info.ident.ref) {
709 return EXIT_FAILURE;
710 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200711 break;
712 case LY_TYPE_INST:
Radek Krejci800af702015-06-02 13:46:01 +0200713 /* TODO require-instance, 9.13.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200714 * - 0..1, true/false */
715 break;
716 case LY_TYPE_INT8:
717 case LY_TYPE_INT16:
718 case LY_TYPE_INT32:
719 case LY_TYPE_INT64:
720 case LY_TYPE_UINT8:
721 case LY_TYPE_UINT16:
722 case LY_TYPE_UINT32:
723 case LY_TYPE_UINT64:
Radek Krejci800af702015-06-02 13:46:01 +0200724 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200725 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
726 break;
727 case LY_TYPE_LEAFREF:
Radek Krejci800af702015-06-02 13:46:01 +0200728 /* TODO path, 9.9.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200729 * - 1, nerekurzivni, string */
730 break;
731 case LY_TYPE_STRING:
Radek Krejci800af702015-06-02 13:46:01 +0200732 /* TODO length, 9.4.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200733 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
734 * pattern, 9.4.6
735 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
736 break;
737 case LY_TYPE_UNION:
Radek Krejci800af702015-06-02 13:46:01 +0200738 /* TODO type, 7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200739 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
740 break;
741 default:
742 /* nothing needed :
743 * LY_TYPE_BOOL, LY_TYPE_EMPTY
744 */
745 break;
746 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200747
748 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200749
750error:
751
752 while(root.child) {
753 lyxml_free_elem(module->ctx, root.child);
754 }
755
756 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200757}
758
759static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
760 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
761{
762 const char *value;
763 struct lyxml_elem *node, *next;
Radek Krejci76c45d32015-05-26 16:01:14 +0200764 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200765
Radek Krejcieac35532015-05-31 19:09:15 +0200766 GETVAL(value, yin, "name");
767 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
768 goto error;
769 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200770 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
771
Radek Krejcieac35532015-05-31 19:09:15 +0200772 /* generic part - status, description, reference */
Radek Krejcib388c152015-06-04 17:03:03 +0200773 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200774 goto error;
775 }
776
Radek Krejcida04f4a2015-05-21 12:54:09 +0200777 LY_TREE_FOR_SAFE(yin->child, next, node) {
778 if (!strcmp(node->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200779 if (tpdf->type.der) {
780 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
781 goto error;
782 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200783 r = fill_yin_type(module, parent, node, &tpdf->type);
Radek Krejcieac35532015-05-31 19:09:15 +0200784 } else if (!strcmp(node->name, "default")) {
785 if (tpdf->dflt) {
786 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
787 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200788 }
Radek Krejcieac35532015-05-31 19:09:15 +0200789 GETVAL(value, node, "value");
790 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
791 } else if (!strcmp(node->name, "units")) {
792 if (tpdf->units) {
793 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
794 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200795 }
Radek Krejcieac35532015-05-31 19:09:15 +0200796 GETVAL(value, node, "name");
797 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
798 } else {
799 LOGVAL(VE_INSTMT, LOGLINE(node), value);
800 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200801 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200802 lyxml_free_elem(module->ctx, node);
803 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +0200804 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200805 }
806 }
807
Radek Krejcieac35532015-05-31 19:09:15 +0200808 /* check mandatory value */
Radek Krejci25d782a2015-05-22 15:03:23 +0200809 if (!tpdf->type.der) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200810 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
Radek Krejcieac35532015-05-31 19:09:15 +0200811 goto error;
812 }
813
Radek Krejci4c31f122015-06-02 14:51:22 +0200814 /* check default value */
815 if (check_default(&tpdf->type, tpdf->dflt)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200816 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200817 }
818
819 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200820
821error:
822
823 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200824}
825
Radek Krejci800af702015-06-02 13:46:01 +0200826static int fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
827{
Radek Krejci8bf99362015-06-03 16:43:21 +0200828 struct lyxml_elem *child, *next;
Radek Krejci800af702015-06-02 13:46:01 +0200829 const char *value;
830
831 GETVAL(value, yin, "condition");
832 must->cond = lydict_insert(module->ctx, value, strlen(value));
833
Radek Krejci8bf99362015-06-03 16:43:21 +0200834 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci800af702015-06-02 13:46:01 +0200835 if (!strcmp(child->name, "description")) {
836 if (must->dsc) {
837 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
838 goto error;
839 }
Radek Krejcib8329282015-06-04 11:04:08 +0200840 must->dsc = read_yin_subnode(module->ctx, child, "text");
Radek Krejci800af702015-06-02 13:46:01 +0200841 if (!must->dsc) {
842 goto error;
843 }
844 } else if (!strcmp(child->name, "reference")) {
845 if (must->ref) {
846 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
847 goto error;
848 }
Radek Krejcib8329282015-06-04 11:04:08 +0200849 must->ref = read_yin_subnode(module->ctx, child, "text");
Radek Krejci800af702015-06-02 13:46:01 +0200850 if (!must->ref) {
851 goto error;
852 }
853 } else if (!strcmp(child->name, "error-app-tag")) {
854 if (must->eapptag) {
855 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
856 goto error;
857 }
Radek Krejcib8329282015-06-04 11:04:08 +0200858 must->eapptag = read_yin_subnode(module->ctx, child, "value");
Radek Krejci800af702015-06-02 13:46:01 +0200859 if (!must->eapptag) {
860 goto error;
861 }
862 } else if (!strcmp(child->name, "error-message")) {
863 if (must->emsg) {
864 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
865 goto error;
866 }
Radek Krejcib8329282015-06-04 11:04:08 +0200867 must->emsg = read_yin_subnode(module->ctx, child, "value");
Radek Krejci800af702015-06-02 13:46:01 +0200868 if (!must->emsg) {
869 goto error;
870 }
871 } else {
872 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
873 goto error;
874 }
875
876 lyxml_free_elem(module->ctx, child);
877 }
878
879
880 return EXIT_SUCCESS;
881
882error:
883
884 return EXIT_FAILURE;
885}
886
Radek Krejciefaeba32015-05-27 14:30:57 +0200887static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
888{
889 struct lyxml_elem *child;
890 const char *value;
891
892 LY_TREE_FOR(yin->child, child) {
893 if (!strcmp(child->name, "prefix")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200894 GETVAL(value, child, "value");
Radek Krejci0af13872015-05-30 11:50:52 +0200895 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
896 goto error;
897 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200898 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
899 } else if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200900 if (imp->rev[0]) {
901 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
902 goto error;
903 }
904 GETVAL(value, child, "date");
905 if (check_date(value, LOGLINE(child))) {
906 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200907 }
908 memcpy(imp->rev, value, LY_REV_SIZE - 1);
909 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200910 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200911 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200912 }
913 }
914
Radek Krejcice7fb782015-05-29 16:52:34 +0200915 /* check mandatory information */
916 if (!imp->prefix) {
917 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
918 goto error;
919 }
920
921 GETVAL(value, yin, "module");
Radek Krejci0af13872015-05-30 11:50:52 +0200922 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
Radek Krejciefaeba32015-05-27 14:30:57 +0200923 if (!imp->module) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200924 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200925 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200926 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
927 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200928 }
929
930 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200931
932error:
933
934 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200935}
936
937static int fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
938{
939 struct lyxml_elem *child;
940 const char *value;
941
942 LY_TREE_FOR(yin->child, child) {
943 if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200944 if (inc->rev[0]) {
945 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
946 goto error;
947 }
948 GETVAL(value, child, "date");
949 if (check_date(value, LOGLINE(child))) {
950 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200951 }
952 memcpy(inc->rev, value, LY_REV_SIZE - 1);
953 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200954 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200955 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200956 }
957 }
958
Radek Krejcice7fb782015-05-29 16:52:34 +0200959 GETVAL(value, yin, "module");
Radek Krejciefaeba32015-05-27 14:30:57 +0200960 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
961 if (!inc->submodule) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200962 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200963 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200964 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
965 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200966 }
967
Radek Krejcice7fb782015-05-29 16:52:34 +0200968 /* check that belongs-to corresponds */
969 if (module->type) {
970 module = ((struct ly_submodule *)module)->belongsto;
971 }
972 if (inc->submodule->belongsto != module) {
973 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
974 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
975 goto error;
976 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200977
978 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200979
980error:
981
982 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200983}
984
985
Radek Krejcida04f4a2015-05-21 12:54:09 +0200986/*
987 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200988 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +0200989 *
990 * ext: 0 - no config
991 * 1 - parse config, but not inherit it
992 * 2 - parse config and if not present, inherit it from parent
Radek Krejcida04f4a2015-05-21 12:54:09 +0200993 */
994static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejcib388c152015-06-04 17:03:03 +0200995 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200996{
997 const char *value;
998 struct lyxml_elem *sub, *next;
999 struct ly_ctx * const ctx = module->ctx;
Radek Krejcice7fb782015-05-29 16:52:34 +02001000 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001001
Radek Krejcib388c152015-06-04 17:03:03 +02001002 if (opt & OPT_MODULE) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001003 mnode->module = module;
1004 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001005
Radek Krejci800af702015-06-02 13:46:01 +02001006 GETVAL(value, xmlnode, "name");
Radek Krejcib388c152015-06-04 17:03:03 +02001007 if ((opt & OPT_IDENT) && check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
Radek Krejcieac35532015-05-31 19:09:15 +02001008 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +02001009 }
Radek Krejci800af702015-06-02 13:46:01 +02001010 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001011
1012 /* process local parameters */
1013 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1014 if (!strcmp(sub->name, "description")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001015 if (mnode->dsc) {
1016 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1017 goto error;
1018 }
Radek Krejcib8329282015-06-04 11:04:08 +02001019 mnode->dsc = read_yin_subnode(ctx, sub, "text");
Radek Krejcice7fb782015-05-29 16:52:34 +02001020 if (!mnode->dsc) {
1021 r = 1;
1022 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001023 } else if (!strcmp(sub->name, "reference")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001024 if (mnode->ref) {
1025 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1026 goto error;
1027 }
Radek Krejcib8329282015-06-04 11:04:08 +02001028 mnode->ref = read_yin_subnode(ctx, sub, "text");
Radek Krejcice7fb782015-05-29 16:52:34 +02001029 if (!mnode->ref) {
1030 r = 1;
1031 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001032 } else if (!strcmp(sub->name, "status")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001033 if (mnode->flags & LY_NODE_STATUS_MASK) {
1034 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1035 goto error;
1036 }
1037 GETVAL(value, sub, "value");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001038 if (!strcmp(value, "current")) {
1039 mnode->flags |= LY_NODE_STATUS_CURR;
1040 } else if (!strcmp(value, "deprecated")) {
1041 mnode->flags |= LY_NODE_STATUS_DEPRC;
1042 } else if (!strcmp(value, "obsolete")) {
1043 mnode->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejcice7fb782015-05-29 16:52:34 +02001044 } else {
1045 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1046 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001047 }
Radek Krejcib388c152015-06-04 17:03:03 +02001048 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001049 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1050 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1051 goto error;
1052 }
1053 GETVAL(value, sub, "value");
Radek Krejci25d782a2015-05-22 15:03:23 +02001054 if (!strcmp(value, "false")) {
1055 mnode->flags |= LY_NODE_CONFIG_R;
1056 } else if (!strcmp(value, "false")) {
1057 mnode->flags |= LY_NODE_CONFIG_W;
Radek Krejcice7fb782015-05-29 16:52:34 +02001058 } else {
1059 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1060 r = 1;
Radek Krejci25d782a2015-05-22 15:03:23 +02001061 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001062 } else {
1063 /* skip the lyxml_free_elem */
1064 continue;
1065 }
1066 lyxml_free_elem(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +02001067 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +02001068 goto error;
Radek Krejcice7fb782015-05-29 16:52:34 +02001069 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001070 }
1071
Radek Krejcib388c152015-06-04 17:03:03 +02001072 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001073 /* get config flag from parent */
1074 if (parent) {
1075 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1076 } else {
1077 /* default config is true */
1078 mnode->flags |= LY_NODE_CONFIG_W;
1079 }
1080 }
1081
1082 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001083
1084error:
1085
1086 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001087}
1088
Radek Krejcib4cf2022015-06-03 14:40:05 +02001089/* additional check in case statement - the child must be unique across
1090 * all other case names and its data children
1091 */
1092static int check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
1093{
1094 struct ly_mnode *mnode, *submnode;
1095
1096 if (new->nodetype == LY_NODE_CHOICE) {
1097 /* we have nested choice in case, so we need recursion */
1098 LY_TREE_FOR(new->child, mnode) {
1099 if (mnode->nodetype == LY_NODE_CASE) {
1100 LY_TREE_FOR(mnode->child, submnode) {
1101 if (check_branch_id(parent, submnode, new, line)) {
1102 return EXIT_FAILURE;
1103 }
1104 }
1105 } else if (check_branch_id(parent, mnode, new, line)) {
1106 return EXIT_FAILURE;
1107 }
1108 }
1109 } else {
1110 LY_TREE_FOR(parent->child, mnode) {
1111 if (mnode == excl) {
1112 continue;
1113 }
1114
1115 if (!strcmp(new->name, mnode->name)) {
1116 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1117 return EXIT_FAILURE;
1118 }
1119 if (mnode->nodetype == LY_NODE_CASE) {
1120 LY_TREE_FOR(mnode->child, submnode) {
1121 if (!strcmp(new->name, submnode->name)) {
1122 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1123 return EXIT_FAILURE;
1124 }
1125 }
1126 }
1127 }
1128 }
1129
1130 return EXIT_SUCCESS;
1131}
1132
1133static struct ly_mnode *read_yin_case(struct ly_module *module,
1134 struct ly_mnode *parent,
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001135 struct lyxml_elem *yin,
1136 int resolve)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001137{
1138 struct lyxml_elem *sub, *next;
1139 struct ly_mnode_case *mcase;
Radek Krejci5c7bff42015-06-03 16:25:23 +02001140 struct ly_mnode *retval, *mnode = NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001141
1142 mcase = calloc(1, sizeof *mcase);
1143 mcase->nodetype = LY_NODE_CASE;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001144 mcase->prev = (struct ly_mnode *)mcase;
1145 retval = (struct ly_mnode *)mcase;
1146
Radek Krejcib388c152015-06-04 17:03:03 +02001147 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001148 goto error;
1149 }
1150
1151 /* process choice's specific children */
1152 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1153 if (!strcmp(sub->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001154 mnode = read_yin_container(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001155 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001156 mnode = read_yin_leaflist(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001157 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001158 mnode = read_yin_leaf(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001159 } else if (!strcmp(sub->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001160 mnode = read_yin_list(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001161 } else if (!strcmp(sub->name, "uses")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001162 mnode = read_yin_uses(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001163 } else if (!strcmp(sub->name, "choice")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001164 mnode = read_yin_choice(module, retval, sub, resolve);
Radek Krejci863c2852015-06-03 15:47:11 +02001165 } else if (!strcmp(sub->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001166 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001167#if 0
1168 } else {
1169 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1170 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001171#else
1172 } else {
1173 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001174#endif
1175 }
1176
1177 if (!mnode) {
1178 goto error;
1179 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
1180 goto error;
1181 }
1182
1183 mnode = NULL;
1184 lyxml_free_elem(module->ctx, sub);
1185 }
1186
Radek Krejcib388c152015-06-04 17:03:03 +02001187 /* inherit config flag */
1188 if (parent) {
1189 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1190 } else {
1191 /* default config is true */
1192 retval->flags |= LY_NODE_CONFIG_W;
1193 }
1194
Radek Krejcib4cf2022015-06-03 14:40:05 +02001195 /* insert the node into the schema tree */
1196 ly_mnode_addchild(parent, retval);
1197 return retval;
1198
1199error:
1200
1201 ly_mnode_free(retval);
1202
1203 return NULL;
1204}
1205
Radek Krejcida04f4a2015-05-21 12:54:09 +02001206static struct ly_mnode *read_yin_choice(struct ly_module *module,
1207 struct ly_mnode *parent,
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001208 struct lyxml_elem *yin,
1209 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001210{
1211 struct lyxml_elem *sub, *next;
1212 struct ly_ctx * const ctx = module->ctx;
Radek Krejci5dea2d52015-06-03 15:45:23 +02001213 struct ly_mnode *retval, *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001214 struct ly_mnode_choice *choice;
Radek Krejcia26eb0c2015-06-03 16:22:52 +02001215 const char *value;
1216 char *dflt_str = NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001217 int f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001218
Radek Krejcida04f4a2015-05-21 12:54:09 +02001219 choice = calloc(1, sizeof *choice);
1220 choice->nodetype = LY_NODE_CHOICE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001221 choice->prev = (struct ly_mnode *)choice;
1222 retval = (struct ly_mnode *)choice;
1223
Radek Krejcib388c152015-06-04 17:03:03 +02001224 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001225 goto error;
1226 }
1227
1228 /* process choice's specific children */
Radek Krejcib4cf2022015-06-03 14:40:05 +02001229 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001230 if (!strcmp(sub->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001231 if (!(mnode = read_yin_container(module, retval, sub, resolve))) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001232 goto error;
1233 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001234 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001235 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001236 goto error;
1237 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001238 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001239 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001240 goto error;
1241 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001242 } else if (!strcmp(sub->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001243 if (!(mnode = read_yin_list(module, retval, sub, resolve))) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001244 goto error;
1245 }
1246 } else if (!strcmp(sub->name, "case")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001247 if (!(mnode = read_yin_case(module, retval, sub, resolve))) {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001248 goto error;
1249 }
Radek Krejci863c2852015-06-03 15:47:11 +02001250 } else if (!strcmp(sub->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001251 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
Radek Krejci863c2852015-06-03 15:47:11 +02001252 goto error;
1253 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001254 } else if (!strcmp(sub->name, "default")) {
1255 if (dflt_str) {
1256 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1257 goto error;
1258 }
1259 GETVAL(value, sub, "value");
1260 dflt_str = strdup(value);
1261 } else if (!strcmp(sub->name, "mandatory")) {
1262 if (f_mand) {
1263 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1264 goto error;
1265 }
1266 /* just checking the flags in leaf is not sufficient, we would allow
1267 * multiple mandatory statements with the "false" value
1268 */
1269 f_mand = 1;
1270
1271 GETVAL(value, sub, "value");
1272 if (!strcmp(value, "true")) {
1273 choice->flags |= LY_NODE_MANDATORY;
1274 } else if (strcmp(value, "false")) {
1275 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1276 goto error;
1277 } /* else false is the default value, so we can ignore it */
1278#if 0
Radek Krejci667b97f2015-05-25 15:03:30 +02001279 } else {
Radek Krejcib4cf2022015-06-03 14:40:05 +02001280 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1281 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001282#else
1283 } else {
1284 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001285#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02001286 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001287
1288 if (mnode && check_branch_id(retval, mnode, mnode,LOGLINE(sub))) {
1289 goto error;
1290 }
1291 mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001292 lyxml_free_elem(ctx, sub);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001293 }
1294
1295 /* check - default is prohibited in combination with mandatory */
1296 if (dflt_str && (choice->flags & LY_NODE_MANDATORY)) {
1297 LOGVAL(VE_SPEC, LOGLINE(yin), "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
1298 goto error;
1299 }
1300
1301 /* link default with the case */
1302 if (dflt_str) {
1303 LY_TREE_FOR(choice->child, mnode) {
1304 if (!strcmp(mnode->name, dflt_str)) {
1305 choice->dflt = mnode;
1306 break;
1307 }
1308 }
1309 if (!choice->dflt) {
1310 /* default branch not found */
1311 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
Radek Krejci25d782a2015-05-22 15:03:23 +02001312 goto error;
1313 }
Radek Krejcia26eb0c2015-06-03 16:22:52 +02001314 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001315 }
1316
Radek Krejcib4cf2022015-06-03 14:40:05 +02001317 /* insert the node into the schema tree */
Radek Krejci812b10a2015-05-28 16:48:25 +02001318 if (parent) {
1319 ly_mnode_addchild(parent, retval);
1320 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001321
1322 return retval;
1323
1324error:
1325
1326 ly_mnode_free(retval);
Radek Krejcia26eb0c2015-06-03 16:22:52 +02001327 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001328
1329 return NULL;
1330}
1331
Radek Krejci863c2852015-06-03 15:47:11 +02001332static struct ly_mnode *read_yin_anyxml(struct ly_module *module,
1333 struct ly_mnode *parent,
Radek Krejcib388c152015-06-04 17:03:03 +02001334 struct lyxml_elem *yin,
1335 int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02001336{
1337 struct ly_mnode *retval;
1338 struct ly_mnode_leaf *anyxml;
1339 struct lyxml_elem *sub, *next;
1340 const char *value;
1341 int r;
1342 int f_mand = 0;
1343 int c_must = 0;
1344
1345 anyxml = calloc(1, sizeof *anyxml);
1346 anyxml->nodetype = LY_NODE_ANYXML;
1347 anyxml->prev = (struct ly_mnode *)anyxml;
1348 retval = (struct ly_mnode *)anyxml;
1349
Radek Krejcib388c152015-06-04 17:03:03 +02001350 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci863c2852015-06-03 15:47:11 +02001351 goto error;
1352 }
1353
1354 LY_TREE_FOR_SAFE(yin->child, next, sub)
1355 {
1356 if (!strcmp(sub->name, "mandatory")) {
1357 if (f_mand) {
1358 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1359 goto error;
1360 }
1361 /* just checking the flags in leaf is not sufficient, we would allow
1362 * multiple mandatory statements with the "false" value
1363 */
1364 f_mand = 1;
1365
1366 GETVAL(value, sub, "value");
1367 if (!strcmp(value, "true")) {
1368 anyxml->flags |= LY_NODE_MANDATORY;
1369 } else if (strcmp(value, "false")) {
1370 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1371 goto error;
1372 } /* else false is the default value, so we can ignore it */
1373
1374 lyxml_free_elem(module->ctx, sub);
1375 } else if (!strcmp(sub->name, "must")) {
1376 c_must++;
1377
1378#if 0
1379 } else {
1380 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1381 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001382#else
1383 } else {
1384 continue;
Radek Krejci863c2852015-06-03 15:47:11 +02001385#endif
1386 }
1387 }
1388
1389 /* middle part - process nodes with cardinality of 0..n */
1390 if (c_must) {
1391 anyxml->must = calloc(c_must, sizeof *anyxml->must);
1392 }
1393
1394 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1395 if (!strcmp(sub->name, "must")) {
1396 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
1397 anyxml->must_size++;
1398
1399 if (r) {
1400 goto error;
1401 }
1402 }
1403
1404 lyxml_free_elem(module->ctx, sub);
1405 }
1406
1407 if (parent) {
1408 ly_mnode_addchild(parent, retval);
1409 }
1410
1411 return retval;
1412
1413error:
1414
1415 ly_mnode_free(retval);
1416
1417 return NULL;
1418}
1419
Radek Krejcida04f4a2015-05-21 12:54:09 +02001420static struct ly_mnode *read_yin_leaf(struct ly_module *module,
1421 struct ly_mnode *parent,
Radek Krejcib388c152015-06-04 17:03:03 +02001422 struct lyxml_elem *yin,
1423 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001424{
1425 struct ly_mnode *retval;
1426 struct ly_mnode_leaf *leaf;
1427 struct lyxml_elem *sub, *next;
Radek Krejci4c31f122015-06-02 14:51:22 +02001428 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001429 int r;
Radek Krejci4c31f122015-06-02 14:51:22 +02001430 int c_must = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001431
Radek Krejcida04f4a2015-05-21 12:54:09 +02001432 leaf = calloc(1, sizeof *leaf);
1433 leaf->nodetype = LY_NODE_LEAF;
1434 leaf->prev = (struct ly_mnode *)leaf;
1435 retval = (struct ly_mnode *)leaf;
1436
Radek Krejcib388c152015-06-04 17:03:03 +02001437 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001438 goto error;
1439 }
1440
Radek Krejci4c31f122015-06-02 14:51:22 +02001441 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001442 if (!strcmp(sub->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001443 if (leaf->type.der) {
1444 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1445 goto error;
1446 }
1447 if (fill_yin_type(module, parent, sub, &leaf->type)) {
1448 goto error;
1449 }
1450 } else if (!strcmp(sub->name, "default")) {
1451 if (leaf->dflt) {
1452 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1453 goto error;
1454 }
1455 GETVAL(value, sub, "value");
1456 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
1457 } else if (!strcmp(sub->name, "units")) {
1458 if (leaf->units) {
1459 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1460 goto error;
1461 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001462 GETVAL(value, sub, "name");
Radek Krejci4c31f122015-06-02 14:51:22 +02001463 leaf->units = lydict_insert(module->ctx, value, strlen(value));
1464 } else if (!strcmp(sub->name, "mandatory")) {
1465 if (f_mand) {
1466 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1467 goto error;
1468 }
1469 /* just checking the flags in leaf is not sufficient, we would allow
1470 * multiple mandatory statements with the "false" value
1471 */
1472 f_mand = 1;
1473
1474 GETVAL(value, sub, "value");
1475 if (!strcmp(value, "true")) {
1476 leaf->flags |= LY_NODE_MANDATORY;
1477 } else if (strcmp(value, "false")) {
1478 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1479 goto error;
1480 } /* else false is the default value, so we can ignore it */
1481 } else if (!strcmp(sub->name, "must")) {
1482 c_must++;
1483
1484 /* skip element free at the end of the loop */
1485 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001486#if 0
Radek Krejci4c31f122015-06-02 14:51:22 +02001487 } else {
1488 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1489 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001490#else
1491 } else {
1492 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001493#endif
Radek Krejci4c31f122015-06-02 14:51:22 +02001494 }
1495
1496 lyxml_free_elem(module->ctx, sub);
1497 }
1498
1499 /* check mandatory parameters */
1500 if (!leaf->type.der) {
1501 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1502 goto error;
1503 }
Radek Krejciccdec642015-06-03 10:58:45 +02001504 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001505 goto error;
1506 }
1507
1508 /* middle part - process nodes with cardinality of 0..n */
1509 if (c_must) {
1510 leaf->must = calloc(c_must, sizeof *leaf->must);
1511 }
1512
1513 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1514 if (!strcmp(sub->name, "must")) {
1515 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
1516 leaf->must_size++;
1517
Radek Krejci25d782a2015-05-22 15:03:23 +02001518 if (r) {
1519 goto error;
1520 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001521 }
Radek Krejci4c31f122015-06-02 14:51:22 +02001522
1523 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001524 }
1525
Radek Krejci812b10a2015-05-28 16:48:25 +02001526 if (parent) {
1527 ly_mnode_addchild(parent, retval);
1528 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001529
1530 return retval;
1531
1532error:
1533
1534 ly_mnode_free(retval);
1535
1536 return NULL;
1537}
1538
1539static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
1540 struct ly_mnode *parent,
Radek Krejcib388c152015-06-04 17:03:03 +02001541 struct lyxml_elem *yin,
1542 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001543{
1544 struct ly_mnode *retval;
1545 struct ly_mnode_leaflist *llist;
1546 struct lyxml_elem *sub, *next;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001547 const char *value;
1548 char *endptr;
Radek Krejci17e93f92015-06-03 11:01:55 +02001549 unsigned long val;
Radek Krejci25d782a2015-05-22 15:03:23 +02001550 int r;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001551 int c_must = 0;
Radek Krejci17e93f92015-06-03 11:01:55 +02001552 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001553
Radek Krejcida04f4a2015-05-21 12:54:09 +02001554 llist = calloc(1, sizeof *llist);
1555 llist->nodetype = LY_NODE_LEAFLIST;
1556 llist->prev = (struct ly_mnode *)llist;
1557 retval = (struct ly_mnode *)llist;
1558
Radek Krejcib388c152015-06-04 17:03:03 +02001559 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001560 goto error;
1561 }
1562
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001563 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001564 if (!strcmp(sub->name, "type")) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001565 if (llist->type.der) {
1566 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1567 goto error;
1568 }
1569 if (fill_yin_type(module, parent, sub, &llist->type)) {
1570 goto error;
1571 }
1572 } else if (!strcmp(sub->name, "units")) {
1573 if (llist->units) {
1574 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1575 goto error;
1576 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001577 GETVAL(value, sub, "name");
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001578 llist->units = lydict_insert(module->ctx, value, strlen(value));
1579 } else if (!strcmp(sub->name, "ordered-by")) {
1580 if (f_ordr) {
1581 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1582 goto error;
1583 }
1584 /* just checking the flags in llist is not sufficient, we would
1585 * allow multiple ordered-by statements with the "system" value
1586 */
1587 f_ordr = 1;
1588
1589 if (llist->flags & LY_NODE_CONFIG_R) {
1590 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
1591 * state data
1592 */
1593 lyxml_free_elem(module->ctx, sub);
1594 continue;
1595 }
1596
1597 GETVAL(value, sub, "value");
1598 if (!strcmp(value, "user")) {
1599 llist->flags |= LY_NODE_USERORDERED;
1600 } else if (strcmp(value, "system")) {
1601 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1602 goto error;
1603 } /* else system is the default value, so we can ignore it */
1604 } else if (!strcmp(sub->name, "must")) {
1605 c_must++;
1606
1607 /* skip element free at the end of the loop */
1608 continue;
1609 } else if (!strcmp(sub->name, "min-elements")) {
1610 if (f_min) {
1611 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1612 goto error;
1613 }
1614 f_min = 1;
1615
1616 GETVAL(value, sub, "value");
1617 while(isspace(value[0])) {
1618 value++;
1619 }
1620
1621 /* convert it to uint32_t */
1622 errno = 0;
1623 endptr = NULL;
1624 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001625 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001626 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1627 goto error;
1628 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001629 llist->min = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001630 } else if (!strcmp(sub->name, "max-elements")) {
1631 if (f_max) {
1632 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1633 goto error;
1634 }
1635 f_max = 1;
1636
1637 GETVAL(value, sub, "value");
1638 while(isspace(value[0])) {
1639 value++;
1640 }
1641
1642 /* convert it to uint32_t */
1643 errno = 0;
1644 endptr = NULL;
1645 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001646 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001647 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1648 goto error;
1649 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001650 llist->max = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001651
Radek Krejci1e3f8902015-06-03 11:00:11 +02001652#if 0
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001653 } else {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001654 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1655 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001656#else
1657 } else {
1658 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001659#endif
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001660 }
1661
1662 lyxml_free_elem(module->ctx, sub);
1663 }
1664
1665 /* check constraints */
1666 if (!llist->type.der) {
1667 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1668 goto error;
1669 }
1670 if (llist->max && llist->min > llist->max) {
1671 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
1672 goto error;
1673 }
1674
1675 /* middle part - process nodes with cardinality of 0..n */
1676 if (c_must) {
1677 llist->must = calloc(c_must, sizeof *llist->must);
1678 }
1679
1680 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1681 if (!strcmp(sub->name, "must")) {
1682 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
1683 llist->must_size++;
1684
Radek Krejci25d782a2015-05-22 15:03:23 +02001685 if (r) {
1686 goto error;
1687 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001688 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001689
1690 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001691 }
1692
Radek Krejci812b10a2015-05-28 16:48:25 +02001693 if (parent) {
1694 ly_mnode_addchild(parent, retval);
1695 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001696
1697 return retval;
1698
1699error:
1700
1701 ly_mnode_free(retval);
1702
1703 return NULL;
1704}
1705
1706static struct ly_mnode *read_yin_list(struct ly_module *module,
1707 struct ly_mnode *parent,
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001708 struct lyxml_elem *yin,
1709 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001710{
1711 struct ly_mnode *retval, *mnode;
1712 struct ly_mnode_list *list;
Radek Krejci345ad742015-06-03 11:04:18 +02001713 struct ly_unique *uniq_s;
1714 struct lyxml_elem *sub, *next, root = {0}, uniq = {0};
1715 int i, r;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001716 size_t len;
Radek Krejci345ad742015-06-03 11:04:18 +02001717 int c_tpdf = 0, c_must = 0, c_uniq = 0;
1718 int f_ordr = 0, f_max = 0, f_min = 0;
1719 const char *key_str = NULL, *uniq_str, *value;
1720 char *auxs;
1721 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001722
Radek Krejcida04f4a2015-05-21 12:54:09 +02001723 list = calloc(1, sizeof *list);
1724 list->nodetype = LY_NODE_LIST;
1725 list->prev = (struct ly_mnode *)list;
1726 retval = (struct ly_mnode *)list;
1727
Radek Krejcib388c152015-06-04 17:03:03 +02001728 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001729 goto error;
1730 }
1731
1732 /* process list's specific children */
Radek Krejci345ad742015-06-03 11:04:18 +02001733 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001734 /* data statements */
1735 if (!strcmp(sub->name, "container") ||
1736 !strcmp(sub->name, "leaf-list") ||
1737 !strcmp(sub->name, "leaf") ||
1738 !strcmp(sub->name, "list") ||
1739 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001740 !strcmp(sub->name, "uses") ||
Radek Krejci863c2852015-06-03 15:47:11 +02001741 !strcmp(sub->name, "grouping") ||
1742 !strcmp(sub->name, "anyxml")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001743 lyxml_unlink_elem(sub);
1744 lyxml_add_child(&root, sub);
1745
1746 /* array counters */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001747 } else if (!strcmp(sub->name, "key")) {
1748 /* check cardinality 0..1 */
1749 if (list->keys_size) {
Radek Krejci345ad742015-06-03 11:04:18 +02001750 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001751 goto error;
1752 }
1753
1754 /* count the number of keys */
Radek Krejci345ad742015-06-03 11:04:18 +02001755 GETVAL(value, sub, "value");
1756 key_str = value;
1757 while((value = strpbrk(value, " \t\n"))) {
Radek Krejcid7f0d012015-05-25 15:04:52 +02001758 list->keys_size++;
Radek Krejci345ad742015-06-03 11:04:18 +02001759 while(isspace(*value)) {
1760 value++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001761 }
1762 }
1763 list->keys_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001764 list->keys = calloc(list->keys_size, sizeof *list->keys);
Radek Krejci345ad742015-06-03 11:04:18 +02001765 } else if (!strcmp(sub->name, "unique")) {
1766 c_uniq++;
1767 lyxml_unlink_elem(sub);
1768 lyxml_add_child(&uniq, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001769 } else if (!strcmp(sub->name, "typedef")) {
1770 c_tpdf++;
Radek Krejci345ad742015-06-03 11:04:18 +02001771 } else if (!strcmp(sub->name, "must")) {
1772 c_must++;
1773
1774 /* optional stetments */
1775 } else if (!strcmp(sub->name, "ordered-by")) {
1776 if (f_ordr) {
1777 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1778 goto error;
1779 }
1780 /* just checking the flags in llist is not sufficient, we would
1781 * allow multiple ordered-by statements with the "system" value
1782 */
1783 f_ordr = 1;
1784
1785 if (list->flags & LY_NODE_CONFIG_R) {
1786 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
1787 * state data
1788 */
1789 lyxml_free_elem(module->ctx, sub);
1790 continue;
1791 }
1792
1793 GETVAL(value, sub, "value");
1794 if (!strcmp(value, "user")) {
1795 list->flags |= LY_NODE_USERORDERED;
1796 } else if (strcmp(value, "system")) {
1797 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1798 goto error;
1799 } /* else system is the default value, so we can ignore it */
1800
1801 lyxml_free_elem(module->ctx, sub);
1802 } else if (!strcmp(sub->name, "min-elements")) {
1803 if (f_min) {
1804 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1805 goto error;
1806 }
1807 f_min = 1;
1808
1809 GETVAL(value, sub, "value");
1810 while(isspace(value[0])) {
1811 value++;
1812 }
1813
1814 /* convert it to uint32_t */
1815 errno = 0;
1816 auxs = NULL;
1817 val = strtoul(value, &auxs, 10);
1818 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
1819 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1820 goto error;
1821 }
1822 list->min = (uint32_t)val;
1823 lyxml_free_elem(module->ctx, sub);
1824 } else if (!strcmp(sub->name, "max-elements")) {
1825 if (f_max) {
1826 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1827 goto error;
1828 }
1829 f_max = 1;
1830
1831 GETVAL(value, sub, "value");
1832 while(isspace(value[0])) {
1833 value++;
1834 }
1835
1836 /* convert it to uint32_t */
1837 errno = 0;
1838 auxs = NULL;
1839 val = strtoul(value, &auxs, 10);
1840 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1841 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1842 goto error;
1843 }
1844 list->max = (uint32_t)val;
1845 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001846 }
1847 }
1848
Radek Krejcid7f0d012015-05-25 15:04:52 +02001849 /* check - if list is configuration, key statement is mandatory */
Radek Krejci3a734ed2015-05-26 15:23:18 +02001850 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
Radek Krejci345ad742015-06-03 11:04:18 +02001851 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
1852 goto error;
1853 }
1854 if (list->max && list->min > list->max) {
1855 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001856 goto error;
1857 }
1858
Radek Krejcida04f4a2015-05-21 12:54:09 +02001859 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1860 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001861 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001862 }
Radek Krejci345ad742015-06-03 11:04:18 +02001863 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001864 if (!strcmp(sub->name, "typedef")) {
Radek Krejci345ad742015-06-03 11:04:18 +02001865 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
1866 list->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001867
1868 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001869 goto error;
1870 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001871 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001872 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001873 }
1874
Radek Krejci345ad742015-06-03 11:04:18 +02001875 /* process unique statements */
1876 if (c_uniq) {
1877 list->unique = calloc(c_uniq, sizeof *list->unique);
1878 }
1879 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
1880 /* count the number of unique values */
1881 GETVAL(value, sub, "value");
1882 uniq_str = value;
1883 uniq_s = &list->unique[list->unique_size];
1884 while((value = strpbrk(value, " \t\n"))) {
1885 uniq_s->leafs_size++;
1886 while(isspace(*value)) {
1887 value++;
1888 }
1889 }
1890 uniq_s->leafs_size++;
1891 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1892 list->unique_size++;
1893
1894 /* interconnect unique values with the leafs */
1895 /* TODO - include searching in uses/grouping */
1896 for (i = 0; i < uniq_s->leafs_size; i++) {
1897 if ((value = strpbrk(uniq_str, " \t\n"))) {
1898 len = value - uniq_str;
1899 while(isspace(*value)) {
1900 value++;
1901 }
1902 } else {
1903 len = strlen(uniq_str);
1904 }
1905 LY_TREE_FOR(list->child, mnode) {
1906 if (!strncmp(mnode->name, uniq_str, len) && !mnode->name[len]) {
1907 uniq_s->leafs[i] = (struct ly_mnode_leaf *)mnode;
1908 break;
1909 }
1910 }
1911
1912 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
1913 goto error;
1914 }
1915
1916 /* prepare for next iteration */
1917 while (value && isspace(*value)) {
1918 value++;
1919 }
1920 uniq_str = value;
1921 }
1922 }
1923
Radek Krejcida04f4a2015-05-21 12:54:09 +02001924 /* last part - process data nodes */
1925 LY_TREE_FOR_SAFE(root.child, next, sub) {
1926 if (!strcmp(sub->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001927 mnode = read_yin_container(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001928 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001929 mnode = read_yin_leaflist(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001930 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001931 mnode = read_yin_leaf(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001932 } else if (!strcmp(sub->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001933 mnode = read_yin_list(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001934 } else if (!strcmp(sub->name, "choice")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001935 mnode = read_yin_choice(module, retval, sub, resolve);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001936 } else if (!strcmp(sub->name, "uses")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001937 mnode = read_yin_uses(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001938 } else if (!strcmp(sub->name, "grouping")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001939 mnode = read_yin_grouping(module, retval, sub, resolve);
Radek Krejci863c2852015-06-03 15:47:11 +02001940 } else if (!strcmp(sub->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02001941 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001942 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001943 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001944 continue;
1945 }
1946 lyxml_free_elem(module->ctx, sub);
1947
Radek Krejci25d782a2015-05-22 15:03:23 +02001948 if (!mnode) {
1949 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001950 }
1951 }
1952
Radek Krejci812b10a2015-05-28 16:48:25 +02001953 if (parent) {
1954 ly_mnode_addchild(parent, retval);
1955 }
1956
Radek Krejci3a734ed2015-05-26 15:23:18 +02001957 if (!key_str) {
1958 /* config false list without a key */
1959 return retval;
1960 }
1961
Radek Krejcid7f0d012015-05-25 15:04:52 +02001962 /* link key leafs into the list structure and check all constraints */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001963 for (i = 0; i < list->keys_size; i++) {
1964 /* get the key name */
Radek Krejci345ad742015-06-03 11:04:18 +02001965 if ((value = strpbrk(key_str, " \t\n"))) {
1966 len = value - key_str;
1967 while(isspace(*value)) {
1968 value++;
1969 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001970 } else {
1971 len = strlen(key_str);
1972 }
Radek Krejci8bc9ca02015-06-04 15:52:46 +02001973
1974 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001975
Radek Krejci345ad742015-06-03 11:04:18 +02001976 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
Radek Krejcid7f0d012015-05-25 15:04:52 +02001977 goto error;
1978 }
1979
1980 /* prepare for next iteration */
Radek Krejci345ad742015-06-03 11:04:18 +02001981 while (value && isspace(*value)) {
1982 value++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001983 }
Radek Krejci345ad742015-06-03 11:04:18 +02001984 key_str = value;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001985 }
1986
Radek Krejcida04f4a2015-05-21 12:54:09 +02001987 return retval;
1988
1989error:
1990
1991 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001992 while(root.child) {
1993 lyxml_free_elem(module->ctx, root.child);
1994 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001995
1996 return NULL;
1997}
1998
1999static struct ly_mnode *read_yin_container(struct ly_module *module,
2000 struct ly_mnode *parent,
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002001 struct lyxml_elem *yin,
2002 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002003{
2004 struct lyxml_elem *sub, *next, root = {0};
2005 struct ly_mnode *mnode = NULL;
2006 struct ly_mnode *retval;
2007 struct ly_mnode_container *cont;
Radek Krejci800af702015-06-02 13:46:01 +02002008 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02002009 int r;
Radek Krejci800af702015-06-02 13:46:01 +02002010 int c_tpdf = 0, c_must = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002011
Radek Krejcida04f4a2015-05-21 12:54:09 +02002012 cont = calloc(1, sizeof *cont);
2013 cont->nodetype = LY_NODE_CONTAINER;
2014 cont->prev = (struct ly_mnode *)cont;
2015 retval = (struct ly_mnode *)cont;
2016
Radek Krejcib388c152015-06-04 17:03:03 +02002017 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002018 goto error;
2019 }
2020
2021 /* process container's specific children */
Radek Krejci4c31f122015-06-02 14:51:22 +02002022 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci800af702015-06-02 13:46:01 +02002023 if (!strcmp(sub->name, "presence")) {
2024 if (cont->presence) {
Radek Krejci4c31f122015-06-02 14:51:22 +02002025 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +02002026 goto error;
2027 }
2028 GETVAL(value, sub, "value");
2029 cont->presence = lydict_insert(module->ctx, value, strlen(value));
2030
Radek Krejci4c31f122015-06-02 14:51:22 +02002031 lyxml_free_elem(module->ctx, sub);
2032
Radek Krejcida04f4a2015-05-21 12:54:09 +02002033 /* data statements */
Radek Krejci800af702015-06-02 13:46:01 +02002034 } else if (!strcmp(sub->name, "container") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02002035 !strcmp(sub->name, "leaf-list") ||
2036 !strcmp(sub->name, "leaf") ||
2037 !strcmp(sub->name, "list") ||
2038 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002039 !strcmp(sub->name, "uses") ||
Radek Krejci863c2852015-06-03 15:47:11 +02002040 !strcmp(sub->name, "grouping")||
2041 !strcmp(sub->name, "anyxml")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002042 lyxml_unlink_elem(sub);
2043 lyxml_add_child(&root, sub);
2044
2045 /* array counters */
2046 } else if (!strcmp(sub->name, "typedef")) {
2047 c_tpdf++;
Radek Krejci800af702015-06-02 13:46:01 +02002048 } else if (!strcmp(sub->name, "must")) {
2049 c_must++;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002050#if 0
Radek Krejci800af702015-06-02 13:46:01 +02002051 } else {
Radek Krejci4c31f122015-06-02 14:51:22 +02002052 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2053 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02002054#else
2055 } else {
2056 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002057#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02002058 }
2059 }
2060
2061 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2062 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002063 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002064 }
Radek Krejci800af702015-06-02 13:46:01 +02002065 if (c_must) {
2066 cont->must = calloc(c_must, sizeof *cont->must);
2067 }
2068
Radek Krejci4c31f122015-06-02 14:51:22 +02002069 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002070 if (!strcmp(sub->name, "typedef")) {
Radek Krejci800af702015-06-02 13:46:01 +02002071 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
2072 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002073
2074 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002075 goto error;
2076 }
Radek Krejci800af702015-06-02 13:46:01 +02002077 } else if (!strcmp(sub->name, "must")) {
2078 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
2079 cont->must_size++;
2080
2081 if (r) {
2082 goto error;
2083 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002084 }
2085
2086 lyxml_free_elem(module->ctx, sub);
2087 }
2088
2089 /* last part - process data nodes */
2090 LY_TREE_FOR_SAFE(root.child, next, sub) {
2091 if (!strcmp(sub->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002092 mnode = read_yin_container(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002093 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002094 mnode = read_yin_leaflist(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002095 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002096 mnode = read_yin_leaf(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002097 } else if (!strcmp(sub->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002098 mnode = read_yin_list(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002099 } else if (!strcmp(sub->name, "choice")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002100 mnode = read_yin_choice(module, retval, sub, resolve);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002101 } else if (!strcmp(sub->name, "uses")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002102 mnode = read_yin_uses(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002103 } else if (!strcmp(sub->name, "grouping")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002104 mnode = read_yin_grouping(module, retval, sub, resolve);
Radek Krejci863c2852015-06-03 15:47:11 +02002105 } else if (!strcmp(sub->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002106 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002107 }
2108 lyxml_free_elem(module->ctx, sub);
2109
Radek Krejci25d782a2015-05-22 15:03:23 +02002110 if (!mnode) {
2111 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002112 }
2113 }
2114
Radek Krejci812b10a2015-05-28 16:48:25 +02002115 if (parent) {
2116 ly_mnode_addchild(parent, retval);
2117 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002118
2119 return retval;
2120
2121error:
2122
2123 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02002124 while (root.child) {
2125 lyxml_free_elem(module->ctx, root.child);
2126 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002127
2128 return NULL;
2129}
2130
2131static struct ly_mnode *read_yin_grouping(struct ly_module *module,
2132 struct ly_mnode *parent,
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002133 struct lyxml_elem *node,
2134 int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002135{
2136 struct lyxml_elem *sub, *next, root = {0};
2137 struct ly_mnode *mnode = NULL;
2138 struct ly_mnode *retval;
2139 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +02002140 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002141 int c_tpdf = 0;
2142
2143 grp = calloc(1, sizeof *grp);
2144 grp->nodetype = LY_NODE_GROUPING;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002145 grp->prev = (struct ly_mnode *)grp;
2146 retval = (struct ly_mnode *)grp;
2147
Radek Krejcib388c152015-06-04 17:03:03 +02002148 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002149 goto error;
2150 }
2151
2152 LY_TREE_FOR_SAFE(node->child, next, sub) {
2153 /* data statements */
2154 if (!strcmp(sub->name, "container") ||
2155 !strcmp(sub->name, "leaf-list") ||
2156 !strcmp(sub->name, "leaf") ||
2157 !strcmp(sub->name, "list") ||
2158 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002159 !strcmp(sub->name, "uses") ||
Radek Krejci77d1dc62015-06-03 16:18:07 +02002160 !strcmp(sub->name, "grouping") ||
2161 !strcmp(sub->name, "anyxml")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002162 lyxml_unlink_elem(sub);
2163 lyxml_add_child(&root, sub);
2164
2165 /* array counters */
2166 } else if (!strcmp(sub->name, "typedef")) {
2167 c_tpdf++;
Radek Krejci77d1dc62015-06-03 16:18:07 +02002168 } else {
2169 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2170 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002171 }
2172 }
2173
2174 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2175 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002176 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002177 }
2178 LY_TREE_FOR_SAFE(node->child, next, sub) {
2179 if (!strcmp(sub->name, "typedef")) {
Radek Krejci77d1dc62015-06-03 16:18:07 +02002180 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
2181 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002182
2183 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002184 goto error;
2185 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002186 }
2187
2188 lyxml_free_elem(module->ctx, sub);
2189 }
2190
2191 /* last part - process data nodes */
2192 LY_TREE_FOR_SAFE(root.child, next, sub) {
2193 if (!strcmp(sub->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002194 mnode = read_yin_container(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002195 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002196 mnode = read_yin_leaflist(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002197 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002198 mnode = read_yin_leaf(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002199 } else if (!strcmp(sub->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002200 mnode = read_yin_list(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002201 } else if (!strcmp(sub->name, "choice")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002202 mnode = read_yin_choice(module, retval, sub, resolve);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002203 } else if (!strcmp(sub->name, "uses")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002204 mnode = read_yin_uses(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002205 } else if (!strcmp(sub->name, "grouping")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002206 mnode = read_yin_grouping(module, retval, sub, resolve);
Radek Krejci77d1dc62015-06-03 16:18:07 +02002207 } else if (!strcmp(sub->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002208 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002209 }
2210 lyxml_free_elem(module->ctx, sub);
2211
Radek Krejci25d782a2015-05-22 15:03:23 +02002212 if (!mnode) {
2213 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002214 }
2215 }
2216
Radek Krejci812b10a2015-05-28 16:48:25 +02002217 if (parent) {
2218 ly_mnode_addchild(parent, retval);
2219 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002220
2221 return retval;
2222
2223error:
2224
2225 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02002226 while (root.child) {
2227 lyxml_free_elem(module->ctx, root.child);
2228 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002229
2230 return NULL;
2231}
2232
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002233/*
2234 * resolve - referenced grouping should be bounded to the namespace (resolved)
2235 * only when uses does not appear in grouping. In a case of grouping's uses,
2236 * we just get information but we do not apply augment or refine to it.
2237 */
2238static struct ly_mnode *read_yin_uses(struct ly_module *module,
2239 struct ly_mnode *parent,
2240 struct lyxml_elem *node, int resolve)
2241{
2242 struct ly_mnode *retval;
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002243 struct ly_mnode *mnode = NULL, *mnode_aux;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002244 struct ly_mnode_uses *uses;
2245 struct ly_module *searchmod = NULL;
2246 const char *name;
2247 int prefix_len = 0;
2248 int i;
2249
2250 uses = calloc(1, sizeof *uses);
2251 uses->nodetype = LY_NODE_USES;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002252 uses->prev = (struct ly_mnode *)uses;
2253 retval = (struct ly_mnode *)uses;
2254
Radek Krejcib388c152015-06-04 17:03:03 +02002255 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002256 goto error;
2257 }
2258
2259 /* get referenced grouping */
2260 name = strchr(uses->name, ':');
2261 if (!name) {
2262 /* no prefix, search in local tree */
2263 name = uses->name;
2264 } else {
2265 /* there is some prefix, check if it refer the same data model */
2266
2267 /* set name to correct position after colon */
2268 prefix_len = name - uses->name;
2269 name++;
2270
2271 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
2272 /* prefix refers to the current module, ignore it */
2273 prefix_len = 0;
2274 }
2275 }
2276
2277 /* search */
2278 if (prefix_len) {
2279 /* in top-level groupings of some other module */
2280 for (i = 0; i < module->imp_size; i++) {
2281 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
2282 && !module->imp[i].prefix[prefix_len]) {
2283 searchmod = module->imp[i].module;
2284 break;
2285 }
2286 }
2287 if (!searchmod) {
2288 /* uses refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +02002289 LOGVAL(VE_INPREFIX, LOGLINE(node), name);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002290 goto error;
2291 }
2292
Radek Krejcia1e97df2015-06-03 11:33:40 +02002293 LY_TREE_FOR(searchmod->data, mnode) {
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002294 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
2295 uses->grp = (struct ly_mnode_grp *)mnode;
2296 break;
2297 }
2298 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002299 } else {
2300 /* in local tree hierarchy */
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002301 for(mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
2302 LY_TREE_FOR(mnode_aux->child, mnode) {
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002303 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
2304 uses->grp = (struct ly_mnode_grp *)mnode;
2305 break;
2306 }
2307 }
2308 }
2309
2310 /* search in top level of the current module */
2311 LY_TREE_FOR(module->data, mnode) {
2312 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
2313 uses->grp = (struct ly_mnode_grp *)mnode;
2314 break;
2315 }
2316 }
2317 }
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002318 if (!uses->grp) {
2319 LOGVAL(VE_INARG, LOGLINE(node), uses->name, "uses");
2320 goto error;
2321 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002322
Radek Krejci812b10a2015-05-28 16:48:25 +02002323 if (parent) {
2324 ly_mnode_addchild(parent, retval);
2325 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002326
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002327 if (resolve) {
Radek Krejcib388c152015-06-04 17:03:03 +02002328 /* inherit config flag */
2329 if (parent) {
2330 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2331 } else {
2332 /* default config is true */
2333 retval->flags |= LY_NODE_CONFIG_W;
2334 }
2335
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002336 /* copy the data nodes from grouping into the uses context */
2337 if (resolve_uses(uses)) {
2338 goto error;
2339 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002340 }
2341
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002342 return retval;
2343
2344error:
2345
2346 ly_mnode_free(retval);
2347
2348 return NULL;
2349}
2350
Radek Krejciefaeba32015-05-27 14:30:57 +02002351/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci0af13872015-05-30 11:50:52 +02002352static int read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002353{
Radek Krejciefaeba32015-05-27 14:30:57 +02002354 struct ly_ctx *ctx = module->ctx;
Radek Krejci0af13872015-05-30 11:50:52 +02002355 struct ly_submodule *submodule = (struct ly_submodule *)module;
Radek Krejciefaeba32015-05-27 14:30:57 +02002356 struct lyxml_elem *next, *node, *child, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +02002357 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002358 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002359 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0; /* counters */
Radek Krejci25d782a2015-05-22 15:03:23 +02002360 int r;
Radek Krejcice7fb782015-05-29 16:52:34 +02002361 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002362
2363 /*
2364 * in the first run, we process elements with cardinality of 1 or 0..1 and
2365 * count elements with cardinality 0..n. Data elements (choices, containers,
2366 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
2367 * need have all top-level and groupings already prepared at that time. In
2368 * the middle loop, we process other elements with carinality of 0..n since
2369 * we need to allocate arrays to store them.
2370 */
2371 LY_TREE_FOR_SAFE(yin->child, next, node) {
2372 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
2373 lyxml_free_elem(ctx, node);
2374 continue;
2375 }
2376
Radek Krejci0af13872015-05-30 11:50:52 +02002377 if (!module->type && !strcmp(node->name, "namespace")) {
2378 if (module->ns) {
2379 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2380 goto error;
2381 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002382 GETVAL(value, node, "uri");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002383 module->ns = lydict_insert(ctx, value, strlen(value));
2384 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02002385 } else if (!module->type && !strcmp(node->name, "prefix")) {
2386 if (module->prefix) {
2387 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2388 goto error;
2389 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002390 GETVAL(value, node, "value");
Radek Krejci0af13872015-05-30 11:50:52 +02002391 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
2392 goto error;
2393 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002394 module->prefix = lydict_insert(ctx, value, strlen(value));
2395 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02002396 } else if (module->type && !strcmp(node->name, "belongs-to")) {
2397 if (submodule->belongsto) {
2398 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2399 goto error;
2400 }
2401 GETVAL(value, node, "module");
2402 submodule->belongsto = ly_ctx_get_module(module->ctx, value, NULL, 0);
2403 if (!submodule->belongsto) {
2404 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
2405 goto error;
2406 }
2407 /* get the prefix substatement, start with checks */
2408 if (!node->child) {
2409 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
2410 goto error;
2411 } else if (strcmp(node->child->name, "prefix")) {
2412 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
2413 goto error;
2414 } else if (node->child->next) {
2415 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
2416 goto error;
2417 }
2418 /* and now finally get the value */
2419 GETVAL(value, node->child, "value");
2420 /* check here differs from a generic prefix check, since this prefix
2421 * don't have to be unique
2422 */
2423 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
2424 goto error;
2425 }
2426 module->prefix = lydict_insert(ctx, value, strlen(value));
2427
2428 /* we are done with belongs-to */
2429 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002430 } else if (!strcmp(node->name, "import")) {
2431 c_imp++;
2432 } else if (!strcmp(node->name, "revision")) {
2433 c_rev++;
2434 } else if (!strcmp(node->name, "typedef")) {
2435 c_tpdf++;
Radek Krejci6793db02015-05-22 17:49:54 +02002436 } else if (!strcmp(node->name, "identity")) {
2437 c_ident++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002438 } else if (!strcmp(node->name, "include")) {
2439 c_inc++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002440
2441 /* data statements */
2442 } else if (!strcmp(node->name, "container") ||
2443 !strcmp(node->name, "leaf-list") ||
2444 !strcmp(node->name, "leaf") ||
2445 !strcmp(node->name, "list") ||
2446 !strcmp(node->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002447 !strcmp(node->name, "uses") ||
Radek Krejci863c2852015-06-03 15:47:11 +02002448 !strcmp(node->name, "grouping") ||
2449 !strcmp(node->name, "anyxml")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002450 lyxml_unlink_elem(node);
2451 lyxml_add_child(&root, node);
2452
2453 /* optional statements */
2454 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002455 if (module->dsc) {
Radek Krejci0af13872015-05-30 11:50:52 +02002456 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002457 goto error;
2458 }
Radek Krejcib8329282015-06-04 11:04:08 +02002459 module->dsc = read_yin_subnode(ctx, node, "text");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002460 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002461 if (!module->dsc) {
2462 goto error;
2463 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002464 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002465 if (module->ref) {
Radek Krejci0af13872015-05-30 11:50:52 +02002466 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002467 goto error;
2468 }
Radek Krejcib8329282015-06-04 11:04:08 +02002469 module->ref = read_yin_subnode(ctx, node, "text");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002470 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002471 if (!module->ref) {
2472 goto error;
2473 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002474 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002475 if (module->org) {
Radek Krejci0af13872015-05-30 11:50:52 +02002476 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002477 goto error;
2478 }
Radek Krejcib8329282015-06-04 11:04:08 +02002479 module->org = read_yin_subnode(ctx, node, "text");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002480 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002481 if (!module->org) {
2482 goto error;
2483 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002484 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002485 if (module->contact) {
Radek Krejci0af13872015-05-30 11:50:52 +02002486 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002487 goto error;
2488 }
Radek Krejcib8329282015-06-04 11:04:08 +02002489 module->contact = read_yin_subnode(ctx, node, "text");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002490 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002491 if (!module->contact) {
2492 goto error;
2493 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002494 } else if (!strcmp(node->name, "yang-version")) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002495 /* TODO: support YANG 1.1 ? */
Radek Krejcib0594bf2015-05-21 23:51:27 +02002496 if (module->version) {
Radek Krejci0af13872015-05-30 11:50:52 +02002497 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002498 goto error;
2499 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002500 GETVAL(value, node, "value");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002501 if (strcmp(value, "1")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002502 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002503 goto error;
2504 }
2505 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002506 lyxml_free_elem(ctx, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02002507#if 0
Radek Krejcice7fb782015-05-29 16:52:34 +02002508 } else {
2509 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
2510 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02002511#else
2512 } else {
2513 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002514#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02002515 }
2516 }
2517
Radek Krejciefaeba32015-05-27 14:30:57 +02002518 if (!submodule) {
2519 /* check for mandatory statements */
2520 if (!module->ns) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002521 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002522 goto error;
2523 }
2524 if (!module->prefix) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002525 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002526 goto error;
2527 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002528 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002529
Radek Krejcida04f4a2015-05-21 12:54:09 +02002530 /* allocate arrays for elements with cardinality of 0..n */
2531 if (c_imp) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002532 module->imp = calloc(c_imp, sizeof *module->imp);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002533 }
2534 if (c_rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002535 module->rev = calloc(c_rev, sizeof *module->rev);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002536 }
2537 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002538 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002539 }
Radek Krejci6793db02015-05-22 17:49:54 +02002540 if (c_ident) {
Radek Krejci6793db02015-05-22 17:49:54 +02002541 module->ident = calloc(c_ident, sizeof *module->ident);
Radek Krejciefaeba32015-05-27 14:30:57 +02002542 }
2543 if (c_inc) {
2544 module->inc = calloc(c_inc, sizeof *module->inc);
Radek Krejci6793db02015-05-22 17:49:54 +02002545 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002546
2547 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2548 LY_TREE_FOR_SAFE(yin->child, next, node) {
2549 if (!strcmp(node->name, "import")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002550 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
2551 module->imp_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002552 if (r) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002553 goto error;
2554 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002555
2556 /* check duplicities in imported modules */
2557 for (i = 0; i < module->imp_size - 1; i++) {
2558 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
2559 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
2560 goto error;
2561 }
2562 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002563 } else if (!strcmp(node->name, "include")) {
2564 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
2565 module->inc_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002566 if (r) {
2567 goto error;
2568 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002569
2570 /* check duplications in include submodules */
2571 for (i = 0; i < module->inc_size - 1; i++) {
Radek Krejci76e5a1b2015-05-29 17:01:08 +02002572 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002573 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->inc[i].submodule->name);
2574 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002575 }
2576 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002577 } else if (!strcmp(node->name, "revision")) {
2578 GETVAL(value, node, "date");
2579 if (check_date(value, LOGLINE(node))) {
2580 goto error;
2581 }
2582 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2583 /* check uniqueness of the revision date - not required by RFC */
2584 for (i = 0; i < module->rev_size; i++) {
2585 if (!strcmp(value, module->rev[i].date)) {
2586 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
2587 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
2588 }
2589 }
2590
2591 LY_TREE_FOR(node->child, child) {
2592 if (!strcmp(child->name, "description")) {
2593 if (module->rev[module->rev_size].dsc) {
2594 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2595 goto error;
2596 }
Radek Krejcib8329282015-06-04 11:04:08 +02002597 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
Radek Krejcice7fb782015-05-29 16:52:34 +02002598 if (!module->rev[module->rev_size].dsc) {
2599 goto error;
2600 }
2601 } else if (!strcmp(child->name, "reference")) {
2602 if (module->rev[module->rev_size].ref) {
2603 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2604 goto error;
2605 }
Radek Krejcib8329282015-06-04 11:04:08 +02002606 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
Radek Krejcice7fb782015-05-29 16:52:34 +02002607 if (!module->rev[module->rev_size].ref) {
2608 goto error;
2609 }
2610 } else {
2611 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2612 goto error;
2613 }
2614 }
2615
2616 /* keep the latest revision at position 0 */
2617 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
2618 /* switch their position */
2619 value = strdup(module->rev[0].date);
2620 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
2621 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2622 free((char*)value);
2623
2624 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
2625 value = module->rev[0].dsc;
2626 module->rev[0].dsc = module->rev[module->rev_size].dsc;
2627 module->rev[module->rev_size].dsc = value;
2628 }
2629
2630 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
2631 value = module->rev[0].ref;
2632 module->rev[0].ref = module->rev[module->rev_size].ref;
2633 module->rev[module->rev_size].ref = value;
2634 }
2635 }
2636
Radek Krejciefaeba32015-05-27 14:30:57 +02002637 module->rev_size++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002638 } else if (!strcmp(node->name, "typedef")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002639 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
2640 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002641
2642 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002643 goto error;
2644 }
Radek Krejci6793db02015-05-22 17:49:54 +02002645 } else if (!strcmp(node->name, "identity")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002646 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
2647 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02002648
2649 if (r) {
Radek Krejci6793db02015-05-22 17:49:54 +02002650 goto error;
2651 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002652 }
2653
2654 lyxml_free_elem(ctx, node);
2655 }
2656
2657 /* last part - process data nodes */
2658 LY_TREE_FOR_SAFE(root.child, next, node) {
2659
2660 if (!strcmp(node->name, "container")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002661 mnode = read_yin_container(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002662 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002663 mnode = read_yin_leaflist(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002664 } else if (!strcmp(node->name, "leaf")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002665 mnode = read_yin_leaf(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002666 } else if (!strcmp(node->name, "list")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002667 mnode = read_yin_list(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002668 } else if (!strcmp(node->name, "choice")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002669 mnode = read_yin_choice(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002670 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002671 mnode = read_yin_grouping(module, NULL, node, 0);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002672 } else if (!strcmp(node->name, "uses")) {
2673 mnode = read_yin_uses(module, NULL, node, 1);
Radek Krejci863c2852015-06-03 15:47:11 +02002674 } else if (!strcmp(node->name, "anyxml")) {
Radek Krejcib388c152015-06-04 17:03:03 +02002675 mnode = read_yin_anyxml(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002676 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02002677 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002678 continue;
2679 }
2680 lyxml_free_elem(ctx, node);
2681
Radek Krejci25d782a2015-05-22 15:03:23 +02002682 if (!mnode) {
2683 goto error;
2684 }
2685
2686 /* include data element */
2687 if (module->data) {
2688 module->data->prev->next = mnode;
2689 mnode->prev = module->data->prev;
2690 module->data->prev = mnode;
2691 } else {
2692 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002693 }
2694 }
2695
Radek Krejciefaeba32015-05-27 14:30:57 +02002696 return EXIT_SUCCESS;
2697
2698error:
2699 /* cleanup */
2700 while (root.child) {
2701 lyxml_free_elem(module->ctx, root.child);
2702 }
2703
2704 return EXIT_FAILURE;
2705}
2706
2707struct ly_submodule *yin_read_submodule(struct ly_module *module, const char *data)
2708{
2709 struct lyxml_elem *yin;
Radek Krejci3045cf32015-05-28 10:58:52 +02002710 struct ly_submodule *submodule = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02002711 const char *value;
2712
Radek Krejci812b10a2015-05-28 16:48:25 +02002713 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02002714
2715 yin = lyxml_read(module->ctx, data, 0);
2716 if (!yin) {
2717 return NULL;
2718 }
2719
2720 /* check root element */
2721 if (!yin->name || strcmp(yin->name, "submodule")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002722 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002723 goto error;
2724 }
2725
Radek Krejci0af13872015-05-30 11:50:52 +02002726 GETVAL(value, yin, "name");
2727 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002728 goto error;
2729 }
2730
2731 submodule = calloc(1, sizeof *submodule);
2732 if (!submodule) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002733 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002734 goto error;
2735 }
2736
2737 submodule->ctx = module->ctx;
2738 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
Radek Krejcice7fb782015-05-29 16:52:34 +02002739 submodule->type = 1;
Radek Krejciefaeba32015-05-27 14:30:57 +02002740
Radek Krejci3045cf32015-05-28 10:58:52 +02002741 LOGVRB("reading submodule %s", submodule->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002742 if (read_sub_module((struct ly_module *)submodule, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002743 goto error;
2744 }
2745
2746 /* cleanup */
2747 lyxml_free_elem(module->ctx, yin);
2748
Radek Krejci3045cf32015-05-28 10:58:52 +02002749 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002750
2751 return submodule;
2752
2753error:
2754 /* cleanup */
2755 lyxml_free_elem(module->ctx, yin);
2756 ly_submodule_free(submodule);
2757
2758 return NULL;
2759}
2760
2761struct ly_module *yin_read_module(struct ly_ctx *ctx, const char *data)
2762{
2763 struct lyxml_elem *yin;
2764 struct ly_module *module = NULL, **newlist = NULL;
2765 const char *value;
2766 int i;
2767
2768 yin = lyxml_read(ctx, data, 0);
2769 if (!yin) {
2770 return NULL;
2771 }
2772
2773 /* check root element */
2774 if (!yin->name || strcmp(yin->name, "module")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002775 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002776 goto error;
2777 }
2778
Radek Krejci0af13872015-05-30 11:50:52 +02002779 GETVAL(value, yin, "name");
2780 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002781 goto error;
2782 }
2783
2784 module = calloc(1, sizeof *module);
2785 if (!module) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002786 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002787 goto error;
2788 }
2789
2790 module->ctx = ctx;
2791 module->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02002792 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02002793
Radek Krejci3045cf32015-05-28 10:58:52 +02002794 LOGVRB("reading module %s", module->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002795 if (read_sub_module(module, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002796 goto error;
2797 }
2798
Radek Krejcida04f4a2015-05-21 12:54:09 +02002799 /* add to the context's list of modules */
2800 if (ctx->models.used == ctx->models.size) {
2801 newlist = realloc(ctx->models.list, ctx->models.size * 2);
2802 if (!newlist) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002803 LOGMEM;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002804 goto error;
2805 }
2806 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
2807 newlist[i] = NULL;
2808 }
2809 ctx->models.size *= 2;
2810 ctx->models.list = newlist;
2811 }
Radek Krejcif6e5e182015-05-27 17:18:07 +02002812 for (i = 0; ctx->models.list[i]; i++) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002813 /* check name (name/revision) and namespace uniqueness */
Radek Krejcif6e5e182015-05-27 17:18:07 +02002814 if (!strcmp(ctx->models.list[i]->name, module->name)) {
2815 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
2816 /* both data models are same, with no revision specified */
Radek Krejci3045cf32015-05-28 10:58:52 +02002817 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.", module->name);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002818 goto error;
2819 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
2820 /* one of the models does not have a revision, so they differs */
2821 continue;
2822 } else {
2823 /* both models have a revision statement which we have to
2824 * compare, revision at position 0 is the last revision
2825 */
2826 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
2827 /* we have the same modules */
Radek Krejci3045cf32015-05-28 10:58:52 +02002828 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name, module->rev[0].date);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002829 goto error;
2830 }
2831 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002832 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
2833 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
2834 ctx->models.list[i]->name, module->name, module->ns);
2835 goto error;
Radek Krejcif6e5e182015-05-27 17:18:07 +02002836 }
2837 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002838 ctx->models.list[i] = module;
2839 ctx->models.used++;
2840
2841 /* cleanup */
2842 lyxml_free_elem(ctx, yin);
2843
Radek Krejci3045cf32015-05-28 10:58:52 +02002844 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002845
2846 return module;
2847
2848error:
2849 /* cleanup */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002850 lyxml_free_elem(ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02002851 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002852
2853 return NULL;
2854}