blob: 34663622945ce696b2c399cc08cd17a7dc7498a3 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file yin.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief YIN parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Radek Krejci812b10a2015-05-28 16:48:25 +020022#include <assert.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020023#include <ctype.h>
Radek Krejci8b4f23c2015-06-02 16:09:25 +020024#include <errno.h>
25#include <limits.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020026#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020027#include <stdlib.h>
28#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020029#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020030
Radek Krejciefdd0ce2015-05-26 16:48:29 +020031#include "../libyang.h"
32#include "../common.h"
33#include "../context.h"
34#include "../dict.h"
35#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020036
Radek Krejciefdd0ce2015-05-26 16:48:29 +020037#include "../tree_internal.h"
38#include "../xml.h"
39
Radek Krejcice7fb782015-05-29 16:52:34 +020040enum LY_IDENT {
41 LY_IDENT_FEATURE,
42 LY_IDENT_IDENTITY,
43 LY_IDENT_TYPE,
44 LY_IDENT_NODE,
Radek Krejci0af13872015-05-30 11:50:52 +020045 LY_IDENT_NAME,
Radek Krejcice7fb782015-05-29 16:52:34 +020046 LY_IDENT_PREFIX
47};
48
Radek Krejciefdd0ce2015-05-26 16:48:29 +020049#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020050
Radek Krejcice7fb782015-05-29 16:52:34 +020051#define GETVAL(value, node, arg) \
52 value = lyxml_get_attr(node, arg, NULL); \
53 if (!value) { \
54 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
55 goto error; \
56 }
57
Radek Krejci25d782a2015-05-22 15:03:23 +020058static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int );
Radek Krejcida04f4a2015-05-21 12:54:09 +020059static struct ly_mnode *read_yin_choice(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
60static struct ly_mnode *read_yin_container(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
61static struct ly_mnode *read_yin_leaf(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
62static struct ly_mnode *read_yin_leaflist(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
63static struct ly_mnode *read_yin_list(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +020064static struct ly_mnode *read_yin_uses(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcida04f4a2015-05-21 12:54:09 +020065static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
66
Radek Krejcieac35532015-05-31 19:09:15 +020067static int dup_typedef_check(const char* type, struct ly_tpdf *tpdf, int size)
68{
69 int i;
70
71 for (i = 0; i < size; i++) {
72 if (!strcmp(type, tpdf[i].name)) {
73 /* name collision */
74 return EXIT_FAILURE;
75 }
76 }
77
78 return EXIT_SUCCESS;
79}
80
Radek Krejcice7fb782015-05-29 16:52:34 +020081static int dup_prefix_check(const char* prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +020082{
Radek Krejcice7fb782015-05-29 16:52:34 +020083 int i;
84
85 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
86 return EXIT_FAILURE;
87 }
88 for (i = 0; i < module->imp_size; i++) {
89 if (!strcmp(module->imp[i].prefix, prefix)) {
90 return EXIT_FAILURE;
91 }
92 }
93
94 return EXIT_SUCCESS;
95}
96
97static int check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
98 struct ly_module *module, struct ly_mnode *parent)
99{
100 int i;
Radek Krejcieac35532015-05-31 19:09:15 +0200101 int size;
102 struct ly_tpdf *tpdf;
103
104
Radek Krejcice7fb782015-05-29 16:52:34 +0200105
106 assert(id);
107
108 /* check id syntax */
109 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
110 LOGVAL(VE_INID, line, id, "invalid start character");
111 return EXIT_FAILURE;
112 }
113 for (i = 1; id[i]; i++) {
114 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
115 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
116 LOGVAL(VE_INID, line, id, "invalid %d. character", i + 1);
117 return EXIT_FAILURE;
118 }
119 }
120
121 if (i > 64) {
122 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
123 }
124
125 switch(type) {
Radek Krejcieac35532015-05-31 19:09:15 +0200126 case LY_IDENT_TYPE:
127 assert(module);
128
129 /* check collision with the built-in types */
130 if (!strcmp(id, "binary") || !strcmp(id,"bits") ||
131 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
132 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
133 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
134 !strcmp(id, "int8") || !strcmp(id, "int16") ||
135 !strcmp(id, "int32") || !strcmp(id, "int64") ||
136 !strcmp(id, "leafref") || !strcmp(id, "string") ||
137 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
138 !strcmp(id, "uint32") || !strcmp(id, "uint64") ||
139 !strcmp(id, "union")) {
140 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
141 return EXIT_FAILURE;
142 }
143
144 /* check locally scoped typedefs (avoid name shadowing) */
145 for ( ; parent; parent = parent->parent) {
146 switch(parent->nodetype) {
147 case LY_NODE_CONTAINER:
148 size = ((struct ly_mnode_container *)parent)->tpdf_size;
149 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
150 break;
151 case LY_NODE_LIST:
152 size = ((struct ly_mnode_list *)parent)->tpdf_size;
153 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
154 break;
155 case LY_NODE_GROUPING:
156 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
157 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
158 break;
159 default:
160 continue;
161 }
162
163 if (dup_typedef_check(id, tpdf, size)) {
164 LOGVAL(VE_DUPID, line, "typedef", id);
165 return EXIT_FAILURE;
166 }
167 }
168
169 /* check top-level names */
170 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
171 LOGVAL(VE_DUPID, line, "typedef", id);
172 return EXIT_FAILURE;
173 }
174
175 /* check submodule's top-level names */
176 for (i = 0; i < module->inc_size; i++) {
177 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
178 LOGVAL(VE_DUPID, line, "typedef", id);
179 return EXIT_FAILURE;
180 }
181 }
182
183 /* check top-level names in the main module */
184 if (module->type) {
185 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
186 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
187 LOGVAL(VE_DUPID, line, "typedef", id);
188 return EXIT_FAILURE;
189 }
190 }
191
192 break;
Radek Krejcice7fb782015-05-29 16:52:34 +0200193 case LY_IDENT_PREFIX:
Radek Krejcieac35532015-05-31 19:09:15 +0200194 assert(module);
195
Radek Krejcice7fb782015-05-29 16:52:34 +0200196 if (module->type) {
197 /* go to the main module */
198 module = ((struct ly_submodule *)module)->belongsto;
199 }
200
201 /* check the main module itself */
202 if (dup_prefix_check(id, module)) {
203 LOGVAL(VE_DUPID, line, "prefix", id);
204 return EXIT_FAILURE;
205 }
206
207 /* and all its submodules */
208 for (i = 0; i < module->inc_size; i++) {
209 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
210 LOGVAL(VE_DUPID, line, "prefix", id);
211 return EXIT_FAILURE;
212 }
213 }
214 break;
215 default:
216 /* no check required */
217 break;
218 }
219
220 return EXIT_SUCCESS;
221}
222
Radek Krejci4c31f122015-06-02 14:51:22 +0200223static int check_default(struct ly_type *type, const char* value)
Radek Krejcieac35532015-05-31 19:09:15 +0200224{
225 /* TODO - RFC 6020, sec. 7.3.4 */
Radek Krejci4c31f122015-06-02 14:51:22 +0200226 (void)type;
227 (void)value;
Radek Krejcieac35532015-05-31 19:09:15 +0200228 return EXIT_SUCCESS;
229}
230
Radek Krejcice7fb782015-05-29 16:52:34 +0200231static int check_date(const char* date, unsigned int line)
232{
233 int i;
234
235 assert(date);
236
237 if (strlen(date) != LY_REV_SIZE - 1) {
238 goto error;
239 }
240
241 for (i = 0; i < LY_REV_SIZE - 1; i++) {
242 if (i == 4 || i == 7) {
243 if (date[i] != '-') {
244 goto error;
245 }
246 } else if (!isdigit(date[i])) {
247 goto error;
248 }
249 }
250
251 return EXIT_SUCCESS;
252
253error:
254
255 LOGVAL(VE_INDATE, line, date);
256 return EXIT_FAILURE;
257}
258
Radek Krejci0af13872015-05-30 11:50:52 +0200259static const char *read_yin_text(struct ly_ctx *ctx, struct lyxml_elem *node)
Radek Krejcice7fb782015-05-29 16:52:34 +0200260{
261 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200262
263 /* there should be <text> child */
264 if (!node->child || !node->child->name
265 || strcmp(node->child->name, "text")) {
Radek Krejci0af13872015-05-30 11:50:52 +0200266 LOGWRN("Expected \"text\" element in \"%s\" element.", node->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200267 } else if (node->child->content) {
268 len = strlen(node->child->content);
269 return lydict_insert(ctx, node->child->content, len);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200270 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200271
272 LOGVAL(VE_INARG, LOGLINE(node), "text", node->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200273 return NULL;
274}
275
276static struct ly_tpdf *find_superior_type(const char *name,
277 struct ly_module *module,
278 struct ly_mnode *parent)
279{
Radek Krejciefaeba32015-05-27 14:30:57 +0200280 int i, j, found = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200281 int prefix_len = 0;
282 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +0200283 struct ly_tpdf *tpdf;
284 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200285
286 qname = strchr(name, ':');
287
288 if (!qname) {
289 /* no prefix, try built-in types */
290 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
291 if (!strcmp(ly_types[i].def->name, name)) {
292 return ly_types[i].def;
293 }
294 }
295 qname = name;
296 } else {
297 /* set qname to correct position after colon */
298 prefix_len = qname - name;
299 qname++;
300
301 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
302 /* prefix refers to the current module, ignore it */
303 prefix_len = 0;
304 }
305 }
306
307 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200308 /* search in local typedefs */
309 while (parent) {
310 switch (parent->nodetype) {
311 case LY_NODE_CONTAINER:
312 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
313 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
314 break;
315 case LY_NODE_LIST:
316 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
317 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
318 break;
319 case LY_NODE_GROUPING:
320 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
321 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
322 break;
323 default:
324 parent = parent->parent;
325 continue;
326 }
327
328 for (i = 0; i < tpdf_size; i++) {
329 if (!strcmp(tpdf[i].name, qname)) {
330 return &tpdf[i];
331 }
332 }
333
334 parent = parent->parent;
335 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200336 } else if (prefix_len) {
337 /* get module where to search */
338 for (i = 0; i < module->imp_size; i++) {
339 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
340 module = module->imp[i].module;
341 found = 1;
342 break;
343 }
344 }
345 if (!found) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200346 return NULL;
347 }
348 }
349
350 /* search in top level typedefs */
351 for (i = 0; i < module->tpdf_size; i++) {
352 if (!strcmp(module->tpdf[i].name, qname)) {
353 return &module->tpdf[i];
354 }
355 }
356
Radek Krejciefaeba32015-05-27 14:30:57 +0200357 /* search in submodules */
358 for (i = 0; i < module->inc_size; i++) {
359 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
360 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
361 return &module->inc[i].submodule->tpdf[j];
362 }
363 }
364 }
365
366 return NULL;
367}
368
369static struct ly_ident *find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
370{
Radek Krejcice7fb782015-05-29 16:52:34 +0200371 unsigned int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200372 struct ly_ident *base_iter;
373 struct ly_ident_der *der;
374
375 for (i = 0; i < module->ident_size; i++) {
376 if (!strcmp(basename, module->ident[i].name)) {
377 /* we are done */
378
379 if (!ident) {
380 /* just search for type, so do not modify anything, just return
381 * the base identity pointer
382 */
383 return &module->ident[i];
384 }
385
386 /* we are resolving identity definition, so now update structures */
387 ident->base = base_iter = &module->ident[i];
388
389 while (base_iter) {
390 for (der = base_iter->der; der && der->next; der = der->next);
391 if (der) {
392 der->next = malloc(sizeof *der);
393 der = der->next;
394 } else {
395 ident->base->der = der = malloc(sizeof *der);
396 }
397 der->next = NULL;
398 der->ident = ident;
399
400 base_iter = base_iter->base;
401 }
402 return ident->base;
403 }
404 }
405
Radek Krejcida04f4a2015-05-21 12:54:09 +0200406 return NULL;
407}
408
Radek Krejci3045cf32015-05-28 10:58:52 +0200409static struct ly_ident *find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200410{
411 const char *name;
412 int prefix_len = 0;
413 int i, found = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200414 struct ly_ident *result;
Radek Krejci3045cf32015-05-28 10:58:52 +0200415 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200416
Radek Krejci3045cf32015-05-28 10:58:52 +0200417 basename = lyxml_get_attr(node, "name", NULL);
Radek Krejci04581c62015-05-22 21:24:00 +0200418 if (!basename) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200419 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
Radek Krejci04581c62015-05-22 21:24:00 +0200420 return NULL;
421 }
422
423 /* search for the base identity */
424 name = strchr(basename, ':');
425 if (name) {
426 /* set name to correct position after colon */
427 prefix_len = name - basename;
428 name++;
429
430 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
431 /* prefix refers to the current module, ignore it */
432 prefix_len = 0;
433 }
434 } else {
435 name = basename;
436 }
437
438 if (prefix_len) {
439 /* get module where to search */
440 for (i = 0; i < module->imp_size; i++) {
441 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
442 && !module->imp[i].prefix[prefix_len]) {
443 module = module->imp[i].module;
444 found = 1;
445 break;
446 }
447 }
448 if (!found) {
449 /* identity refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +0200450 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
Radek Krejci04581c62015-05-22 21:24:00 +0200451 return NULL;
452 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200453 } else {
454 /* search in submodules */
455 for (i = 0; i < module->inc_size; i++) {
456 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
457 if (result) {
458 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200459 }
Radek Krejci04581c62015-05-22 21:24:00 +0200460 }
461 }
462
Radek Krejciefaeba32015-05-27 14:30:57 +0200463 /* search in the identified module */
464 result = find_base_ident_sub(module, ident, name);
465 if (!result) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200466 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
Radek Krejciefaeba32015-05-27 14:30:57 +0200467 }
468
469 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200470}
471
472static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
473{
474 struct lyxml_elem *node, *next;
475
476 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
477 return EXIT_FAILURE;
478 }
479 ident->module = module;
480
481 LY_TREE_FOR_SAFE(yin->child, next, node) {
482 if (!strcmp(node->name, "base")) {
483 if (ident->base) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200484 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200485 return EXIT_FAILURE;
486 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200487 if (!find_base_ident(module, ident, node)) {
Radek Krejci04581c62015-05-22 21:24:00 +0200488 return EXIT_FAILURE;
489 }
490 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200491 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200492 return EXIT_FAILURE;
493 }
494
495 lyxml_free_elem(module->ctx, node);
496 }
497
498 return EXIT_SUCCESS;
499}
500
Radek Krejcida04f4a2015-05-21 12:54:09 +0200501static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
502 struct lyxml_elem *yin, struct ly_type *type)
503{
Radek Krejci25d782a2015-05-22 15:03:23 +0200504 const char *value, *delim;
505 struct lyxml_elem *next, *node, root = {0};
506 int i, j, r;
507 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200508
Radek Krejci800af702015-06-02 13:46:01 +0200509 GETVAL(value, yin, "name")
Radek Krejci25d782a2015-05-22 15:03:23 +0200510 delim = strchr(value, ':');
511 if (delim) {
512 type->prefix = lydict_insert(module->ctx, value, delim - value);
513 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200514
Radek Krejcida04f4a2015-05-21 12:54:09 +0200515 type->der = find_superior_type(value, module, parent);
Radek Krejci3045cf32015-05-28 10:58:52 +0200516 if (!type->der) {
517 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +0200518 goto error;
Radek Krejci3045cf32015-05-28 10:58:52 +0200519 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200520 type->base = type->der->type.base;
521
522 switch (type->base) {
523 case LY_TYPE_BINARY:
Radek Krejci800af702015-06-02 13:46:01 +0200524 /* TODO length, 9.4.4
Radek Krejci04581c62015-05-22 21:24:00 +0200525 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
526 * hodnoty se musi vejit do 64b, podelementy
Radek Krejci25d782a2015-05-22 15:03:23 +0200527 */
528 break;
529 case LY_TYPE_BITS:
Radek Krejci800af702015-06-02 13:46:01 +0200530 /* TODO bit, 9.7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200531 * 1..n, nerekurzivni, stringy s podelementy */
532 break;
533 case LY_TYPE_DEC64:
Radek Krejci800af702015-06-02 13:46:01 +0200534 /* TODO fraction-digits, 9.3.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200535 * - MUST, 1, nerekurzivni, hodnota 1-18 */
Radek Krejci800af702015-06-02 13:46:01 +0200536 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200537 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
538 break;
539 case LY_TYPE_ENUM:
Radek Krejci6793db02015-05-22 17:49:54 +0200540 /* RFC 6020 9.6 */
Radek Krejci04581c62015-05-22 21:24:00 +0200541
Radek Krejci25d782a2015-05-22 15:03:23 +0200542 /* get enum specification, at least one must be present */
543 LY_TREE_FOR_SAFE(yin->child, next, node) {
544 if (!strcmp(node->name, "enum")) {
545 lyxml_unlink_elem(node);
546 lyxml_add_child(&root, node);
547 type->info.enums.count++;
548 }
549 }
550 if (yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200551 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200552 goto error;
553 }
554 if (!type->info.enums.count) {
555 if (type->der->type.der) {
556 /* this is just a derived type with no enum specified */
557 break;
558 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200559 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
Radek Krejci25d782a2015-05-22 15:03:23 +0200560 goto error;
561 }
562
563 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
564 for (i = v = 0; root.child; i++) {
565 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0);
566 if (r) {
567 type->info.enums.count = i + 1;
568 goto error;
569 }
570 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
571 value = type->info.enums.list[i].name;
572 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200573 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
Radek Krejci25d782a2015-05-22 15:03:23 +0200574 type->info.enums.count = i + 1;
575 goto error;
576 }
577
578 /* check the name uniqueness */
579 for (j = 0; j < i; j++) {
580 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200581 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200582 type->info.enums.count = i + 1;
583 goto error;
584 }
585 }
586
587 node = root.child->child;
588 if (node && !strcmp(node->name, "value")) {
589 value = lyxml_get_attr(node, "value", NULL);
590 v_ = strtol(value, NULL, 10);
591
592 /* range check */
593 if (v_ < INT32_MIN || v_ > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200594 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200595 type->info.enums.count = i + 1;
596 goto error;
597 }
598 type->info.enums.list[i].value = v_;
599
600 /* keep the highest enum value for automatic increment */
601 if (type->info.enums.list[i].value > v) {
602 v = type->info.enums.list[i].value;
603 v++;
604 } else {
605 /* check that the value is unique */
606 for (j = 0; j < i; j++) {
607 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200608 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value, type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200609 type->info.enums.count = i + 1;
610 goto error;
611 }
612 }
613 }
614 } else {
615 /* assign value automatically */
616 if (v > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200617 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200618 type->info.enums.count = i + 1;
619 goto error;
620 }
621 type->info.enums.list[i].value = v;
622 v++;
623 }
624 lyxml_free_elem(module->ctx, root.child);
625 }
626 break;
627 case LY_TYPE_IDENT:
Radek Krejci04581c62015-05-22 21:24:00 +0200628 /* RFC 6020 9.10 */
629
630 /* get base specification, exactly one must be present */
631 if (!yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200632 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
Radek Krejci04581c62015-05-22 21:24:00 +0200633 goto error;
634 }
635 if (strcmp(yin->child->name, "base")) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200636 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200637 goto error;
638 }
639 if (yin->child->next) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200640 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200641 goto error;
642 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200643 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
Radek Krejci04581c62015-05-22 21:24:00 +0200644 if (!type->info.ident.ref) {
645 return EXIT_FAILURE;
646 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200647 break;
648 case LY_TYPE_INST:
Radek Krejci800af702015-06-02 13:46:01 +0200649 /* TODO require-instance, 9.13.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200650 * - 0..1, true/false */
651 break;
652 case LY_TYPE_INT8:
653 case LY_TYPE_INT16:
654 case LY_TYPE_INT32:
655 case LY_TYPE_INT64:
656 case LY_TYPE_UINT8:
657 case LY_TYPE_UINT16:
658 case LY_TYPE_UINT32:
659 case LY_TYPE_UINT64:
Radek Krejci800af702015-06-02 13:46:01 +0200660 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200661 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
662 break;
663 case LY_TYPE_LEAFREF:
Radek Krejci800af702015-06-02 13:46:01 +0200664 /* TODO path, 9.9.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200665 * - 1, nerekurzivni, string */
666 break;
667 case LY_TYPE_STRING:
Radek Krejci800af702015-06-02 13:46:01 +0200668 /* TODO length, 9.4.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200669 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
670 * pattern, 9.4.6
671 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
672 break;
673 case LY_TYPE_UNION:
Radek Krejci800af702015-06-02 13:46:01 +0200674 /* TODO type, 7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200675 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
676 break;
677 default:
678 /* nothing needed :
679 * LY_TYPE_BOOL, LY_TYPE_EMPTY
680 */
681 break;
682 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200683
684 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200685
686error:
687
688 while(root.child) {
689 lyxml_free_elem(module->ctx, root.child);
690 }
691
692 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200693}
694
695static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
696 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
697{
698 const char *value;
699 struct lyxml_elem *node, *next;
Radek Krejci76c45d32015-05-26 16:01:14 +0200700 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200701
Radek Krejcieac35532015-05-31 19:09:15 +0200702 GETVAL(value, yin, "name");
703 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
704 goto error;
705 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200706 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
707
Radek Krejcieac35532015-05-31 19:09:15 +0200708 /* generic part - status, description, reference */
709 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, 0)) {
710 goto error;
711 }
712
Radek Krejcida04f4a2015-05-21 12:54:09 +0200713 LY_TREE_FOR_SAFE(yin->child, next, node) {
714 if (!strcmp(node->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200715 if (tpdf->type.der) {
716 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
717 goto error;
718 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200719 r = fill_yin_type(module, parent, node, &tpdf->type);
Radek Krejcieac35532015-05-31 19:09:15 +0200720 } else if (!strcmp(node->name, "default")) {
721 if (tpdf->dflt) {
722 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
723 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200724 }
Radek Krejcieac35532015-05-31 19:09:15 +0200725 GETVAL(value, node, "value");
726 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
727 } else if (!strcmp(node->name, "units")) {
728 if (tpdf->units) {
729 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
730 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200731 }
Radek Krejcieac35532015-05-31 19:09:15 +0200732 GETVAL(value, node, "name");
733 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
734 } else {
735 LOGVAL(VE_INSTMT, LOGLINE(node), value);
736 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200737 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200738 lyxml_free_elem(module->ctx, node);
739 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +0200740 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200741 }
742 }
743
Radek Krejcieac35532015-05-31 19:09:15 +0200744 /* check mandatory value */
Radek Krejci25d782a2015-05-22 15:03:23 +0200745 if (!tpdf->type.der) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200746 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
Radek Krejcieac35532015-05-31 19:09:15 +0200747 goto error;
748 }
749
Radek Krejci4c31f122015-06-02 14:51:22 +0200750 /* check default value */
751 if (check_default(&tpdf->type, tpdf->dflt)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200752 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200753 }
754
755 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200756
757error:
758
759 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200760}
761
Radek Krejci800af702015-06-02 13:46:01 +0200762static int fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
763{
764 struct lyxml_elem *child;
765 const char *value;
766
767 GETVAL(value, yin, "condition");
768 must->cond = lydict_insert(module->ctx, value, strlen(value));
769
770 LY_TREE_FOR(yin->child, child) {
771 if (!strcmp(child->name, "description")) {
772 if (must->dsc) {
773 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
774 goto error;
775 }
776 must->dsc = read_yin_text(module->ctx, child);
777 if (!must->dsc) {
778 goto error;
779 }
780 } else if (!strcmp(child->name, "reference")) {
781 if (must->ref) {
782 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
783 goto error;
784 }
785 must->ref = read_yin_text(module->ctx, child);
786 if (!must->ref) {
787 goto error;
788 }
789 } else if (!strcmp(child->name, "error-app-tag")) {
790 if (must->eapptag) {
791 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
792 goto error;
793 }
794 must->eapptag = read_yin_text(module->ctx, child);
795 if (!must->eapptag) {
796 goto error;
797 }
798 } else if (!strcmp(child->name, "error-message")) {
799 if (must->emsg) {
800 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
801 goto error;
802 }
803 must->emsg = read_yin_text(module->ctx, child);
804 if (!must->emsg) {
805 goto error;
806 }
807 } else {
808 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
809 goto error;
810 }
811
812 lyxml_free_elem(module->ctx, child);
813 }
814
815
816 return EXIT_SUCCESS;
817
818error:
819
820 return EXIT_FAILURE;
821}
822
Radek Krejciefaeba32015-05-27 14:30:57 +0200823static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
824{
825 struct lyxml_elem *child;
826 const char *value;
827
828 LY_TREE_FOR(yin->child, child) {
829 if (!strcmp(child->name, "prefix")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200830 GETVAL(value, child, "value");
Radek Krejci0af13872015-05-30 11:50:52 +0200831 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
832 goto error;
833 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200834 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
835 } else if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200836 if (imp->rev[0]) {
837 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
838 goto error;
839 }
840 GETVAL(value, child, "date");
841 if (check_date(value, LOGLINE(child))) {
842 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200843 }
844 memcpy(imp->rev, value, LY_REV_SIZE - 1);
845 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200846 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200847 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200848 }
849 }
850
Radek Krejcice7fb782015-05-29 16:52:34 +0200851 /* check mandatory information */
852 if (!imp->prefix) {
853 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
854 goto error;
855 }
856
857 GETVAL(value, yin, "module");
Radek Krejci0af13872015-05-30 11:50:52 +0200858 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
Radek Krejciefaeba32015-05-27 14:30:57 +0200859 if (!imp->module) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200860 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200861 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200862 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
863 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200864 }
865
866 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200867
868error:
869
870 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200871}
872
873static int fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
874{
875 struct lyxml_elem *child;
876 const char *value;
877
878 LY_TREE_FOR(yin->child, child) {
879 if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200880 if (inc->rev[0]) {
881 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
882 goto error;
883 }
884 GETVAL(value, child, "date");
885 if (check_date(value, LOGLINE(child))) {
886 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200887 }
888 memcpy(inc->rev, value, LY_REV_SIZE - 1);
889 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200890 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200891 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200892 }
893 }
894
Radek Krejcice7fb782015-05-29 16:52:34 +0200895 GETVAL(value, yin, "module");
Radek Krejciefaeba32015-05-27 14:30:57 +0200896 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
897 if (!inc->submodule) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200898 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200899 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200900 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
901 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200902 }
903
Radek Krejcice7fb782015-05-29 16:52:34 +0200904 /* check that belongs-to corresponds */
905 if (module->type) {
906 module = ((struct ly_submodule *)module)->belongsto;
907 }
908 if (inc->submodule->belongsto != module) {
909 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
910 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
911 goto error;
912 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200913
914 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200915
916error:
917
918 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200919}
920
921
Radek Krejcida04f4a2015-05-21 12:54:09 +0200922/*
923 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200924 * description, reference, status, optionaly config
Radek Krejcida04f4a2015-05-21 12:54:09 +0200925 */
926static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejci25d782a2015-05-22 15:03:23 +0200927 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int ext)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200928{
929 const char *value;
930 struct lyxml_elem *sub, *next;
931 struct ly_ctx * const ctx = module->ctx;
Radek Krejcice7fb782015-05-29 16:52:34 +0200932 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200933
Radek Krejci25d782a2015-05-22 15:03:23 +0200934 if (ext) {
935 mnode->module = module;
936 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200937
Radek Krejci800af702015-06-02 13:46:01 +0200938 GETVAL(value, xmlnode, "name");
939 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200940 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200941 }
Radek Krejci800af702015-06-02 13:46:01 +0200942 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +0200943
944 /* process local parameters */
945 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
946 if (!strcmp(sub->name, "description")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200947 if (mnode->dsc) {
948 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
949 goto error;
950 }
Radek Krejci0af13872015-05-30 11:50:52 +0200951 mnode->dsc = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200952 if (!mnode->dsc) {
953 r = 1;
954 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200955 } else if (!strcmp(sub->name, "reference")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200956 if (mnode->ref) {
957 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
958 goto error;
959 }
Radek Krejci0af13872015-05-30 11:50:52 +0200960 mnode->ref = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200961 if (!mnode->ref) {
962 r = 1;
963 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200964 } else if (!strcmp(sub->name, "status")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200965 if (mnode->flags & LY_NODE_STATUS_MASK) {
966 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
967 goto error;
968 }
969 GETVAL(value, sub, "value");
Radek Krejcida04f4a2015-05-21 12:54:09 +0200970 if (!strcmp(value, "current")) {
971 mnode->flags |= LY_NODE_STATUS_CURR;
972 } else if (!strcmp(value, "deprecated")) {
973 mnode->flags |= LY_NODE_STATUS_DEPRC;
974 } else if (!strcmp(value, "obsolete")) {
975 mnode->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejcice7fb782015-05-29 16:52:34 +0200976 } else {
977 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
978 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200979 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200980 } else if (ext && !strcmp(sub->name, "config")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200981 if (mnode->flags & LY_NODE_CONFIG_MASK) {
982 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
983 goto error;
984 }
985 GETVAL(value, sub, "value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200986 if (!strcmp(value, "false")) {
987 mnode->flags |= LY_NODE_CONFIG_R;
988 } else if (!strcmp(value, "false")) {
989 mnode->flags |= LY_NODE_CONFIG_W;
Radek Krejcice7fb782015-05-29 16:52:34 +0200990 } else {
991 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
992 r = 1;
Radek Krejci25d782a2015-05-22 15:03:23 +0200993 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200994 } else {
995 /* skip the lyxml_free_elem */
996 continue;
997 }
998 lyxml_free_elem(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200999 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +02001000 goto error;
Radek Krejcice7fb782015-05-29 16:52:34 +02001001 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001002 }
1003
Radek Krejci25d782a2015-05-22 15:03:23 +02001004 if (ext && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001005 /* get config flag from parent */
1006 if (parent) {
1007 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1008 } else {
1009 /* default config is true */
1010 mnode->flags |= LY_NODE_CONFIG_W;
1011 }
1012 }
1013
1014 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001015
1016error:
1017
1018 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001019}
1020
1021static struct ly_mnode *read_yin_choice(struct ly_module *module,
1022 struct ly_mnode *parent,
1023 struct lyxml_elem *node)
1024{
1025 struct lyxml_elem *sub, *next;
1026 struct ly_ctx * const ctx = module->ctx;
Radek Krejci25d782a2015-05-22 15:03:23 +02001027 struct ly_mnode *retval, *r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001028 struct ly_mnode_choice *choice;
1029
Radek Krejcida04f4a2015-05-21 12:54:09 +02001030 choice = calloc(1, sizeof *choice);
1031 choice->nodetype = LY_NODE_CHOICE;
1032 choice->module = module;
1033 choice->prev = (struct ly_mnode *)choice;
1034 retval = (struct ly_mnode *)choice;
1035
Radek Krejci25d782a2015-05-22 15:03:23 +02001036 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001037 goto error;
1038 }
1039
1040 /* process choice's specific children */
1041 LY_TREE_FOR_SAFE(node->child, next, sub) {
1042 if (!strcmp(sub->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001043 r = read_yin_container(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001044 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001045 r = read_yin_leaflist(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001046 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001047 r = read_yin_leaf(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001048 } else if (!strcmp(sub->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001049 r = read_yin_list(module, retval, sub);
Radek Krejci667b97f2015-05-25 15:03:30 +02001050 } else {
1051 continue;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001052 }
1053 lyxml_free_elem(ctx, sub);
Radek Krejci25d782a2015-05-22 15:03:23 +02001054 if (!r) {
1055 goto error;
1056 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001057 }
1058
Radek Krejci812b10a2015-05-28 16:48:25 +02001059 if (parent) {
1060 ly_mnode_addchild(parent, retval);
1061 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001062
1063 return retval;
1064
1065error:
1066
1067 ly_mnode_free(retval);
1068
1069 return NULL;
1070}
1071
1072static struct ly_mnode *read_yin_leaf(struct ly_module *module,
1073 struct ly_mnode *parent,
Radek Krejci4c31f122015-06-02 14:51:22 +02001074 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001075{
1076 struct ly_mnode *retval;
1077 struct ly_mnode_leaf *leaf;
1078 struct lyxml_elem *sub, *next;
Radek Krejci4c31f122015-06-02 14:51:22 +02001079 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001080 int r;
Radek Krejci4c31f122015-06-02 14:51:22 +02001081 int c_must = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001082
Radek Krejcida04f4a2015-05-21 12:54:09 +02001083 leaf = calloc(1, sizeof *leaf);
1084 leaf->nodetype = LY_NODE_LEAF;
1085 leaf->prev = (struct ly_mnode *)leaf;
1086 retval = (struct ly_mnode *)leaf;
1087
Radek Krejci4c31f122015-06-02 14:51:22 +02001088 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001089 goto error;
1090 }
1091
Radek Krejci4c31f122015-06-02 14:51:22 +02001092 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001093 if (!strcmp(sub->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001094 if (leaf->type.der) {
1095 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1096 goto error;
1097 }
1098 if (fill_yin_type(module, parent, sub, &leaf->type)) {
1099 goto error;
1100 }
1101 } else if (!strcmp(sub->name, "default")) {
1102 if (leaf->dflt) {
1103 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1104 goto error;
1105 }
1106 GETVAL(value, sub, "value");
1107 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
1108 } else if (!strcmp(sub->name, "units")) {
1109 if (leaf->units) {
1110 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1111 goto error;
1112 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001113 GETVAL(value, sub, "name");
Radek Krejci4c31f122015-06-02 14:51:22 +02001114 leaf->units = lydict_insert(module->ctx, value, strlen(value));
1115 } else if (!strcmp(sub->name, "mandatory")) {
1116 if (f_mand) {
1117 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1118 goto error;
1119 }
1120 /* just checking the flags in leaf is not sufficient, we would allow
1121 * multiple mandatory statements with the "false" value
1122 */
1123 f_mand = 1;
1124
1125 GETVAL(value, sub, "value");
1126 if (!strcmp(value, "true")) {
1127 leaf->flags |= LY_NODE_MANDATORY;
1128 } else if (strcmp(value, "false")) {
1129 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1130 goto error;
1131 } /* else false is the default value, so we can ignore it */
1132 } else if (!strcmp(sub->name, "must")) {
1133 c_must++;
1134
1135 /* skip element free at the end of the loop */
1136 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001137#if 0
Radek Krejci4c31f122015-06-02 14:51:22 +02001138 } else {
1139 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1140 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001141#endif
Radek Krejci4c31f122015-06-02 14:51:22 +02001142 }
1143
1144 lyxml_free_elem(module->ctx, sub);
1145 }
1146
1147 /* check mandatory parameters */
1148 if (!leaf->type.der) {
1149 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1150 goto error;
1151 }
Radek Krejciccdec642015-06-03 10:58:45 +02001152 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001153 goto error;
1154 }
1155
1156 /* middle part - process nodes with cardinality of 0..n */
1157 if (c_must) {
1158 leaf->must = calloc(c_must, sizeof *leaf->must);
1159 }
1160
1161 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1162 if (!strcmp(sub->name, "must")) {
1163 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
1164 leaf->must_size++;
1165
Radek Krejci25d782a2015-05-22 15:03:23 +02001166 if (r) {
1167 goto error;
1168 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001169 }
Radek Krejci4c31f122015-06-02 14:51:22 +02001170
1171 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001172 }
1173
Radek Krejci812b10a2015-05-28 16:48:25 +02001174 if (parent) {
1175 ly_mnode_addchild(parent, retval);
1176 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001177
1178 return retval;
1179
1180error:
1181
1182 ly_mnode_free(retval);
1183
1184 return NULL;
1185}
1186
1187static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
1188 struct ly_mnode *parent,
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001189 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001190{
1191 struct ly_mnode *retval;
1192 struct ly_mnode_leaflist *llist;
1193 struct lyxml_elem *sub, *next;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001194 const char *value;
1195 char *endptr;
Radek Krejci17e93f92015-06-03 11:01:55 +02001196 unsigned long val;
Radek Krejci25d782a2015-05-22 15:03:23 +02001197 int r;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001198 int c_must = 0;
Radek Krejci17e93f92015-06-03 11:01:55 +02001199 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001200
Radek Krejcida04f4a2015-05-21 12:54:09 +02001201 llist = calloc(1, sizeof *llist);
1202 llist->nodetype = LY_NODE_LEAFLIST;
1203 llist->prev = (struct ly_mnode *)llist;
1204 retval = (struct ly_mnode *)llist;
1205
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001206 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001207 goto error;
1208 }
1209
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001210 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001211 if (!strcmp(sub->name, "type")) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001212 if (llist->type.der) {
1213 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1214 goto error;
1215 }
1216 if (fill_yin_type(module, parent, sub, &llist->type)) {
1217 goto error;
1218 }
1219 } else if (!strcmp(sub->name, "units")) {
1220 if (llist->units) {
1221 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1222 goto error;
1223 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001224 GETVAL(value, sub, "name");
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001225 llist->units = lydict_insert(module->ctx, value, strlen(value));
1226 } else if (!strcmp(sub->name, "ordered-by")) {
1227 if (f_ordr) {
1228 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1229 goto error;
1230 }
1231 /* just checking the flags in llist is not sufficient, we would
1232 * allow multiple ordered-by statements with the "system" value
1233 */
1234 f_ordr = 1;
1235
1236 if (llist->flags & LY_NODE_CONFIG_R) {
1237 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
1238 * state data
1239 */
1240 lyxml_free_elem(module->ctx, sub);
1241 continue;
1242 }
1243
1244 GETVAL(value, sub, "value");
1245 if (!strcmp(value, "user")) {
1246 llist->flags |= LY_NODE_USERORDERED;
1247 } else if (strcmp(value, "system")) {
1248 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1249 goto error;
1250 } /* else system is the default value, so we can ignore it */
1251 } else if (!strcmp(sub->name, "must")) {
1252 c_must++;
1253
1254 /* skip element free at the end of the loop */
1255 continue;
1256 } else if (!strcmp(sub->name, "min-elements")) {
1257 if (f_min) {
1258 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1259 goto error;
1260 }
1261 f_min = 1;
1262
1263 GETVAL(value, sub, "value");
1264 while(isspace(value[0])) {
1265 value++;
1266 }
1267
1268 /* convert it to uint32_t */
1269 errno = 0;
1270 endptr = NULL;
1271 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001272 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001273 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1274 goto error;
1275 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001276 llist->min = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001277 } else if (!strcmp(sub->name, "max-elements")) {
1278 if (f_max) {
1279 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1280 goto error;
1281 }
1282 f_max = 1;
1283
1284 GETVAL(value, sub, "value");
1285 while(isspace(value[0])) {
1286 value++;
1287 }
1288
1289 /* convert it to uint32_t */
1290 errno = 0;
1291 endptr = NULL;
1292 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001293 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001294 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1295 goto error;
1296 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001297 llist->max = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001298
1299 } else {
Radek Krejci1e3f8902015-06-03 11:00:11 +02001300#if 0
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001301 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1302 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001303#endif
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001304 }
1305
1306 lyxml_free_elem(module->ctx, sub);
1307 }
1308
1309 /* check constraints */
1310 if (!llist->type.der) {
1311 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1312 goto error;
1313 }
1314 if (llist->max && llist->min > llist->max) {
1315 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
1316 goto error;
1317 }
1318
1319 /* middle part - process nodes with cardinality of 0..n */
1320 if (c_must) {
1321 llist->must = calloc(c_must, sizeof *llist->must);
1322 }
1323
1324 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1325 if (!strcmp(sub->name, "must")) {
1326 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
1327 llist->must_size++;
1328
Radek Krejci25d782a2015-05-22 15:03:23 +02001329 if (r) {
1330 goto error;
1331 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001332 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001333
1334 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001335 }
1336
Radek Krejci812b10a2015-05-28 16:48:25 +02001337 if (parent) {
1338 ly_mnode_addchild(parent, retval);
1339 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001340
1341 return retval;
1342
1343error:
1344
1345 ly_mnode_free(retval);
1346
1347 return NULL;
1348}
1349
1350static struct ly_mnode *read_yin_list(struct ly_module *module,
1351 struct ly_mnode *parent,
1352 struct lyxml_elem *node)
1353{
1354 struct ly_mnode *retval, *mnode;
1355 struct ly_mnode_list *list;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001356 struct ly_mnode_leaf *key;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001357 struct lyxml_elem *sub, *next, root = {0};
Radek Krejcid7f0d012015-05-25 15:04:52 +02001358 int i, j, r;
1359 size_t len;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001360 int c_tpdf = 0;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001361 const char *key_str = NULL, *s;
1362 char *dup;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001363
Radek Krejcida04f4a2015-05-21 12:54:09 +02001364 list = calloc(1, sizeof *list);
1365 list->nodetype = LY_NODE_LIST;
1366 list->prev = (struct ly_mnode *)list;
1367 retval = (struct ly_mnode *)list;
1368
Radek Krejci25d782a2015-05-22 15:03:23 +02001369 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001370 goto error;
1371 }
1372
1373 /* process list's specific children */
1374 LY_TREE_FOR_SAFE(node->child, next, sub) {
1375 /* data statements */
1376 if (!strcmp(sub->name, "container") ||
1377 !strcmp(sub->name, "leaf-list") ||
1378 !strcmp(sub->name, "leaf") ||
1379 !strcmp(sub->name, "list") ||
1380 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001381 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001382 !strcmp(sub->name, "grouping")) {
1383 lyxml_unlink_elem(sub);
1384 lyxml_add_child(&root, sub);
1385
1386 /* array counters */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001387 } else if (!strcmp(sub->name, "key")) {
1388 /* check cardinality 0..1 */
1389 if (list->keys_size) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001390 LOGVAL(VE_TOOMANY, LOGLINE(sub), "key", list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001391 goto error;
1392 }
1393
1394 /* count the number of keys */
1395 key_str = s = lyxml_get_attr(sub, "value", NULL);
1396 if (!s) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001397 LOGVAL(VE_MISSARG, LOGLINE(sub), "value", "key");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001398 goto error;
1399 }
1400 while((s = strpbrk(s, " \t\n"))) {
1401 list->keys_size++;
1402 while(isspace(*s)) {
1403 s++;
1404 }
1405 }
1406 list->keys_size++;
1407
1408 list->keys = calloc(list->keys_size, sizeof *list->keys);
1409
Radek Krejcida04f4a2015-05-21 12:54:09 +02001410 } else if (!strcmp(sub->name, "typedef")) {
1411 c_tpdf++;
1412 }
1413 }
1414
Radek Krejcid7f0d012015-05-25 15:04:52 +02001415 /* check - if list is configuration, key statement is mandatory */
Radek Krejci3a734ed2015-05-26 15:23:18 +02001416 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001417 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "key", "list");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001418 goto error;
1419 }
1420
Radek Krejcida04f4a2015-05-21 12:54:09 +02001421 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1422 if (c_tpdf) {
1423 list->tpdf_size = c_tpdf;
1424 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
1425 c_tpdf = 0;
1426 }
1427 LY_TREE_FOR_SAFE(node->child, next, sub) {
1428 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001429 r = fill_yin_typedef(module, retval, sub, &list->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001430 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001431
1432 if (r) {
1433 list->tpdf_size = c_tpdf;
1434 goto error;
1435 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001436 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001437 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001438 }
1439
1440 /* last part - process data nodes */
1441 LY_TREE_FOR_SAFE(root.child, next, sub) {
1442 if (!strcmp(sub->name, "container")) {
1443 mnode = read_yin_container(module, retval, sub);
1444 } else if (!strcmp(sub->name, "leaf-list")) {
1445 mnode = read_yin_leaflist(module, retval, sub);
1446 } else if (!strcmp(sub->name, "leaf")) {
1447 mnode = read_yin_leaf(module, retval, sub);
1448 } else if (!strcmp(sub->name, "list")) {
1449 mnode = read_yin_list(module, retval, sub);
1450 } else if (!strcmp(sub->name, "choice")) {
1451 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001452 } else if (!strcmp(sub->name, "uses")) {
1453 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001454 } else if (!strcmp(sub->name, "grouping")) {
1455 mnode = read_yin_grouping(module, retval, sub);
1456 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001457 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001458 continue;
1459 }
1460 lyxml_free_elem(module->ctx, sub);
1461
Radek Krejci25d782a2015-05-22 15:03:23 +02001462 if (!mnode) {
1463 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001464 }
1465 }
1466
Radek Krejci812b10a2015-05-28 16:48:25 +02001467 if (parent) {
1468 ly_mnode_addchild(parent, retval);
1469 }
1470
Radek Krejci3a734ed2015-05-26 15:23:18 +02001471 if (!key_str) {
1472 /* config false list without a key */
1473 return retval;
1474 }
1475
Radek Krejcid7f0d012015-05-25 15:04:52 +02001476 /* link key leafs into the list structure and check all constraints */
1477 /* TODO - include searching in uses/grouping */
1478 for (i = 0; i < list->keys_size; i++) {
1479 /* get the key name */
1480 if ((s = strpbrk(key_str, " \t\n"))) {
1481 len = s - key_str;
1482 } else {
1483 len = strlen(key_str);
1484 }
1485 LY_TREE_FOR(list->child, mnode) {
1486 if (!strncmp(mnode->name, key_str, len) && !mnode->name[len]) {
1487 list->keys[i] = mnode;
1488 break;
1489 }
1490 }
1491 key = (struct ly_mnode_leaf *)list->keys[i];
1492
1493 /* existence */
1494 if (!key) {
1495 if ((s = strpbrk(key_str, " \t\n"))) {
1496 len = s - key_str;
1497 dup = strdup(key_str);
1498 dup[len] = '\0';
1499 key_str = dup;
1500 }
Radek Krejci3045cf32015-05-28 10:58:52 +02001501 LOGVAL(VE_KEY_MISS, LOGLINE(node), key_str);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001502 if (s) {
1503 free(dup);
1504 }
1505 goto error;
1506 }
1507
Radek Krejci3045cf32015-05-28 10:58:52 +02001508 /* uniqueness */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001509 for (j = i - 1; j >= 0; j--) {
1510 if (list->keys[i] == list->keys[j]) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001511 LOGVAL(VE_KEY_DUP, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001512 goto error;
1513 }
1514 }
1515
1516 /* key is a leaf */
1517 if (key->nodetype != LY_NODE_LEAF) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001518 LOGVAL(VE_KEY_NLEAF, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001519 goto error;
1520 }
1521
1522 /* type of the leaf is not built-in empty */
1523 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001524 LOGVAL(VE_KEY_TYPE, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001525 goto error;
1526 }
1527
1528 /* config attribute is the same as of the list */
1529 if ((list->flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001530 LOGVAL(VE_KEY_CONFIG, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001531 goto error;
1532 }
1533
1534 /* prepare for next iteration */
1535 while (s && isspace(*s)) {
1536 s++;
1537 }
1538 key_str = s;
1539 }
1540
Radek Krejcida04f4a2015-05-21 12:54:09 +02001541 return retval;
1542
1543error:
1544
1545 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001546 while(root.child) {
1547 lyxml_free_elem(module->ctx, root.child);
1548 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001549
1550 return NULL;
1551}
1552
1553static struct ly_mnode *read_yin_container(struct ly_module *module,
1554 struct ly_mnode *parent,
Radek Krejci4c31f122015-06-02 14:51:22 +02001555 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001556{
1557 struct lyxml_elem *sub, *next, root = {0};
1558 struct ly_mnode *mnode = NULL;
1559 struct ly_mnode *retval;
1560 struct ly_mnode_container *cont;
Radek Krejci800af702015-06-02 13:46:01 +02001561 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001562 int r;
Radek Krejci800af702015-06-02 13:46:01 +02001563 int c_tpdf = 0, c_must = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001564
Radek Krejcida04f4a2015-05-21 12:54:09 +02001565 cont = calloc(1, sizeof *cont);
1566 cont->nodetype = LY_NODE_CONTAINER;
1567 cont->prev = (struct ly_mnode *)cont;
1568 retval = (struct ly_mnode *)cont;
1569
Radek Krejci4c31f122015-06-02 14:51:22 +02001570 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001571 goto error;
1572 }
1573
1574 /* process container's specific children */
Radek Krejci4c31f122015-06-02 14:51:22 +02001575 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci800af702015-06-02 13:46:01 +02001576 if (!strcmp(sub->name, "presence")) {
1577 if (cont->presence) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001578 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +02001579 goto error;
1580 }
1581 GETVAL(value, sub, "value");
1582 cont->presence = lydict_insert(module->ctx, value, strlen(value));
1583
Radek Krejci4c31f122015-06-02 14:51:22 +02001584 lyxml_free_elem(module->ctx, sub);
1585
Radek Krejcida04f4a2015-05-21 12:54:09 +02001586 /* data statements */
Radek Krejci800af702015-06-02 13:46:01 +02001587 } else if (!strcmp(sub->name, "container") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001588 !strcmp(sub->name, "leaf-list") ||
1589 !strcmp(sub->name, "leaf") ||
1590 !strcmp(sub->name, "list") ||
1591 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001592 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001593 !strcmp(sub->name, "grouping")) {
1594 lyxml_unlink_elem(sub);
1595 lyxml_add_child(&root, sub);
1596
1597 /* array counters */
1598 } else if (!strcmp(sub->name, "typedef")) {
1599 c_tpdf++;
Radek Krejci800af702015-06-02 13:46:01 +02001600 } else if (!strcmp(sub->name, "must")) {
1601 c_must++;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001602#if 0
Radek Krejci800af702015-06-02 13:46:01 +02001603 } else {
Radek Krejci4c31f122015-06-02 14:51:22 +02001604 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1605 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001606#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02001607 }
1608 }
1609
1610 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1611 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001612 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001613 }
Radek Krejci800af702015-06-02 13:46:01 +02001614 if (c_must) {
1615 cont->must = calloc(c_must, sizeof *cont->must);
1616 }
1617
Radek Krejci4c31f122015-06-02 14:51:22 +02001618 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001619 if (!strcmp(sub->name, "typedef")) {
Radek Krejci800af702015-06-02 13:46:01 +02001620 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
1621 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001622
1623 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001624 goto error;
1625 }
Radek Krejci800af702015-06-02 13:46:01 +02001626 } else if (!strcmp(sub->name, "must")) {
1627 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
1628 cont->must_size++;
1629
1630 if (r) {
1631 goto error;
1632 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001633 }
1634
1635 lyxml_free_elem(module->ctx, sub);
1636 }
1637
1638 /* last part - process data nodes */
1639 LY_TREE_FOR_SAFE(root.child, next, sub) {
1640 if (!strcmp(sub->name, "container")) {
1641 mnode = read_yin_container(module, retval, sub);
1642 } else if (!strcmp(sub->name, "leaf-list")) {
1643 mnode = read_yin_leaflist(module, retval, sub);
1644 } else if (!strcmp(sub->name, "leaf")) {
1645 mnode = read_yin_leaf(module, retval, sub);
1646 } else if (!strcmp(sub->name, "list")) {
1647 mnode = read_yin_list(module, retval, sub);
1648 } else if (!strcmp(sub->name, "choice")) {
1649 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001650 } else if (!strcmp(sub->name, "uses")) {
1651 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001652 } else if (!strcmp(sub->name, "grouping")) {
1653 mnode = read_yin_grouping(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001654 }
1655 lyxml_free_elem(module->ctx, sub);
1656
Radek Krejci25d782a2015-05-22 15:03:23 +02001657 if (!mnode) {
1658 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001659 }
1660 }
1661
Radek Krejci812b10a2015-05-28 16:48:25 +02001662 if (parent) {
1663 ly_mnode_addchild(parent, retval);
1664 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001665
1666 return retval;
1667
1668error:
1669
1670 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001671 while (root.child) {
1672 lyxml_free_elem(module->ctx, root.child);
1673 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001674
1675 return NULL;
1676}
1677
1678static struct ly_mnode *read_yin_grouping(struct ly_module *module,
1679 struct ly_mnode *parent,
1680 struct lyxml_elem *node)
1681{
1682 struct lyxml_elem *sub, *next, root = {0};
1683 struct ly_mnode *mnode = NULL;
1684 struct ly_mnode *retval;
1685 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +02001686 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001687 int c_tpdf = 0;
1688
1689 grp = calloc(1, sizeof *grp);
1690 grp->nodetype = LY_NODE_GROUPING;
1691 grp->module = module;
1692 grp->prev = (struct ly_mnode *)grp;
1693 retval = (struct ly_mnode *)grp;
1694
Radek Krejci25d782a2015-05-22 15:03:23 +02001695 if (read_yin_common(module, parent, retval, node, 0)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001696 goto error;
1697 }
1698
1699 LY_TREE_FOR_SAFE(node->child, next, sub) {
1700 /* data statements */
1701 if (!strcmp(sub->name, "container") ||
1702 !strcmp(sub->name, "leaf-list") ||
1703 !strcmp(sub->name, "leaf") ||
1704 !strcmp(sub->name, "list") ||
1705 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001706 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001707 !strcmp(sub->name, "grouping")) {
1708 lyxml_unlink_elem(sub);
1709 lyxml_add_child(&root, sub);
1710
1711 /* array counters */
1712 } else if (!strcmp(sub->name, "typedef")) {
1713 c_tpdf++;
1714 }
1715 }
1716
1717 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1718 if (c_tpdf) {
1719 grp->tpdf_size = c_tpdf;
1720 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
1721 c_tpdf = 0;
1722 }
1723 LY_TREE_FOR_SAFE(node->child, next, sub) {
1724 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001725 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001726 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001727
1728 if (r) {
1729 grp->tpdf_size = c_tpdf;
1730 goto error;
1731 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001732 }
1733
1734 lyxml_free_elem(module->ctx, sub);
1735 }
1736
1737 /* last part - process data nodes */
1738 LY_TREE_FOR_SAFE(root.child, next, sub) {
1739 if (!strcmp(sub->name, "container")) {
1740 mnode = read_yin_container(module, retval, sub);
1741 } else if (!strcmp(sub->name, "leaf-list")) {
1742 mnode = read_yin_leaflist(module, retval, sub);
1743 } else if (!strcmp(sub->name, "leaf")) {
1744 mnode = read_yin_leaf(module, retval, sub);
1745 } else if (!strcmp(sub->name, "list")) {
1746 mnode = read_yin_list(module, retval, sub);
1747 } else if (!strcmp(sub->name, "choice")) {
1748 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001749 } else if (!strcmp(sub->name, "uses")) {
1750 mnode = read_yin_uses(module, retval, sub, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001751 } else if (!strcmp(sub->name, "grouping")) {
1752 mnode = read_yin_grouping(module, retval, sub);
1753 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001754 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001755 continue;
1756 }
1757 lyxml_free_elem(module->ctx, sub);
1758
Radek Krejci25d782a2015-05-22 15:03:23 +02001759 if (!mnode) {
1760 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001761 }
1762 }
1763
Radek Krejci812b10a2015-05-28 16:48:25 +02001764 if (parent) {
1765 ly_mnode_addchild(parent, retval);
1766 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001767
1768 return retval;
1769
1770error:
1771
1772 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001773 while (root.child) {
1774 lyxml_free_elem(module->ctx, root.child);
1775 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001776
1777 return NULL;
1778}
1779
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001780/*
1781 * resolve - referenced grouping should be bounded to the namespace (resolved)
1782 * only when uses does not appear in grouping. In a case of grouping's uses,
1783 * we just get information but we do not apply augment or refine to it.
1784 */
1785static struct ly_mnode *read_yin_uses(struct ly_module *module,
1786 struct ly_mnode *parent,
1787 struct lyxml_elem *node, int resolve)
1788{
1789 struct ly_mnode *retval;
1790 struct ly_mnode *mnode = NULL, *par;
1791 struct ly_mnode_uses *uses;
1792 struct ly_module *searchmod = NULL;
1793 const char *name;
1794 int prefix_len = 0;
1795 int i;
1796
1797 uses = calloc(1, sizeof *uses);
1798 uses->nodetype = LY_NODE_USES;
1799 uses->module = module;
1800 uses->prev = (struct ly_mnode *)uses;
1801 retval = (struct ly_mnode *)uses;
1802
1803 if (read_yin_common(module, parent, retval, node, 0)) {
1804 goto error;
1805 }
1806
1807 /* get referenced grouping */
1808 name = strchr(uses->name, ':');
1809 if (!name) {
1810 /* no prefix, search in local tree */
1811 name = uses->name;
1812 } else {
1813 /* there is some prefix, check if it refer the same data model */
1814
1815 /* set name to correct position after colon */
1816 prefix_len = name - uses->name;
1817 name++;
1818
1819 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1820 /* prefix refers to the current module, ignore it */
1821 prefix_len = 0;
1822 }
1823 }
1824
1825 /* search */
1826 if (prefix_len) {
1827 /* in top-level groupings of some other module */
1828 for (i = 0; i < module->imp_size; i++) {
1829 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
1830 && !module->imp[i].prefix[prefix_len]) {
1831 searchmod = module->imp[i].module;
1832 break;
1833 }
1834 }
1835 if (!searchmod) {
1836 /* uses refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +02001837 LOGVAL(VE_INPREFIX, LOGLINE(node), name);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001838 goto error;
1839 }
1840
1841 LY_TREE_FOR(module->data, mnode) {
1842 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1843 uses->grp = (struct ly_mnode_grp *)mnode;
1844 break;
1845 }
1846 }
1847
1848 if (!uses->grp) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001849 LOGVAL(VE_INARG, LOGLINE(node), uses->name, "uses");
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001850 goto error;
1851 }
1852
1853 } else {
1854 /* in local tree hierarchy */
1855 for(par = parent; par; par = par->parent) {
1856 LY_TREE_FOR(parent->child, mnode) {
1857 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1858 uses->grp = (struct ly_mnode_grp *)mnode;
1859 break;
1860 }
1861 }
1862 }
1863
1864 /* search in top level of the current module */
1865 LY_TREE_FOR(module->data, mnode) {
1866 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1867 uses->grp = (struct ly_mnode_grp *)mnode;
1868 break;
1869 }
1870 }
1871 }
1872
Radek Krejci812b10a2015-05-28 16:48:25 +02001873 if (parent) {
1874 ly_mnode_addchild(parent, retval);
1875 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001876
1877 if (!resolve) {
Radek Krejci812b10a2015-05-28 16:48:25 +02001878 /* this is uses statement inside the grouping, so do not bound grouping
1879 * to the current content
1880 */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001881 return retval;
1882 }
1883
1884 /* TODO */
1885
1886 return retval;
1887
1888error:
1889
1890 ly_mnode_free(retval);
1891
1892 return NULL;
1893}
1894
Radek Krejciefaeba32015-05-27 14:30:57 +02001895/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci0af13872015-05-30 11:50:52 +02001896static int read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001897{
Radek Krejciefaeba32015-05-27 14:30:57 +02001898 struct ly_ctx *ctx = module->ctx;
Radek Krejci0af13872015-05-30 11:50:52 +02001899 struct ly_submodule *submodule = (struct ly_submodule *)module;
Radek Krejciefaeba32015-05-27 14:30:57 +02001900 struct lyxml_elem *next, *node, *child, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +02001901 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001902 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001903 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0; /* counters */
Radek Krejci25d782a2015-05-22 15:03:23 +02001904 int r;
Radek Krejcice7fb782015-05-29 16:52:34 +02001905 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001906
1907 /*
1908 * in the first run, we process elements with cardinality of 1 or 0..1 and
1909 * count elements with cardinality 0..n. Data elements (choices, containers,
1910 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
1911 * need have all top-level and groupings already prepared at that time. In
1912 * the middle loop, we process other elements with carinality of 0..n since
1913 * we need to allocate arrays to store them.
1914 */
1915 LY_TREE_FOR_SAFE(yin->child, next, node) {
1916 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1917 lyxml_free_elem(ctx, node);
1918 continue;
1919 }
1920
Radek Krejci0af13872015-05-30 11:50:52 +02001921 if (!module->type && !strcmp(node->name, "namespace")) {
1922 if (module->ns) {
1923 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1924 goto error;
1925 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001926 GETVAL(value, node, "uri");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001927 module->ns = lydict_insert(ctx, value, strlen(value));
1928 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02001929 } else if (!module->type && !strcmp(node->name, "prefix")) {
1930 if (module->prefix) {
1931 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1932 goto error;
1933 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001934 GETVAL(value, node, "value");
Radek Krejci0af13872015-05-30 11:50:52 +02001935 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
1936 goto error;
1937 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001938 module->prefix = lydict_insert(ctx, value, strlen(value));
1939 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02001940 } else if (module->type && !strcmp(node->name, "belongs-to")) {
1941 if (submodule->belongsto) {
1942 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1943 goto error;
1944 }
1945 GETVAL(value, node, "module");
1946 submodule->belongsto = ly_ctx_get_module(module->ctx, value, NULL, 0);
1947 if (!submodule->belongsto) {
1948 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1949 goto error;
1950 }
1951 /* get the prefix substatement, start with checks */
1952 if (!node->child) {
1953 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
1954 goto error;
1955 } else if (strcmp(node->child->name, "prefix")) {
1956 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
1957 goto error;
1958 } else if (node->child->next) {
1959 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
1960 goto error;
1961 }
1962 /* and now finally get the value */
1963 GETVAL(value, node->child, "value");
1964 /* check here differs from a generic prefix check, since this prefix
1965 * don't have to be unique
1966 */
1967 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
1968 goto error;
1969 }
1970 module->prefix = lydict_insert(ctx, value, strlen(value));
1971
1972 /* we are done with belongs-to */
1973 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001974 } else if (!strcmp(node->name, "import")) {
1975 c_imp++;
1976 } else if (!strcmp(node->name, "revision")) {
1977 c_rev++;
1978 } else if (!strcmp(node->name, "typedef")) {
1979 c_tpdf++;
Radek Krejci6793db02015-05-22 17:49:54 +02001980 } else if (!strcmp(node->name, "identity")) {
1981 c_ident++;
Radek Krejciefaeba32015-05-27 14:30:57 +02001982 } else if (!strcmp(node->name, "include")) {
1983 c_inc++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001984
1985 /* data statements */
1986 } else if (!strcmp(node->name, "container") ||
1987 !strcmp(node->name, "leaf-list") ||
1988 !strcmp(node->name, "leaf") ||
1989 !strcmp(node->name, "list") ||
1990 !strcmp(node->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001991 !strcmp(node->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001992 !strcmp(node->name, "grouping")) {
1993 lyxml_unlink_elem(node);
1994 lyxml_add_child(&root, node);
1995
1996 /* optional statements */
1997 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001998 if (module->dsc) {
Radek Krejci0af13872015-05-30 11:50:52 +02001999 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002000 goto error;
2001 }
Radek Krejci0af13872015-05-30 11:50:52 +02002002 module->dsc = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002003 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002004 if (!module->dsc) {
2005 goto error;
2006 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002007 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002008 if (module->ref) {
Radek Krejci0af13872015-05-30 11:50:52 +02002009 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002010 goto error;
2011 }
Radek Krejci0af13872015-05-30 11:50:52 +02002012 module->ref = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002013 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002014 if (!module->ref) {
2015 goto error;
2016 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002017 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002018 if (module->org) {
Radek Krejci0af13872015-05-30 11:50:52 +02002019 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002020 goto error;
2021 }
Radek Krejci0af13872015-05-30 11:50:52 +02002022 module->org = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002023 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002024 if (!module->org) {
2025 goto error;
2026 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002027 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002028 if (module->contact) {
Radek Krejci0af13872015-05-30 11:50:52 +02002029 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002030 goto error;
2031 }
Radek Krejci0af13872015-05-30 11:50:52 +02002032 module->contact = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002033 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002034 if (!module->contact) {
2035 goto error;
2036 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002037 } else if (!strcmp(node->name, "yang-version")) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002038 /* TODO: support YANG 1.1 ? */
Radek Krejcib0594bf2015-05-21 23:51:27 +02002039 if (module->version) {
Radek Krejci0af13872015-05-30 11:50:52 +02002040 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002041 goto error;
2042 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002043 GETVAL(value, node, "value");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002044 if (strcmp(value, "1")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002045 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002046 goto error;
2047 }
2048 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002049 lyxml_free_elem(ctx, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02002050#if 0
Radek Krejcice7fb782015-05-29 16:52:34 +02002051 } else {
2052 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
2053 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002054#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02002055 }
2056 }
2057
Radek Krejciefaeba32015-05-27 14:30:57 +02002058 if (!submodule) {
2059 /* check for mandatory statements */
2060 if (!module->ns) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002061 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002062 goto error;
2063 }
2064 if (!module->prefix) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002065 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002066 goto error;
2067 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002068 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002069
Radek Krejcida04f4a2015-05-21 12:54:09 +02002070 /* allocate arrays for elements with cardinality of 0..n */
2071 if (c_imp) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002072 module->imp = calloc(c_imp, sizeof *module->imp);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002073 }
2074 if (c_rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002075 module->rev = calloc(c_rev, sizeof *module->rev);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002076 }
2077 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002078 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002079 }
Radek Krejci6793db02015-05-22 17:49:54 +02002080 if (c_ident) {
Radek Krejci6793db02015-05-22 17:49:54 +02002081 module->ident = calloc(c_ident, sizeof *module->ident);
Radek Krejciefaeba32015-05-27 14:30:57 +02002082 }
2083 if (c_inc) {
2084 module->inc = calloc(c_inc, sizeof *module->inc);
Radek Krejci6793db02015-05-22 17:49:54 +02002085 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002086
2087 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2088 LY_TREE_FOR_SAFE(yin->child, next, node) {
2089 if (!strcmp(node->name, "import")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002090 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
2091 module->imp_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002092 if (r) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002093 goto error;
2094 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002095
2096 /* check duplicities in imported modules */
2097 for (i = 0; i < module->imp_size - 1; i++) {
2098 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
2099 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
2100 goto error;
2101 }
2102 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002103 } else if (!strcmp(node->name, "include")) {
2104 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
2105 module->inc_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002106 if (r) {
2107 goto error;
2108 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002109
2110 /* check duplications in include submodules */
2111 for (i = 0; i < module->inc_size - 1; i++) {
Radek Krejci76e5a1b2015-05-29 17:01:08 +02002112 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002113 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->inc[i].submodule->name);
2114 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002115 }
2116 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002117 } else if (!strcmp(node->name, "revision")) {
2118 GETVAL(value, node, "date");
2119 if (check_date(value, LOGLINE(node))) {
2120 goto error;
2121 }
2122 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2123 /* check uniqueness of the revision date - not required by RFC */
2124 for (i = 0; i < module->rev_size; i++) {
2125 if (!strcmp(value, module->rev[i].date)) {
2126 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
2127 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
2128 }
2129 }
2130
2131 LY_TREE_FOR(node->child, child) {
2132 if (!strcmp(child->name, "description")) {
2133 if (module->rev[module->rev_size].dsc) {
2134 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2135 goto error;
2136 }
Radek Krejci0af13872015-05-30 11:50:52 +02002137 module->rev[module->rev_size].dsc = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02002138 if (!module->rev[module->rev_size].dsc) {
2139 goto error;
2140 }
2141 } else if (!strcmp(child->name, "reference")) {
2142 if (module->rev[module->rev_size].ref) {
2143 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2144 goto error;
2145 }
Radek Krejci0af13872015-05-30 11:50:52 +02002146 module->rev[module->rev_size].ref = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02002147 if (!module->rev[module->rev_size].ref) {
2148 goto error;
2149 }
2150 } else {
2151 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2152 goto error;
2153 }
2154 }
2155
2156 /* keep the latest revision at position 0 */
2157 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
2158 /* switch their position */
2159 value = strdup(module->rev[0].date);
2160 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
2161 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2162 free((char*)value);
2163
2164 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
2165 value = module->rev[0].dsc;
2166 module->rev[0].dsc = module->rev[module->rev_size].dsc;
2167 module->rev[module->rev_size].dsc = value;
2168 }
2169
2170 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
2171 value = module->rev[0].ref;
2172 module->rev[0].ref = module->rev[module->rev_size].ref;
2173 module->rev[module->rev_size].ref = value;
2174 }
2175 }
2176
Radek Krejciefaeba32015-05-27 14:30:57 +02002177 module->rev_size++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002178 } else if (!strcmp(node->name, "typedef")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002179 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
2180 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002181
2182 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002183 goto error;
2184 }
Radek Krejci6793db02015-05-22 17:49:54 +02002185 } else if (!strcmp(node->name, "identity")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002186 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
2187 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02002188
2189 if (r) {
Radek Krejci6793db02015-05-22 17:49:54 +02002190 goto error;
2191 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002192 }
2193
2194 lyxml_free_elem(ctx, node);
2195 }
2196
2197 /* last part - process data nodes */
2198 LY_TREE_FOR_SAFE(root.child, next, node) {
2199
2200 if (!strcmp(node->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002201 mnode = read_yin_container(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002202 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002203 mnode = read_yin_leaflist(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002204 } else if (!strcmp(node->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002205 mnode = read_yin_leaf(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002206 } else if (!strcmp(node->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002207 mnode = read_yin_list(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002208 } else if (!strcmp(node->name, "choice")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002209 mnode = read_yin_choice(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002210 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002211 mnode = read_yin_grouping(module, NULL, node);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002212 } else if (!strcmp(node->name, "uses")) {
2213 mnode = read_yin_uses(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002214 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02002215 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002216 continue;
2217 }
2218 lyxml_free_elem(ctx, node);
2219
Radek Krejci25d782a2015-05-22 15:03:23 +02002220 if (!mnode) {
2221 goto error;
2222 }
2223
2224 /* include data element */
2225 if (module->data) {
2226 module->data->prev->next = mnode;
2227 mnode->prev = module->data->prev;
2228 module->data->prev = mnode;
2229 } else {
2230 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002231 }
2232 }
2233
Radek Krejciefaeba32015-05-27 14:30:57 +02002234 return EXIT_SUCCESS;
2235
2236error:
2237 /* cleanup */
2238 while (root.child) {
2239 lyxml_free_elem(module->ctx, root.child);
2240 }
2241
2242 return EXIT_FAILURE;
2243}
2244
2245struct ly_submodule *yin_read_submodule(struct ly_module *module, const char *data)
2246{
2247 struct lyxml_elem *yin;
Radek Krejci3045cf32015-05-28 10:58:52 +02002248 struct ly_submodule *submodule = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02002249 const char *value;
2250
Radek Krejci812b10a2015-05-28 16:48:25 +02002251 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02002252
2253 yin = lyxml_read(module->ctx, data, 0);
2254 if (!yin) {
2255 return NULL;
2256 }
2257
2258 /* check root element */
2259 if (!yin->name || strcmp(yin->name, "submodule")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002260 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002261 goto error;
2262 }
2263
Radek Krejci0af13872015-05-30 11:50:52 +02002264 GETVAL(value, yin, "name");
2265 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002266 goto error;
2267 }
2268
2269 submodule = calloc(1, sizeof *submodule);
2270 if (!submodule) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002271 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002272 goto error;
2273 }
2274
2275 submodule->ctx = module->ctx;
2276 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
Radek Krejcice7fb782015-05-29 16:52:34 +02002277 submodule->type = 1;
Radek Krejciefaeba32015-05-27 14:30:57 +02002278
Radek Krejci3045cf32015-05-28 10:58:52 +02002279 LOGVRB("reading submodule %s", submodule->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002280 if (read_sub_module((struct ly_module *)submodule, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002281 goto error;
2282 }
2283
2284 /* cleanup */
2285 lyxml_free_elem(module->ctx, yin);
2286
Radek Krejci3045cf32015-05-28 10:58:52 +02002287 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002288
2289 return submodule;
2290
2291error:
2292 /* cleanup */
2293 lyxml_free_elem(module->ctx, yin);
2294 ly_submodule_free(submodule);
2295
2296 return NULL;
2297}
2298
2299struct ly_module *yin_read_module(struct ly_ctx *ctx, const char *data)
2300{
2301 struct lyxml_elem *yin;
2302 struct ly_module *module = NULL, **newlist = NULL;
2303 const char *value;
2304 int i;
2305
2306 yin = lyxml_read(ctx, data, 0);
2307 if (!yin) {
2308 return NULL;
2309 }
2310
2311 /* check root element */
2312 if (!yin->name || strcmp(yin->name, "module")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002313 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002314 goto error;
2315 }
2316
Radek Krejci0af13872015-05-30 11:50:52 +02002317 GETVAL(value, yin, "name");
2318 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002319 goto error;
2320 }
2321
2322 module = calloc(1, sizeof *module);
2323 if (!module) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002324 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002325 goto error;
2326 }
2327
2328 module->ctx = ctx;
2329 module->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02002330 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02002331
Radek Krejci3045cf32015-05-28 10:58:52 +02002332 LOGVRB("reading module %s", module->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002333 if (read_sub_module(module, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002334 goto error;
2335 }
2336
Radek Krejcida04f4a2015-05-21 12:54:09 +02002337 /* add to the context's list of modules */
2338 if (ctx->models.used == ctx->models.size) {
2339 newlist = realloc(ctx->models.list, ctx->models.size * 2);
2340 if (!newlist) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002341 LOGMEM;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002342 goto error;
2343 }
2344 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
2345 newlist[i] = NULL;
2346 }
2347 ctx->models.size *= 2;
2348 ctx->models.list = newlist;
2349 }
Radek Krejcif6e5e182015-05-27 17:18:07 +02002350 for (i = 0; ctx->models.list[i]; i++) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002351 /* check name (name/revision) and namespace uniqueness */
Radek Krejcif6e5e182015-05-27 17:18:07 +02002352 if (!strcmp(ctx->models.list[i]->name, module->name)) {
2353 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
2354 /* both data models are same, with no revision specified */
Radek Krejci3045cf32015-05-28 10:58:52 +02002355 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.", module->name);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002356 goto error;
2357 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
2358 /* one of the models does not have a revision, so they differs */
2359 continue;
2360 } else {
2361 /* both models have a revision statement which we have to
2362 * compare, revision at position 0 is the last revision
2363 */
2364 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
2365 /* we have the same modules */
Radek Krejci3045cf32015-05-28 10:58:52 +02002366 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name, module->rev[0].date);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002367 goto error;
2368 }
2369 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002370 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
2371 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
2372 ctx->models.list[i]->name, module->name, module->ns);
2373 goto error;
Radek Krejcif6e5e182015-05-27 17:18:07 +02002374 }
2375 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002376 ctx->models.list[i] = module;
2377 ctx->models.used++;
2378
2379 /* cleanup */
2380 lyxml_free_elem(ctx, yin);
2381
Radek Krejci3045cf32015-05-28 10:58:52 +02002382 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002383
2384 return module;
2385
2386error:
2387 /* cleanup */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002388 lyxml_free_elem(ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02002389 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002390
2391 return NULL;
2392}