blob: f50b9d578fed8a504c28a90300b6b79e52c42c24 [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
28#include "libyang.h"
29#include "common.h"
30#include "context.h"
31#include "dict.h"
32#include "yin.h"
33
34#include "tree_internal.h"
35#include "xml.h"
36
Radek Krejci25d782a2015-05-22 15:03:23 +020037static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int );
Radek Krejcida04f4a2015-05-21 12:54:09 +020038static struct ly_mnode *read_yin_choice(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
39static struct ly_mnode *read_yin_container(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
40static struct ly_mnode *read_yin_leaf(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
41static struct ly_mnode *read_yin_leaflist(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
42static struct ly_mnode *read_yin_list(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
43static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
44
45static char *read_yin_text(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
46{
47 char *value;
48
49 /* there should be <text> child */
50 if (!node->child || !node->child->name
51 || strcmp(node->child->name, "text")) {
52 LY_WRN("Expected \"text\" element in \"%s\" element.", name);
53 } else {
54 value = node->child->content;
55 if (value) {
56 return lydict_insert(ctx, value, strlen(value));
57 }
58 }
59 return NULL;
60}
61
62static struct ly_tpdf *find_superior_type(const char *name,
63 struct ly_module *module,
64 struct ly_mnode *parent)
65{
66 int i, found = 0;
67 int prefix_len = 0;
68 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +020069 struct ly_tpdf *tpdf;
70 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +020071
72 qname = strchr(name, ':');
73
74 if (!qname) {
75 /* no prefix, try built-in types */
76 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
77 if (!strcmp(ly_types[i].def->name, name)) {
78 return ly_types[i].def;
79 }
80 }
81 qname = name;
82 } else {
83 /* set qname to correct position after colon */
84 prefix_len = qname - name;
85 qname++;
86
87 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
88 /* prefix refers to the current module, ignore it */
89 prefix_len = 0;
90 }
91 }
92
93 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +020094 /* search in local typedefs */
95 while (parent) {
96 switch (parent->nodetype) {
97 case LY_NODE_CONTAINER:
98 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
99 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
100 break;
101 case LY_NODE_LIST:
102 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
103 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
104 break;
105 case LY_NODE_GROUPING:
106 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
107 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
108 break;
109 default:
110 parent = parent->parent;
111 continue;
112 }
113
114 for (i = 0; i < tpdf_size; i++) {
115 if (!strcmp(tpdf[i].name, qname)) {
116 return &tpdf[i];
117 }
118 }
119
120 parent = parent->parent;
121 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200122 } else if (prefix_len) {
123 /* get module where to search */
124 for (i = 0; i < module->imp_size; i++) {
125 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
126 module = module->imp[i].module;
127 found = 1;
128 break;
129 }
130 }
131 if (!found) {
132 /* TODO - syntax error */
133 return NULL;
134 }
135 }
136
137 /* search in top level typedefs */
138 for (i = 0; i < module->tpdf_size; i++) {
139 if (!strcmp(module->tpdf[i].name, qname)) {
140 return &module->tpdf[i];
141 }
142 }
143
144 return NULL;
145}
146
147static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
148 struct lyxml_elem *yin, struct ly_type *type)
149{
Radek Krejci25d782a2015-05-22 15:03:23 +0200150 const char *value, *delim;
151 struct lyxml_elem *next, *node, root = {0};
152 int i, j, r;
153 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200154
155 value = lyxml_get_attr(yin, "name", NULL);
Radek Krejci25d782a2015-05-22 15:03:23 +0200156 delim = strchr(value, ':');
157 if (delim) {
158 type->prefix = lydict_insert(module->ctx, value, delim - value);
159 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200160 type->der = find_superior_type(value, module, parent);
Radek Krejci25d782a2015-05-22 15:03:23 +0200161 /* TODO error */
162 type->base = type->der->type.base;
163
164 switch (type->base) {
165 case LY_TYPE_BINARY:
166 /* length, 9.4.4
167 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
168 */
169 break;
170 case LY_TYPE_BITS:
171 /* bit, 9.7.4
172 * 1..n, nerekurzivni, stringy s podelementy */
173 break;
174 case LY_TYPE_DEC64:
175 /* fraction-digits, 9.3.4
176 * - MUST, 1, nerekurzivni, hodnota 1-18 */
177 /* range, 9.2.4
178 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
179 break;
180 case LY_TYPE_ENUM:
181 /* RFC 6020 9.6.4 */
182 if (type->der->module) {
183 ly_verr(LY_VERR_BAD_RESTR, "enum");
184 goto error;
185 }
186 /* get enum specification, at least one must be present */
187 LY_TREE_FOR_SAFE(yin->child, next, node) {
188 if (!strcmp(node->name, "enum")) {
189 lyxml_unlink_elem(node);
190 lyxml_add_child(&root, node);
191 type->info.enums.count++;
192 }
193 }
194 if (yin->child) {
195 ly_verr(LY_VERR_UNEXP_STMT, yin->child->name);
196 goto error;
197 }
198 if (!type->info.enums.count) {
199 if (type->der->type.der) {
200 /* this is just a derived type with no enum specified */
201 break;
202 }
203 ly_verr(LY_VERR_MISS_STMT2, "enum", "type");
204 goto error;
205 }
206
207 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
208 for (i = v = 0; root.child; i++) {
209 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0);
210 if (r) {
211 type->info.enums.count = i + 1;
212 goto error;
213 }
214 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
215 value = type->info.enums.list[i].name;
216 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
217 ly_verr(LY_VERR_ENUM_WS, value);
218 type->info.enums.count = i + 1;
219 goto error;
220 }
221
222 /* check the name uniqueness */
223 for (j = 0; j < i; j++) {
224 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
225 ly_verr(LY_VERR_ENUM_DUP_NAME, type->info.enums.list[i].name);
226 type->info.enums.count = i + 1;
227 goto error;
228 }
229 }
230
231 node = root.child->child;
232 if (node && !strcmp(node->name, "value")) {
233 value = lyxml_get_attr(node, "value", NULL);
234 v_ = strtol(value, NULL, 10);
235
236 /* range check */
237 if (v_ < INT32_MIN || v_ > INT32_MAX) {
238 ly_verr(LY_VERR_UNEXP_VAL, value, "enum/value");
239 type->info.enums.count = i + 1;
240 goto error;
241 }
242 type->info.enums.list[i].value = v_;
243
244 /* keep the highest enum value for automatic increment */
245 if (type->info.enums.list[i].value > v) {
246 v = type->info.enums.list[i].value;
247 v++;
248 } else {
249 /* check that the value is unique */
250 for (j = 0; j < i; j++) {
251 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
252 ly_verr(LY_VERR_ENUM_DUP_VAL, type->info.enums.list[i].value, type->info.enums.list[i].name);
253 type->info.enums.count = i + 1;
254 goto error;
255 }
256 }
257 }
258 } else {
259 /* assign value automatically */
260 if (v > INT32_MAX) {
261 ly_verr(LY_VERR_UNEXP_VAL, "2147483648", "enum/value");
262 type->info.enums.count = i + 1;
263 goto error;
264 }
265 type->info.enums.list[i].value = v;
266 v++;
267 }
268 lyxml_free_elem(module->ctx, root.child);
269 }
270 break;
271 case LY_TYPE_IDENT:
272 /* base, 9.10.2
273 * - 1, nerekurzivni. string */
274 break;
275 case LY_TYPE_INST:
276 /* require-instance, 9.13.2
277 * - 0..1, true/false */
278 break;
279 case LY_TYPE_INT8:
280 case LY_TYPE_INT16:
281 case LY_TYPE_INT32:
282 case LY_TYPE_INT64:
283 case LY_TYPE_UINT8:
284 case LY_TYPE_UINT16:
285 case LY_TYPE_UINT32:
286 case LY_TYPE_UINT64:
287 /* range, 9.2.4
288 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
289 break;
290 case LY_TYPE_LEAFREF:
291 /* path, 9.9.2
292 * - 1, nerekurzivni, string */
293 break;
294 case LY_TYPE_STRING:
295 /* length, 9.4.4
296 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
297 * pattern, 9.4.6
298 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
299 break;
300 case LY_TYPE_UNION:
301 /* type, 7.4
302 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
303 break;
304 default:
305 /* nothing needed :
306 * LY_TYPE_BOOL, LY_TYPE_EMPTY
307 */
308 break;
309 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200310
311 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200312
313error:
314
315 while(root.child) {
316 lyxml_free_elem(module->ctx, root.child);
317 }
318
319 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200320}
321
322static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
323 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
324{
325 const char *value;
326 struct lyxml_elem *node, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +0200327 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200328
329 value = lyxml_get_attr(yin, "name", NULL);
330 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
331
332 LY_TREE_FOR_SAFE(yin->child, next, node) {
333 if (!strcmp(node->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200334 r = fill_yin_type(module, parent, node, &tpdf->type);
335
Radek Krejcida04f4a2015-05-21 12:54:09 +0200336 /* optional statements */
337 } else if (!strcmp(node->name, "description")) {
338 tpdf->dsc = read_yin_text(module->ctx, node, "description");
Radek Krejci25d782a2015-05-22 15:03:23 +0200339 if (!tpdf->dsc) {
340 r = 1;
341 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200342 } else if (!strcmp(node->name, "reference")) {
343 tpdf->ref = read_yin_text(module->ctx, node, "reference");
Radek Krejci25d782a2015-05-22 15:03:23 +0200344 if (!tpdf->dsc) {
345 r = 1;
346 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200347 } else if (!strcmp(node->name, "status")) {
348 value = lyxml_get_attr(node, "value", NULL);
349 if (!strcmp(value, "current")) {
350 tpdf->flags |= LY_NODE_STATUS_CURR;
351 } else if (!strcmp(value, "deprecated")) {
352 tpdf->flags |= LY_NODE_STATUS_DEPRC;
353 } else if (!strcmp(value, "obsolete")) {
354 tpdf->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejci25d782a2015-05-22 15:03:23 +0200355 } else {
356 ly_verr(LY_VERR_UNEXP_VAL, value, "status");
357 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200358 }
359 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200360 lyxml_free_elem(module->ctx, node);
361 if (r) {
362 return EXIT_FAILURE;
363 }
364 }
365
366 if (!tpdf->type.der) {
367 ly_verr(LY_VERR_MISS_STMT2, "type", "typedef");
368 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200369 }
370
371 return EXIT_SUCCESS;
372}
373
374/*
375 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200376 * description, reference, status, optionaly config
Radek Krejcida04f4a2015-05-21 12:54:09 +0200377 */
378static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejci25d782a2015-05-22 15:03:23 +0200379 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int ext)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200380{
381 const char *value;
382 struct lyxml_elem *sub, *next;
383 struct ly_ctx * const ctx = module->ctx;
384
Radek Krejci25d782a2015-05-22 15:03:23 +0200385 if (ext) {
386 mnode->module = module;
387 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200388
389 value = lyxml_get_attr(xmlnode, "name", NULL);
390 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci25d782a2015-05-22 15:03:23 +0200391 if (!mnode->name || !mnode->name[0]) {
392 ly_verr(LY_VERR_MISS_ARG, "name", xmlnode->name);
393 return EXIT_FAILURE;
394 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200395
396 /* process local parameters */
397 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
398 if (!strcmp(sub->name, "description")) {
399 mnode->dsc = read_yin_text(ctx, sub, "description");
400 } else if (!strcmp(sub->name, "reference")) {
401 mnode->ref = read_yin_text(ctx, sub, "reference");
Radek Krejcida04f4a2015-05-21 12:54:09 +0200402 } else if (!strcmp(sub->name, "status")) {
403 value = lyxml_get_attr(sub, "value", NULL);
404 if (!strcmp(value, "current")) {
405 mnode->flags |= LY_NODE_STATUS_CURR;
406 } else if (!strcmp(value, "deprecated")) {
407 mnode->flags |= LY_NODE_STATUS_DEPRC;
408 } else if (!strcmp(value, "obsolete")) {
409 mnode->flags |= LY_NODE_STATUS_OBSLT;
410 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200411 } else if (ext && !strcmp(sub->name, "config")) {
412 value = lyxml_get_attr(sub, "value", NULL);
413 if (!strcmp(value, "false")) {
414 mnode->flags |= LY_NODE_CONFIG_R;
415 } else if (!strcmp(value, "false")) {
416 mnode->flags |= LY_NODE_CONFIG_W;
417 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200418 } else {
419 /* skip the lyxml_free_elem */
420 continue;
421 }
422 lyxml_free_elem(ctx, sub);
423 }
424
Radek Krejci25d782a2015-05-22 15:03:23 +0200425 if (ext && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200426 /* get config flag from parent */
427 if (parent) {
428 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
429 } else {
430 /* default config is true */
431 mnode->flags |= LY_NODE_CONFIG_W;
432 }
433 }
434
435 return EXIT_SUCCESS;
436}
437
438static struct ly_mnode *read_yin_choice(struct ly_module *module,
439 struct ly_mnode *parent,
440 struct lyxml_elem *node)
441{
442 struct lyxml_elem *sub, *next;
443 struct ly_ctx * const ctx = module->ctx;
Radek Krejci25d782a2015-05-22 15:03:23 +0200444 struct ly_mnode *retval, *r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200445 struct ly_mnode_choice *choice;
446
447 if (!module || !node) {
448 ly_errno = LY_EINVAL;
449 return NULL;
450 }
451
452 choice = calloc(1, sizeof *choice);
453 choice->nodetype = LY_NODE_CHOICE;
454 choice->module = module;
455 choice->prev = (struct ly_mnode *)choice;
456 retval = (struct ly_mnode *)choice;
457
Radek Krejci25d782a2015-05-22 15:03:23 +0200458 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200459 goto error;
460 }
461
462 /* process choice's specific children */
463 LY_TREE_FOR_SAFE(node->child, next, sub) {
464 if (!strcmp(sub->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200465 r = read_yin_container(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200466 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200467 r = read_yin_leaflist(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200468 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200469 r = read_yin_leaf(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200470 } else if (!strcmp(sub->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200471 r = read_yin_list(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200472 }
473 lyxml_free_elem(ctx, sub);
Radek Krejci25d782a2015-05-22 15:03:23 +0200474 if (!r) {
475 goto error;
476 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200477 }
478
479 ly_mnode_addchild(parent, retval);
480
481 return retval;
482
483error:
484
485 ly_mnode_free(retval);
486
487 return NULL;
488}
489
490static struct ly_mnode *read_yin_leaf(struct ly_module *module,
491 struct ly_mnode *parent,
492 struct lyxml_elem *node)
493{
494 struct ly_mnode *retval;
495 struct ly_mnode_leaf *leaf;
496 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +0200497 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200498
499 if (!module || !node) {
500 ly_errno = LY_EINVAL;
501 return NULL;
502 }
503
504 leaf = calloc(1, sizeof *leaf);
505 leaf->nodetype = LY_NODE_LEAF;
506 leaf->prev = (struct ly_mnode *)leaf;
507 retval = (struct ly_mnode *)leaf;
508
Radek Krejci25d782a2015-05-22 15:03:23 +0200509 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200510 goto error;
511 }
512
513 LY_TREE_FOR_SAFE(node->child, next, sub) {
514 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200515 r = fill_yin_type(module, parent, sub, &leaf->type);
516 if (r) {
517 goto error;
518 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200519 }
520 }
521
522 ly_mnode_addchild(parent, retval);
523
524 return retval;
525
526error:
527
528 ly_mnode_free(retval);
529
530 return NULL;
531}
532
533static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
534 struct ly_mnode *parent,
535 struct lyxml_elem *node)
536{
537 struct ly_mnode *retval;
538 struct ly_mnode_leaflist *llist;
539 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +0200540 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200541
542 if (!module || !node) {
543 ly_errno = LY_EINVAL;
544 return NULL;
545 }
546
547 llist = calloc(1, sizeof *llist);
548 llist->nodetype = LY_NODE_LEAFLIST;
549 llist->prev = (struct ly_mnode *)llist;
550 retval = (struct ly_mnode *)llist;
551
Radek Krejci25d782a2015-05-22 15:03:23 +0200552 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200553 goto error;
554 }
555
556 LY_TREE_FOR_SAFE(node->child, next, sub) {
557 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200558 r = fill_yin_type(module, parent, sub, &llist->type);
559 if (r) {
560 goto error;
561 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200562 }
563 }
564
565 ly_mnode_addchild(parent, retval);
566
567 return retval;
568
569error:
570
571 ly_mnode_free(retval);
572
573 return NULL;
574}
575
576static struct ly_mnode *read_yin_list(struct ly_module *module,
577 struct ly_mnode *parent,
578 struct lyxml_elem *node)
579{
580 struct ly_mnode *retval, *mnode;
581 struct ly_mnode_list *list;
582 struct lyxml_elem *sub, *next, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +0200583 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200584 int c_tpdf = 0;
585
586 if (!module || !node) {
587 ly_errno = LY_EINVAL;
588 return NULL;
589 }
590
591 list = calloc(1, sizeof *list);
592 list->nodetype = LY_NODE_LIST;
593 list->prev = (struct ly_mnode *)list;
594 retval = (struct ly_mnode *)list;
595
Radek Krejci25d782a2015-05-22 15:03:23 +0200596 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200597 goto error;
598 }
599
600 /* process list's specific children */
601 LY_TREE_FOR_SAFE(node->child, next, sub) {
602 /* data statements */
603 if (!strcmp(sub->name, "container") ||
604 !strcmp(sub->name, "leaf-list") ||
605 !strcmp(sub->name, "leaf") ||
606 !strcmp(sub->name, "list") ||
607 !strcmp(sub->name, "choice") ||
608 !strcmp(sub->name, "grouping")) {
609 lyxml_unlink_elem(sub);
610 lyxml_add_child(&root, sub);
611
612 /* array counters */
613 } else if (!strcmp(sub->name, "typedef")) {
614 c_tpdf++;
615 }
616 }
617
618 /* middle part - process nodes with cardinality of 0..n except the data nodes */
619 if (c_tpdf) {
620 list->tpdf_size = c_tpdf;
621 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
622 c_tpdf = 0;
623 }
624 LY_TREE_FOR_SAFE(node->child, next, sub) {
625 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200626 r = fill_yin_typedef(module, retval, sub, &list->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200627 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +0200628
629 if (r) {
630 list->tpdf_size = c_tpdf;
631 goto error;
632 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200633 }
634
635 lyxml_free_elem(module->ctx, sub);
636 }
637
638 /* last part - process data nodes */
639 LY_TREE_FOR_SAFE(root.child, next, sub) {
640 if (!strcmp(sub->name, "container")) {
641 mnode = read_yin_container(module, retval, sub);
642 } else if (!strcmp(sub->name, "leaf-list")) {
643 mnode = read_yin_leaflist(module, retval, sub);
644 } else if (!strcmp(sub->name, "leaf")) {
645 mnode = read_yin_leaf(module, retval, sub);
646 } else if (!strcmp(sub->name, "list")) {
647 mnode = read_yin_list(module, retval, sub);
648 } else if (!strcmp(sub->name, "choice")) {
649 mnode = read_yin_choice(module, retval, sub);
650 } else if (!strcmp(sub->name, "grouping")) {
651 mnode = read_yin_grouping(module, retval, sub);
652 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +0200653 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +0200654 continue;
655 }
656 lyxml_free_elem(module->ctx, sub);
657
Radek Krejci25d782a2015-05-22 15:03:23 +0200658 if (!mnode) {
659 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200660 }
661 }
662
663 ly_mnode_addchild(parent, retval);
664
665 return retval;
666
667error:
668
669 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +0200670 while(root.child) {
671 lyxml_free_elem(module->ctx, root.child);
672 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200673
674 return NULL;
675}
676
677static struct ly_mnode *read_yin_container(struct ly_module *module,
678 struct ly_mnode *parent,
679 struct lyxml_elem *node)
680{
681 struct lyxml_elem *sub, *next, root = {0};
682 struct ly_mnode *mnode = NULL;
683 struct ly_mnode *retval;
684 struct ly_mnode_container *cont;
Radek Krejci25d782a2015-05-22 15:03:23 +0200685 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200686 int c_tpdf = 0;
687
688 if (!module || !node) {
689 ly_errno = LY_EINVAL;
690 return NULL;
691 }
692
693 cont = calloc(1, sizeof *cont);
694 cont->nodetype = LY_NODE_CONTAINER;
695 cont->prev = (struct ly_mnode *)cont;
696 retval = (struct ly_mnode *)cont;
697
Radek Krejci25d782a2015-05-22 15:03:23 +0200698 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200699 goto error;
700 }
701
702 /* process container's specific children */
703 LY_TREE_FOR_SAFE(node->child, next, sub) {
704 /* data statements */
705 if (!strcmp(sub->name, "container") ||
706 !strcmp(sub->name, "leaf-list") ||
707 !strcmp(sub->name, "leaf") ||
708 !strcmp(sub->name, "list") ||
709 !strcmp(sub->name, "choice") ||
710 !strcmp(sub->name, "grouping")) {
711 lyxml_unlink_elem(sub);
712 lyxml_add_child(&root, sub);
713
714 /* array counters */
715 } else if (!strcmp(sub->name, "typedef")) {
716 c_tpdf++;
717 }
718 }
719
720 /* middle part - process nodes with cardinality of 0..n except the data nodes */
721 if (c_tpdf) {
722 cont->tpdf_size = c_tpdf;
723 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
724 c_tpdf = 0;
725 }
726 LY_TREE_FOR_SAFE(node->child, next, sub) {
727 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200728 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200729 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +0200730
731 if (r) {
732 cont->tpdf_size = c_tpdf;
733 goto error;
734 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200735 }
736
737 lyxml_free_elem(module->ctx, sub);
738 }
739
740 /* last part - process data nodes */
741 LY_TREE_FOR_SAFE(root.child, next, sub) {
742 if (!strcmp(sub->name, "container")) {
743 mnode = read_yin_container(module, retval, sub);
744 } else if (!strcmp(sub->name, "leaf-list")) {
745 mnode = read_yin_leaflist(module, retval, sub);
746 } else if (!strcmp(sub->name, "leaf")) {
747 mnode = read_yin_leaf(module, retval, sub);
748 } else if (!strcmp(sub->name, "list")) {
749 mnode = read_yin_list(module, retval, sub);
750 } else if (!strcmp(sub->name, "choice")) {
751 mnode = read_yin_choice(module, retval, sub);
752 } else if (!strcmp(sub->name, "grouping")) {
753 mnode = read_yin_grouping(module, retval, sub);
754 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +0200755 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +0200756 continue;
757 }
758 lyxml_free_elem(module->ctx, sub);
759
Radek Krejci25d782a2015-05-22 15:03:23 +0200760 if (!mnode) {
761 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200762 }
763 }
764
765 ly_mnode_addchild(parent, retval);
766
767 return retval;
768
769error:
770
771 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +0200772 while (root.child) {
773 lyxml_free_elem(module->ctx, root.child);
774 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200775
776 return NULL;
777}
778
779static struct ly_mnode *read_yin_grouping(struct ly_module *module,
780 struct ly_mnode *parent,
781 struct lyxml_elem *node)
782{
783 struct lyxml_elem *sub, *next, root = {0};
784 struct ly_mnode *mnode = NULL;
785 struct ly_mnode *retval;
786 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +0200787 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200788 int c_tpdf = 0;
789
790 grp = calloc(1, sizeof *grp);
791 grp->nodetype = LY_NODE_GROUPING;
792 grp->module = module;
793 grp->prev = (struct ly_mnode *)grp;
794 retval = (struct ly_mnode *)grp;
795
Radek Krejci25d782a2015-05-22 15:03:23 +0200796 if (read_yin_common(module, parent, retval, node, 0)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200797 goto error;
798 }
799
800 LY_TREE_FOR_SAFE(node->child, next, sub) {
801 /* data statements */
802 if (!strcmp(sub->name, "container") ||
803 !strcmp(sub->name, "leaf-list") ||
804 !strcmp(sub->name, "leaf") ||
805 !strcmp(sub->name, "list") ||
806 !strcmp(sub->name, "choice") ||
807 !strcmp(sub->name, "grouping")) {
808 lyxml_unlink_elem(sub);
809 lyxml_add_child(&root, sub);
810
811 /* array counters */
812 } else if (!strcmp(sub->name, "typedef")) {
813 c_tpdf++;
814 }
815 }
816
817 /* middle part - process nodes with cardinality of 0..n except the data nodes */
818 if (c_tpdf) {
819 grp->tpdf_size = c_tpdf;
820 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
821 c_tpdf = 0;
822 }
823 LY_TREE_FOR_SAFE(node->child, next, sub) {
824 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200825 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200826 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +0200827
828 if (r) {
829 grp->tpdf_size = c_tpdf;
830 goto error;
831 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200832 }
833
834 lyxml_free_elem(module->ctx, sub);
835 }
836
837 /* last part - process data nodes */
838 LY_TREE_FOR_SAFE(root.child, next, sub) {
839 if (!strcmp(sub->name, "container")) {
840 mnode = read_yin_container(module, retval, sub);
841 } else if (!strcmp(sub->name, "leaf-list")) {
842 mnode = read_yin_leaflist(module, retval, sub);
843 } else if (!strcmp(sub->name, "leaf")) {
844 mnode = read_yin_leaf(module, retval, sub);
845 } else if (!strcmp(sub->name, "list")) {
846 mnode = read_yin_list(module, retval, sub);
847 } else if (!strcmp(sub->name, "choice")) {
848 mnode = read_yin_choice(module, retval, sub);
849 } else if (!strcmp(sub->name, "grouping")) {
850 mnode = read_yin_grouping(module, retval, sub);
851 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +0200852 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +0200853 continue;
854 }
855 lyxml_free_elem(module->ctx, sub);
856
Radek Krejci25d782a2015-05-22 15:03:23 +0200857 if (!mnode) {
858 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200859 }
860 }
861
862 ly_mnode_addchild(parent, retval);
863
864 return retval;
865
866error:
867
868 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +0200869 while (root.child) {
870 lyxml_free_elem(module->ctx, root.child);
871 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200872
873 return NULL;
874}
875
876struct ly_module *ly_read_yin(struct ly_ctx *ctx, const char *data)
877{
878 struct lyxml_elem *yin, *node, *next, *child, root = {0};
879 struct ly_module *module = NULL, **newlist = NULL, *imp;
Radek Krejci25d782a2015-05-22 15:03:23 +0200880 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200881 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +0200882 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200883 int i;
884 /* counters */
885 int c_imp = 0, c_rev = 0, c_tpdf = 0;
886
887 yin = lyxml_read(ctx, data, 0);
888 if (!yin) {
889 return NULL;
890 }
891
892 /* check root element */
893 if (!yin->name || strcmp(yin->name, "module")) {
894 /* TODO: support submodules */
Radek Krejcibb3257d2015-05-21 23:03:51 +0200895 ly_verr(LY_VERR_UNEXP_STMT, yin->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200896 goto error;
897 }
898
899 value = lyxml_get_attr(yin, "name", NULL);
900 if (!value) {
901 LY_ERR(LY_EVALID, "Missing \"name\" attribute of the \"module\".");
902 goto error;
903 }
904
905 module = calloc(1, sizeof *module);
906 if (!module) {
907 ly_errno = LY_EFATAL;
908 goto error;
909 }
910
911 module->ctx = ctx;
912 module->name = lydict_insert(ctx, value, strlen(value));
913
914 LY_VRB("reading module %s", module->name);
915
916 /*
917 * in the first run, we process elements with cardinality of 1 or 0..1 and
918 * count elements with cardinality 0..n. Data elements (choices, containers,
919 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
920 * need have all top-level and groupings already prepared at that time. In
921 * the middle loop, we process other elements with carinality of 0..n since
922 * we need to allocate arrays to store them.
923 */
924 LY_TREE_FOR_SAFE(yin->child, next, node) {
925 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
926 lyxml_free_elem(ctx, node);
927 continue;
928 }
929
930 if (!strcmp(node->name, "namespace")) {
931 value = lyxml_get_attr(node, "uri", NULL);
932 if (!value) {
933 LY_ERR(LY_EVALID,
934 "%s: Missing \"uri\" attribute in \"namespace\" element.", module->name);
935 goto error;
936 }
937 module->ns = lydict_insert(ctx, value, strlen(value));
938 lyxml_free_elem(ctx, node);
939 } else if (!strcmp(node->name, "prefix")) {
940 value = lyxml_get_attr(node, "value", NULL);
941 if (!value) {
942 LY_ERR(LY_EVALID,
943 "%s: Missing \"value\" attribute in \"prefix\" element.", module->name);
944 goto error;
945 }
946 module->prefix = lydict_insert(ctx, value, strlen(value));
947 lyxml_free_elem(ctx, node);
948 } else if (!strcmp(node->name, "import")) {
949 c_imp++;
950 } else if (!strcmp(node->name, "revision")) {
951 c_rev++;
952 } else if (!strcmp(node->name, "typedef")) {
953 c_tpdf++;
954
955 /* data statements */
956 } else if (!strcmp(node->name, "container") ||
957 !strcmp(node->name, "leaf-list") ||
958 !strcmp(node->name, "leaf") ||
959 !strcmp(node->name, "list") ||
960 !strcmp(node->name, "choice") ||
961 !strcmp(node->name, "grouping")) {
962 lyxml_unlink_elem(node);
963 lyxml_add_child(&root, node);
964
965 /* optional statements */
966 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +0200967 if (module->dsc) {
968 ly_verr(LY_VERR_TOOMANY, "description", "module");
969 goto error;
970 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200971 module->dsc = read_yin_text(ctx, node, "description");
972 lyxml_free_elem(ctx, node);
973 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +0200974 if (module->ref) {
975 ly_verr(LY_VERR_TOOMANY, "reference", "module");
976 goto error;
977 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200978 module->ref = read_yin_text(ctx, node, "reference");
979 lyxml_free_elem(ctx, node);
980 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +0200981 if (module->org) {
982 ly_verr(LY_VERR_TOOMANY, "organization", "module");
983 goto error;
984 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200985 module->org = read_yin_text(ctx, node, "organization");
986 lyxml_free_elem(ctx, node);
987 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +0200988 if (module->contact) {
989 ly_verr(LY_VERR_TOOMANY, "contact", "module");
990 goto error;
991 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200992 module->contact = read_yin_text(ctx, node, "contact");
993 lyxml_free_elem(ctx, node);
994 } else if (!strcmp(node->name, "yang-version")) {
995 /* TODO: support YANG 1.1 */
Radek Krejcib0594bf2015-05-21 23:51:27 +0200996 if (module->version) {
997 ly_verr(LY_VERR_TOOMANY, "yang-version", "module");
Radek Krejcida04f4a2015-05-21 12:54:09 +0200998 goto error;
999 }
Radek Krejcib0594bf2015-05-21 23:51:27 +02001000 value = lyxml_get_attr(node, "value", NULL);
1001 if (strcmp(value, "1")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001002 ly_verr(LY_VERR_UNEXP_VAL, value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02001003 goto error;
1004 }
1005 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001006 lyxml_free_elem(ctx, node);
1007 }
1008 }
1009
Radek Krejcibb3257d2015-05-21 23:03:51 +02001010 /* check for mandatory statements */
1011 if (!module->ns) {
1012 ly_verr(LY_VERR_MISS_STMT2, "namespace", "module");
1013 goto error;
1014 }
1015 if (!module->prefix) {
1016 ly_verr(LY_VERR_MISS_STMT2, "prefix", "module");
1017 goto error;
1018 }
1019
1020
Radek Krejcida04f4a2015-05-21 12:54:09 +02001021 /* allocate arrays for elements with cardinality of 0..n */
1022 if (c_imp) {
1023 module->imp_size = c_imp;
1024 module->imp = calloc(c_imp, sizeof *module->imp);
1025 c_imp = 0;
1026 }
1027 if (c_rev) {
1028 module->rev_size = c_rev;
1029 module->rev = calloc(c_rev, sizeof *module->rev);
1030 c_rev = 0;
1031 }
1032 if (c_tpdf) {
1033 module->tpdf_size = c_tpdf;
1034 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
1035 c_tpdf = 0;
1036 }
1037
1038 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1039 LY_TREE_FOR_SAFE(yin->child, next, node) {
1040 if (!strcmp(node->name, "import")) {
1041 LY_TREE_FOR(node->child, child) {
1042 if (!strcmp(child->name, "prefix")) {
1043 value = lyxml_get_attr(child, "value", NULL);
1044 module->imp[c_imp].prefix = lydict_insert(ctx, value, strlen(value));
1045 } else if (!strcmp(child->name, "revision-date")) {
1046 value = lyxml_get_attr(child, "date", NULL);
1047 memcpy(module->imp[c_imp].rev,
1048 lyxml_get_attr(child, "date", NULL),
1049 LY_REV_SIZE - 1);
1050 }
1051 }
1052 value = lyxml_get_attr(node, "module", NULL);
1053 imp = ly_ctx_get_model(ctx, value, module->imp[c_imp].rev[0] ? module->imp[c_imp].rev : NULL);
1054 if (!imp) {
1055 LY_ERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
1056 value, module->name);
1057 goto error;
1058 }
1059 module->imp[c_imp].module = imp;
1060 c_imp++;
1061 } else if (!strcmp(node->name, "revision")) {
1062 memcpy(module->rev[c_rev].date,
1063 lyxml_get_attr(node, "date", NULL), LY_REV_SIZE - 1);
1064 LY_TREE_FOR(node->child, child) {
1065 if (!strcmp(child->name, "description")) {
1066 module->rev[c_rev].dsc = read_yin_text(ctx, child, "description");
1067 } else if (!strcmp(child->name, "reference")) {
1068 module->rev[c_rev].ref = read_yin_text(ctx, child, "reference");
1069 }
1070 }
1071 c_rev++;
1072 } else if (!strcmp(node->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001073 r = fill_yin_typedef(module, NULL, node, &module->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001074 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001075
1076 if (r) {
1077 module->tpdf_size = c_tpdf;
1078 goto error;
1079 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001080 }
1081
1082 lyxml_free_elem(ctx, node);
1083 }
1084
1085 /* last part - process data nodes */
1086 LY_TREE_FOR_SAFE(root.child, next, node) {
1087
1088 if (!strcmp(node->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001089 mnode = read_yin_container(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001090 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001091 mnode = read_yin_leaflist(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001092 } else if (!strcmp(node->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001093 mnode = read_yin_leaf(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001094 } else if (!strcmp(node->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001095 mnode = read_yin_list(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001096 } else if (!strcmp(node->name, "choice")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001097 mnode = read_yin_choice(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001098 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001099 mnode = read_yin_grouping(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001100 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001101 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001102 continue;
1103 }
1104 lyxml_free_elem(ctx, node);
1105
Radek Krejci25d782a2015-05-22 15:03:23 +02001106 if (!mnode) {
1107 goto error;
1108 }
1109
1110 /* include data element */
1111 if (module->data) {
1112 module->data->prev->next = mnode;
1113 mnode->prev = module->data->prev;
1114 module->data->prev = mnode;
1115 } else {
1116 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001117 }
1118 }
1119
1120 /* add to the context's list of modules */
1121 if (ctx->models.used == ctx->models.size) {
1122 newlist = realloc(ctx->models.list, ctx->models.size * 2);
1123 if (!newlist) {
1124 LY_ERR(LY_EFATAL, NULL);
1125 goto error;
1126 }
1127 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
1128 newlist[i] = NULL;
1129 }
1130 ctx->models.size *= 2;
1131 ctx->models.list = newlist;
1132 }
1133 for (i = 0; ctx->models.list[i]; i++);
1134 ctx->models.list[i] = module;
1135 ctx->models.used++;
1136
1137 /* cleanup */
1138 lyxml_free_elem(ctx, yin);
1139
1140 LY_VRB("module %s successfully parsed", module->name);
1141
1142 return module;
1143
1144error:
1145 /* cleanup */
Radek Krejci25d782a2015-05-22 15:03:23 +02001146 while (root.child) {
1147 lyxml_free_elem(module->ctx, root.child);
1148 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001149 lyxml_free_elem(ctx, yin);
1150 ly_model_free(module);
1151
1152 return NULL;
1153}