blob: f555d52487ee43a54ce6e0c00384041c4abcc8e0 [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 Krejci345ad742015-06-03 11:04:18 +0200223static int check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line, const char *name, int len)
224{
225 char *dup = NULL;
226 int j;
227
228 /* existence */
229 if (!key) {
230 if (name[len] != '\0') {
231 dup = strdup(name);
232 dup[len] = '\0';
233 name = dup;
234 }
235 LOGVAL(VE_KEY_MISS, line, name);
236 free(dup);
237 return EXIT_FAILURE;
238 }
239
240 /* uniqueness */
241 for (j = index - 1; j >= 0; j--) {
242 if (list[index] == list[j]) {
243 LOGVAL(VE_KEY_DUP, line, key->name);
244 return EXIT_FAILURE;
245 }
246 }
247
248 /* key is a leaf */
249 if (key->nodetype != LY_NODE_LEAF) {
250 LOGVAL(VE_KEY_NLEAF, line, key->name);
251 return EXIT_FAILURE;
252 }
253
254 /* type of the leaf is not built-in empty */
255 if (key->type.base == LY_TYPE_EMPTY) {
256 LOGVAL(VE_KEY_TYPE, line, key->name);
257 return EXIT_FAILURE;
258 }
259
260 /* config attribute is the same as of the list */
261 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
262 LOGVAL(VE_KEY_CONFIG, line, key->name);
263 return EXIT_FAILURE;
264 }
265
266 return EXIT_SUCCESS;
267}
268
Radek Krejci4c31f122015-06-02 14:51:22 +0200269static int check_default(struct ly_type *type, const char* value)
Radek Krejcieac35532015-05-31 19:09:15 +0200270{
271 /* TODO - RFC 6020, sec. 7.3.4 */
Radek Krejci4c31f122015-06-02 14:51:22 +0200272 (void)type;
273 (void)value;
Radek Krejcieac35532015-05-31 19:09:15 +0200274 return EXIT_SUCCESS;
275}
276
Radek Krejcice7fb782015-05-29 16:52:34 +0200277static int check_date(const char* date, unsigned int line)
278{
279 int i;
280
281 assert(date);
282
283 if (strlen(date) != LY_REV_SIZE - 1) {
284 goto error;
285 }
286
287 for (i = 0; i < LY_REV_SIZE - 1; i++) {
288 if (i == 4 || i == 7) {
289 if (date[i] != '-') {
290 goto error;
291 }
292 } else if (!isdigit(date[i])) {
293 goto error;
294 }
295 }
296
297 return EXIT_SUCCESS;
298
299error:
300
301 LOGVAL(VE_INDATE, line, date);
302 return EXIT_FAILURE;
303}
304
Radek Krejci0af13872015-05-30 11:50:52 +0200305static const char *read_yin_text(struct ly_ctx *ctx, struct lyxml_elem *node)
Radek Krejcice7fb782015-05-29 16:52:34 +0200306{
307 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200308
309 /* there should be <text> child */
310 if (!node->child || !node->child->name
311 || strcmp(node->child->name, "text")) {
Radek Krejci0af13872015-05-30 11:50:52 +0200312 LOGWRN("Expected \"text\" element in \"%s\" element.", node->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200313 } else if (node->child->content) {
314 len = strlen(node->child->content);
315 return lydict_insert(ctx, node->child->content, len);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200316 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200317
318 LOGVAL(VE_INARG, LOGLINE(node), "text", node->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200319 return NULL;
320}
321
322static struct ly_tpdf *find_superior_type(const char *name,
323 struct ly_module *module,
324 struct ly_mnode *parent)
325{
Radek Krejciefaeba32015-05-27 14:30:57 +0200326 int i, j, found = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200327 int prefix_len = 0;
328 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +0200329 struct ly_tpdf *tpdf;
330 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200331
332 qname = strchr(name, ':');
333
334 if (!qname) {
335 /* no prefix, try built-in types */
336 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
337 if (!strcmp(ly_types[i].def->name, name)) {
338 return ly_types[i].def;
339 }
340 }
341 qname = name;
342 } else {
343 /* set qname to correct position after colon */
344 prefix_len = qname - name;
345 qname++;
346
347 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
348 /* prefix refers to the current module, ignore it */
349 prefix_len = 0;
350 }
351 }
352
353 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200354 /* search in local typedefs */
355 while (parent) {
356 switch (parent->nodetype) {
357 case LY_NODE_CONTAINER:
358 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
359 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
360 break;
361 case LY_NODE_LIST:
362 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
363 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
364 break;
365 case LY_NODE_GROUPING:
366 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
367 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
368 break;
369 default:
370 parent = parent->parent;
371 continue;
372 }
373
374 for (i = 0; i < tpdf_size; i++) {
375 if (!strcmp(tpdf[i].name, qname)) {
376 return &tpdf[i];
377 }
378 }
379
380 parent = parent->parent;
381 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200382 } else if (prefix_len) {
383 /* get module where to search */
384 for (i = 0; i < module->imp_size; i++) {
385 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
386 module = module->imp[i].module;
387 found = 1;
388 break;
389 }
390 }
391 if (!found) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200392 return NULL;
393 }
394 }
395
396 /* search in top level typedefs */
397 for (i = 0; i < module->tpdf_size; i++) {
398 if (!strcmp(module->tpdf[i].name, qname)) {
399 return &module->tpdf[i];
400 }
401 }
402
Radek Krejciefaeba32015-05-27 14:30:57 +0200403 /* search in submodules */
404 for (i = 0; i < module->inc_size; i++) {
405 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
406 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
407 return &module->inc[i].submodule->tpdf[j];
408 }
409 }
410 }
411
412 return NULL;
413}
414
415static struct ly_ident *find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
416{
Radek Krejcice7fb782015-05-29 16:52:34 +0200417 unsigned int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200418 struct ly_ident *base_iter;
419 struct ly_ident_der *der;
420
421 for (i = 0; i < module->ident_size; i++) {
422 if (!strcmp(basename, module->ident[i].name)) {
423 /* we are done */
424
425 if (!ident) {
426 /* just search for type, so do not modify anything, just return
427 * the base identity pointer
428 */
429 return &module->ident[i];
430 }
431
432 /* we are resolving identity definition, so now update structures */
433 ident->base = base_iter = &module->ident[i];
434
435 while (base_iter) {
436 for (der = base_iter->der; der && der->next; der = der->next);
437 if (der) {
438 der->next = malloc(sizeof *der);
439 der = der->next;
440 } else {
441 ident->base->der = der = malloc(sizeof *der);
442 }
443 der->next = NULL;
444 der->ident = ident;
445
446 base_iter = base_iter->base;
447 }
448 return ident->base;
449 }
450 }
451
Radek Krejcida04f4a2015-05-21 12:54:09 +0200452 return NULL;
453}
454
Radek Krejci3045cf32015-05-28 10:58:52 +0200455static 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 +0200456{
457 const char *name;
458 int prefix_len = 0;
459 int i, found = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200460 struct ly_ident *result;
Radek Krejci3045cf32015-05-28 10:58:52 +0200461 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200462
Radek Krejci3045cf32015-05-28 10:58:52 +0200463 basename = lyxml_get_attr(node, "name", NULL);
Radek Krejci04581c62015-05-22 21:24:00 +0200464 if (!basename) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200465 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
Radek Krejci04581c62015-05-22 21:24:00 +0200466 return NULL;
467 }
468
469 /* search for the base identity */
470 name = strchr(basename, ':');
471 if (name) {
472 /* set name to correct position after colon */
473 prefix_len = name - basename;
474 name++;
475
476 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
477 /* prefix refers to the current module, ignore it */
478 prefix_len = 0;
479 }
480 } else {
481 name = basename;
482 }
483
484 if (prefix_len) {
485 /* get module where to search */
486 for (i = 0; i < module->imp_size; i++) {
487 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
488 && !module->imp[i].prefix[prefix_len]) {
489 module = module->imp[i].module;
490 found = 1;
491 break;
492 }
493 }
494 if (!found) {
495 /* identity refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +0200496 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
Radek Krejci04581c62015-05-22 21:24:00 +0200497 return NULL;
498 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200499 } else {
500 /* search in submodules */
501 for (i = 0; i < module->inc_size; i++) {
502 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
503 if (result) {
504 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200505 }
Radek Krejci04581c62015-05-22 21:24:00 +0200506 }
507 }
508
Radek Krejciefaeba32015-05-27 14:30:57 +0200509 /* search in the identified module */
510 result = find_base_ident_sub(module, ident, name);
511 if (!result) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200512 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
Radek Krejciefaeba32015-05-27 14:30:57 +0200513 }
514
515 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200516}
517
518static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
519{
520 struct lyxml_elem *node, *next;
521
522 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
523 return EXIT_FAILURE;
524 }
525 ident->module = module;
526
527 LY_TREE_FOR_SAFE(yin->child, next, node) {
528 if (!strcmp(node->name, "base")) {
529 if (ident->base) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200530 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200531 return EXIT_FAILURE;
532 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200533 if (!find_base_ident(module, ident, node)) {
Radek Krejci04581c62015-05-22 21:24:00 +0200534 return EXIT_FAILURE;
535 }
536 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200537 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200538 return EXIT_FAILURE;
539 }
540
541 lyxml_free_elem(module->ctx, node);
542 }
543
544 return EXIT_SUCCESS;
545}
546
Radek Krejcida04f4a2015-05-21 12:54:09 +0200547static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
548 struct lyxml_elem *yin, struct ly_type *type)
549{
Radek Krejci25d782a2015-05-22 15:03:23 +0200550 const char *value, *delim;
551 struct lyxml_elem *next, *node, root = {0};
552 int i, j, r;
553 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200554
Radek Krejci800af702015-06-02 13:46:01 +0200555 GETVAL(value, yin, "name")
Radek Krejci25d782a2015-05-22 15:03:23 +0200556 delim = strchr(value, ':');
557 if (delim) {
558 type->prefix = lydict_insert(module->ctx, value, delim - value);
559 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200560
Radek Krejcida04f4a2015-05-21 12:54:09 +0200561 type->der = find_superior_type(value, module, parent);
Radek Krejci3045cf32015-05-28 10:58:52 +0200562 if (!type->der) {
563 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +0200564 goto error;
Radek Krejci3045cf32015-05-28 10:58:52 +0200565 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200566 type->base = type->der->type.base;
567
568 switch (type->base) {
569 case LY_TYPE_BINARY:
Radek Krejci800af702015-06-02 13:46:01 +0200570 /* TODO length, 9.4.4
Radek Krejci04581c62015-05-22 21:24:00 +0200571 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
572 * hodnoty se musi vejit do 64b, podelementy
Radek Krejci25d782a2015-05-22 15:03:23 +0200573 */
574 break;
575 case LY_TYPE_BITS:
Radek Krejci800af702015-06-02 13:46:01 +0200576 /* TODO bit, 9.7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200577 * 1..n, nerekurzivni, stringy s podelementy */
578 break;
579 case LY_TYPE_DEC64:
Radek Krejci800af702015-06-02 13:46:01 +0200580 /* TODO fraction-digits, 9.3.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200581 * - MUST, 1, nerekurzivni, hodnota 1-18 */
Radek Krejci800af702015-06-02 13:46:01 +0200582 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200583 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
584 break;
585 case LY_TYPE_ENUM:
Radek Krejci6793db02015-05-22 17:49:54 +0200586 /* RFC 6020 9.6 */
Radek Krejci04581c62015-05-22 21:24:00 +0200587
Radek Krejci25d782a2015-05-22 15:03:23 +0200588 /* get enum specification, at least one must be present */
589 LY_TREE_FOR_SAFE(yin->child, next, node) {
590 if (!strcmp(node->name, "enum")) {
591 lyxml_unlink_elem(node);
592 lyxml_add_child(&root, node);
593 type->info.enums.count++;
594 }
595 }
596 if (yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200597 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200598 goto error;
599 }
600 if (!type->info.enums.count) {
601 if (type->der->type.der) {
602 /* this is just a derived type with no enum specified */
603 break;
604 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200605 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
Radek Krejci25d782a2015-05-22 15:03:23 +0200606 goto error;
607 }
608
609 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
610 for (i = v = 0; root.child; i++) {
611 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0);
612 if (r) {
613 type->info.enums.count = i + 1;
614 goto error;
615 }
616 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
617 value = type->info.enums.list[i].name;
618 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200619 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
Radek Krejci25d782a2015-05-22 15:03:23 +0200620 type->info.enums.count = i + 1;
621 goto error;
622 }
623
624 /* check the name uniqueness */
625 for (j = 0; j < i; j++) {
626 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200627 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200628 type->info.enums.count = i + 1;
629 goto error;
630 }
631 }
632
633 node = root.child->child;
634 if (node && !strcmp(node->name, "value")) {
635 value = lyxml_get_attr(node, "value", NULL);
636 v_ = strtol(value, NULL, 10);
637
638 /* range check */
639 if (v_ < INT32_MIN || v_ > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200640 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200641 type->info.enums.count = i + 1;
642 goto error;
643 }
644 type->info.enums.list[i].value = v_;
645
646 /* keep the highest enum value for automatic increment */
647 if (type->info.enums.list[i].value > v) {
648 v = type->info.enums.list[i].value;
649 v++;
650 } else {
651 /* check that the value is unique */
652 for (j = 0; j < i; j++) {
653 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200654 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 +0200655 type->info.enums.count = i + 1;
656 goto error;
657 }
658 }
659 }
660 } else {
661 /* assign value automatically */
662 if (v > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200663 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200664 type->info.enums.count = i + 1;
665 goto error;
666 }
667 type->info.enums.list[i].value = v;
668 v++;
669 }
670 lyxml_free_elem(module->ctx, root.child);
671 }
672 break;
673 case LY_TYPE_IDENT:
Radek Krejci04581c62015-05-22 21:24:00 +0200674 /* RFC 6020 9.10 */
675
676 /* get base specification, exactly one must be present */
677 if (!yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200678 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
Radek Krejci04581c62015-05-22 21:24:00 +0200679 goto error;
680 }
681 if (strcmp(yin->child->name, "base")) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200682 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200683 goto error;
684 }
685 if (yin->child->next) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200686 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200687 goto error;
688 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200689 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
Radek Krejci04581c62015-05-22 21:24:00 +0200690 if (!type->info.ident.ref) {
691 return EXIT_FAILURE;
692 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200693 break;
694 case LY_TYPE_INST:
Radek Krejci800af702015-06-02 13:46:01 +0200695 /* TODO require-instance, 9.13.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200696 * - 0..1, true/false */
697 break;
698 case LY_TYPE_INT8:
699 case LY_TYPE_INT16:
700 case LY_TYPE_INT32:
701 case LY_TYPE_INT64:
702 case LY_TYPE_UINT8:
703 case LY_TYPE_UINT16:
704 case LY_TYPE_UINT32:
705 case LY_TYPE_UINT64:
Radek Krejci800af702015-06-02 13:46:01 +0200706 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200707 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
708 break;
709 case LY_TYPE_LEAFREF:
Radek Krejci800af702015-06-02 13:46:01 +0200710 /* TODO path, 9.9.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200711 * - 1, nerekurzivni, string */
712 break;
713 case LY_TYPE_STRING:
Radek Krejci800af702015-06-02 13:46:01 +0200714 /* TODO length, 9.4.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200715 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
716 * pattern, 9.4.6
717 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
718 break;
719 case LY_TYPE_UNION:
Radek Krejci800af702015-06-02 13:46:01 +0200720 /* TODO type, 7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200721 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
722 break;
723 default:
724 /* nothing needed :
725 * LY_TYPE_BOOL, LY_TYPE_EMPTY
726 */
727 break;
728 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200729
730 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200731
732error:
733
734 while(root.child) {
735 lyxml_free_elem(module->ctx, root.child);
736 }
737
738 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200739}
740
741static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
742 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
743{
744 const char *value;
745 struct lyxml_elem *node, *next;
Radek Krejci76c45d32015-05-26 16:01:14 +0200746 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200747
Radek Krejcieac35532015-05-31 19:09:15 +0200748 GETVAL(value, yin, "name");
749 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
750 goto error;
751 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200752 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
753
Radek Krejcieac35532015-05-31 19:09:15 +0200754 /* generic part - status, description, reference */
755 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, 0)) {
756 goto error;
757 }
758
Radek Krejcida04f4a2015-05-21 12:54:09 +0200759 LY_TREE_FOR_SAFE(yin->child, next, node) {
760 if (!strcmp(node->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200761 if (tpdf->type.der) {
762 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
763 goto error;
764 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200765 r = fill_yin_type(module, parent, node, &tpdf->type);
Radek Krejcieac35532015-05-31 19:09:15 +0200766 } else if (!strcmp(node->name, "default")) {
767 if (tpdf->dflt) {
768 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
769 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200770 }
Radek Krejcieac35532015-05-31 19:09:15 +0200771 GETVAL(value, node, "value");
772 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
773 } else if (!strcmp(node->name, "units")) {
774 if (tpdf->units) {
775 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
776 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200777 }
Radek Krejcieac35532015-05-31 19:09:15 +0200778 GETVAL(value, node, "name");
779 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
780 } else {
781 LOGVAL(VE_INSTMT, LOGLINE(node), value);
782 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200783 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200784 lyxml_free_elem(module->ctx, node);
785 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +0200786 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200787 }
788 }
789
Radek Krejcieac35532015-05-31 19:09:15 +0200790 /* check mandatory value */
Radek Krejci25d782a2015-05-22 15:03:23 +0200791 if (!tpdf->type.der) {
Radek Krejci4c31f122015-06-02 14:51:22 +0200792 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
Radek Krejcieac35532015-05-31 19:09:15 +0200793 goto error;
794 }
795
Radek Krejci4c31f122015-06-02 14:51:22 +0200796 /* check default value */
797 if (check_default(&tpdf->type, tpdf->dflt)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200798 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200799 }
800
801 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200802
803error:
804
805 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200806}
807
Radek Krejci800af702015-06-02 13:46:01 +0200808static int fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
809{
810 struct lyxml_elem *child;
811 const char *value;
812
813 GETVAL(value, yin, "condition");
814 must->cond = lydict_insert(module->ctx, value, strlen(value));
815
816 LY_TREE_FOR(yin->child, child) {
817 if (!strcmp(child->name, "description")) {
818 if (must->dsc) {
819 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
820 goto error;
821 }
822 must->dsc = read_yin_text(module->ctx, child);
823 if (!must->dsc) {
824 goto error;
825 }
826 } else if (!strcmp(child->name, "reference")) {
827 if (must->ref) {
828 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
829 goto error;
830 }
831 must->ref = read_yin_text(module->ctx, child);
832 if (!must->ref) {
833 goto error;
834 }
835 } else if (!strcmp(child->name, "error-app-tag")) {
836 if (must->eapptag) {
837 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
838 goto error;
839 }
840 must->eapptag = read_yin_text(module->ctx, child);
841 if (!must->eapptag) {
842 goto error;
843 }
844 } else if (!strcmp(child->name, "error-message")) {
845 if (must->emsg) {
846 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
847 goto error;
848 }
849 must->emsg = read_yin_text(module->ctx, child);
850 if (!must->emsg) {
851 goto error;
852 }
853 } else {
854 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
855 goto error;
856 }
857
858 lyxml_free_elem(module->ctx, child);
859 }
860
861
862 return EXIT_SUCCESS;
863
864error:
865
866 return EXIT_FAILURE;
867}
868
Radek Krejciefaeba32015-05-27 14:30:57 +0200869static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
870{
871 struct lyxml_elem *child;
872 const char *value;
873
874 LY_TREE_FOR(yin->child, child) {
875 if (!strcmp(child->name, "prefix")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200876 GETVAL(value, child, "value");
Radek Krejci0af13872015-05-30 11:50:52 +0200877 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
878 goto error;
879 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200880 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
881 } else if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200882 if (imp->rev[0]) {
883 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
884 goto error;
885 }
886 GETVAL(value, child, "date");
887 if (check_date(value, LOGLINE(child))) {
888 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200889 }
890 memcpy(imp->rev, value, LY_REV_SIZE - 1);
891 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200892 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200893 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200894 }
895 }
896
Radek Krejcice7fb782015-05-29 16:52:34 +0200897 /* check mandatory information */
898 if (!imp->prefix) {
899 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
900 goto error;
901 }
902
903 GETVAL(value, yin, "module");
Radek Krejci0af13872015-05-30 11:50:52 +0200904 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
Radek Krejciefaeba32015-05-27 14:30:57 +0200905 if (!imp->module) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200906 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200907 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200908 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
909 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200910 }
911
912 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200913
914error:
915
916 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200917}
918
919static int fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
920{
921 struct lyxml_elem *child;
922 const char *value;
923
924 LY_TREE_FOR(yin->child, child) {
925 if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200926 if (inc->rev[0]) {
927 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
928 goto error;
929 }
930 GETVAL(value, child, "date");
931 if (check_date(value, LOGLINE(child))) {
932 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200933 }
934 memcpy(inc->rev, value, LY_REV_SIZE - 1);
935 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200936 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200937 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200938 }
939 }
940
Radek Krejcice7fb782015-05-29 16:52:34 +0200941 GETVAL(value, yin, "module");
Radek Krejciefaeba32015-05-27 14:30:57 +0200942 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
943 if (!inc->submodule) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200944 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200945 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200946 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
947 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200948 }
949
Radek Krejcice7fb782015-05-29 16:52:34 +0200950 /* check that belongs-to corresponds */
951 if (module->type) {
952 module = ((struct ly_submodule *)module)->belongsto;
953 }
954 if (inc->submodule->belongsto != module) {
955 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
956 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
957 goto error;
958 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200959
960 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200961
962error:
963
964 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200965}
966
967
Radek Krejcida04f4a2015-05-21 12:54:09 +0200968/*
969 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200970 * description, reference, status, optionaly config
Radek Krejcida04f4a2015-05-21 12:54:09 +0200971 */
972static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejci25d782a2015-05-22 15:03:23 +0200973 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int ext)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200974{
975 const char *value;
976 struct lyxml_elem *sub, *next;
977 struct ly_ctx * const ctx = module->ctx;
Radek Krejcice7fb782015-05-29 16:52:34 +0200978 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200979
Radek Krejci25d782a2015-05-22 15:03:23 +0200980 if (ext) {
981 mnode->module = module;
982 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200983
Radek Krejci800af702015-06-02 13:46:01 +0200984 GETVAL(value, xmlnode, "name");
985 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200986 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200987 }
Radek Krejci800af702015-06-02 13:46:01 +0200988 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +0200989
990 /* process local parameters */
991 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
992 if (!strcmp(sub->name, "description")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200993 if (mnode->dsc) {
994 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
995 goto error;
996 }
Radek Krejci0af13872015-05-30 11:50:52 +0200997 mnode->dsc = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200998 if (!mnode->dsc) {
999 r = 1;
1000 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001001 } else if (!strcmp(sub->name, "reference")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001002 if (mnode->ref) {
1003 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1004 goto error;
1005 }
Radek Krejci0af13872015-05-30 11:50:52 +02001006 mnode->ref = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +02001007 if (!mnode->ref) {
1008 r = 1;
1009 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001010 } else if (!strcmp(sub->name, "status")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001011 if (mnode->flags & LY_NODE_STATUS_MASK) {
1012 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1013 goto error;
1014 }
1015 GETVAL(value, sub, "value");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001016 if (!strcmp(value, "current")) {
1017 mnode->flags |= LY_NODE_STATUS_CURR;
1018 } else if (!strcmp(value, "deprecated")) {
1019 mnode->flags |= LY_NODE_STATUS_DEPRC;
1020 } else if (!strcmp(value, "obsolete")) {
1021 mnode->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejcice7fb782015-05-29 16:52:34 +02001022 } else {
1023 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1024 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001025 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001026 } else if (ext && !strcmp(sub->name, "config")) {
Radek Krejcieac35532015-05-31 19:09:15 +02001027 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1028 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1029 goto error;
1030 }
1031 GETVAL(value, sub, "value");
Radek Krejci25d782a2015-05-22 15:03:23 +02001032 if (!strcmp(value, "false")) {
1033 mnode->flags |= LY_NODE_CONFIG_R;
1034 } else if (!strcmp(value, "false")) {
1035 mnode->flags |= LY_NODE_CONFIG_W;
Radek Krejcice7fb782015-05-29 16:52:34 +02001036 } else {
1037 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1038 r = 1;
Radek Krejci25d782a2015-05-22 15:03:23 +02001039 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001040 } else {
1041 /* skip the lyxml_free_elem */
1042 continue;
1043 }
1044 lyxml_free_elem(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +02001045 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +02001046 goto error;
Radek Krejcice7fb782015-05-29 16:52:34 +02001047 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001048 }
1049
Radek Krejci25d782a2015-05-22 15:03:23 +02001050 if (ext && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001051 /* get config flag from parent */
1052 if (parent) {
1053 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1054 } else {
1055 /* default config is true */
1056 mnode->flags |= LY_NODE_CONFIG_W;
1057 }
1058 }
1059
1060 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001061
1062error:
1063
1064 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001065}
1066
1067static struct ly_mnode *read_yin_choice(struct ly_module *module,
1068 struct ly_mnode *parent,
1069 struct lyxml_elem *node)
1070{
1071 struct lyxml_elem *sub, *next;
1072 struct ly_ctx * const ctx = module->ctx;
Radek Krejci25d782a2015-05-22 15:03:23 +02001073 struct ly_mnode *retval, *r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001074 struct ly_mnode_choice *choice;
1075
Radek Krejcida04f4a2015-05-21 12:54:09 +02001076 choice = calloc(1, sizeof *choice);
1077 choice->nodetype = LY_NODE_CHOICE;
1078 choice->module = module;
1079 choice->prev = (struct ly_mnode *)choice;
1080 retval = (struct ly_mnode *)choice;
1081
Radek Krejci25d782a2015-05-22 15:03:23 +02001082 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001083 goto error;
1084 }
1085
1086 /* process choice's specific children */
1087 LY_TREE_FOR_SAFE(node->child, next, sub) {
1088 if (!strcmp(sub->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001089 r = read_yin_container(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001090 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001091 r = read_yin_leaflist(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001092 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001093 r = read_yin_leaf(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001094 } else if (!strcmp(sub->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001095 r = read_yin_list(module, retval, sub);
Radek Krejci667b97f2015-05-25 15:03:30 +02001096 } else {
1097 continue;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001098 }
1099 lyxml_free_elem(ctx, sub);
Radek Krejci25d782a2015-05-22 15:03:23 +02001100 if (!r) {
1101 goto error;
1102 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001103 }
1104
Radek Krejci812b10a2015-05-28 16:48:25 +02001105 if (parent) {
1106 ly_mnode_addchild(parent, retval);
1107 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001108
1109 return retval;
1110
1111error:
1112
1113 ly_mnode_free(retval);
1114
1115 return NULL;
1116}
1117
1118static struct ly_mnode *read_yin_leaf(struct ly_module *module,
1119 struct ly_mnode *parent,
Radek Krejci4c31f122015-06-02 14:51:22 +02001120 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001121{
1122 struct ly_mnode *retval;
1123 struct ly_mnode_leaf *leaf;
1124 struct lyxml_elem *sub, *next;
Radek Krejci4c31f122015-06-02 14:51:22 +02001125 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001126 int r;
Radek Krejci4c31f122015-06-02 14:51:22 +02001127 int c_must = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001128
Radek Krejcida04f4a2015-05-21 12:54:09 +02001129 leaf = calloc(1, sizeof *leaf);
1130 leaf->nodetype = LY_NODE_LEAF;
1131 leaf->prev = (struct ly_mnode *)leaf;
1132 retval = (struct ly_mnode *)leaf;
1133
Radek Krejci4c31f122015-06-02 14:51:22 +02001134 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001135 goto error;
1136 }
1137
Radek Krejci4c31f122015-06-02 14:51:22 +02001138 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001139 if (!strcmp(sub->name, "type")) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001140 if (leaf->type.der) {
1141 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1142 goto error;
1143 }
1144 if (fill_yin_type(module, parent, sub, &leaf->type)) {
1145 goto error;
1146 }
1147 } else if (!strcmp(sub->name, "default")) {
1148 if (leaf->dflt) {
1149 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1150 goto error;
1151 }
1152 GETVAL(value, sub, "value");
1153 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
1154 } else if (!strcmp(sub->name, "units")) {
1155 if (leaf->units) {
1156 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1157 goto error;
1158 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001159 GETVAL(value, sub, "name");
Radek Krejci4c31f122015-06-02 14:51:22 +02001160 leaf->units = lydict_insert(module->ctx, value, strlen(value));
1161 } else if (!strcmp(sub->name, "mandatory")) {
1162 if (f_mand) {
1163 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1164 goto error;
1165 }
1166 /* just checking the flags in leaf is not sufficient, we would allow
1167 * multiple mandatory statements with the "false" value
1168 */
1169 f_mand = 1;
1170
1171 GETVAL(value, sub, "value");
1172 if (!strcmp(value, "true")) {
1173 leaf->flags |= LY_NODE_MANDATORY;
1174 } else if (strcmp(value, "false")) {
1175 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1176 goto error;
1177 } /* else false is the default value, so we can ignore it */
1178 } else if (!strcmp(sub->name, "must")) {
1179 c_must++;
1180
1181 /* skip element free at the end of the loop */
1182 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001183#if 0
Radek Krejci4c31f122015-06-02 14:51:22 +02001184 } else {
1185 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1186 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001187#endif
Radek Krejci4c31f122015-06-02 14:51:22 +02001188 }
1189
1190 lyxml_free_elem(module->ctx, sub);
1191 }
1192
1193 /* check mandatory parameters */
1194 if (!leaf->type.der) {
1195 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1196 goto error;
1197 }
Radek Krejciccdec642015-06-03 10:58:45 +02001198 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001199 goto error;
1200 }
1201
1202 /* middle part - process nodes with cardinality of 0..n */
1203 if (c_must) {
1204 leaf->must = calloc(c_must, sizeof *leaf->must);
1205 }
1206
1207 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1208 if (!strcmp(sub->name, "must")) {
1209 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
1210 leaf->must_size++;
1211
Radek Krejci25d782a2015-05-22 15:03:23 +02001212 if (r) {
1213 goto error;
1214 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001215 }
Radek Krejci4c31f122015-06-02 14:51:22 +02001216
1217 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001218 }
1219
Radek Krejci812b10a2015-05-28 16:48:25 +02001220 if (parent) {
1221 ly_mnode_addchild(parent, retval);
1222 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001223
1224 return retval;
1225
1226error:
1227
1228 ly_mnode_free(retval);
1229
1230 return NULL;
1231}
1232
1233static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
1234 struct ly_mnode *parent,
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001235 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001236{
1237 struct ly_mnode *retval;
1238 struct ly_mnode_leaflist *llist;
1239 struct lyxml_elem *sub, *next;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001240 const char *value;
1241 char *endptr;
Radek Krejci17e93f92015-06-03 11:01:55 +02001242 unsigned long val;
Radek Krejci25d782a2015-05-22 15:03:23 +02001243 int r;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001244 int c_must = 0;
Radek Krejci17e93f92015-06-03 11:01:55 +02001245 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001246
Radek Krejcida04f4a2015-05-21 12:54:09 +02001247 llist = calloc(1, sizeof *llist);
1248 llist->nodetype = LY_NODE_LEAFLIST;
1249 llist->prev = (struct ly_mnode *)llist;
1250 retval = (struct ly_mnode *)llist;
1251
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001252 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001253 goto error;
1254 }
1255
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001256 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001257 if (!strcmp(sub->name, "type")) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001258 if (llist->type.der) {
1259 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1260 goto error;
1261 }
1262 if (fill_yin_type(module, parent, sub, &llist->type)) {
1263 goto error;
1264 }
1265 } else if (!strcmp(sub->name, "units")) {
1266 if (llist->units) {
1267 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1268 goto error;
1269 }
Radek Krejcif4f4d9f2015-06-03 10:57:45 +02001270 GETVAL(value, sub, "name");
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001271 llist->units = lydict_insert(module->ctx, value, strlen(value));
1272 } else if (!strcmp(sub->name, "ordered-by")) {
1273 if (f_ordr) {
1274 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1275 goto error;
1276 }
1277 /* just checking the flags in llist is not sufficient, we would
1278 * allow multiple ordered-by statements with the "system" value
1279 */
1280 f_ordr = 1;
1281
1282 if (llist->flags & LY_NODE_CONFIG_R) {
1283 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
1284 * state data
1285 */
1286 lyxml_free_elem(module->ctx, sub);
1287 continue;
1288 }
1289
1290 GETVAL(value, sub, "value");
1291 if (!strcmp(value, "user")) {
1292 llist->flags |= LY_NODE_USERORDERED;
1293 } else if (strcmp(value, "system")) {
1294 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1295 goto error;
1296 } /* else system is the default value, so we can ignore it */
1297 } else if (!strcmp(sub->name, "must")) {
1298 c_must++;
1299
1300 /* skip element free at the end of the loop */
1301 continue;
1302 } else if (!strcmp(sub->name, "min-elements")) {
1303 if (f_min) {
1304 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1305 goto error;
1306 }
1307 f_min = 1;
1308
1309 GETVAL(value, sub, "value");
1310 while(isspace(value[0])) {
1311 value++;
1312 }
1313
1314 /* convert it to uint32_t */
1315 errno = 0;
1316 endptr = NULL;
1317 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001318 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001319 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1320 goto error;
1321 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001322 llist->min = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001323 } else if (!strcmp(sub->name, "max-elements")) {
1324 if (f_max) {
1325 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1326 goto error;
1327 }
1328 f_max = 1;
1329
1330 GETVAL(value, sub, "value");
1331 while(isspace(value[0])) {
1332 value++;
1333 }
1334
1335 /* convert it to uint32_t */
1336 errno = 0;
1337 endptr = NULL;
1338 val = strtoul(value, &endptr, 10);
Radek Krejci78fc30e2015-06-03 11:02:50 +02001339 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001340 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1341 goto error;
1342 }
Radek Krejci17e93f92015-06-03 11:01:55 +02001343 llist->max = (uint32_t)val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001344
1345 } else {
Radek Krejci1e3f8902015-06-03 11:00:11 +02001346#if 0
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001347 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1348 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001349#endif
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001350 }
1351
1352 lyxml_free_elem(module->ctx, sub);
1353 }
1354
1355 /* check constraints */
1356 if (!llist->type.der) {
1357 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1358 goto error;
1359 }
1360 if (llist->max && llist->min > llist->max) {
1361 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
1362 goto error;
1363 }
1364
1365 /* middle part - process nodes with cardinality of 0..n */
1366 if (c_must) {
1367 llist->must = calloc(c_must, sizeof *llist->must);
1368 }
1369
1370 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1371 if (!strcmp(sub->name, "must")) {
1372 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
1373 llist->must_size++;
1374
Radek Krejci25d782a2015-05-22 15:03:23 +02001375 if (r) {
1376 goto error;
1377 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001378 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02001379
1380 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001381 }
1382
Radek Krejci812b10a2015-05-28 16:48:25 +02001383 if (parent) {
1384 ly_mnode_addchild(parent, retval);
1385 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001386
1387 return retval;
1388
1389error:
1390
1391 ly_mnode_free(retval);
1392
1393 return NULL;
1394}
1395
1396static struct ly_mnode *read_yin_list(struct ly_module *module,
1397 struct ly_mnode *parent,
Radek Krejci345ad742015-06-03 11:04:18 +02001398 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001399{
1400 struct ly_mnode *retval, *mnode;
1401 struct ly_mnode_list *list;
Radek Krejci345ad742015-06-03 11:04:18 +02001402 struct ly_unique *uniq_s;
1403 struct lyxml_elem *sub, *next, root = {0}, uniq = {0};
1404 int i, r;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001405 size_t len;
Radek Krejci345ad742015-06-03 11:04:18 +02001406 int c_tpdf = 0, c_must = 0, c_uniq = 0;
1407 int f_ordr = 0, f_max = 0, f_min = 0;
1408 const char *key_str = NULL, *uniq_str, *value;
1409 char *auxs;
1410 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001411
Radek Krejcida04f4a2015-05-21 12:54:09 +02001412 list = calloc(1, sizeof *list);
1413 list->nodetype = LY_NODE_LIST;
1414 list->prev = (struct ly_mnode *)list;
1415 retval = (struct ly_mnode *)list;
1416
Radek Krejci345ad742015-06-03 11:04:18 +02001417 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001418 goto error;
1419 }
1420
1421 /* process list's specific children */
Radek Krejci345ad742015-06-03 11:04:18 +02001422 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001423 /* data statements */
1424 if (!strcmp(sub->name, "container") ||
1425 !strcmp(sub->name, "leaf-list") ||
1426 !strcmp(sub->name, "leaf") ||
1427 !strcmp(sub->name, "list") ||
1428 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001429 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001430 !strcmp(sub->name, "grouping")) {
1431 lyxml_unlink_elem(sub);
1432 lyxml_add_child(&root, sub);
1433
1434 /* array counters */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001435 } else if (!strcmp(sub->name, "key")) {
1436 /* check cardinality 0..1 */
1437 if (list->keys_size) {
Radek Krejci345ad742015-06-03 11:04:18 +02001438 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001439 goto error;
1440 }
1441
1442 /* count the number of keys */
Radek Krejci345ad742015-06-03 11:04:18 +02001443 GETVAL(value, sub, "value");
1444 key_str = value;
1445 while((value = strpbrk(value, " \t\n"))) {
Radek Krejcid7f0d012015-05-25 15:04:52 +02001446 list->keys_size++;
Radek Krejci345ad742015-06-03 11:04:18 +02001447 while(isspace(*value)) {
1448 value++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001449 }
1450 }
1451 list->keys_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001452 list->keys = calloc(list->keys_size, sizeof *list->keys);
Radek Krejci345ad742015-06-03 11:04:18 +02001453 } else if (!strcmp(sub->name, "unique")) {
1454 c_uniq++;
1455 lyxml_unlink_elem(sub);
1456 lyxml_add_child(&uniq, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001457 } else if (!strcmp(sub->name, "typedef")) {
1458 c_tpdf++;
Radek Krejci345ad742015-06-03 11:04:18 +02001459 } else if (!strcmp(sub->name, "must")) {
1460 c_must++;
1461
1462 /* optional stetments */
1463 } else if (!strcmp(sub->name, "ordered-by")) {
1464 if (f_ordr) {
1465 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1466 goto error;
1467 }
1468 /* just checking the flags in llist is not sufficient, we would
1469 * allow multiple ordered-by statements with the "system" value
1470 */
1471 f_ordr = 1;
1472
1473 if (list->flags & LY_NODE_CONFIG_R) {
1474 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
1475 * state data
1476 */
1477 lyxml_free_elem(module->ctx, sub);
1478 continue;
1479 }
1480
1481 GETVAL(value, sub, "value");
1482 if (!strcmp(value, "user")) {
1483 list->flags |= LY_NODE_USERORDERED;
1484 } else if (strcmp(value, "system")) {
1485 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1486 goto error;
1487 } /* else system is the default value, so we can ignore it */
1488
1489 lyxml_free_elem(module->ctx, sub);
1490 } else if (!strcmp(sub->name, "min-elements")) {
1491 if (f_min) {
1492 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1493 goto error;
1494 }
1495 f_min = 1;
1496
1497 GETVAL(value, sub, "value");
1498 while(isspace(value[0])) {
1499 value++;
1500 }
1501
1502 /* convert it to uint32_t */
1503 errno = 0;
1504 auxs = NULL;
1505 val = strtoul(value, &auxs, 10);
1506 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
1507 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1508 goto error;
1509 }
1510 list->min = (uint32_t)val;
1511 lyxml_free_elem(module->ctx, sub);
1512 } else if (!strcmp(sub->name, "max-elements")) {
1513 if (f_max) {
1514 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1515 goto error;
1516 }
1517 f_max = 1;
1518
1519 GETVAL(value, sub, "value");
1520 while(isspace(value[0])) {
1521 value++;
1522 }
1523
1524 /* convert it to uint32_t */
1525 errno = 0;
1526 auxs = NULL;
1527 val = strtoul(value, &auxs, 10);
1528 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1529 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1530 goto error;
1531 }
1532 list->max = (uint32_t)val;
1533 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001534 }
1535 }
1536
Radek Krejcid7f0d012015-05-25 15:04:52 +02001537 /* check - if list is configuration, key statement is mandatory */
Radek Krejci3a734ed2015-05-26 15:23:18 +02001538 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
Radek Krejci345ad742015-06-03 11:04:18 +02001539 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
1540 goto error;
1541 }
1542 if (list->max && list->min > list->max) {
1543 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001544 goto error;
1545 }
1546
Radek Krejcida04f4a2015-05-21 12:54:09 +02001547 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1548 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001549 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001550 }
Radek Krejci345ad742015-06-03 11:04:18 +02001551 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001552 if (!strcmp(sub->name, "typedef")) {
Radek Krejci345ad742015-06-03 11:04:18 +02001553 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
1554 list->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001555
1556 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001557 goto error;
1558 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001559 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001560 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001561 }
1562
Radek Krejci345ad742015-06-03 11:04:18 +02001563 /* process unique statements */
1564 if (c_uniq) {
1565 list->unique = calloc(c_uniq, sizeof *list->unique);
1566 }
1567 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
1568 /* count the number of unique values */
1569 GETVAL(value, sub, "value");
1570 uniq_str = value;
1571 uniq_s = &list->unique[list->unique_size];
1572 while((value = strpbrk(value, " \t\n"))) {
1573 uniq_s->leafs_size++;
1574 while(isspace(*value)) {
1575 value++;
1576 }
1577 }
1578 uniq_s->leafs_size++;
1579 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1580 list->unique_size++;
1581
1582 /* interconnect unique values with the leafs */
1583 /* TODO - include searching in uses/grouping */
1584 for (i = 0; i < uniq_s->leafs_size; i++) {
1585 if ((value = strpbrk(uniq_str, " \t\n"))) {
1586 len = value - uniq_str;
1587 while(isspace(*value)) {
1588 value++;
1589 }
1590 } else {
1591 len = strlen(uniq_str);
1592 }
1593 LY_TREE_FOR(list->child, mnode) {
1594 if (!strncmp(mnode->name, uniq_str, len) && !mnode->name[len]) {
1595 uniq_s->leafs[i] = (struct ly_mnode_leaf *)mnode;
1596 break;
1597 }
1598 }
1599
1600 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
1601 goto error;
1602 }
1603
1604 /* prepare for next iteration */
1605 while (value && isspace(*value)) {
1606 value++;
1607 }
1608 uniq_str = value;
1609 }
1610 }
1611
Radek Krejcida04f4a2015-05-21 12:54:09 +02001612 /* last part - process data nodes */
1613 LY_TREE_FOR_SAFE(root.child, next, sub) {
1614 if (!strcmp(sub->name, "container")) {
1615 mnode = read_yin_container(module, retval, sub);
1616 } else if (!strcmp(sub->name, "leaf-list")) {
1617 mnode = read_yin_leaflist(module, retval, sub);
1618 } else if (!strcmp(sub->name, "leaf")) {
1619 mnode = read_yin_leaf(module, retval, sub);
1620 } else if (!strcmp(sub->name, "list")) {
1621 mnode = read_yin_list(module, retval, sub);
1622 } else if (!strcmp(sub->name, "choice")) {
1623 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001624 } else if (!strcmp(sub->name, "uses")) {
1625 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001626 } else if (!strcmp(sub->name, "grouping")) {
1627 mnode = read_yin_grouping(module, retval, sub);
1628 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001629 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001630 continue;
1631 }
1632 lyxml_free_elem(module->ctx, sub);
1633
Radek Krejci25d782a2015-05-22 15:03:23 +02001634 if (!mnode) {
1635 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001636 }
1637 }
1638
Radek Krejci812b10a2015-05-28 16:48:25 +02001639 if (parent) {
1640 ly_mnode_addchild(parent, retval);
1641 }
1642
Radek Krejci3a734ed2015-05-26 15:23:18 +02001643 if (!key_str) {
1644 /* config false list without a key */
1645 return retval;
1646 }
1647
Radek Krejcid7f0d012015-05-25 15:04:52 +02001648 /* link key leafs into the list structure and check all constraints */
1649 /* TODO - include searching in uses/grouping */
1650 for (i = 0; i < list->keys_size; i++) {
1651 /* get the key name */
Radek Krejci345ad742015-06-03 11:04:18 +02001652 if ((value = strpbrk(key_str, " \t\n"))) {
1653 len = value - key_str;
1654 while(isspace(*value)) {
1655 value++;
1656 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001657 } else {
1658 len = strlen(key_str);
1659 }
1660 LY_TREE_FOR(list->child, mnode) {
1661 if (!strncmp(mnode->name, key_str, len) && !mnode->name[len]) {
Radek Krejci345ad742015-06-03 11:04:18 +02001662 list->keys[i] = (struct ly_mnode_leaf *)mnode;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001663 break;
1664 }
1665 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001666
Radek Krejci345ad742015-06-03 11:04:18 +02001667 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
Radek Krejcid7f0d012015-05-25 15:04:52 +02001668 goto error;
1669 }
1670
1671 /* prepare for next iteration */
Radek Krejci345ad742015-06-03 11:04:18 +02001672 while (value && isspace(*value)) {
1673 value++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001674 }
Radek Krejci345ad742015-06-03 11:04:18 +02001675 key_str = value;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001676 }
1677
Radek Krejcida04f4a2015-05-21 12:54:09 +02001678 return retval;
1679
1680error:
1681
1682 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001683 while(root.child) {
1684 lyxml_free_elem(module->ctx, root.child);
1685 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001686
1687 return NULL;
1688}
1689
1690static struct ly_mnode *read_yin_container(struct ly_module *module,
1691 struct ly_mnode *parent,
Radek Krejci4c31f122015-06-02 14:51:22 +02001692 struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001693{
1694 struct lyxml_elem *sub, *next, root = {0};
1695 struct ly_mnode *mnode = NULL;
1696 struct ly_mnode *retval;
1697 struct ly_mnode_container *cont;
Radek Krejci800af702015-06-02 13:46:01 +02001698 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001699 int r;
Radek Krejci800af702015-06-02 13:46:01 +02001700 int c_tpdf = 0, c_must = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001701
Radek Krejcida04f4a2015-05-21 12:54:09 +02001702 cont = calloc(1, sizeof *cont);
1703 cont->nodetype = LY_NODE_CONTAINER;
1704 cont->prev = (struct ly_mnode *)cont;
1705 retval = (struct ly_mnode *)cont;
1706
Radek Krejci4c31f122015-06-02 14:51:22 +02001707 if (read_yin_common(module, parent, retval, yin, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001708 goto error;
1709 }
1710
1711 /* process container's specific children */
Radek Krejci4c31f122015-06-02 14:51:22 +02001712 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci800af702015-06-02 13:46:01 +02001713 if (!strcmp(sub->name, "presence")) {
1714 if (cont->presence) {
Radek Krejci4c31f122015-06-02 14:51:22 +02001715 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +02001716 goto error;
1717 }
1718 GETVAL(value, sub, "value");
1719 cont->presence = lydict_insert(module->ctx, value, strlen(value));
1720
Radek Krejci4c31f122015-06-02 14:51:22 +02001721 lyxml_free_elem(module->ctx, sub);
1722
Radek Krejcida04f4a2015-05-21 12:54:09 +02001723 /* data statements */
Radek Krejci800af702015-06-02 13:46:01 +02001724 } else if (!strcmp(sub->name, "container") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001725 !strcmp(sub->name, "leaf-list") ||
1726 !strcmp(sub->name, "leaf") ||
1727 !strcmp(sub->name, "list") ||
1728 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001729 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001730 !strcmp(sub->name, "grouping")) {
1731 lyxml_unlink_elem(sub);
1732 lyxml_add_child(&root, sub);
1733
1734 /* array counters */
1735 } else if (!strcmp(sub->name, "typedef")) {
1736 c_tpdf++;
Radek Krejci800af702015-06-02 13:46:01 +02001737 } else if (!strcmp(sub->name, "must")) {
1738 c_must++;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001739#if 0
Radek Krejci800af702015-06-02 13:46:01 +02001740 } else {
Radek Krejci4c31f122015-06-02 14:51:22 +02001741 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1742 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02001743#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02001744 }
1745 }
1746
1747 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1748 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001749 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001750 }
Radek Krejci800af702015-06-02 13:46:01 +02001751 if (c_must) {
1752 cont->must = calloc(c_must, sizeof *cont->must);
1753 }
1754
Radek Krejci4c31f122015-06-02 14:51:22 +02001755 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001756 if (!strcmp(sub->name, "typedef")) {
Radek Krejci800af702015-06-02 13:46:01 +02001757 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
1758 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001759
1760 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001761 goto error;
1762 }
Radek Krejci800af702015-06-02 13:46:01 +02001763 } else if (!strcmp(sub->name, "must")) {
1764 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
1765 cont->must_size++;
1766
1767 if (r) {
1768 goto error;
1769 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001770 }
1771
1772 lyxml_free_elem(module->ctx, sub);
1773 }
1774
1775 /* last part - process data nodes */
1776 LY_TREE_FOR_SAFE(root.child, next, sub) {
1777 if (!strcmp(sub->name, "container")) {
1778 mnode = read_yin_container(module, retval, sub);
1779 } else if (!strcmp(sub->name, "leaf-list")) {
1780 mnode = read_yin_leaflist(module, retval, sub);
1781 } else if (!strcmp(sub->name, "leaf")) {
1782 mnode = read_yin_leaf(module, retval, sub);
1783 } else if (!strcmp(sub->name, "list")) {
1784 mnode = read_yin_list(module, retval, sub);
1785 } else if (!strcmp(sub->name, "choice")) {
1786 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001787 } else if (!strcmp(sub->name, "uses")) {
1788 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001789 } else if (!strcmp(sub->name, "grouping")) {
1790 mnode = read_yin_grouping(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001791 }
1792 lyxml_free_elem(module->ctx, sub);
1793
Radek Krejci25d782a2015-05-22 15:03:23 +02001794 if (!mnode) {
1795 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001796 }
1797 }
1798
Radek Krejci812b10a2015-05-28 16:48:25 +02001799 if (parent) {
1800 ly_mnode_addchild(parent, retval);
1801 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001802
1803 return retval;
1804
1805error:
1806
1807 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001808 while (root.child) {
1809 lyxml_free_elem(module->ctx, root.child);
1810 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001811
1812 return NULL;
1813}
1814
1815static struct ly_mnode *read_yin_grouping(struct ly_module *module,
1816 struct ly_mnode *parent,
1817 struct lyxml_elem *node)
1818{
1819 struct lyxml_elem *sub, *next, root = {0};
1820 struct ly_mnode *mnode = NULL;
1821 struct ly_mnode *retval;
1822 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +02001823 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001824 int c_tpdf = 0;
1825
1826 grp = calloc(1, sizeof *grp);
1827 grp->nodetype = LY_NODE_GROUPING;
1828 grp->module = module;
1829 grp->prev = (struct ly_mnode *)grp;
1830 retval = (struct ly_mnode *)grp;
1831
Radek Krejci25d782a2015-05-22 15:03:23 +02001832 if (read_yin_common(module, parent, retval, node, 0)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001833 goto error;
1834 }
1835
1836 LY_TREE_FOR_SAFE(node->child, next, sub) {
1837 /* data statements */
1838 if (!strcmp(sub->name, "container") ||
1839 !strcmp(sub->name, "leaf-list") ||
1840 !strcmp(sub->name, "leaf") ||
1841 !strcmp(sub->name, "list") ||
1842 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001843 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001844 !strcmp(sub->name, "grouping")) {
1845 lyxml_unlink_elem(sub);
1846 lyxml_add_child(&root, sub);
1847
1848 /* array counters */
1849 } else if (!strcmp(sub->name, "typedef")) {
1850 c_tpdf++;
1851 }
1852 }
1853
1854 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1855 if (c_tpdf) {
1856 grp->tpdf_size = c_tpdf;
1857 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
1858 c_tpdf = 0;
1859 }
1860 LY_TREE_FOR_SAFE(node->child, next, sub) {
1861 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001862 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001863 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001864
1865 if (r) {
1866 grp->tpdf_size = c_tpdf;
1867 goto error;
1868 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001869 }
1870
1871 lyxml_free_elem(module->ctx, sub);
1872 }
1873
1874 /* last part - process data nodes */
1875 LY_TREE_FOR_SAFE(root.child, next, sub) {
1876 if (!strcmp(sub->name, "container")) {
1877 mnode = read_yin_container(module, retval, sub);
1878 } else if (!strcmp(sub->name, "leaf-list")) {
1879 mnode = read_yin_leaflist(module, retval, sub);
1880 } else if (!strcmp(sub->name, "leaf")) {
1881 mnode = read_yin_leaf(module, retval, sub);
1882 } else if (!strcmp(sub->name, "list")) {
1883 mnode = read_yin_list(module, retval, sub);
1884 } else if (!strcmp(sub->name, "choice")) {
1885 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001886 } else if (!strcmp(sub->name, "uses")) {
1887 mnode = read_yin_uses(module, retval, sub, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001888 } else if (!strcmp(sub->name, "grouping")) {
1889 mnode = read_yin_grouping(module, retval, sub);
1890 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001891 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001892 continue;
1893 }
1894 lyxml_free_elem(module->ctx, sub);
1895
Radek Krejci25d782a2015-05-22 15:03:23 +02001896 if (!mnode) {
1897 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001898 }
1899 }
1900
Radek Krejci812b10a2015-05-28 16:48:25 +02001901 if (parent) {
1902 ly_mnode_addchild(parent, retval);
1903 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001904
1905 return retval;
1906
1907error:
1908
1909 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001910 while (root.child) {
1911 lyxml_free_elem(module->ctx, root.child);
1912 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001913
1914 return NULL;
1915}
1916
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001917/*
1918 * resolve - referenced grouping should be bounded to the namespace (resolved)
1919 * only when uses does not appear in grouping. In a case of grouping's uses,
1920 * we just get information but we do not apply augment or refine to it.
1921 */
1922static struct ly_mnode *read_yin_uses(struct ly_module *module,
1923 struct ly_mnode *parent,
1924 struct lyxml_elem *node, int resolve)
1925{
1926 struct ly_mnode *retval;
1927 struct ly_mnode *mnode = NULL, *par;
1928 struct ly_mnode_uses *uses;
1929 struct ly_module *searchmod = NULL;
1930 const char *name;
1931 int prefix_len = 0;
1932 int i;
1933
1934 uses = calloc(1, sizeof *uses);
1935 uses->nodetype = LY_NODE_USES;
1936 uses->module = module;
1937 uses->prev = (struct ly_mnode *)uses;
1938 retval = (struct ly_mnode *)uses;
1939
1940 if (read_yin_common(module, parent, retval, node, 0)) {
1941 goto error;
1942 }
1943
1944 /* get referenced grouping */
1945 name = strchr(uses->name, ':');
1946 if (!name) {
1947 /* no prefix, search in local tree */
1948 name = uses->name;
1949 } else {
1950 /* there is some prefix, check if it refer the same data model */
1951
1952 /* set name to correct position after colon */
1953 prefix_len = name - uses->name;
1954 name++;
1955
1956 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1957 /* prefix refers to the current module, ignore it */
1958 prefix_len = 0;
1959 }
1960 }
1961
1962 /* search */
1963 if (prefix_len) {
1964 /* in top-level groupings of some other module */
1965 for (i = 0; i < module->imp_size; i++) {
1966 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
1967 && !module->imp[i].prefix[prefix_len]) {
1968 searchmod = module->imp[i].module;
1969 break;
1970 }
1971 }
1972 if (!searchmod) {
1973 /* uses refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +02001974 LOGVAL(VE_INPREFIX, LOGLINE(node), name);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001975 goto error;
1976 }
1977
1978 LY_TREE_FOR(module->data, mnode) {
1979 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1980 uses->grp = (struct ly_mnode_grp *)mnode;
1981 break;
1982 }
1983 }
1984
1985 if (!uses->grp) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001986 LOGVAL(VE_INARG, LOGLINE(node), uses->name, "uses");
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001987 goto error;
1988 }
1989
1990 } else {
1991 /* in local tree hierarchy */
1992 for(par = parent; par; par = par->parent) {
1993 LY_TREE_FOR(parent->child, mnode) {
1994 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1995 uses->grp = (struct ly_mnode_grp *)mnode;
1996 break;
1997 }
1998 }
1999 }
2000
2001 /* search in top level of the current module */
2002 LY_TREE_FOR(module->data, mnode) {
2003 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
2004 uses->grp = (struct ly_mnode_grp *)mnode;
2005 break;
2006 }
2007 }
2008 }
2009
Radek Krejci812b10a2015-05-28 16:48:25 +02002010 if (parent) {
2011 ly_mnode_addchild(parent, retval);
2012 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002013
2014 if (!resolve) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002015 /* this is uses statement inside the grouping, so do not bound grouping
2016 * to the current content
2017 */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002018 return retval;
2019 }
2020
2021 /* TODO */
2022
2023 return retval;
2024
2025error:
2026
2027 ly_mnode_free(retval);
2028
2029 return NULL;
2030}
2031
Radek Krejciefaeba32015-05-27 14:30:57 +02002032/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci0af13872015-05-30 11:50:52 +02002033static int read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002034{
Radek Krejciefaeba32015-05-27 14:30:57 +02002035 struct ly_ctx *ctx = module->ctx;
Radek Krejci0af13872015-05-30 11:50:52 +02002036 struct ly_submodule *submodule = (struct ly_submodule *)module;
Radek Krejciefaeba32015-05-27 14:30:57 +02002037 struct lyxml_elem *next, *node, *child, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +02002038 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002039 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002040 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0; /* counters */
Radek Krejci25d782a2015-05-22 15:03:23 +02002041 int r;
Radek Krejcice7fb782015-05-29 16:52:34 +02002042 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002043
2044 /*
2045 * in the first run, we process elements with cardinality of 1 or 0..1 and
2046 * count elements with cardinality 0..n. Data elements (choices, containers,
2047 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
2048 * need have all top-level and groupings already prepared at that time. In
2049 * the middle loop, we process other elements with carinality of 0..n since
2050 * we need to allocate arrays to store them.
2051 */
2052 LY_TREE_FOR_SAFE(yin->child, next, node) {
2053 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
2054 lyxml_free_elem(ctx, node);
2055 continue;
2056 }
2057
Radek Krejci0af13872015-05-30 11:50:52 +02002058 if (!module->type && !strcmp(node->name, "namespace")) {
2059 if (module->ns) {
2060 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2061 goto error;
2062 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002063 GETVAL(value, node, "uri");
Radek Krejcida04f4a2015-05-21 12:54:09 +02002064 module->ns = lydict_insert(ctx, value, strlen(value));
2065 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02002066 } else if (!module->type && !strcmp(node->name, "prefix")) {
2067 if (module->prefix) {
2068 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2069 goto error;
2070 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002071 GETVAL(value, node, "value");
Radek Krejci0af13872015-05-30 11:50:52 +02002072 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
2073 goto error;
2074 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002075 module->prefix = lydict_insert(ctx, value, strlen(value));
2076 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02002077 } else if (module->type && !strcmp(node->name, "belongs-to")) {
2078 if (submodule->belongsto) {
2079 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
2080 goto error;
2081 }
2082 GETVAL(value, node, "module");
2083 submodule->belongsto = ly_ctx_get_module(module->ctx, value, NULL, 0);
2084 if (!submodule->belongsto) {
2085 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
2086 goto error;
2087 }
2088 /* get the prefix substatement, start with checks */
2089 if (!node->child) {
2090 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
2091 goto error;
2092 } else if (strcmp(node->child->name, "prefix")) {
2093 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
2094 goto error;
2095 } else if (node->child->next) {
2096 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
2097 goto error;
2098 }
2099 /* and now finally get the value */
2100 GETVAL(value, node->child, "value");
2101 /* check here differs from a generic prefix check, since this prefix
2102 * don't have to be unique
2103 */
2104 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
2105 goto error;
2106 }
2107 module->prefix = lydict_insert(ctx, value, strlen(value));
2108
2109 /* we are done with belongs-to */
2110 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002111 } else if (!strcmp(node->name, "import")) {
2112 c_imp++;
2113 } else if (!strcmp(node->name, "revision")) {
2114 c_rev++;
2115 } else if (!strcmp(node->name, "typedef")) {
2116 c_tpdf++;
Radek Krejci6793db02015-05-22 17:49:54 +02002117 } else if (!strcmp(node->name, "identity")) {
2118 c_ident++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002119 } else if (!strcmp(node->name, "include")) {
2120 c_inc++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002121
2122 /* data statements */
2123 } else if (!strcmp(node->name, "container") ||
2124 !strcmp(node->name, "leaf-list") ||
2125 !strcmp(node->name, "leaf") ||
2126 !strcmp(node->name, "list") ||
2127 !strcmp(node->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002128 !strcmp(node->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02002129 !strcmp(node->name, "grouping")) {
2130 lyxml_unlink_elem(node);
2131 lyxml_add_child(&root, node);
2132
2133 /* optional statements */
2134 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002135 if (module->dsc) {
Radek Krejci0af13872015-05-30 11:50:52 +02002136 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002137 goto error;
2138 }
Radek Krejci0af13872015-05-30 11:50:52 +02002139 module->dsc = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002140 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002141 if (!module->dsc) {
2142 goto error;
2143 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002144 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002145 if (module->ref) {
Radek Krejci0af13872015-05-30 11:50:52 +02002146 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002147 goto error;
2148 }
Radek Krejci0af13872015-05-30 11:50:52 +02002149 module->ref = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002150 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002151 if (!module->ref) {
2152 goto error;
2153 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002154 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002155 if (module->org) {
Radek Krejci0af13872015-05-30 11:50:52 +02002156 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002157 goto error;
2158 }
Radek Krejci0af13872015-05-30 11:50:52 +02002159 module->org = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002160 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002161 if (!module->org) {
2162 goto error;
2163 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002164 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02002165 if (module->contact) {
Radek Krejci0af13872015-05-30 11:50:52 +02002166 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02002167 goto error;
2168 }
Radek Krejci0af13872015-05-30 11:50:52 +02002169 module->contact = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002170 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02002171 if (!module->contact) {
2172 goto error;
2173 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002174 } else if (!strcmp(node->name, "yang-version")) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002175 /* TODO: support YANG 1.1 ? */
Radek Krejcib0594bf2015-05-21 23:51:27 +02002176 if (module->version) {
Radek Krejci0af13872015-05-30 11:50:52 +02002177 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002178 goto error;
2179 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002180 GETVAL(value, node, "value");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002181 if (strcmp(value, "1")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002182 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02002183 goto error;
2184 }
2185 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002186 lyxml_free_elem(ctx, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02002187#if 0
Radek Krejcice7fb782015-05-29 16:52:34 +02002188 } else {
2189 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
2190 goto error;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002191#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02002192 }
2193 }
2194
Radek Krejciefaeba32015-05-27 14:30:57 +02002195 if (!submodule) {
2196 /* check for mandatory statements */
2197 if (!module->ns) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002198 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002199 goto error;
2200 }
2201 if (!module->prefix) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002202 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02002203 goto error;
2204 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002205 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02002206
Radek Krejcida04f4a2015-05-21 12:54:09 +02002207 /* allocate arrays for elements with cardinality of 0..n */
2208 if (c_imp) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002209 module->imp = calloc(c_imp, sizeof *module->imp);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002210 }
2211 if (c_rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002212 module->rev = calloc(c_rev, sizeof *module->rev);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002213 }
2214 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002215 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002216 }
Radek Krejci6793db02015-05-22 17:49:54 +02002217 if (c_ident) {
Radek Krejci6793db02015-05-22 17:49:54 +02002218 module->ident = calloc(c_ident, sizeof *module->ident);
Radek Krejciefaeba32015-05-27 14:30:57 +02002219 }
2220 if (c_inc) {
2221 module->inc = calloc(c_inc, sizeof *module->inc);
Radek Krejci6793db02015-05-22 17:49:54 +02002222 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002223
2224 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2225 LY_TREE_FOR_SAFE(yin->child, next, node) {
2226 if (!strcmp(node->name, "import")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002227 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
2228 module->imp_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002229 if (r) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02002230 goto error;
2231 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002232
2233 /* check duplicities in imported modules */
2234 for (i = 0; i < module->imp_size - 1; i++) {
2235 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
2236 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
2237 goto error;
2238 }
2239 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002240 } else if (!strcmp(node->name, "include")) {
2241 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
2242 module->inc_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02002243 if (r) {
2244 goto error;
2245 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002246
2247 /* check duplications in include submodules */
2248 for (i = 0; i < module->inc_size - 1; i++) {
Radek Krejci76e5a1b2015-05-29 17:01:08 +02002249 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002250 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->inc[i].submodule->name);
2251 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002252 }
2253 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002254 } else if (!strcmp(node->name, "revision")) {
2255 GETVAL(value, node, "date");
2256 if (check_date(value, LOGLINE(node))) {
2257 goto error;
2258 }
2259 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2260 /* check uniqueness of the revision date - not required by RFC */
2261 for (i = 0; i < module->rev_size; i++) {
2262 if (!strcmp(value, module->rev[i].date)) {
2263 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
2264 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
2265 }
2266 }
2267
2268 LY_TREE_FOR(node->child, child) {
2269 if (!strcmp(child->name, "description")) {
2270 if (module->rev[module->rev_size].dsc) {
2271 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2272 goto error;
2273 }
Radek Krejci0af13872015-05-30 11:50:52 +02002274 module->rev[module->rev_size].dsc = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02002275 if (!module->rev[module->rev_size].dsc) {
2276 goto error;
2277 }
2278 } else if (!strcmp(child->name, "reference")) {
2279 if (module->rev[module->rev_size].ref) {
2280 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
2281 goto error;
2282 }
Radek Krejci0af13872015-05-30 11:50:52 +02002283 module->rev[module->rev_size].ref = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02002284 if (!module->rev[module->rev_size].ref) {
2285 goto error;
2286 }
2287 } else {
2288 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2289 goto error;
2290 }
2291 }
2292
2293 /* keep the latest revision at position 0 */
2294 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
2295 /* switch their position */
2296 value = strdup(module->rev[0].date);
2297 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
2298 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
2299 free((char*)value);
2300
2301 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
2302 value = module->rev[0].dsc;
2303 module->rev[0].dsc = module->rev[module->rev_size].dsc;
2304 module->rev[module->rev_size].dsc = value;
2305 }
2306
2307 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
2308 value = module->rev[0].ref;
2309 module->rev[0].ref = module->rev[module->rev_size].ref;
2310 module->rev[module->rev_size].ref = value;
2311 }
2312 }
2313
Radek Krejciefaeba32015-05-27 14:30:57 +02002314 module->rev_size++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002315 } else if (!strcmp(node->name, "typedef")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002316 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
2317 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002318
2319 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002320 goto error;
2321 }
Radek Krejci6793db02015-05-22 17:49:54 +02002322 } else if (!strcmp(node->name, "identity")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002323 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
2324 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02002325
2326 if (r) {
Radek Krejci6793db02015-05-22 17:49:54 +02002327 goto error;
2328 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002329 }
2330
2331 lyxml_free_elem(ctx, node);
2332 }
2333
2334 /* last part - process data nodes */
2335 LY_TREE_FOR_SAFE(root.child, next, node) {
2336
2337 if (!strcmp(node->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002338 mnode = read_yin_container(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002339 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002340 mnode = read_yin_leaflist(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002341 } else if (!strcmp(node->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002342 mnode = read_yin_leaf(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002343 } else if (!strcmp(node->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002344 mnode = read_yin_list(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002345 } else if (!strcmp(node->name, "choice")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002346 mnode = read_yin_choice(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002347 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002348 mnode = read_yin_grouping(module, NULL, node);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002349 } else if (!strcmp(node->name, "uses")) {
2350 mnode = read_yin_uses(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002351 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02002352 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002353 continue;
2354 }
2355 lyxml_free_elem(ctx, node);
2356
Radek Krejci25d782a2015-05-22 15:03:23 +02002357 if (!mnode) {
2358 goto error;
2359 }
2360
2361 /* include data element */
2362 if (module->data) {
2363 module->data->prev->next = mnode;
2364 mnode->prev = module->data->prev;
2365 module->data->prev = mnode;
2366 } else {
2367 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002368 }
2369 }
2370
Radek Krejciefaeba32015-05-27 14:30:57 +02002371 return EXIT_SUCCESS;
2372
2373error:
2374 /* cleanup */
2375 while (root.child) {
2376 lyxml_free_elem(module->ctx, root.child);
2377 }
2378
2379 return EXIT_FAILURE;
2380}
2381
2382struct ly_submodule *yin_read_submodule(struct ly_module *module, const char *data)
2383{
2384 struct lyxml_elem *yin;
Radek Krejci3045cf32015-05-28 10:58:52 +02002385 struct ly_submodule *submodule = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02002386 const char *value;
2387
Radek Krejci812b10a2015-05-28 16:48:25 +02002388 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02002389
2390 yin = lyxml_read(module->ctx, data, 0);
2391 if (!yin) {
2392 return NULL;
2393 }
2394
2395 /* check root element */
2396 if (!yin->name || strcmp(yin->name, "submodule")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002397 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002398 goto error;
2399 }
2400
Radek Krejci0af13872015-05-30 11:50:52 +02002401 GETVAL(value, yin, "name");
2402 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002403 goto error;
2404 }
2405
2406 submodule = calloc(1, sizeof *submodule);
2407 if (!submodule) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002408 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002409 goto error;
2410 }
2411
2412 submodule->ctx = module->ctx;
2413 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
Radek Krejcice7fb782015-05-29 16:52:34 +02002414 submodule->type = 1;
Radek Krejciefaeba32015-05-27 14:30:57 +02002415
Radek Krejci3045cf32015-05-28 10:58:52 +02002416 LOGVRB("reading submodule %s", submodule->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002417 if (read_sub_module((struct ly_module *)submodule, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002418 goto error;
2419 }
2420
2421 /* cleanup */
2422 lyxml_free_elem(module->ctx, yin);
2423
Radek Krejci3045cf32015-05-28 10:58:52 +02002424 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002425
2426 return submodule;
2427
2428error:
2429 /* cleanup */
2430 lyxml_free_elem(module->ctx, yin);
2431 ly_submodule_free(submodule);
2432
2433 return NULL;
2434}
2435
2436struct ly_module *yin_read_module(struct ly_ctx *ctx, const char *data)
2437{
2438 struct lyxml_elem *yin;
2439 struct ly_module *module = NULL, **newlist = NULL;
2440 const char *value;
2441 int i;
2442
2443 yin = lyxml_read(ctx, data, 0);
2444 if (!yin) {
2445 return NULL;
2446 }
2447
2448 /* check root element */
2449 if (!yin->name || strcmp(yin->name, "module")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002450 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002451 goto error;
2452 }
2453
Radek Krejci0af13872015-05-30 11:50:52 +02002454 GETVAL(value, yin, "name");
2455 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002456 goto error;
2457 }
2458
2459 module = calloc(1, sizeof *module);
2460 if (!module) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002461 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002462 goto error;
2463 }
2464
2465 module->ctx = ctx;
2466 module->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02002467 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02002468
Radek Krejci3045cf32015-05-28 10:58:52 +02002469 LOGVRB("reading module %s", module->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002470 if (read_sub_module(module, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002471 goto error;
2472 }
2473
Radek Krejcida04f4a2015-05-21 12:54:09 +02002474 /* add to the context's list of modules */
2475 if (ctx->models.used == ctx->models.size) {
2476 newlist = realloc(ctx->models.list, ctx->models.size * 2);
2477 if (!newlist) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002478 LOGMEM;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002479 goto error;
2480 }
2481 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
2482 newlist[i] = NULL;
2483 }
2484 ctx->models.size *= 2;
2485 ctx->models.list = newlist;
2486 }
Radek Krejcif6e5e182015-05-27 17:18:07 +02002487 for (i = 0; ctx->models.list[i]; i++) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002488 /* check name (name/revision) and namespace uniqueness */
Radek Krejcif6e5e182015-05-27 17:18:07 +02002489 if (!strcmp(ctx->models.list[i]->name, module->name)) {
2490 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
2491 /* both data models are same, with no revision specified */
Radek Krejci3045cf32015-05-28 10:58:52 +02002492 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.", module->name);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002493 goto error;
2494 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
2495 /* one of the models does not have a revision, so they differs */
2496 continue;
2497 } else {
2498 /* both models have a revision statement which we have to
2499 * compare, revision at position 0 is the last revision
2500 */
2501 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
2502 /* we have the same modules */
Radek Krejci3045cf32015-05-28 10:58:52 +02002503 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name, module->rev[0].date);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002504 goto error;
2505 }
2506 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002507 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
2508 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
2509 ctx->models.list[i]->name, module->name, module->ns);
2510 goto error;
Radek Krejcif6e5e182015-05-27 17:18:07 +02002511 }
2512 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002513 ctx->models.list[i] = module;
2514 ctx->models.used++;
2515
2516 /* cleanup */
2517 lyxml_free_elem(ctx, yin);
2518
Radek Krejci3045cf32015-05-28 10:58:52 +02002519 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002520
2521 return module;
2522
2523error:
2524 /* cleanup */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002525 lyxml_free_elem(ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02002526 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002527
2528 return NULL;
2529}