blob: 5b35c544683c797124dd686911e7eb3028c0ad19 [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 Krejci25d782a2015-05-22 15:03:23 +020022#include <ctype.h>
23#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020024#include <stdlib.h>
25#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020026#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020027
Radek Krejciefdd0ce2015-05-26 16:48:29 +020028#include "../libyang.h"
29#include "../common.h"
30#include "../context.h"
31#include "../dict.h"
32#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020033
Radek Krejciefdd0ce2015-05-26 16:48:29 +020034#include "../tree_internal.h"
35#include "../xml.h"
36
37#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020038
Radek Krejci25d782a2015-05-22 15:03:23 +020039static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int );
Radek Krejcida04f4a2015-05-21 12:54:09 +020040static struct ly_mnode *read_yin_choice(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
41static struct ly_mnode *read_yin_container(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
42static struct ly_mnode *read_yin_leaf(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
43static struct ly_mnode *read_yin_leaflist(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
44static struct ly_mnode *read_yin_list(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +020045static struct ly_mnode *read_yin_uses(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcida04f4a2015-05-21 12:54:09 +020046static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
47
48static char *read_yin_text(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
49{
50 char *value;
51
52 /* there should be <text> child */
53 if (!node->child || !node->child->name
54 || strcmp(node->child->name, "text")) {
55 LY_WRN("Expected \"text\" element in \"%s\" element.", name);
56 } else {
57 value = node->child->content;
58 if (value) {
59 return lydict_insert(ctx, value, strlen(value));
60 }
61 }
62 return NULL;
63}
64
65static struct ly_tpdf *find_superior_type(const char *name,
66 struct ly_module *module,
67 struct ly_mnode *parent)
68{
Radek Krejciefaeba32015-05-27 14:30:57 +020069 int i, j, found = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +020070 int prefix_len = 0;
71 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +020072 struct ly_tpdf *tpdf;
73 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +020074
75 qname = strchr(name, ':');
76
77 if (!qname) {
78 /* no prefix, try built-in types */
79 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
80 if (!strcmp(ly_types[i].def->name, name)) {
81 return ly_types[i].def;
82 }
83 }
84 qname = name;
85 } else {
86 /* set qname to correct position after colon */
87 prefix_len = qname - name;
88 qname++;
89
90 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
91 /* prefix refers to the current module, ignore it */
92 prefix_len = 0;
93 }
94 }
95
96 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +020097 /* search in local typedefs */
98 while (parent) {
99 switch (parent->nodetype) {
100 case LY_NODE_CONTAINER:
101 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
102 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
103 break;
104 case LY_NODE_LIST:
105 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
106 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
107 break;
108 case LY_NODE_GROUPING:
109 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
110 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
111 break;
112 default:
113 parent = parent->parent;
114 continue;
115 }
116
117 for (i = 0; i < tpdf_size; i++) {
118 if (!strcmp(tpdf[i].name, qname)) {
119 return &tpdf[i];
120 }
121 }
122
123 parent = parent->parent;
124 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200125 } else if (prefix_len) {
126 /* get module where to search */
127 for (i = 0; i < module->imp_size; i++) {
128 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
129 module = module->imp[i].module;
130 found = 1;
131 break;
132 }
133 }
134 if (!found) {
135 /* TODO - syntax error */
136 return NULL;
137 }
138 }
139
140 /* search in top level typedefs */
141 for (i = 0; i < module->tpdf_size; i++) {
142 if (!strcmp(module->tpdf[i].name, qname)) {
143 return &module->tpdf[i];
144 }
145 }
146
Radek Krejciefaeba32015-05-27 14:30:57 +0200147 /* search in submodules */
148 for (i = 0; i < module->inc_size; i++) {
149 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
150 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
151 return &module->inc[i].submodule->tpdf[j];
152 }
153 }
154 }
155
156 return NULL;
157}
158
159static struct ly_ident *find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
160{
161 int i;
162 struct ly_ident *base_iter;
163 struct ly_ident_der *der;
164
165 for (i = 0; i < module->ident_size; i++) {
166 if (!strcmp(basename, module->ident[i].name)) {
167 /* we are done */
168
169 if (!ident) {
170 /* just search for type, so do not modify anything, just return
171 * the base identity pointer
172 */
173 return &module->ident[i];
174 }
175
176 /* we are resolving identity definition, so now update structures */
177 ident->base = base_iter = &module->ident[i];
178
179 while (base_iter) {
180 for (der = base_iter->der; der && der->next; der = der->next);
181 if (der) {
182 der->next = malloc(sizeof *der);
183 der = der->next;
184 } else {
185 ident->base->der = der = malloc(sizeof *der);
186 }
187 der->next = NULL;
188 der->ident = ident;
189
190 base_iter = base_iter->base;
191 }
192 return ident->base;
193 }
194 }
195
Radek Krejcida04f4a2015-05-21 12:54:09 +0200196 return NULL;
197}
198
Radek Krejci04581c62015-05-22 21:24:00 +0200199static struct ly_ident *find_base_ident(struct ly_module *module, struct ly_ident *ident, const char *basename)
200{
201 const char *name;
202 int prefix_len = 0;
203 int i, found = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200204 struct ly_ident *result;
Radek Krejci04581c62015-05-22 21:24:00 +0200205
206 if (!basename) {
207 ly_verr(LY_VERR_MISS_ARG, "name", "base");
208 return NULL;
209 }
210
211 /* search for the base identity */
212 name = strchr(basename, ':');
213 if (name) {
214 /* set name to correct position after colon */
215 prefix_len = name - basename;
216 name++;
217
218 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
219 /* prefix refers to the current module, ignore it */
220 prefix_len = 0;
221 }
222 } else {
223 name = basename;
224 }
225
226 if (prefix_len) {
227 /* get module where to search */
228 for (i = 0; i < module->imp_size; i++) {
229 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
230 && !module->imp[i].prefix[prefix_len]) {
231 module = module->imp[i].module;
232 found = 1;
233 break;
234 }
235 }
236 if (!found) {
237 /* identity refers unknown data model */
238 ly_verr(LY_VERR_UNEXP_PREFIX, basename);
239 return NULL;
240 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200241 } else {
242 /* search in submodules */
243 for (i = 0; i < module->inc_size; i++) {
244 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
245 if (result) {
246 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200247 }
Radek Krejci04581c62015-05-22 21:24:00 +0200248 }
249 }
250
Radek Krejciefaeba32015-05-27 14:30:57 +0200251 /* search in the identified module */
252 result = find_base_ident_sub(module, ident, name);
253 if (!result) {
254 ly_verr(LY_VERR_UNEXP_VAL, basename, ident ? "identity" : "type");
255 }
256
257 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200258}
259
260static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
261{
262 struct lyxml_elem *node, *next;
263
264 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
265 return EXIT_FAILURE;
266 }
267 ident->module = module;
268
269 LY_TREE_FOR_SAFE(yin->child, next, node) {
270 if (!strcmp(node->name, "base")) {
271 if (ident->base) {
272 ly_verr(LY_VERR_TOOMANY, "base", "identity");
273 return EXIT_FAILURE;
274 }
275 if (!find_base_ident(module, ident, lyxml_get_attr(node, "name", NULL))) {
276 return EXIT_FAILURE;
277 }
278 } else {
279 ly_verr(LY_VERR_UNEXP_STMT, node->name, "identity");
280 return EXIT_FAILURE;
281 }
282
283 lyxml_free_elem(module->ctx, node);
284 }
285
286 return EXIT_SUCCESS;
287}
288
Radek Krejcida04f4a2015-05-21 12:54:09 +0200289static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
290 struct lyxml_elem *yin, struct ly_type *type)
291{
Radek Krejci25d782a2015-05-22 15:03:23 +0200292 const char *value, *delim;
293 struct lyxml_elem *next, *node, root = {0};
294 int i, j, r;
295 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200296
297 value = lyxml_get_attr(yin, "name", NULL);
Radek Krejci667b97f2015-05-25 15:03:30 +0200298 if (!value) {
299 ly_verr(LY_VERR_MISS_ARG, "name", yin->name);
300 return EXIT_FAILURE;
301 }
302
Radek Krejci25d782a2015-05-22 15:03:23 +0200303 delim = strchr(value, ':');
304 if (delim) {
305 type->prefix = lydict_insert(module->ctx, value, delim - value);
306 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200307
Radek Krejcida04f4a2015-05-21 12:54:09 +0200308 type->der = find_superior_type(value, module, parent);
Radek Krejci25d782a2015-05-22 15:03:23 +0200309 /* TODO error */
310 type->base = type->der->type.base;
311
312 switch (type->base) {
313 case LY_TYPE_BINARY:
314 /* length, 9.4.4
Radek Krejci04581c62015-05-22 21:24:00 +0200315 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
316 * hodnoty se musi vejit do 64b, podelementy
Radek Krejci25d782a2015-05-22 15:03:23 +0200317 */
318 break;
319 case LY_TYPE_BITS:
320 /* bit, 9.7.4
321 * 1..n, nerekurzivni, stringy s podelementy */
322 break;
323 case LY_TYPE_DEC64:
324 /* fraction-digits, 9.3.4
325 * - MUST, 1, nerekurzivni, hodnota 1-18 */
326 /* range, 9.2.4
327 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
328 break;
329 case LY_TYPE_ENUM:
Radek Krejci6793db02015-05-22 17:49:54 +0200330 /* RFC 6020 9.6 */
Radek Krejci04581c62015-05-22 21:24:00 +0200331
Radek Krejci25d782a2015-05-22 15:03:23 +0200332 /* get enum specification, at least one must be present */
333 LY_TREE_FOR_SAFE(yin->child, next, node) {
334 if (!strcmp(node->name, "enum")) {
335 lyxml_unlink_elem(node);
336 lyxml_add_child(&root, node);
337 type->info.enums.count++;
338 }
339 }
340 if (yin->child) {
341 ly_verr(LY_VERR_UNEXP_STMT, yin->child->name);
342 goto error;
343 }
344 if (!type->info.enums.count) {
345 if (type->der->type.der) {
346 /* this is just a derived type with no enum specified */
347 break;
348 }
349 ly_verr(LY_VERR_MISS_STMT2, "enum", "type");
350 goto error;
351 }
352
353 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
354 for (i = v = 0; root.child; i++) {
355 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0);
356 if (r) {
357 type->info.enums.count = i + 1;
358 goto error;
359 }
360 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
361 value = type->info.enums.list[i].name;
362 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
363 ly_verr(LY_VERR_ENUM_WS, value);
364 type->info.enums.count = i + 1;
365 goto error;
366 }
367
368 /* check the name uniqueness */
369 for (j = 0; j < i; j++) {
370 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
371 ly_verr(LY_VERR_ENUM_DUP_NAME, type->info.enums.list[i].name);
372 type->info.enums.count = i + 1;
373 goto error;
374 }
375 }
376
377 node = root.child->child;
378 if (node && !strcmp(node->name, "value")) {
379 value = lyxml_get_attr(node, "value", NULL);
380 v_ = strtol(value, NULL, 10);
381
382 /* range check */
383 if (v_ < INT32_MIN || v_ > INT32_MAX) {
384 ly_verr(LY_VERR_UNEXP_VAL, value, "enum/value");
385 type->info.enums.count = i + 1;
386 goto error;
387 }
388 type->info.enums.list[i].value = v_;
389
390 /* keep the highest enum value for automatic increment */
391 if (type->info.enums.list[i].value > v) {
392 v = type->info.enums.list[i].value;
393 v++;
394 } else {
395 /* check that the value is unique */
396 for (j = 0; j < i; j++) {
397 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
398 ly_verr(LY_VERR_ENUM_DUP_VAL, type->info.enums.list[i].value, type->info.enums.list[i].name);
399 type->info.enums.count = i + 1;
400 goto error;
401 }
402 }
403 }
404 } else {
405 /* assign value automatically */
406 if (v > INT32_MAX) {
407 ly_verr(LY_VERR_UNEXP_VAL, "2147483648", "enum/value");
408 type->info.enums.count = i + 1;
409 goto error;
410 }
411 type->info.enums.list[i].value = v;
412 v++;
413 }
414 lyxml_free_elem(module->ctx, root.child);
415 }
416 break;
417 case LY_TYPE_IDENT:
Radek Krejci04581c62015-05-22 21:24:00 +0200418 /* RFC 6020 9.10 */
419
420 /* get base specification, exactly one must be present */
421 if (!yin->child) {
422 ly_verr(LY_VERR_MISS_STMT2, "base", "type");
423 goto error;
424 }
425 if (strcmp(yin->child->name, "base")) {
426 ly_verr(LY_VERR_UNEXP_STMT, yin->child->name);
427 goto error;
428 }
429 if (yin->child->next) {
430 ly_verr(LY_VERR_UNEXP_STMT, yin->child->next->name);
431 goto error;
432 }
433 type->info.ident.ref = find_base_ident(module, NULL, lyxml_get_attr(yin->child, "name", NULL));
434 if (!type->info.ident.ref) {
435 return EXIT_FAILURE;
436 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200437 break;
438 case LY_TYPE_INST:
439 /* require-instance, 9.13.2
440 * - 0..1, true/false */
441 break;
442 case LY_TYPE_INT8:
443 case LY_TYPE_INT16:
444 case LY_TYPE_INT32:
445 case LY_TYPE_INT64:
446 case LY_TYPE_UINT8:
447 case LY_TYPE_UINT16:
448 case LY_TYPE_UINT32:
449 case LY_TYPE_UINT64:
450 /* range, 9.2.4
451 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
452 break;
453 case LY_TYPE_LEAFREF:
454 /* path, 9.9.2
455 * - 1, nerekurzivni, string */
456 break;
457 case LY_TYPE_STRING:
458 /* length, 9.4.4
459 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
460 * pattern, 9.4.6
461 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
462 break;
463 case LY_TYPE_UNION:
464 /* type, 7.4
465 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
466 break;
467 default:
468 /* nothing needed :
469 * LY_TYPE_BOOL, LY_TYPE_EMPTY
470 */
471 break;
472 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200473
474 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200475
476error:
477
478 while(root.child) {
479 lyxml_free_elem(module->ctx, root.child);
480 }
481
482 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200483}
484
485static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
486 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
487{
488 const char *value;
489 struct lyxml_elem *node, *next;
Radek Krejci76c45d32015-05-26 16:01:14 +0200490 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200491
492 value = lyxml_get_attr(yin, "name", NULL);
493 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
494
495 LY_TREE_FOR_SAFE(yin->child, next, node) {
496 if (!strcmp(node->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200497 r = fill_yin_type(module, parent, node, &tpdf->type);
498
Radek Krejcida04f4a2015-05-21 12:54:09 +0200499 /* optional statements */
500 } else if (!strcmp(node->name, "description")) {
501 tpdf->dsc = read_yin_text(module->ctx, node, "description");
Radek Krejci25d782a2015-05-22 15:03:23 +0200502 if (!tpdf->dsc) {
503 r = 1;
504 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200505 } else if (!strcmp(node->name, "reference")) {
506 tpdf->ref = read_yin_text(module->ctx, node, "reference");
Radek Krejcidcf9d922015-05-26 15:42:32 +0200507 if (!tpdf->ref) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200508 r = 1;
509 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200510 } else if (!strcmp(node->name, "status")) {
511 value = lyxml_get_attr(node, "value", NULL);
512 if (!strcmp(value, "current")) {
513 tpdf->flags |= LY_NODE_STATUS_CURR;
514 } else if (!strcmp(value, "deprecated")) {
515 tpdf->flags |= LY_NODE_STATUS_DEPRC;
516 } else if (!strcmp(value, "obsolete")) {
517 tpdf->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejci25d782a2015-05-22 15:03:23 +0200518 } else {
519 ly_verr(LY_VERR_UNEXP_VAL, value, "status");
520 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200521 }
522 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200523 lyxml_free_elem(module->ctx, node);
524 if (r) {
525 return EXIT_FAILURE;
526 }
527 }
528
529 if (!tpdf->type.der) {
530 ly_verr(LY_VERR_MISS_STMT2, "type", "typedef");
531 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200532 }
533
534 return EXIT_SUCCESS;
535}
536
Radek Krejciefaeba32015-05-27 14:30:57 +0200537static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
538{
539 struct lyxml_elem *child;
540 const char *value;
541
542 LY_TREE_FOR(yin->child, child) {
543 if (!strcmp(child->name, "prefix")) {
544 value = lyxml_get_attr(child, "value", NULL);
545 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
546 } else if (!strcmp(child->name, "revision-date")) {
547 value = lyxml_get_attr(child, "date", NULL);
548 if (!value) {
549 ly_verr(LY_VERR_MISS_ARG, "date", "revision-date");
550 return EXIT_FAILURE;
551 }
552 memcpy(imp->rev, value, LY_REV_SIZE - 1);
553 } else {
554 ly_verr(LY_VERR_UNEXP_STMT, child->name);
555 return EXIT_FAILURE;
556 }
557 }
558
559 value = lyxml_get_attr(yin, "module", NULL);
560 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL);
561 if (!imp->module) {
562 LY_ERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
563 value, module->name);
564 return EXIT_FAILURE;
565 }
566
567 return EXIT_SUCCESS;
568}
569
570static int fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
571{
572 struct lyxml_elem *child;
573 const char *value;
574
575 LY_TREE_FOR(yin->child, child) {
576 if (!strcmp(child->name, "revision-date")) {
577 value = lyxml_get_attr(child, "date", NULL);
578 if (!value) {
579 ly_verr(LY_VERR_MISS_ARG, "date", "revision-date");
580 return EXIT_FAILURE;
581 }
582 memcpy(inc->rev, value, LY_REV_SIZE - 1);
583 } else {
584 ly_verr(LY_VERR_UNEXP_STMT, child->name);
585 return EXIT_FAILURE;
586 }
587 }
588
589 value = lyxml_get_attr(yin, "module", NULL);
590 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
591 if (!inc->submodule) {
592 LY_ERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
593 value, module->name);
594 return EXIT_FAILURE;
595 }
596
597
598 return EXIT_SUCCESS;
599}
600
601
Radek Krejcida04f4a2015-05-21 12:54:09 +0200602/*
603 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200604 * description, reference, status, optionaly config
Radek Krejcida04f4a2015-05-21 12:54:09 +0200605 */
606static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejci25d782a2015-05-22 15:03:23 +0200607 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int ext)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200608{
609 const char *value;
610 struct lyxml_elem *sub, *next;
611 struct ly_ctx * const ctx = module->ctx;
612
Radek Krejci25d782a2015-05-22 15:03:23 +0200613 if (ext) {
614 mnode->module = module;
615 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200616
617 value = lyxml_get_attr(xmlnode, "name", NULL);
618 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci25d782a2015-05-22 15:03:23 +0200619 if (!mnode->name || !mnode->name[0]) {
620 ly_verr(LY_VERR_MISS_ARG, "name", xmlnode->name);
621 return EXIT_FAILURE;
622 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200623
624 /* process local parameters */
625 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
626 if (!strcmp(sub->name, "description")) {
627 mnode->dsc = read_yin_text(ctx, sub, "description");
628 } else if (!strcmp(sub->name, "reference")) {
629 mnode->ref = read_yin_text(ctx, sub, "reference");
Radek Krejcida04f4a2015-05-21 12:54:09 +0200630 } else if (!strcmp(sub->name, "status")) {
631 value = lyxml_get_attr(sub, "value", NULL);
632 if (!strcmp(value, "current")) {
633 mnode->flags |= LY_NODE_STATUS_CURR;
634 } else if (!strcmp(value, "deprecated")) {
635 mnode->flags |= LY_NODE_STATUS_DEPRC;
636 } else if (!strcmp(value, "obsolete")) {
637 mnode->flags |= LY_NODE_STATUS_OBSLT;
638 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200639 } else if (ext && !strcmp(sub->name, "config")) {
640 value = lyxml_get_attr(sub, "value", NULL);
641 if (!strcmp(value, "false")) {
642 mnode->flags |= LY_NODE_CONFIG_R;
643 } else if (!strcmp(value, "false")) {
644 mnode->flags |= LY_NODE_CONFIG_W;
645 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200646 } else {
647 /* skip the lyxml_free_elem */
648 continue;
649 }
650 lyxml_free_elem(ctx, sub);
651 }
652
Radek Krejci25d782a2015-05-22 15:03:23 +0200653 if (ext && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200654 /* get config flag from parent */
655 if (parent) {
656 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
657 } else {
658 /* default config is true */
659 mnode->flags |= LY_NODE_CONFIG_W;
660 }
661 }
662
663 return EXIT_SUCCESS;
664}
665
666static struct ly_mnode *read_yin_choice(struct ly_module *module,
667 struct ly_mnode *parent,
668 struct lyxml_elem *node)
669{
670 struct lyxml_elem *sub, *next;
671 struct ly_ctx * const ctx = module->ctx;
Radek Krejci25d782a2015-05-22 15:03:23 +0200672 struct ly_mnode *retval, *r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200673 struct ly_mnode_choice *choice;
674
Radek Krejcida04f4a2015-05-21 12:54:09 +0200675 choice = calloc(1, sizeof *choice);
676 choice->nodetype = LY_NODE_CHOICE;
677 choice->module = module;
678 choice->prev = (struct ly_mnode *)choice;
679 retval = (struct ly_mnode *)choice;
680
Radek Krejci25d782a2015-05-22 15:03:23 +0200681 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200682 goto error;
683 }
684
685 /* process choice's specific children */
686 LY_TREE_FOR_SAFE(node->child, next, sub) {
687 if (!strcmp(sub->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200688 r = read_yin_container(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200689 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200690 r = read_yin_leaflist(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200691 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200692 r = read_yin_leaf(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200693 } else if (!strcmp(sub->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200694 r = read_yin_list(module, retval, sub);
Radek Krejci667b97f2015-05-25 15:03:30 +0200695 } else {
696 continue;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200697 }
698 lyxml_free_elem(ctx, sub);
Radek Krejci25d782a2015-05-22 15:03:23 +0200699 if (!r) {
700 goto error;
701 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200702 }
703
704 ly_mnode_addchild(parent, retval);
705
706 return retval;
707
708error:
709
710 ly_mnode_free(retval);
711
712 return NULL;
713}
714
715static struct ly_mnode *read_yin_leaf(struct ly_module *module,
716 struct ly_mnode *parent,
717 struct lyxml_elem *node)
718{
719 struct ly_mnode *retval;
720 struct ly_mnode_leaf *leaf;
721 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +0200722 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200723
Radek Krejcida04f4a2015-05-21 12:54:09 +0200724 leaf = calloc(1, sizeof *leaf);
725 leaf->nodetype = LY_NODE_LEAF;
726 leaf->prev = (struct ly_mnode *)leaf;
727 retval = (struct ly_mnode *)leaf;
728
Radek Krejci25d782a2015-05-22 15:03:23 +0200729 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200730 goto error;
731 }
732
733 LY_TREE_FOR_SAFE(node->child, next, sub) {
734 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200735 r = fill_yin_type(module, parent, sub, &leaf->type);
736 if (r) {
737 goto error;
738 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200739 }
740 }
741
742 ly_mnode_addchild(parent, retval);
743
744 return retval;
745
746error:
747
748 ly_mnode_free(retval);
749
750 return NULL;
751}
752
753static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
754 struct ly_mnode *parent,
755 struct lyxml_elem *node)
756{
757 struct ly_mnode *retval;
758 struct ly_mnode_leaflist *llist;
759 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +0200760 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200761
Radek Krejcida04f4a2015-05-21 12:54:09 +0200762 llist = calloc(1, sizeof *llist);
763 llist->nodetype = LY_NODE_LEAFLIST;
764 llist->prev = (struct ly_mnode *)llist;
765 retval = (struct ly_mnode *)llist;
766
Radek Krejci25d782a2015-05-22 15:03:23 +0200767 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200768 goto error;
769 }
770
771 LY_TREE_FOR_SAFE(node->child, next, sub) {
772 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200773 r = fill_yin_type(module, parent, sub, &llist->type);
774 if (r) {
775 goto error;
776 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200777 }
778 }
779
780 ly_mnode_addchild(parent, retval);
781
782 return retval;
783
784error:
785
786 ly_mnode_free(retval);
787
788 return NULL;
789}
790
791static struct ly_mnode *read_yin_list(struct ly_module *module,
792 struct ly_mnode *parent,
793 struct lyxml_elem *node)
794{
795 struct ly_mnode *retval, *mnode;
796 struct ly_mnode_list *list;
Radek Krejcid7f0d012015-05-25 15:04:52 +0200797 struct ly_mnode_leaf *key;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200798 struct lyxml_elem *sub, *next, root = {0};
Radek Krejcid7f0d012015-05-25 15:04:52 +0200799 int i, j, r;
800 size_t len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200801 int c_tpdf = 0;
Radek Krejcid7f0d012015-05-25 15:04:52 +0200802 const char *key_str = NULL, *s;
803 char *dup;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200804
Radek Krejcida04f4a2015-05-21 12:54:09 +0200805 list = calloc(1, sizeof *list);
806 list->nodetype = LY_NODE_LIST;
807 list->prev = (struct ly_mnode *)list;
808 retval = (struct ly_mnode *)list;
809
Radek Krejci25d782a2015-05-22 15:03:23 +0200810 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200811 goto error;
812 }
813
814 /* process list's specific children */
815 LY_TREE_FOR_SAFE(node->child, next, sub) {
816 /* data statements */
817 if (!strcmp(sub->name, "container") ||
818 !strcmp(sub->name, "leaf-list") ||
819 !strcmp(sub->name, "leaf") ||
820 !strcmp(sub->name, "list") ||
821 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200822 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +0200823 !strcmp(sub->name, "grouping")) {
824 lyxml_unlink_elem(sub);
825 lyxml_add_child(&root, sub);
826
827 /* array counters */
Radek Krejcid7f0d012015-05-25 15:04:52 +0200828 } else if (!strcmp(sub->name, "key")) {
829 /* check cardinality 0..1 */
830 if (list->keys_size) {
831 ly_verr(LY_VERR_TOOMANY, "key", list->name);
832 goto error;
833 }
834
835 /* count the number of keys */
836 key_str = s = lyxml_get_attr(sub, "value", NULL);
837 if (!s) {
838 ly_verr(LY_VERR_MISS_ARG, "value", "key");
839 goto error;
840 }
841 while((s = strpbrk(s, " \t\n"))) {
842 list->keys_size++;
843 while(isspace(*s)) {
844 s++;
845 }
846 }
847 list->keys_size++;
848
849 list->keys = calloc(list->keys_size, sizeof *list->keys);
850
Radek Krejcida04f4a2015-05-21 12:54:09 +0200851 } else if (!strcmp(sub->name, "typedef")) {
852 c_tpdf++;
853 }
854 }
855
Radek Krejcid7f0d012015-05-25 15:04:52 +0200856 /* check - if list is configuration, key statement is mandatory */
Radek Krejci3a734ed2015-05-26 15:23:18 +0200857 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
Radek Krejcid7f0d012015-05-25 15:04:52 +0200858 ly_verr(LY_VERR_MISS_STMT2, "key", "list");
859 goto error;
860 }
861
Radek Krejcida04f4a2015-05-21 12:54:09 +0200862 /* middle part - process nodes with cardinality of 0..n except the data nodes */
863 if (c_tpdf) {
864 list->tpdf_size = c_tpdf;
865 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
866 c_tpdf = 0;
867 }
868 LY_TREE_FOR_SAFE(node->child, next, sub) {
869 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200870 r = fill_yin_typedef(module, retval, sub, &list->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200871 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +0200872
873 if (r) {
874 list->tpdf_size = c_tpdf;
875 goto error;
876 }
Radek Krejcid7f0d012015-05-25 15:04:52 +0200877 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200878 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200879 }
880
881 /* last part - process data nodes */
882 LY_TREE_FOR_SAFE(root.child, next, sub) {
883 if (!strcmp(sub->name, "container")) {
884 mnode = read_yin_container(module, retval, sub);
885 } else if (!strcmp(sub->name, "leaf-list")) {
886 mnode = read_yin_leaflist(module, retval, sub);
887 } else if (!strcmp(sub->name, "leaf")) {
888 mnode = read_yin_leaf(module, retval, sub);
889 } else if (!strcmp(sub->name, "list")) {
890 mnode = read_yin_list(module, retval, sub);
891 } else if (!strcmp(sub->name, "choice")) {
892 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +0200893 } else if (!strcmp(sub->name, "uses")) {
894 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200895 } else if (!strcmp(sub->name, "grouping")) {
896 mnode = read_yin_grouping(module, retval, sub);
897 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +0200898 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +0200899 continue;
900 }
901 lyxml_free_elem(module->ctx, sub);
902
Radek Krejci25d782a2015-05-22 15:03:23 +0200903 if (!mnode) {
904 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200905 }
906 }
907
Radek Krejci3a734ed2015-05-26 15:23:18 +0200908 ly_mnode_addchild(parent, retval);
909 if (!key_str) {
910 /* config false list without a key */
911 return retval;
912 }
913
Radek Krejcid7f0d012015-05-25 15:04:52 +0200914 /* link key leafs into the list structure and check all constraints */
915 /* TODO - include searching in uses/grouping */
916 for (i = 0; i < list->keys_size; i++) {
917 /* get the key name */
918 if ((s = strpbrk(key_str, " \t\n"))) {
919 len = s - key_str;
920 } else {
921 len = strlen(key_str);
922 }
923 LY_TREE_FOR(list->child, mnode) {
924 if (!strncmp(mnode->name, key_str, len) && !mnode->name[len]) {
925 list->keys[i] = mnode;
926 break;
927 }
928 }
929 key = (struct ly_mnode_leaf *)list->keys[i];
930
931 /* existence */
932 if (!key) {
933 if ((s = strpbrk(key_str, " \t\n"))) {
934 len = s - key_str;
935 dup = strdup(key_str);
936 dup[len] = '\0';
937 key_str = dup;
938 }
939 ly_verr(LY_VERR_KEY_MISS, key_str);
940 if (s) {
941 free(dup);
942 }
943 goto error;
944 }
945
946 /* uniquness */
947 for (j = i - 1; j >= 0; j--) {
948 if (list->keys[i] == list->keys[j]) {
949 ly_verr(LY_VERR_KEY_DUP, key->name, list->name);
950 goto error;
951 }
952 }
953
954 /* key is a leaf */
955 if (key->nodetype != LY_NODE_LEAF) {
956 ly_verr(LY_VERR_KEY_NLEAF, key->name, list->name);
957 goto error;
958 }
959
960 /* type of the leaf is not built-in empty */
961 if (key->type.base == LY_TYPE_EMPTY) {
962 ly_verr(LY_VERR_KEY_TYPE, key->name, list->name);
963 goto error;
964 }
965
966 /* config attribute is the same as of the list */
967 if ((list->flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
968 ly_verr(LY_VERR_KEY_CONFIG, key->name, list->name);
969 goto error;
970 }
971
972 /* prepare for next iteration */
973 while (s && isspace(*s)) {
974 s++;
975 }
976 key_str = s;
977 }
978
Radek Krejcida04f4a2015-05-21 12:54:09 +0200979 return retval;
980
981error:
982
983 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +0200984 while(root.child) {
985 lyxml_free_elem(module->ctx, root.child);
986 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200987
988 return NULL;
989}
990
991static struct ly_mnode *read_yin_container(struct ly_module *module,
992 struct ly_mnode *parent,
993 struct lyxml_elem *node)
994{
995 struct lyxml_elem *sub, *next, root = {0};
996 struct ly_mnode *mnode = NULL;
997 struct ly_mnode *retval;
998 struct ly_mnode_container *cont;
Radek Krejci25d782a2015-05-22 15:03:23 +0200999 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001000 int c_tpdf = 0;
1001
Radek Krejcida04f4a2015-05-21 12:54:09 +02001002 cont = calloc(1, sizeof *cont);
1003 cont->nodetype = LY_NODE_CONTAINER;
1004 cont->prev = (struct ly_mnode *)cont;
1005 retval = (struct ly_mnode *)cont;
1006
Radek Krejci25d782a2015-05-22 15:03:23 +02001007 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001008 goto error;
1009 }
1010
1011 /* process container's specific children */
1012 LY_TREE_FOR_SAFE(node->child, next, sub) {
1013 /* data statements */
1014 if (!strcmp(sub->name, "container") ||
1015 !strcmp(sub->name, "leaf-list") ||
1016 !strcmp(sub->name, "leaf") ||
1017 !strcmp(sub->name, "list") ||
1018 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001019 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001020 !strcmp(sub->name, "grouping")) {
1021 lyxml_unlink_elem(sub);
1022 lyxml_add_child(&root, sub);
1023
1024 /* array counters */
1025 } else if (!strcmp(sub->name, "typedef")) {
1026 c_tpdf++;
1027 }
1028 }
1029
1030 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1031 if (c_tpdf) {
1032 cont->tpdf_size = c_tpdf;
1033 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
1034 c_tpdf = 0;
1035 }
1036 LY_TREE_FOR_SAFE(node->child, next, sub) {
1037 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001038 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001039 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001040
1041 if (r) {
1042 cont->tpdf_size = c_tpdf;
1043 goto error;
1044 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001045 }
1046
1047 lyxml_free_elem(module->ctx, sub);
1048 }
1049
1050 /* last part - process data nodes */
1051 LY_TREE_FOR_SAFE(root.child, next, sub) {
1052 if (!strcmp(sub->name, "container")) {
1053 mnode = read_yin_container(module, retval, sub);
1054 } else if (!strcmp(sub->name, "leaf-list")) {
1055 mnode = read_yin_leaflist(module, retval, sub);
1056 } else if (!strcmp(sub->name, "leaf")) {
1057 mnode = read_yin_leaf(module, retval, sub);
1058 } else if (!strcmp(sub->name, "list")) {
1059 mnode = read_yin_list(module, retval, sub);
1060 } else if (!strcmp(sub->name, "choice")) {
1061 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001062 } else if (!strcmp(sub->name, "uses")) {
1063 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001064 } else if (!strcmp(sub->name, "grouping")) {
1065 mnode = read_yin_grouping(module, retval, sub);
1066 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001067 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001068 continue;
1069 }
1070 lyxml_free_elem(module->ctx, sub);
1071
Radek Krejci25d782a2015-05-22 15:03:23 +02001072 if (!mnode) {
1073 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001074 }
1075 }
1076
1077 ly_mnode_addchild(parent, retval);
1078
1079 return retval;
1080
1081error:
1082
1083 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001084 while (root.child) {
1085 lyxml_free_elem(module->ctx, root.child);
1086 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001087
1088 return NULL;
1089}
1090
1091static struct ly_mnode *read_yin_grouping(struct ly_module *module,
1092 struct ly_mnode *parent,
1093 struct lyxml_elem *node)
1094{
1095 struct lyxml_elem *sub, *next, root = {0};
1096 struct ly_mnode *mnode = NULL;
1097 struct ly_mnode *retval;
1098 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +02001099 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001100 int c_tpdf = 0;
1101
1102 grp = calloc(1, sizeof *grp);
1103 grp->nodetype = LY_NODE_GROUPING;
1104 grp->module = module;
1105 grp->prev = (struct ly_mnode *)grp;
1106 retval = (struct ly_mnode *)grp;
1107
Radek Krejci25d782a2015-05-22 15:03:23 +02001108 if (read_yin_common(module, parent, retval, node, 0)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001109 goto error;
1110 }
1111
1112 LY_TREE_FOR_SAFE(node->child, next, sub) {
1113 /* data statements */
1114 if (!strcmp(sub->name, "container") ||
1115 !strcmp(sub->name, "leaf-list") ||
1116 !strcmp(sub->name, "leaf") ||
1117 !strcmp(sub->name, "list") ||
1118 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001119 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001120 !strcmp(sub->name, "grouping")) {
1121 lyxml_unlink_elem(sub);
1122 lyxml_add_child(&root, sub);
1123
1124 /* array counters */
1125 } else if (!strcmp(sub->name, "typedef")) {
1126 c_tpdf++;
1127 }
1128 }
1129
1130 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1131 if (c_tpdf) {
1132 grp->tpdf_size = c_tpdf;
1133 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
1134 c_tpdf = 0;
1135 }
1136 LY_TREE_FOR_SAFE(node->child, next, sub) {
1137 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001138 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001139 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001140
1141 if (r) {
1142 grp->tpdf_size = c_tpdf;
1143 goto error;
1144 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001145 }
1146
1147 lyxml_free_elem(module->ctx, sub);
1148 }
1149
1150 /* last part - process data nodes */
1151 LY_TREE_FOR_SAFE(root.child, next, sub) {
1152 if (!strcmp(sub->name, "container")) {
1153 mnode = read_yin_container(module, retval, sub);
1154 } else if (!strcmp(sub->name, "leaf-list")) {
1155 mnode = read_yin_leaflist(module, retval, sub);
1156 } else if (!strcmp(sub->name, "leaf")) {
1157 mnode = read_yin_leaf(module, retval, sub);
1158 } else if (!strcmp(sub->name, "list")) {
1159 mnode = read_yin_list(module, retval, sub);
1160 } else if (!strcmp(sub->name, "choice")) {
1161 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001162 } else if (!strcmp(sub->name, "uses")) {
1163 mnode = read_yin_uses(module, retval, sub, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001164 } else if (!strcmp(sub->name, "grouping")) {
1165 mnode = read_yin_grouping(module, retval, sub);
1166 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001167 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001168 continue;
1169 }
1170 lyxml_free_elem(module->ctx, sub);
1171
Radek Krejci25d782a2015-05-22 15:03:23 +02001172 if (!mnode) {
1173 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001174 }
1175 }
1176
1177 ly_mnode_addchild(parent, retval);
1178
1179 return retval;
1180
1181error:
1182
1183 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001184 while (root.child) {
1185 lyxml_free_elem(module->ctx, root.child);
1186 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001187
1188 return NULL;
1189}
1190
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001191/*
1192 * resolve - referenced grouping should be bounded to the namespace (resolved)
1193 * only when uses does not appear in grouping. In a case of grouping's uses,
1194 * we just get information but we do not apply augment or refine to it.
1195 */
1196static struct ly_mnode *read_yin_uses(struct ly_module *module,
1197 struct ly_mnode *parent,
1198 struct lyxml_elem *node, int resolve)
1199{
1200 struct ly_mnode *retval;
1201 struct ly_mnode *mnode = NULL, *par;
1202 struct ly_mnode_uses *uses;
1203 struct ly_module *searchmod = NULL;
1204 const char *name;
1205 int prefix_len = 0;
1206 int i;
1207
1208 uses = calloc(1, sizeof *uses);
1209 uses->nodetype = LY_NODE_USES;
1210 uses->module = module;
1211 uses->prev = (struct ly_mnode *)uses;
1212 retval = (struct ly_mnode *)uses;
1213
1214 if (read_yin_common(module, parent, retval, node, 0)) {
1215 goto error;
1216 }
1217
1218 /* get referenced grouping */
1219 name = strchr(uses->name, ':');
1220 if (!name) {
1221 /* no prefix, search in local tree */
1222 name = uses->name;
1223 } else {
1224 /* there is some prefix, check if it refer the same data model */
1225
1226 /* set name to correct position after colon */
1227 prefix_len = name - uses->name;
1228 name++;
1229
1230 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1231 /* prefix refers to the current module, ignore it */
1232 prefix_len = 0;
1233 }
1234 }
1235
1236 /* search */
1237 if (prefix_len) {
1238 /* in top-level groupings of some other module */
1239 for (i = 0; i < module->imp_size; i++) {
1240 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
1241 && !module->imp[i].prefix[prefix_len]) {
1242 searchmod = module->imp[i].module;
1243 break;
1244 }
1245 }
1246 if (!searchmod) {
1247 /* uses refers unknown data model */
1248 ly_verr(LY_VERR_UNEXP_PREFIX, name);
1249 goto error;
1250 }
1251
1252 LY_TREE_FOR(module->data, mnode) {
1253 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1254 uses->grp = (struct ly_mnode_grp *)mnode;
1255 break;
1256 }
1257 }
1258
1259 if (!uses->grp) {
1260 ly_verr(LY_VERR_UNEXP_VAL, uses->name, "uses");
1261 goto error;
1262 }
1263
1264 } else {
1265 /* in local tree hierarchy */
1266 for(par = parent; par; par = par->parent) {
1267 LY_TREE_FOR(parent->child, mnode) {
1268 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1269 uses->grp = (struct ly_mnode_grp *)mnode;
1270 break;
1271 }
1272 }
1273 }
1274
1275 /* search in top level of the current module */
1276 LY_TREE_FOR(module->data, mnode) {
1277 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1278 uses->grp = (struct ly_mnode_grp *)mnode;
1279 break;
1280 }
1281 }
1282 }
1283
1284 ly_mnode_addchild(parent, retval);
1285
1286 if (!resolve) {
1287 return retval;
1288 }
1289
1290 /* TODO */
1291
1292 return retval;
1293
1294error:
1295
1296 ly_mnode_free(retval);
1297
1298 return NULL;
1299}
1300
Radek Krejciefaeba32015-05-27 14:30:57 +02001301/* common code for yin_read_module() and yin_read_submodule() */
1302static int read_sub_module(struct ly_module *module, struct lyxml_elem *yin, int submodule)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001303{
Radek Krejciefaeba32015-05-27 14:30:57 +02001304 struct ly_ctx *ctx = module->ctx;
1305 struct lyxml_elem *next, *node, *child, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +02001306 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001307 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001308 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0; /* counters */
Radek Krejci25d782a2015-05-22 15:03:23 +02001309 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001310
1311 /*
1312 * in the first run, we process elements with cardinality of 1 or 0..1 and
1313 * count elements with cardinality 0..n. Data elements (choices, containers,
1314 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
1315 * need have all top-level and groupings already prepared at that time. In
1316 * the middle loop, we process other elements with carinality of 0..n since
1317 * we need to allocate arrays to store them.
1318 */
1319 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejcif6e5e182015-05-27 17:18:07 +02001320 /* TODO: belongs-to */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001321 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1322 lyxml_free_elem(ctx, node);
1323 continue;
1324 }
1325
Radek Krejciefaeba32015-05-27 14:30:57 +02001326 if (!submodule && !strcmp(node->name, "namespace")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001327 value = lyxml_get_attr(node, "uri", NULL);
1328 if (!value) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001329 LY_ERR(LY_EVALID, "%s: Missing \"uri\" attribute in \"namespace\" element.", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001330 goto error;
1331 }
1332 module->ns = lydict_insert(ctx, value, strlen(value));
1333 lyxml_free_elem(ctx, node);
Radek Krejciefaeba32015-05-27 14:30:57 +02001334 } else if (!submodule && !strcmp(node->name, "prefix")) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001335 value = lyxml_get_attr(node, "value", NULL);
1336 if (!value) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001337 LY_ERR(LY_EVALID, "%s: Missing \"value\" attribute in \"prefix\" element.", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001338 goto error;
1339 }
1340 module->prefix = lydict_insert(ctx, value, strlen(value));
1341 lyxml_free_elem(ctx, node);
1342 } else if (!strcmp(node->name, "import")) {
1343 c_imp++;
1344 } else if (!strcmp(node->name, "revision")) {
1345 c_rev++;
1346 } else if (!strcmp(node->name, "typedef")) {
1347 c_tpdf++;
Radek Krejci6793db02015-05-22 17:49:54 +02001348 } else if (!strcmp(node->name, "identity")) {
1349 c_ident++;
Radek Krejciefaeba32015-05-27 14:30:57 +02001350 } else if (!strcmp(node->name, "include")) {
1351 c_inc++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001352
1353 /* data statements */
1354 } else if (!strcmp(node->name, "container") ||
1355 !strcmp(node->name, "leaf-list") ||
1356 !strcmp(node->name, "leaf") ||
1357 !strcmp(node->name, "list") ||
1358 !strcmp(node->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001359 !strcmp(node->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001360 !strcmp(node->name, "grouping")) {
1361 lyxml_unlink_elem(node);
1362 lyxml_add_child(&root, node);
1363
1364 /* optional statements */
1365 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001366 if (module->dsc) {
1367 ly_verr(LY_VERR_TOOMANY, "description", "module");
1368 goto error;
1369 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001370 module->dsc = read_yin_text(ctx, node, "description");
1371 lyxml_free_elem(ctx, node);
1372 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001373 if (module->ref) {
1374 ly_verr(LY_VERR_TOOMANY, "reference", "module");
1375 goto error;
1376 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001377 module->ref = read_yin_text(ctx, node, "reference");
1378 lyxml_free_elem(ctx, node);
1379 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001380 if (module->org) {
1381 ly_verr(LY_VERR_TOOMANY, "organization", "module");
1382 goto error;
1383 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001384 module->org = read_yin_text(ctx, node, "organization");
1385 lyxml_free_elem(ctx, node);
1386 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001387 if (module->contact) {
1388 ly_verr(LY_VERR_TOOMANY, "contact", "module");
1389 goto error;
1390 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001391 module->contact = read_yin_text(ctx, node, "contact");
1392 lyxml_free_elem(ctx, node);
1393 } else if (!strcmp(node->name, "yang-version")) {
1394 /* TODO: support YANG 1.1 */
Radek Krejcib0594bf2015-05-21 23:51:27 +02001395 if (module->version) {
1396 ly_verr(LY_VERR_TOOMANY, "yang-version", "module");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001397 goto error;
1398 }
Radek Krejcib0594bf2015-05-21 23:51:27 +02001399 value = lyxml_get_attr(node, "value", NULL);
1400 if (strcmp(value, "1")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001401 ly_verr(LY_VERR_UNEXP_VAL, value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02001402 goto error;
1403 }
1404 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001405 lyxml_free_elem(ctx, node);
1406 }
1407 }
1408
Radek Krejciefaeba32015-05-27 14:30:57 +02001409 if (!submodule) {
1410 /* check for mandatory statements */
1411 if (!module->ns) {
1412 ly_verr(LY_VERR_MISS_STMT2, "namespace", "module");
1413 goto error;
1414 }
1415 if (!module->prefix) {
1416 ly_verr(LY_VERR_MISS_STMT2, "prefix", "module");
1417 goto error;
1418 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02001419 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02001420
Radek Krejcida04f4a2015-05-21 12:54:09 +02001421 /* allocate arrays for elements with cardinality of 0..n */
1422 if (c_imp) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001423 module->imp = calloc(c_imp, sizeof *module->imp);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001424 }
1425 if (c_rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001426 module->rev = calloc(c_rev, sizeof *module->rev);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001427 }
1428 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001429 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001430 }
Radek Krejci6793db02015-05-22 17:49:54 +02001431 if (c_ident) {
Radek Krejci6793db02015-05-22 17:49:54 +02001432 module->ident = calloc(c_ident, sizeof *module->ident);
Radek Krejciefaeba32015-05-27 14:30:57 +02001433 }
1434 if (c_inc) {
1435 module->inc = calloc(c_inc, sizeof *module->inc);
Radek Krejci6793db02015-05-22 17:49:54 +02001436 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001437
1438 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1439 LY_TREE_FOR_SAFE(yin->child, next, node) {
1440 if (!strcmp(node->name, "import")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001441 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
1442 module->imp_size++;
1443
1444 if (r) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001445 goto error;
1446 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001447 } else if (!strcmp(node->name, "include")) {
1448 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
1449 module->inc_size++;
1450
1451 if (r) {
1452 goto error;
1453 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001454 } else if (!strcmp(node->name, "revision")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001455 memcpy(module->rev[module->rev_size].date,
Radek Krejcida04f4a2015-05-21 12:54:09 +02001456 lyxml_get_attr(node, "date", NULL), LY_REV_SIZE - 1);
1457 LY_TREE_FOR(node->child, child) {
1458 if (!strcmp(child->name, "description")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001459 module->rev[module->rev_size].dsc = read_yin_text(ctx, child, "description");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001460 } else if (!strcmp(child->name, "reference")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001461 module->rev[module->rev_size].ref = read_yin_text(ctx, child, "reference");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001462 }
1463 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001464 module->rev_size++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001465 } else if (!strcmp(node->name, "typedef")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001466 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
1467 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001468
1469 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001470 goto error;
1471 }
Radek Krejci6793db02015-05-22 17:49:54 +02001472 } else if (!strcmp(node->name, "identity")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001473 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
1474 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02001475
1476 if (r) {
Radek Krejci6793db02015-05-22 17:49:54 +02001477 goto error;
1478 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001479 }
1480
1481 lyxml_free_elem(ctx, node);
1482 }
1483
1484 /* last part - process data nodes */
1485 LY_TREE_FOR_SAFE(root.child, next, node) {
1486
1487 if (!strcmp(node->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001488 mnode = read_yin_container(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001489 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001490 mnode = read_yin_leaflist(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001491 } else if (!strcmp(node->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001492 mnode = read_yin_leaf(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001493 } else if (!strcmp(node->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001494 mnode = read_yin_list(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001495 } else if (!strcmp(node->name, "choice")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001496 mnode = read_yin_choice(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001497 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001498 mnode = read_yin_grouping(module, NULL, node);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001499 } else if (!strcmp(node->name, "uses")) {
1500 mnode = read_yin_uses(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001501 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001502 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001503 continue;
1504 }
1505 lyxml_free_elem(ctx, node);
1506
Radek Krejci25d782a2015-05-22 15:03:23 +02001507 if (!mnode) {
1508 goto error;
1509 }
1510
1511 /* include data element */
1512 if (module->data) {
1513 module->data->prev->next = mnode;
1514 mnode->prev = module->data->prev;
1515 module->data->prev = mnode;
1516 } else {
1517 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001518 }
1519 }
1520
Radek Krejciefaeba32015-05-27 14:30:57 +02001521 return EXIT_SUCCESS;
1522
1523error:
1524 /* cleanup */
1525 while (root.child) {
1526 lyxml_free_elem(module->ctx, root.child);
1527 }
1528
1529 return EXIT_FAILURE;
1530}
1531
1532struct ly_submodule *yin_read_submodule(struct ly_module *module, const char *data)
1533{
1534 struct lyxml_elem *yin;
1535 struct ly_submodule *submodule;
1536 const char *value;
1537
1538
1539 yin = lyxml_read(module->ctx, data, 0);
1540 if (!yin) {
1541 return NULL;
1542 }
1543
1544 /* check root element */
1545 if (!yin->name || strcmp(yin->name, "submodule")) {
1546 ly_verr(LY_VERR_UNEXP_STMT, yin->name);
1547 goto error;
1548 }
1549
1550 value = lyxml_get_attr(yin, "name", NULL);
1551 if (!value) {
1552 ly_verr(LY_VERR_MISS_ARG, "name", "submodule");
1553 goto error;
1554 }
1555
1556 submodule = calloc(1, sizeof *submodule);
1557 if (!submodule) {
1558 ly_errno = LY_EFATAL;
1559 goto error;
1560 }
1561
1562 submodule->ctx = module->ctx;
1563 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
1564
1565 LY_VRB("reading submodule %s", submodule->name);
1566 if (read_sub_module((struct ly_module *)submodule, yin, 1)) {
1567 goto error;
1568 }
1569
1570 /* cleanup */
1571 lyxml_free_elem(module->ctx, yin);
1572
1573 LY_VRB("submodule %s successfully parsed", submodule->name);
1574
1575 return submodule;
1576
1577error:
1578 /* cleanup */
1579 lyxml_free_elem(module->ctx, yin);
1580 ly_submodule_free(submodule);
1581
1582 return NULL;
1583}
1584
1585struct ly_module *yin_read_module(struct ly_ctx *ctx, const char *data)
1586{
1587 struct lyxml_elem *yin;
1588 struct ly_module *module = NULL, **newlist = NULL;
1589 const char *value;
1590 int i;
1591
1592 yin = lyxml_read(ctx, data, 0);
1593 if (!yin) {
1594 return NULL;
1595 }
1596
1597 /* check root element */
1598 if (!yin->name || strcmp(yin->name, "module")) {
1599 ly_verr(LY_VERR_UNEXP_STMT, yin->name);
1600 goto error;
1601 }
1602
1603 value = lyxml_get_attr(yin, "name", NULL);
1604 if (!value) {
1605 ly_verr(LY_VERR_MISS_ARG, "name", "module");
1606 goto error;
1607 }
1608
1609 module = calloc(1, sizeof *module);
1610 if (!module) {
1611 ly_errno = LY_EFATAL;
1612 goto error;
1613 }
1614
1615 module->ctx = ctx;
1616 module->name = lydict_insert(ctx, value, strlen(value));
1617
1618 LY_VRB("reading module %s", module->name);
1619 if (read_sub_module(module, yin, 0)) {
1620 goto error;
1621 }
1622
Radek Krejcida04f4a2015-05-21 12:54:09 +02001623 /* add to the context's list of modules */
1624 if (ctx->models.used == ctx->models.size) {
1625 newlist = realloc(ctx->models.list, ctx->models.size * 2);
1626 if (!newlist) {
1627 LY_ERR(LY_EFATAL, NULL);
1628 goto error;
1629 }
1630 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
1631 newlist[i] = NULL;
1632 }
1633 ctx->models.size *= 2;
1634 ctx->models.list = newlist;
1635 }
Radek Krejcif6e5e182015-05-27 17:18:07 +02001636 for (i = 0; ctx->models.list[i]; i++) {
1637 /* check name (name/revision) uniqueness */
1638 if (!strcmp(ctx->models.list[i]->name, module->name)) {
1639 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
1640 /* both data models are same, with no revision specified */
1641 LY_ERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.", module->name);
1642 goto error;
1643 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
1644 /* one of the models does not have a revision, so they differs */
1645 continue;
1646 } else {
1647 /* both models have a revision statement which we have to
1648 * compare, revision at position 0 is the last revision
1649 */
1650 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
1651 /* we have the same modules */
1652 LY_ERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name, module->rev[0].date);
1653 goto error;
1654 }
1655 }
1656 }
1657 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001658 ctx->models.list[i] = module;
1659 ctx->models.used++;
1660
1661 /* cleanup */
1662 lyxml_free_elem(ctx, yin);
1663
1664 LY_VRB("module %s successfully parsed", module->name);
1665
1666 return module;
1667
1668error:
1669 /* cleanup */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001670 lyxml_free_elem(ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02001671 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001672
1673 return NULL;
1674}