blob: a9d16497ff015a621c89dec8be8b42d17c5e45c0 [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>
24#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020025#include <stdlib.h>
26#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020027#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020028
Radek Krejciefdd0ce2015-05-26 16:48:29 +020029#include "../libyang.h"
30#include "../common.h"
31#include "../context.h"
32#include "../dict.h"
33#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020034
Radek Krejciefdd0ce2015-05-26 16:48:29 +020035#include "../tree_internal.h"
36#include "../xml.h"
37
Radek Krejcice7fb782015-05-29 16:52:34 +020038enum LY_IDENT {
39 LY_IDENT_FEATURE,
40 LY_IDENT_IDENTITY,
41 LY_IDENT_TYPE,
42 LY_IDENT_NODE,
Radek Krejci0af13872015-05-30 11:50:52 +020043 LY_IDENT_NAME,
Radek Krejcice7fb782015-05-29 16:52:34 +020044 LY_IDENT_PREFIX
45};
46
Radek Krejciefdd0ce2015-05-26 16:48:29 +020047#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020048
Radek Krejcice7fb782015-05-29 16:52:34 +020049#define GETVAL(value, node, arg) \
50 value = lyxml_get_attr(node, arg, NULL); \
51 if (!value) { \
52 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
53 goto error; \
54 }
55
Radek Krejci25d782a2015-05-22 15:03:23 +020056static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int );
Radek Krejcida04f4a2015-05-21 12:54:09 +020057static struct ly_mnode *read_yin_choice(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
58static struct ly_mnode *read_yin_container(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
59static struct ly_mnode *read_yin_leaf(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
60static struct ly_mnode *read_yin_leaflist(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
61static struct ly_mnode *read_yin_list(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +020062static struct ly_mnode *read_yin_uses(struct ly_module *, struct ly_mnode *, struct lyxml_elem *, int);
Radek Krejcida04f4a2015-05-21 12:54:09 +020063static struct ly_mnode *read_yin_grouping(struct ly_module *, struct ly_mnode *, struct lyxml_elem *);
64
Radek Krejcieac35532015-05-31 19:09:15 +020065static int dup_typedef_check(const char* type, struct ly_tpdf *tpdf, int size)
66{
67 int i;
68
69 for (i = 0; i < size; i++) {
70 if (!strcmp(type, tpdf[i].name)) {
71 /* name collision */
72 return EXIT_FAILURE;
73 }
74 }
75
76 return EXIT_SUCCESS;
77}
78
Radek Krejcice7fb782015-05-29 16:52:34 +020079static int dup_prefix_check(const char* prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +020080{
Radek Krejcice7fb782015-05-29 16:52:34 +020081 int i;
82
83 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
84 return EXIT_FAILURE;
85 }
86 for (i = 0; i < module->imp_size; i++) {
87 if (!strcmp(module->imp[i].prefix, prefix)) {
88 return EXIT_FAILURE;
89 }
90 }
91
92 return EXIT_SUCCESS;
93}
94
95static int check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
96 struct ly_module *module, struct ly_mnode *parent)
97{
98 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020099 int size;
100 struct ly_tpdf *tpdf;
101
102
Radek Krejcice7fb782015-05-29 16:52:34 +0200103
104 assert(id);
105
106 /* check id syntax */
107 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
108 LOGVAL(VE_INID, line, id, "invalid start character");
109 return EXIT_FAILURE;
110 }
111 for (i = 1; id[i]; i++) {
112 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
113 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
114 LOGVAL(VE_INID, line, id, "invalid %d. character", i + 1);
115 return EXIT_FAILURE;
116 }
117 }
118
119 if (i > 64) {
120 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
121 }
122
123 switch(type) {
Radek Krejcieac35532015-05-31 19:09:15 +0200124 case LY_IDENT_TYPE:
125 assert(module);
126
127 /* check collision with the built-in types */
128 if (!strcmp(id, "binary") || !strcmp(id,"bits") ||
129 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
130 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
131 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
132 !strcmp(id, "int8") || !strcmp(id, "int16") ||
133 !strcmp(id, "int32") || !strcmp(id, "int64") ||
134 !strcmp(id, "leafref") || !strcmp(id, "string") ||
135 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
136 !strcmp(id, "uint32") || !strcmp(id, "uint64") ||
137 !strcmp(id, "union")) {
138 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
139 return EXIT_FAILURE;
140 }
141
142 /* check locally scoped typedefs (avoid name shadowing) */
143 for ( ; parent; parent = parent->parent) {
144 switch(parent->nodetype) {
145 case LY_NODE_CONTAINER:
146 size = ((struct ly_mnode_container *)parent)->tpdf_size;
147 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
148 break;
149 case LY_NODE_LIST:
150 size = ((struct ly_mnode_list *)parent)->tpdf_size;
151 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
152 break;
153 case LY_NODE_GROUPING:
154 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
155 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
156 break;
157 default:
158 continue;
159 }
160
161 if (dup_typedef_check(id, tpdf, size)) {
162 LOGVAL(VE_DUPID, line, "typedef", id);
163 return EXIT_FAILURE;
164 }
165 }
166
167 /* check top-level names */
168 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
169 LOGVAL(VE_DUPID, line, "typedef", id);
170 return EXIT_FAILURE;
171 }
172
173 /* check submodule's top-level names */
174 for (i = 0; i < module->inc_size; i++) {
175 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
176 LOGVAL(VE_DUPID, line, "typedef", id);
177 return EXIT_FAILURE;
178 }
179 }
180
181 /* check top-level names in the main module */
182 if (module->type) {
183 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
184 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
185 LOGVAL(VE_DUPID, line, "typedef", id);
186 return EXIT_FAILURE;
187 }
188 }
189
190 break;
Radek Krejcice7fb782015-05-29 16:52:34 +0200191 case LY_IDENT_PREFIX:
Radek Krejcieac35532015-05-31 19:09:15 +0200192 assert(module);
193
Radek Krejcice7fb782015-05-29 16:52:34 +0200194 if (module->type) {
195 /* go to the main module */
196 module = ((struct ly_submodule *)module)->belongsto;
197 }
198
199 /* check the main module itself */
200 if (dup_prefix_check(id, module)) {
201 LOGVAL(VE_DUPID, line, "prefix", id);
202 return EXIT_FAILURE;
203 }
204
205 /* and all its submodules */
206 for (i = 0; i < module->inc_size; i++) {
207 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
208 LOGVAL(VE_DUPID, line, "prefix", id);
209 return EXIT_FAILURE;
210 }
211 }
212 break;
213 default:
214 /* no check required */
215 break;
216 }
217
218 return EXIT_SUCCESS;
219}
220
Radek Krejcieac35532015-05-31 19:09:15 +0200221static int check_default(struct ly_tpdf *tpdf)
222{
223 /* TODO - RFC 6020, sec. 7.3.4 */
224 (void)tpdf;
225 return EXIT_SUCCESS;
226}
227
Radek Krejcice7fb782015-05-29 16:52:34 +0200228static int check_date(const char* date, unsigned int line)
229{
230 int i;
231
232 assert(date);
233
234 if (strlen(date) != LY_REV_SIZE - 1) {
235 goto error;
236 }
237
238 for (i = 0; i < LY_REV_SIZE - 1; i++) {
239 if (i == 4 || i == 7) {
240 if (date[i] != '-') {
241 goto error;
242 }
243 } else if (!isdigit(date[i])) {
244 goto error;
245 }
246 }
247
248 return EXIT_SUCCESS;
249
250error:
251
252 LOGVAL(VE_INDATE, line, date);
253 return EXIT_FAILURE;
254}
255
Radek Krejci0af13872015-05-30 11:50:52 +0200256static const char *read_yin_text(struct ly_ctx *ctx, struct lyxml_elem *node)
Radek Krejcice7fb782015-05-29 16:52:34 +0200257{
258 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200259
260 /* there should be <text> child */
261 if (!node->child || !node->child->name
262 || strcmp(node->child->name, "text")) {
Radek Krejci0af13872015-05-30 11:50:52 +0200263 LOGWRN("Expected \"text\" element in \"%s\" element.", node->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200264 } else if (node->child->content) {
265 len = strlen(node->child->content);
266 return lydict_insert(ctx, node->child->content, len);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200267 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200268
269 LOGVAL(VE_INARG, LOGLINE(node), "text", node->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200270 return NULL;
271}
272
273static struct ly_tpdf *find_superior_type(const char *name,
274 struct ly_module *module,
275 struct ly_mnode *parent)
276{
Radek Krejciefaeba32015-05-27 14:30:57 +0200277 int i, j, found = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200278 int prefix_len = 0;
279 const char *qname;
Radek Krejci25d782a2015-05-22 15:03:23 +0200280 struct ly_tpdf *tpdf;
281 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200282
283 qname = strchr(name, ':');
284
285 if (!qname) {
286 /* no prefix, try built-in types */
287 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
288 if (!strcmp(ly_types[i].def->name, name)) {
289 return ly_types[i].def;
290 }
291 }
292 qname = name;
293 } else {
294 /* set qname to correct position after colon */
295 prefix_len = qname - name;
296 qname++;
297
298 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
299 /* prefix refers to the current module, ignore it */
300 prefix_len = 0;
301 }
302 }
303
304 if (!prefix_len && parent) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200305 /* search in local typedefs */
306 while (parent) {
307 switch (parent->nodetype) {
308 case LY_NODE_CONTAINER:
309 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
310 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
311 break;
312 case LY_NODE_LIST:
313 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
314 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
315 break;
316 case LY_NODE_GROUPING:
317 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
318 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
319 break;
320 default:
321 parent = parent->parent;
322 continue;
323 }
324
325 for (i = 0; i < tpdf_size; i++) {
326 if (!strcmp(tpdf[i].name, qname)) {
327 return &tpdf[i];
328 }
329 }
330
331 parent = parent->parent;
332 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200333 } else if (prefix_len) {
334 /* get module where to search */
335 for (i = 0; i < module->imp_size; i++) {
336 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
337 module = module->imp[i].module;
338 found = 1;
339 break;
340 }
341 }
342 if (!found) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200343 return NULL;
344 }
345 }
346
347 /* search in top level typedefs */
348 for (i = 0; i < module->tpdf_size; i++) {
349 if (!strcmp(module->tpdf[i].name, qname)) {
350 return &module->tpdf[i];
351 }
352 }
353
Radek Krejciefaeba32015-05-27 14:30:57 +0200354 /* search in submodules */
355 for (i = 0; i < module->inc_size; i++) {
356 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
357 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
358 return &module->inc[i].submodule->tpdf[j];
359 }
360 }
361 }
362
363 return NULL;
364}
365
366static struct ly_ident *find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
367{
Radek Krejcice7fb782015-05-29 16:52:34 +0200368 unsigned int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200369 struct ly_ident *base_iter;
370 struct ly_ident_der *der;
371
372 for (i = 0; i < module->ident_size; i++) {
373 if (!strcmp(basename, module->ident[i].name)) {
374 /* we are done */
375
376 if (!ident) {
377 /* just search for type, so do not modify anything, just return
378 * the base identity pointer
379 */
380 return &module->ident[i];
381 }
382
383 /* we are resolving identity definition, so now update structures */
384 ident->base = base_iter = &module->ident[i];
385
386 while (base_iter) {
387 for (der = base_iter->der; der && der->next; der = der->next);
388 if (der) {
389 der->next = malloc(sizeof *der);
390 der = der->next;
391 } else {
392 ident->base->der = der = malloc(sizeof *der);
393 }
394 der->next = NULL;
395 der->ident = ident;
396
397 base_iter = base_iter->base;
398 }
399 return ident->base;
400 }
401 }
402
Radek Krejcida04f4a2015-05-21 12:54:09 +0200403 return NULL;
404}
405
Radek Krejci3045cf32015-05-28 10:58:52 +0200406static 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 +0200407{
408 const char *name;
409 int prefix_len = 0;
410 int i, found = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200411 struct ly_ident *result;
Radek Krejci3045cf32015-05-28 10:58:52 +0200412 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200413
Radek Krejci3045cf32015-05-28 10:58:52 +0200414 basename = lyxml_get_attr(node, "name", NULL);
Radek Krejci04581c62015-05-22 21:24:00 +0200415 if (!basename) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200416 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
Radek Krejci04581c62015-05-22 21:24:00 +0200417 return NULL;
418 }
419
420 /* search for the base identity */
421 name = strchr(basename, ':');
422 if (name) {
423 /* set name to correct position after colon */
424 prefix_len = name - basename;
425 name++;
426
427 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
428 /* prefix refers to the current module, ignore it */
429 prefix_len = 0;
430 }
431 } else {
432 name = basename;
433 }
434
435 if (prefix_len) {
436 /* get module where to search */
437 for (i = 0; i < module->imp_size; i++) {
438 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
439 && !module->imp[i].prefix[prefix_len]) {
440 module = module->imp[i].module;
441 found = 1;
442 break;
443 }
444 }
445 if (!found) {
446 /* identity refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +0200447 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
Radek Krejci04581c62015-05-22 21:24:00 +0200448 return NULL;
449 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200450 } else {
451 /* search in submodules */
452 for (i = 0; i < module->inc_size; i++) {
453 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
454 if (result) {
455 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200456 }
Radek Krejci04581c62015-05-22 21:24:00 +0200457 }
458 }
459
Radek Krejciefaeba32015-05-27 14:30:57 +0200460 /* search in the identified module */
461 result = find_base_ident_sub(module, ident, name);
462 if (!result) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200463 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
Radek Krejciefaeba32015-05-27 14:30:57 +0200464 }
465
466 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200467}
468
469static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
470{
471 struct lyxml_elem *node, *next;
472
473 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
474 return EXIT_FAILURE;
475 }
476 ident->module = module;
477
478 LY_TREE_FOR_SAFE(yin->child, next, node) {
479 if (!strcmp(node->name, "base")) {
480 if (ident->base) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200481 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200482 return EXIT_FAILURE;
483 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200484 if (!find_base_ident(module, ident, node)) {
Radek Krejci04581c62015-05-22 21:24:00 +0200485 return EXIT_FAILURE;
486 }
487 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200488 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
Radek Krejci04581c62015-05-22 21:24:00 +0200489 return EXIT_FAILURE;
490 }
491
492 lyxml_free_elem(module->ctx, node);
493 }
494
495 return EXIT_SUCCESS;
496}
497
Radek Krejcida04f4a2015-05-21 12:54:09 +0200498static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
499 struct lyxml_elem *yin, struct ly_type *type)
500{
Radek Krejci25d782a2015-05-22 15:03:23 +0200501 const char *value, *delim;
502 struct lyxml_elem *next, *node, root = {0};
503 int i, j, r;
504 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200505
Radek Krejci800af702015-06-02 13:46:01 +0200506 GETVAL(value, yin, "name")
Radek Krejci25d782a2015-05-22 15:03:23 +0200507 delim = strchr(value, ':');
508 if (delim) {
509 type->prefix = lydict_insert(module->ctx, value, delim - value);
510 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200511
Radek Krejcida04f4a2015-05-21 12:54:09 +0200512 type->der = find_superior_type(value, module, parent);
Radek Krejci3045cf32015-05-28 10:58:52 +0200513 if (!type->der) {
514 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
Radek Krejci800af702015-06-02 13:46:01 +0200515 goto error;
Radek Krejci3045cf32015-05-28 10:58:52 +0200516 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200517 type->base = type->der->type.base;
518
519 switch (type->base) {
520 case LY_TYPE_BINARY:
Radek Krejci800af702015-06-02 13:46:01 +0200521 /* TODO length, 9.4.4
Radek Krejci04581c62015-05-22 21:24:00 +0200522 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
523 * hodnoty se musi vejit do 64b, podelementy
Radek Krejci25d782a2015-05-22 15:03:23 +0200524 */
525 break;
526 case LY_TYPE_BITS:
Radek Krejci800af702015-06-02 13:46:01 +0200527 /* TODO bit, 9.7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200528 * 1..n, nerekurzivni, stringy s podelementy */
529 break;
530 case LY_TYPE_DEC64:
Radek Krejci800af702015-06-02 13:46:01 +0200531 /* TODO fraction-digits, 9.3.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200532 * - MUST, 1, nerekurzivni, hodnota 1-18 */
Radek Krejci800af702015-06-02 13:46:01 +0200533 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200534 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
535 break;
536 case LY_TYPE_ENUM:
Radek Krejci6793db02015-05-22 17:49:54 +0200537 /* RFC 6020 9.6 */
Radek Krejci04581c62015-05-22 21:24:00 +0200538
Radek Krejci25d782a2015-05-22 15:03:23 +0200539 /* get enum specification, at least one must be present */
540 LY_TREE_FOR_SAFE(yin->child, next, node) {
541 if (!strcmp(node->name, "enum")) {
542 lyxml_unlink_elem(node);
543 lyxml_add_child(&root, node);
544 type->info.enums.count++;
545 }
546 }
547 if (yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200548 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200549 goto error;
550 }
551 if (!type->info.enums.count) {
552 if (type->der->type.der) {
553 /* this is just a derived type with no enum specified */
554 break;
555 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200556 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
Radek Krejci25d782a2015-05-22 15:03:23 +0200557 goto error;
558 }
559
560 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
561 for (i = v = 0; root.child; i++) {
562 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, 0);
563 if (r) {
564 type->info.enums.count = i + 1;
565 goto error;
566 }
567 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
568 value = type->info.enums.list[i].name;
569 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200570 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
Radek Krejci25d782a2015-05-22 15:03:23 +0200571 type->info.enums.count = i + 1;
572 goto error;
573 }
574
575 /* check the name uniqueness */
576 for (j = 0; j < i; j++) {
577 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200578 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
Radek Krejci25d782a2015-05-22 15:03:23 +0200579 type->info.enums.count = i + 1;
580 goto error;
581 }
582 }
583
584 node = root.child->child;
585 if (node && !strcmp(node->name, "value")) {
586 value = lyxml_get_attr(node, "value", NULL);
587 v_ = strtol(value, NULL, 10);
588
589 /* range check */
590 if (v_ < INT32_MIN || v_ > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200591 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200592 type->info.enums.count = i + 1;
593 goto error;
594 }
595 type->info.enums.list[i].value = v_;
596
597 /* keep the highest enum value for automatic increment */
598 if (type->info.enums.list[i].value > v) {
599 v = type->info.enums.list[i].value;
600 v++;
601 } else {
602 /* check that the value is unique */
603 for (j = 0; j < i; j++) {
604 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200605 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 +0200606 type->info.enums.count = i + 1;
607 goto error;
608 }
609 }
610 }
611 } else {
612 /* assign value automatically */
613 if (v > INT32_MAX) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200614 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200615 type->info.enums.count = i + 1;
616 goto error;
617 }
618 type->info.enums.list[i].value = v;
619 v++;
620 }
621 lyxml_free_elem(module->ctx, root.child);
622 }
623 break;
624 case LY_TYPE_IDENT:
Radek Krejci04581c62015-05-22 21:24:00 +0200625 /* RFC 6020 9.10 */
626
627 /* get base specification, exactly one must be present */
628 if (!yin->child) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200629 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
Radek Krejci04581c62015-05-22 21:24:00 +0200630 goto error;
631 }
632 if (strcmp(yin->child->name, "base")) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200633 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200634 goto error;
635 }
636 if (yin->child->next) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200637 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
Radek Krejci04581c62015-05-22 21:24:00 +0200638 goto error;
639 }
Radek Krejci3045cf32015-05-28 10:58:52 +0200640 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
Radek Krejci04581c62015-05-22 21:24:00 +0200641 if (!type->info.ident.ref) {
642 return EXIT_FAILURE;
643 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200644 break;
645 case LY_TYPE_INST:
Radek Krejci800af702015-06-02 13:46:01 +0200646 /* TODO require-instance, 9.13.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200647 * - 0..1, true/false */
648 break;
649 case LY_TYPE_INT8:
650 case LY_TYPE_INT16:
651 case LY_TYPE_INT32:
652 case LY_TYPE_INT64:
653 case LY_TYPE_UINT8:
654 case LY_TYPE_UINT16:
655 case LY_TYPE_UINT32:
656 case LY_TYPE_UINT64:
Radek Krejci800af702015-06-02 13:46:01 +0200657 /* TODO range, 9.2.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200658 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
659 break;
660 case LY_TYPE_LEAFREF:
Radek Krejci800af702015-06-02 13:46:01 +0200661 /* TODO path, 9.9.2
Radek Krejci25d782a2015-05-22 15:03:23 +0200662 * - 1, nerekurzivni, string */
663 break;
664 case LY_TYPE_STRING:
Radek Krejci800af702015-06-02 13:46:01 +0200665 /* TODO length, 9.4.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200666 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
667 * pattern, 9.4.6
668 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
669 break;
670 case LY_TYPE_UNION:
Radek Krejci800af702015-06-02 13:46:01 +0200671 /* TODO type, 7.4
Radek Krejci25d782a2015-05-22 15:03:23 +0200672 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
673 break;
674 default:
675 /* nothing needed :
676 * LY_TYPE_BOOL, LY_TYPE_EMPTY
677 */
678 break;
679 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200680
681 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200682
683error:
684
685 while(root.child) {
686 lyxml_free_elem(module->ctx, root.child);
687 }
688
689 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200690}
691
692static int fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent,
693 struct lyxml_elem *yin, struct ly_tpdf *tpdf)
694{
695 const char *value;
696 struct lyxml_elem *node, *next;
Radek Krejci76c45d32015-05-26 16:01:14 +0200697 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200698
Radek Krejcieac35532015-05-31 19:09:15 +0200699 GETVAL(value, yin, "name");
700 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
701 goto error;
702 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200703 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
704
Radek Krejcieac35532015-05-31 19:09:15 +0200705 /* generic part - status, description, reference */
706 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, 0)) {
707 goto error;
708 }
709
Radek Krejcida04f4a2015-05-21 12:54:09 +0200710 LY_TREE_FOR_SAFE(yin->child, next, node) {
711 if (!strcmp(node->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +0200712 r = fill_yin_type(module, parent, node, &tpdf->type);
Radek Krejcieac35532015-05-31 19:09:15 +0200713 } else if (!strcmp(node->name, "default")) {
714 if (tpdf->dflt) {
715 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
716 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200717 }
Radek Krejcieac35532015-05-31 19:09:15 +0200718 GETVAL(value, node, "value");
719 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
720 } else if (!strcmp(node->name, "units")) {
721 if (tpdf->units) {
722 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
723 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200724 }
Radek Krejcieac35532015-05-31 19:09:15 +0200725 GETVAL(value, node, "name");
726 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
727 } else {
728 LOGVAL(VE_INSTMT, LOGLINE(node), value);
729 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200730 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200731 lyxml_free_elem(module->ctx, node);
732 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +0200733 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200734 }
735 }
736
Radek Krejcieac35532015-05-31 19:09:15 +0200737 /* check mandatory value */
Radek Krejci25d782a2015-05-22 15:03:23 +0200738 if (!tpdf->type.der) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200739 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", "typedef");
Radek Krejcieac35532015-05-31 19:09:15 +0200740 goto error;
741 }
742
743 /* default value */
744 if (check_default(tpdf)) {
745 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200746 }
747
748 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200749
750error:
751
752 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200753}
754
Radek Krejci800af702015-06-02 13:46:01 +0200755static int fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
756{
757 struct lyxml_elem *child;
758 const char *value;
759
760 GETVAL(value, yin, "condition");
761 must->cond = lydict_insert(module->ctx, value, strlen(value));
762
763 LY_TREE_FOR(yin->child, child) {
764 if (!strcmp(child->name, "description")) {
765 if (must->dsc) {
766 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
767 goto error;
768 }
769 must->dsc = read_yin_text(module->ctx, child);
770 if (!must->dsc) {
771 goto error;
772 }
773 } else if (!strcmp(child->name, "reference")) {
774 if (must->ref) {
775 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
776 goto error;
777 }
778 must->ref = read_yin_text(module->ctx, child);
779 if (!must->ref) {
780 goto error;
781 }
782 } else if (!strcmp(child->name, "error-app-tag")) {
783 if (must->eapptag) {
784 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
785 goto error;
786 }
787 must->eapptag = read_yin_text(module->ctx, child);
788 if (!must->eapptag) {
789 goto error;
790 }
791 } else if (!strcmp(child->name, "error-message")) {
792 if (must->emsg) {
793 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
794 goto error;
795 }
796 must->emsg = read_yin_text(module->ctx, child);
797 if (!must->emsg) {
798 goto error;
799 }
800 } else {
801 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
802 goto error;
803 }
804
805 lyxml_free_elem(module->ctx, child);
806 }
807
808
809 return EXIT_SUCCESS;
810
811error:
812
813 return EXIT_FAILURE;
814}
815
Radek Krejciefaeba32015-05-27 14:30:57 +0200816static int fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
817{
818 struct lyxml_elem *child;
819 const char *value;
820
821 LY_TREE_FOR(yin->child, child) {
822 if (!strcmp(child->name, "prefix")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200823 GETVAL(value, child, "value");
Radek Krejci0af13872015-05-30 11:50:52 +0200824 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
825 goto error;
826 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200827 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
828 } else if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200829 if (imp->rev[0]) {
830 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
831 goto error;
832 }
833 GETVAL(value, child, "date");
834 if (check_date(value, LOGLINE(child))) {
835 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200836 }
837 memcpy(imp->rev, value, LY_REV_SIZE - 1);
838 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200839 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200840 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200841 }
842 }
843
Radek Krejcice7fb782015-05-29 16:52:34 +0200844 /* check mandatory information */
845 if (!imp->prefix) {
846 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
847 goto error;
848 }
849
850 GETVAL(value, yin, "module");
Radek Krejci0af13872015-05-30 11:50:52 +0200851 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
Radek Krejciefaeba32015-05-27 14:30:57 +0200852 if (!imp->module) {
Radek Krejci3045cf32015-05-28 10:58:52 +0200853 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200854 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200855 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
856 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200857 }
858
859 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200860
861error:
862
863 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200864}
865
866static int fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
867{
868 struct lyxml_elem *child;
869 const char *value;
870
871 LY_TREE_FOR(yin->child, child) {
872 if (!strcmp(child->name, "revision-date")) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200873 if (inc->rev[0]) {
874 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
875 goto error;
876 }
877 GETVAL(value, child, "date");
878 if (check_date(value, LOGLINE(child))) {
879 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200880 }
881 memcpy(inc->rev, value, LY_REV_SIZE - 1);
882 } else {
Radek Krejci3045cf32015-05-28 10:58:52 +0200883 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200884 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200885 }
886 }
887
Radek Krejcice7fb782015-05-29 16:52:34 +0200888 GETVAL(value, yin, "module");
Radek Krejciefaeba32015-05-27 14:30:57 +0200889 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
890 if (!inc->submodule) {
Radek Krejcice7fb782015-05-29 16:52:34 +0200891 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.",
Radek Krejciefaeba32015-05-27 14:30:57 +0200892 value, module->name);
Radek Krejcice7fb782015-05-29 16:52:34 +0200893 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
894 goto error;
Radek Krejciefaeba32015-05-27 14:30:57 +0200895 }
896
Radek Krejcice7fb782015-05-29 16:52:34 +0200897 /* check that belongs-to corresponds */
898 if (module->type) {
899 module = ((struct ly_submodule *)module)->belongsto;
900 }
901 if (inc->submodule->belongsto != module) {
902 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
903 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
904 goto error;
905 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200906
907 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200908
909error:
910
911 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +0200912}
913
914
Radek Krejcida04f4a2015-05-21 12:54:09 +0200915/*
916 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +0200917 * description, reference, status, optionaly config
Radek Krejcida04f4a2015-05-21 12:54:09 +0200918 */
919static int read_yin_common(struct ly_module *module, struct ly_mnode *parent,
Radek Krejci25d782a2015-05-22 15:03:23 +0200920 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int ext)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200921{
922 const char *value;
923 struct lyxml_elem *sub, *next;
924 struct ly_ctx * const ctx = module->ctx;
Radek Krejcice7fb782015-05-29 16:52:34 +0200925 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200926
Radek Krejci25d782a2015-05-22 15:03:23 +0200927 if (ext) {
928 mnode->module = module;
929 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200930
Radek Krejci800af702015-06-02 13:46:01 +0200931 GETVAL(value, xmlnode, "name");
932 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
Radek Krejcieac35532015-05-31 19:09:15 +0200933 goto error;
Radek Krejci25d782a2015-05-22 15:03:23 +0200934 }
Radek Krejci800af702015-06-02 13:46:01 +0200935 mnode->name = lydict_insert(ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +0200936
937 /* process local parameters */
938 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
939 if (!strcmp(sub->name, "description")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200940 if (mnode->dsc) {
941 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
942 goto error;
943 }
Radek Krejci0af13872015-05-30 11:50:52 +0200944 mnode->dsc = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200945 if (!mnode->dsc) {
946 r = 1;
947 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200948 } else if (!strcmp(sub->name, "reference")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200949 if (mnode->ref) {
950 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
951 goto error;
952 }
Radek Krejci0af13872015-05-30 11:50:52 +0200953 mnode->ref = read_yin_text(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200954 if (!mnode->ref) {
955 r = 1;
956 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200957 } else if (!strcmp(sub->name, "status")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200958 if (mnode->flags & LY_NODE_STATUS_MASK) {
959 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
960 goto error;
961 }
962 GETVAL(value, sub, "value");
Radek Krejcida04f4a2015-05-21 12:54:09 +0200963 if (!strcmp(value, "current")) {
964 mnode->flags |= LY_NODE_STATUS_CURR;
965 } else if (!strcmp(value, "deprecated")) {
966 mnode->flags |= LY_NODE_STATUS_DEPRC;
967 } else if (!strcmp(value, "obsolete")) {
968 mnode->flags |= LY_NODE_STATUS_OBSLT;
Radek Krejcice7fb782015-05-29 16:52:34 +0200969 } else {
970 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
971 r = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200972 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200973 } else if (ext && !strcmp(sub->name, "config")) {
Radek Krejcieac35532015-05-31 19:09:15 +0200974 if (mnode->flags & LY_NODE_CONFIG_MASK) {
975 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
976 goto error;
977 }
978 GETVAL(value, sub, "value");
Radek Krejci25d782a2015-05-22 15:03:23 +0200979 if (!strcmp(value, "false")) {
980 mnode->flags |= LY_NODE_CONFIG_R;
981 } else if (!strcmp(value, "false")) {
982 mnode->flags |= LY_NODE_CONFIG_W;
Radek Krejcice7fb782015-05-29 16:52:34 +0200983 } else {
984 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
985 r = 1;
Radek Krejci25d782a2015-05-22 15:03:23 +0200986 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200987 } else {
988 /* skip the lyxml_free_elem */
989 continue;
990 }
991 lyxml_free_elem(ctx, sub);
Radek Krejcice7fb782015-05-29 16:52:34 +0200992 if (r) {
Radek Krejcieac35532015-05-31 19:09:15 +0200993 goto error;
Radek Krejcice7fb782015-05-29 16:52:34 +0200994 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200995 }
996
Radek Krejci25d782a2015-05-22 15:03:23 +0200997 if (ext && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +0200998 /* get config flag from parent */
999 if (parent) {
1000 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1001 } else {
1002 /* default config is true */
1003 mnode->flags |= LY_NODE_CONFIG_W;
1004 }
1005 }
1006
1007 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001008
1009error:
1010
1011 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001012}
1013
1014static struct ly_mnode *read_yin_choice(struct ly_module *module,
1015 struct ly_mnode *parent,
1016 struct lyxml_elem *node)
1017{
1018 struct lyxml_elem *sub, *next;
1019 struct ly_ctx * const ctx = module->ctx;
Radek Krejci25d782a2015-05-22 15:03:23 +02001020 struct ly_mnode *retval, *r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001021 struct ly_mnode_choice *choice;
1022
Radek Krejcida04f4a2015-05-21 12:54:09 +02001023 choice = calloc(1, sizeof *choice);
1024 choice->nodetype = LY_NODE_CHOICE;
1025 choice->module = module;
1026 choice->prev = (struct ly_mnode *)choice;
1027 retval = (struct ly_mnode *)choice;
1028
Radek Krejci25d782a2015-05-22 15:03:23 +02001029 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001030 goto error;
1031 }
1032
1033 /* process choice's specific children */
1034 LY_TREE_FOR_SAFE(node->child, next, sub) {
1035 if (!strcmp(sub->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001036 r = read_yin_container(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001037 } else if (!strcmp(sub->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001038 r = read_yin_leaflist(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001039 } else if (!strcmp(sub->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001040 r = read_yin_leaf(module, retval, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001041 } else if (!strcmp(sub->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001042 r = read_yin_list(module, retval, sub);
Radek Krejci667b97f2015-05-25 15:03:30 +02001043 } else {
1044 continue;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001045 }
1046 lyxml_free_elem(ctx, sub);
Radek Krejci25d782a2015-05-22 15:03:23 +02001047 if (!r) {
1048 goto error;
1049 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001050 }
1051
Radek Krejci812b10a2015-05-28 16:48:25 +02001052 if (parent) {
1053 ly_mnode_addchild(parent, retval);
1054 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001055
1056 return retval;
1057
1058error:
1059
1060 ly_mnode_free(retval);
1061
1062 return NULL;
1063}
1064
1065static struct ly_mnode *read_yin_leaf(struct ly_module *module,
1066 struct ly_mnode *parent,
1067 struct lyxml_elem *node)
1068{
1069 struct ly_mnode *retval;
1070 struct ly_mnode_leaf *leaf;
1071 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +02001072 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001073
Radek Krejcida04f4a2015-05-21 12:54:09 +02001074 leaf = calloc(1, sizeof *leaf);
1075 leaf->nodetype = LY_NODE_LEAF;
1076 leaf->prev = (struct ly_mnode *)leaf;
1077 retval = (struct ly_mnode *)leaf;
1078
Radek Krejci25d782a2015-05-22 15:03:23 +02001079 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001080 goto error;
1081 }
1082
1083 LY_TREE_FOR_SAFE(node->child, next, sub) {
1084 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001085 r = fill_yin_type(module, parent, sub, &leaf->type);
1086 if (r) {
1087 goto error;
1088 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001089 }
1090 }
1091
Radek Krejci812b10a2015-05-28 16:48:25 +02001092 if (parent) {
1093 ly_mnode_addchild(parent, retval);
1094 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001095
1096 return retval;
1097
1098error:
1099
1100 ly_mnode_free(retval);
1101
1102 return NULL;
1103}
1104
1105static struct ly_mnode *read_yin_leaflist(struct ly_module *module,
1106 struct ly_mnode *parent,
1107 struct lyxml_elem *node)
1108{
1109 struct ly_mnode *retval;
1110 struct ly_mnode_leaflist *llist;
1111 struct lyxml_elem *sub, *next;
Radek Krejci25d782a2015-05-22 15:03:23 +02001112 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001113
Radek Krejcida04f4a2015-05-21 12:54:09 +02001114 llist = calloc(1, sizeof *llist);
1115 llist->nodetype = LY_NODE_LEAFLIST;
1116 llist->prev = (struct ly_mnode *)llist;
1117 retval = (struct ly_mnode *)llist;
1118
Radek Krejci25d782a2015-05-22 15:03:23 +02001119 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001120 goto error;
1121 }
1122
1123 LY_TREE_FOR_SAFE(node->child, next, sub) {
1124 if (!strcmp(sub->name, "type")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001125 r = fill_yin_type(module, parent, sub, &llist->type);
1126 if (r) {
1127 goto error;
1128 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001129 }
1130 }
1131
Radek Krejci812b10a2015-05-28 16:48:25 +02001132 if (parent) {
1133 ly_mnode_addchild(parent, retval);
1134 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001135
1136 return retval;
1137
1138error:
1139
1140 ly_mnode_free(retval);
1141
1142 return NULL;
1143}
1144
1145static struct ly_mnode *read_yin_list(struct ly_module *module,
1146 struct ly_mnode *parent,
1147 struct lyxml_elem *node)
1148{
1149 struct ly_mnode *retval, *mnode;
1150 struct ly_mnode_list *list;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001151 struct ly_mnode_leaf *key;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001152 struct lyxml_elem *sub, *next, root = {0};
Radek Krejcid7f0d012015-05-25 15:04:52 +02001153 int i, j, r;
1154 size_t len;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001155 int c_tpdf = 0;
Radek Krejcid7f0d012015-05-25 15:04:52 +02001156 const char *key_str = NULL, *s;
1157 char *dup;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001158
Radek Krejcida04f4a2015-05-21 12:54:09 +02001159 list = calloc(1, sizeof *list);
1160 list->nodetype = LY_NODE_LIST;
1161 list->prev = (struct ly_mnode *)list;
1162 retval = (struct ly_mnode *)list;
1163
Radek Krejci25d782a2015-05-22 15:03:23 +02001164 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001165 goto error;
1166 }
1167
1168 /* process list's specific children */
1169 LY_TREE_FOR_SAFE(node->child, next, sub) {
1170 /* data statements */
1171 if (!strcmp(sub->name, "container") ||
1172 !strcmp(sub->name, "leaf-list") ||
1173 !strcmp(sub->name, "leaf") ||
1174 !strcmp(sub->name, "list") ||
1175 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001176 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001177 !strcmp(sub->name, "grouping")) {
1178 lyxml_unlink_elem(sub);
1179 lyxml_add_child(&root, sub);
1180
1181 /* array counters */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001182 } else if (!strcmp(sub->name, "key")) {
1183 /* check cardinality 0..1 */
1184 if (list->keys_size) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001185 LOGVAL(VE_TOOMANY, LOGLINE(sub), "key", list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001186 goto error;
1187 }
1188
1189 /* count the number of keys */
1190 key_str = s = lyxml_get_attr(sub, "value", NULL);
1191 if (!s) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001192 LOGVAL(VE_MISSARG, LOGLINE(sub), "value", "key");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001193 goto error;
1194 }
1195 while((s = strpbrk(s, " \t\n"))) {
1196 list->keys_size++;
1197 while(isspace(*s)) {
1198 s++;
1199 }
1200 }
1201 list->keys_size++;
1202
1203 list->keys = calloc(list->keys_size, sizeof *list->keys);
1204
Radek Krejcida04f4a2015-05-21 12:54:09 +02001205 } else if (!strcmp(sub->name, "typedef")) {
1206 c_tpdf++;
1207 }
1208 }
1209
Radek Krejcid7f0d012015-05-25 15:04:52 +02001210 /* check - if list is configuration, key statement is mandatory */
Radek Krejci3a734ed2015-05-26 15:23:18 +02001211 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001212 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "key", "list");
Radek Krejcid7f0d012015-05-25 15:04:52 +02001213 goto error;
1214 }
1215
Radek Krejcida04f4a2015-05-21 12:54:09 +02001216 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1217 if (c_tpdf) {
1218 list->tpdf_size = c_tpdf;
1219 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
1220 c_tpdf = 0;
1221 }
1222 LY_TREE_FOR_SAFE(node->child, next, sub) {
1223 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001224 r = fill_yin_typedef(module, retval, sub, &list->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001225 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001226
1227 if (r) {
1228 list->tpdf_size = c_tpdf;
1229 goto error;
1230 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02001231 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001232 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001233 }
1234
1235 /* last part - process data nodes */
1236 LY_TREE_FOR_SAFE(root.child, next, sub) {
1237 if (!strcmp(sub->name, "container")) {
1238 mnode = read_yin_container(module, retval, sub);
1239 } else if (!strcmp(sub->name, "leaf-list")) {
1240 mnode = read_yin_leaflist(module, retval, sub);
1241 } else if (!strcmp(sub->name, "leaf")) {
1242 mnode = read_yin_leaf(module, retval, sub);
1243 } else if (!strcmp(sub->name, "list")) {
1244 mnode = read_yin_list(module, retval, sub);
1245 } else if (!strcmp(sub->name, "choice")) {
1246 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001247 } else if (!strcmp(sub->name, "uses")) {
1248 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001249 } else if (!strcmp(sub->name, "grouping")) {
1250 mnode = read_yin_grouping(module, retval, sub);
1251 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001252 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001253 continue;
1254 }
1255 lyxml_free_elem(module->ctx, sub);
1256
Radek Krejci25d782a2015-05-22 15:03:23 +02001257 if (!mnode) {
1258 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001259 }
1260 }
1261
Radek Krejci812b10a2015-05-28 16:48:25 +02001262 if (parent) {
1263 ly_mnode_addchild(parent, retval);
1264 }
1265
Radek Krejci3a734ed2015-05-26 15:23:18 +02001266 if (!key_str) {
1267 /* config false list without a key */
1268 return retval;
1269 }
1270
Radek Krejcid7f0d012015-05-25 15:04:52 +02001271 /* link key leafs into the list structure and check all constraints */
1272 /* TODO - include searching in uses/grouping */
1273 for (i = 0; i < list->keys_size; i++) {
1274 /* get the key name */
1275 if ((s = strpbrk(key_str, " \t\n"))) {
1276 len = s - key_str;
1277 } else {
1278 len = strlen(key_str);
1279 }
1280 LY_TREE_FOR(list->child, mnode) {
1281 if (!strncmp(mnode->name, key_str, len) && !mnode->name[len]) {
1282 list->keys[i] = mnode;
1283 break;
1284 }
1285 }
1286 key = (struct ly_mnode_leaf *)list->keys[i];
1287
1288 /* existence */
1289 if (!key) {
1290 if ((s = strpbrk(key_str, " \t\n"))) {
1291 len = s - key_str;
1292 dup = strdup(key_str);
1293 dup[len] = '\0';
1294 key_str = dup;
1295 }
Radek Krejci3045cf32015-05-28 10:58:52 +02001296 LOGVAL(VE_KEY_MISS, LOGLINE(node), key_str);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001297 if (s) {
1298 free(dup);
1299 }
1300 goto error;
1301 }
1302
Radek Krejci3045cf32015-05-28 10:58:52 +02001303 /* uniqueness */
Radek Krejcid7f0d012015-05-25 15:04:52 +02001304 for (j = i - 1; j >= 0; j--) {
1305 if (list->keys[i] == list->keys[j]) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001306 LOGVAL(VE_KEY_DUP, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001307 goto error;
1308 }
1309 }
1310
1311 /* key is a leaf */
1312 if (key->nodetype != LY_NODE_LEAF) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001313 LOGVAL(VE_KEY_NLEAF, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001314 goto error;
1315 }
1316
1317 /* type of the leaf is not built-in empty */
1318 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001319 LOGVAL(VE_KEY_TYPE, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001320 goto error;
1321 }
1322
1323 /* config attribute is the same as of the list */
1324 if ((list->flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001325 LOGVAL(VE_KEY_CONFIG, LOGLINE(node), key->name, list->name);
Radek Krejcid7f0d012015-05-25 15:04:52 +02001326 goto error;
1327 }
1328
1329 /* prepare for next iteration */
1330 while (s && isspace(*s)) {
1331 s++;
1332 }
1333 key_str = s;
1334 }
1335
Radek Krejcida04f4a2015-05-21 12:54:09 +02001336 return retval;
1337
1338error:
1339
1340 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001341 while(root.child) {
1342 lyxml_free_elem(module->ctx, root.child);
1343 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001344
1345 return NULL;
1346}
1347
1348static struct ly_mnode *read_yin_container(struct ly_module *module,
1349 struct ly_mnode *parent,
1350 struct lyxml_elem *node)
1351{
1352 struct lyxml_elem *sub, *next, root = {0};
1353 struct ly_mnode *mnode = NULL;
1354 struct ly_mnode *retval;
1355 struct ly_mnode_container *cont;
Radek Krejci800af702015-06-02 13:46:01 +02001356 const char *value;
Radek Krejci25d782a2015-05-22 15:03:23 +02001357 int r;
Radek Krejci800af702015-06-02 13:46:01 +02001358 int c_tpdf = 0, c_must = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001359
Radek Krejcida04f4a2015-05-21 12:54:09 +02001360 cont = calloc(1, sizeof *cont);
1361 cont->nodetype = LY_NODE_CONTAINER;
1362 cont->prev = (struct ly_mnode *)cont;
1363 retval = (struct ly_mnode *)cont;
1364
Radek Krejci25d782a2015-05-22 15:03:23 +02001365 if (read_yin_common(module, parent, retval, node, 1)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001366 goto error;
1367 }
1368
1369 /* process container's specific children */
1370 LY_TREE_FOR_SAFE(node->child, next, sub) {
Radek Krejci800af702015-06-02 13:46:01 +02001371 if (!strcmp(sub->name, "presence")) {
1372 if (cont->presence) {
1373 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
1374 goto error;
1375 }
1376 GETVAL(value, sub, "value");
1377 cont->presence = lydict_insert(module->ctx, value, strlen(value));
1378
Radek Krejcida04f4a2015-05-21 12:54:09 +02001379 /* data statements */
Radek Krejci800af702015-06-02 13:46:01 +02001380 } else if (!strcmp(sub->name, "container") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001381 !strcmp(sub->name, "leaf-list") ||
1382 !strcmp(sub->name, "leaf") ||
1383 !strcmp(sub->name, "list") ||
1384 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001385 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001386 !strcmp(sub->name, "grouping")) {
1387 lyxml_unlink_elem(sub);
1388 lyxml_add_child(&root, sub);
1389
1390 /* array counters */
1391 } else if (!strcmp(sub->name, "typedef")) {
1392 c_tpdf++;
Radek Krejci800af702015-06-02 13:46:01 +02001393 } else if (!strcmp(sub->name, "must")) {
1394 c_must++;
1395 } else {
1396
Radek Krejcida04f4a2015-05-21 12:54:09 +02001397 }
1398 }
1399
1400 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1401 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001402 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001403 }
Radek Krejci800af702015-06-02 13:46:01 +02001404 if (c_must) {
1405 cont->must = calloc(c_must, sizeof *cont->must);
1406 }
1407
Radek Krejcida04f4a2015-05-21 12:54:09 +02001408 LY_TREE_FOR_SAFE(node->child, next, sub) {
1409 if (!strcmp(sub->name, "typedef")) {
Radek Krejci800af702015-06-02 13:46:01 +02001410 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
1411 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001412
1413 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001414 goto error;
1415 }
Radek Krejci800af702015-06-02 13:46:01 +02001416 } else if (!strcmp(sub->name, "must")) {
1417 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
1418 cont->must_size++;
1419
1420 if (r) {
1421 goto error;
1422 }
1423#if 0
1424 } else {
1425 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1426 goto error;
1427#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02001428 }
1429
1430 lyxml_free_elem(module->ctx, sub);
1431 }
1432
1433 /* last part - process data nodes */
1434 LY_TREE_FOR_SAFE(root.child, next, sub) {
1435 if (!strcmp(sub->name, "container")) {
1436 mnode = read_yin_container(module, retval, sub);
1437 } else if (!strcmp(sub->name, "leaf-list")) {
1438 mnode = read_yin_leaflist(module, retval, sub);
1439 } else if (!strcmp(sub->name, "leaf")) {
1440 mnode = read_yin_leaf(module, retval, sub);
1441 } else if (!strcmp(sub->name, "list")) {
1442 mnode = read_yin_list(module, retval, sub);
1443 } else if (!strcmp(sub->name, "choice")) {
1444 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001445 } else if (!strcmp(sub->name, "uses")) {
1446 mnode = read_yin_uses(module, retval, sub, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001447 } else if (!strcmp(sub->name, "grouping")) {
1448 mnode = read_yin_grouping(module, retval, sub);
1449 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001450 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001451 continue;
1452 }
1453 lyxml_free_elem(module->ctx, sub);
1454
Radek Krejci25d782a2015-05-22 15:03:23 +02001455 if (!mnode) {
1456 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001457 }
1458 }
1459
Radek Krejci812b10a2015-05-28 16:48:25 +02001460 if (parent) {
1461 ly_mnode_addchild(parent, retval);
1462 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001463
1464 return retval;
1465
1466error:
1467
1468 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001469 while (root.child) {
1470 lyxml_free_elem(module->ctx, root.child);
1471 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001472
1473 return NULL;
1474}
1475
1476static struct ly_mnode *read_yin_grouping(struct ly_module *module,
1477 struct ly_mnode *parent,
1478 struct lyxml_elem *node)
1479{
1480 struct lyxml_elem *sub, *next, root = {0};
1481 struct ly_mnode *mnode = NULL;
1482 struct ly_mnode *retval;
1483 struct ly_mnode_grp *grp;
Radek Krejci25d782a2015-05-22 15:03:23 +02001484 int r;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001485 int c_tpdf = 0;
1486
1487 grp = calloc(1, sizeof *grp);
1488 grp->nodetype = LY_NODE_GROUPING;
1489 grp->module = module;
1490 grp->prev = (struct ly_mnode *)grp;
1491 retval = (struct ly_mnode *)grp;
1492
Radek Krejci25d782a2015-05-22 15:03:23 +02001493 if (read_yin_common(module, parent, retval, node, 0)) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001494 goto error;
1495 }
1496
1497 LY_TREE_FOR_SAFE(node->child, next, sub) {
1498 /* data statements */
1499 if (!strcmp(sub->name, "container") ||
1500 !strcmp(sub->name, "leaf-list") ||
1501 !strcmp(sub->name, "leaf") ||
1502 !strcmp(sub->name, "list") ||
1503 !strcmp(sub->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001504 !strcmp(sub->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001505 !strcmp(sub->name, "grouping")) {
1506 lyxml_unlink_elem(sub);
1507 lyxml_add_child(&root, sub);
1508
1509 /* array counters */
1510 } else if (!strcmp(sub->name, "typedef")) {
1511 c_tpdf++;
1512 }
1513 }
1514
1515 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1516 if (c_tpdf) {
1517 grp->tpdf_size = c_tpdf;
1518 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
1519 c_tpdf = 0;
1520 }
1521 LY_TREE_FOR_SAFE(node->child, next, sub) {
1522 if (!strcmp(sub->name, "typedef")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001523 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[c_tpdf]);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001524 c_tpdf++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001525
1526 if (r) {
1527 grp->tpdf_size = c_tpdf;
1528 goto error;
1529 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001530 }
1531
1532 lyxml_free_elem(module->ctx, sub);
1533 }
1534
1535 /* last part - process data nodes */
1536 LY_TREE_FOR_SAFE(root.child, next, sub) {
1537 if (!strcmp(sub->name, "container")) {
1538 mnode = read_yin_container(module, retval, sub);
1539 } else if (!strcmp(sub->name, "leaf-list")) {
1540 mnode = read_yin_leaflist(module, retval, sub);
1541 } else if (!strcmp(sub->name, "leaf")) {
1542 mnode = read_yin_leaf(module, retval, sub);
1543 } else if (!strcmp(sub->name, "list")) {
1544 mnode = read_yin_list(module, retval, sub);
1545 } else if (!strcmp(sub->name, "choice")) {
1546 mnode = read_yin_choice(module, retval, sub);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001547 } else if (!strcmp(sub->name, "uses")) {
1548 mnode = read_yin_uses(module, retval, sub, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001549 } else if (!strcmp(sub->name, "grouping")) {
1550 mnode = read_yin_grouping(module, retval, sub);
1551 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02001552 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02001553 continue;
1554 }
1555 lyxml_free_elem(module->ctx, sub);
1556
Radek Krejci25d782a2015-05-22 15:03:23 +02001557 if (!mnode) {
1558 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001559 }
1560 }
1561
Radek Krejci812b10a2015-05-28 16:48:25 +02001562 if (parent) {
1563 ly_mnode_addchild(parent, retval);
1564 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001565
1566 return retval;
1567
1568error:
1569
1570 ly_mnode_free(retval);
Radek Krejci25d782a2015-05-22 15:03:23 +02001571 while (root.child) {
1572 lyxml_free_elem(module->ctx, root.child);
1573 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001574
1575 return NULL;
1576}
1577
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001578/*
1579 * resolve - referenced grouping should be bounded to the namespace (resolved)
1580 * only when uses does not appear in grouping. In a case of grouping's uses,
1581 * we just get information but we do not apply augment or refine to it.
1582 */
1583static struct ly_mnode *read_yin_uses(struct ly_module *module,
1584 struct ly_mnode *parent,
1585 struct lyxml_elem *node, int resolve)
1586{
1587 struct ly_mnode *retval;
1588 struct ly_mnode *mnode = NULL, *par;
1589 struct ly_mnode_uses *uses;
1590 struct ly_module *searchmod = NULL;
1591 const char *name;
1592 int prefix_len = 0;
1593 int i;
1594
1595 uses = calloc(1, sizeof *uses);
1596 uses->nodetype = LY_NODE_USES;
1597 uses->module = module;
1598 uses->prev = (struct ly_mnode *)uses;
1599 retval = (struct ly_mnode *)uses;
1600
1601 if (read_yin_common(module, parent, retval, node, 0)) {
1602 goto error;
1603 }
1604
1605 /* get referenced grouping */
1606 name = strchr(uses->name, ':');
1607 if (!name) {
1608 /* no prefix, search in local tree */
1609 name = uses->name;
1610 } else {
1611 /* there is some prefix, check if it refer the same data model */
1612
1613 /* set name to correct position after colon */
1614 prefix_len = name - uses->name;
1615 name++;
1616
1617 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1618 /* prefix refers to the current module, ignore it */
1619 prefix_len = 0;
1620 }
1621 }
1622
1623 /* search */
1624 if (prefix_len) {
1625 /* in top-level groupings of some other module */
1626 for (i = 0; i < module->imp_size; i++) {
1627 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
1628 && !module->imp[i].prefix[prefix_len]) {
1629 searchmod = module->imp[i].module;
1630 break;
1631 }
1632 }
1633 if (!searchmod) {
1634 /* uses refers unknown data model */
Radek Krejci3045cf32015-05-28 10:58:52 +02001635 LOGVAL(VE_INPREFIX, LOGLINE(node), name);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001636 goto error;
1637 }
1638
1639 LY_TREE_FOR(module->data, mnode) {
1640 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1641 uses->grp = (struct ly_mnode_grp *)mnode;
1642 break;
1643 }
1644 }
1645
1646 if (!uses->grp) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001647 LOGVAL(VE_INARG, LOGLINE(node), uses->name, "uses");
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001648 goto error;
1649 }
1650
1651 } else {
1652 /* in local tree hierarchy */
1653 for(par = parent; par; par = par->parent) {
1654 LY_TREE_FOR(parent->child, mnode) {
1655 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1656 uses->grp = (struct ly_mnode_grp *)mnode;
1657 break;
1658 }
1659 }
1660 }
1661
1662 /* search in top level of the current module */
1663 LY_TREE_FOR(module->data, mnode) {
1664 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
1665 uses->grp = (struct ly_mnode_grp *)mnode;
1666 break;
1667 }
1668 }
1669 }
1670
Radek Krejci812b10a2015-05-28 16:48:25 +02001671 if (parent) {
1672 ly_mnode_addchild(parent, retval);
1673 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001674
1675 if (!resolve) {
Radek Krejci812b10a2015-05-28 16:48:25 +02001676 /* this is uses statement inside the grouping, so do not bound grouping
1677 * to the current content
1678 */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001679 return retval;
1680 }
1681
1682 /* TODO */
1683
1684 return retval;
1685
1686error:
1687
1688 ly_mnode_free(retval);
1689
1690 return NULL;
1691}
1692
Radek Krejciefaeba32015-05-27 14:30:57 +02001693/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci0af13872015-05-30 11:50:52 +02001694static int read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001695{
Radek Krejciefaeba32015-05-27 14:30:57 +02001696 struct ly_ctx *ctx = module->ctx;
Radek Krejci0af13872015-05-30 11:50:52 +02001697 struct ly_submodule *submodule = (struct ly_submodule *)module;
Radek Krejciefaeba32015-05-27 14:30:57 +02001698 struct lyxml_elem *next, *node, *child, root = {0};
Radek Krejci25d782a2015-05-22 15:03:23 +02001699 struct ly_mnode *mnode = NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001700 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001701 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0; /* counters */
Radek Krejci25d782a2015-05-22 15:03:23 +02001702 int r;
Radek Krejcice7fb782015-05-29 16:52:34 +02001703 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001704
1705 /*
1706 * in the first run, we process elements with cardinality of 1 or 0..1 and
1707 * count elements with cardinality 0..n. Data elements (choices, containers,
1708 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
1709 * need have all top-level and groupings already prepared at that time. In
1710 * the middle loop, we process other elements with carinality of 0..n since
1711 * we need to allocate arrays to store them.
1712 */
1713 LY_TREE_FOR_SAFE(yin->child, next, node) {
1714 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1715 lyxml_free_elem(ctx, node);
1716 continue;
1717 }
1718
Radek Krejci0af13872015-05-30 11:50:52 +02001719 if (!module->type && !strcmp(node->name, "namespace")) {
1720 if (module->ns) {
1721 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1722 goto error;
1723 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001724 GETVAL(value, node, "uri");
Radek Krejcida04f4a2015-05-21 12:54:09 +02001725 module->ns = lydict_insert(ctx, value, strlen(value));
1726 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02001727 } else if (!module->type && !strcmp(node->name, "prefix")) {
1728 if (module->prefix) {
1729 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1730 goto error;
1731 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001732 GETVAL(value, node, "value");
Radek Krejci0af13872015-05-30 11:50:52 +02001733 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
1734 goto error;
1735 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001736 module->prefix = lydict_insert(ctx, value, strlen(value));
1737 lyxml_free_elem(ctx, node);
Radek Krejci0af13872015-05-30 11:50:52 +02001738 } else if (module->type && !strcmp(node->name, "belongs-to")) {
1739 if (submodule->belongsto) {
1740 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1741 goto error;
1742 }
1743 GETVAL(value, node, "module");
1744 submodule->belongsto = ly_ctx_get_module(module->ctx, value, NULL, 0);
1745 if (!submodule->belongsto) {
1746 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1747 goto error;
1748 }
1749 /* get the prefix substatement, start with checks */
1750 if (!node->child) {
1751 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
1752 goto error;
1753 } else if (strcmp(node->child->name, "prefix")) {
1754 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
1755 goto error;
1756 } else if (node->child->next) {
1757 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
1758 goto error;
1759 }
1760 /* and now finally get the value */
1761 GETVAL(value, node->child, "value");
1762 /* check here differs from a generic prefix check, since this prefix
1763 * don't have to be unique
1764 */
1765 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
1766 goto error;
1767 }
1768 module->prefix = lydict_insert(ctx, value, strlen(value));
1769
1770 /* we are done with belongs-to */
1771 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001772 } else if (!strcmp(node->name, "import")) {
1773 c_imp++;
1774 } else if (!strcmp(node->name, "revision")) {
1775 c_rev++;
1776 } else if (!strcmp(node->name, "typedef")) {
1777 c_tpdf++;
Radek Krejci6793db02015-05-22 17:49:54 +02001778 } else if (!strcmp(node->name, "identity")) {
1779 c_ident++;
Radek Krejciefaeba32015-05-27 14:30:57 +02001780 } else if (!strcmp(node->name, "include")) {
1781 c_inc++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001782
1783 /* data statements */
1784 } else if (!strcmp(node->name, "container") ||
1785 !strcmp(node->name, "leaf-list") ||
1786 !strcmp(node->name, "leaf") ||
1787 !strcmp(node->name, "list") ||
1788 !strcmp(node->name, "choice") ||
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02001789 !strcmp(node->name, "uses") ||
Radek Krejcida04f4a2015-05-21 12:54:09 +02001790 !strcmp(node->name, "grouping")) {
1791 lyxml_unlink_elem(node);
1792 lyxml_add_child(&root, node);
1793
1794 /* optional statements */
1795 } else if (!strcmp(node->name, "description")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001796 if (module->dsc) {
Radek Krejci0af13872015-05-30 11:50:52 +02001797 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02001798 goto error;
1799 }
Radek Krejci0af13872015-05-30 11:50:52 +02001800 module->dsc = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001801 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02001802 if (!module->dsc) {
1803 goto error;
1804 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001805 } else if (!strcmp(node->name, "reference")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001806 if (module->ref) {
Radek Krejci0af13872015-05-30 11:50:52 +02001807 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02001808 goto error;
1809 }
Radek Krejci0af13872015-05-30 11:50:52 +02001810 module->ref = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001811 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02001812 if (!module->ref) {
1813 goto error;
1814 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001815 } else if (!strcmp(node->name, "organization")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001816 if (module->org) {
Radek Krejci0af13872015-05-30 11:50:52 +02001817 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02001818 goto error;
1819 }
Radek Krejci0af13872015-05-30 11:50:52 +02001820 module->org = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001821 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02001822 if (!module->org) {
1823 goto error;
1824 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001825 } else if (!strcmp(node->name, "contact")) {
Radek Krejcib0594bf2015-05-21 23:51:27 +02001826 if (module->contact) {
Radek Krejci0af13872015-05-30 11:50:52 +02001827 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcib0594bf2015-05-21 23:51:27 +02001828 goto error;
1829 }
Radek Krejci0af13872015-05-30 11:50:52 +02001830 module->contact = read_yin_text(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001831 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02001832 if (!module->contact) {
1833 goto error;
1834 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001835 } else if (!strcmp(node->name, "yang-version")) {
Radek Krejcice7fb782015-05-29 16:52:34 +02001836 /* TODO: support YANG 1.1 ? */
Radek Krejcib0594bf2015-05-21 23:51:27 +02001837 if (module->version) {
Radek Krejci0af13872015-05-30 11:50:52 +02001838 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001839 goto error;
1840 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001841 GETVAL(value, node, "value");
Radek Krejcib0594bf2015-05-21 23:51:27 +02001842 if (strcmp(value, "1")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001843 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
Radek Krejcib0594bf2015-05-21 23:51:27 +02001844 goto error;
1845 }
1846 module->version = 1;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001847 lyxml_free_elem(ctx, node);
Radek Krejcice7fb782015-05-29 16:52:34 +02001848#if 0
1849 } else {
1850 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1851 goto error;
1852#endif
Radek Krejcida04f4a2015-05-21 12:54:09 +02001853 }
1854 }
1855
Radek Krejciefaeba32015-05-27 14:30:57 +02001856 if (!submodule) {
1857 /* check for mandatory statements */
1858 if (!module->ns) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001859 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02001860 goto error;
1861 }
1862 if (!module->prefix) {
Radek Krejci3045cf32015-05-28 10:58:52 +02001863 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
Radek Krejciefaeba32015-05-27 14:30:57 +02001864 goto error;
1865 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02001866 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02001867
Radek Krejcida04f4a2015-05-21 12:54:09 +02001868 /* allocate arrays for elements with cardinality of 0..n */
1869 if (c_imp) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001870 module->imp = calloc(c_imp, sizeof *module->imp);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001871 }
1872 if (c_rev) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001873 module->rev = calloc(c_rev, sizeof *module->rev);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001874 }
1875 if (c_tpdf) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001876 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001877 }
Radek Krejci6793db02015-05-22 17:49:54 +02001878 if (c_ident) {
Radek Krejci6793db02015-05-22 17:49:54 +02001879 module->ident = calloc(c_ident, sizeof *module->ident);
Radek Krejciefaeba32015-05-27 14:30:57 +02001880 }
1881 if (c_inc) {
1882 module->inc = calloc(c_inc, sizeof *module->inc);
Radek Krejci6793db02015-05-22 17:49:54 +02001883 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001884
1885 /* middle part - process nodes with cardinality of 0..n except the data nodes */
1886 LY_TREE_FOR_SAFE(yin->child, next, node) {
1887 if (!strcmp(node->name, "import")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001888 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
1889 module->imp_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02001890 if (r) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02001891 goto error;
1892 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001893
1894 /* check duplicities in imported modules */
1895 for (i = 0; i < module->imp_size - 1; i++) {
1896 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
1897 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
1898 goto error;
1899 }
1900 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001901 } else if (!strcmp(node->name, "include")) {
1902 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
1903 module->inc_size++;
Radek Krejciefaeba32015-05-27 14:30:57 +02001904 if (r) {
1905 goto error;
1906 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001907
1908 /* check duplications in include submodules */
1909 for (i = 0; i < module->inc_size - 1; i++) {
Radek Krejci76e5a1b2015-05-29 17:01:08 +02001910 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
Radek Krejcice7fb782015-05-29 16:52:34 +02001911 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->inc[i].submodule->name);
1912 goto error;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001913 }
1914 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001915 } else if (!strcmp(node->name, "revision")) {
1916 GETVAL(value, node, "date");
1917 if (check_date(value, LOGLINE(node))) {
1918 goto error;
1919 }
1920 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
1921 /* check uniqueness of the revision date - not required by RFC */
1922 for (i = 0; i < module->rev_size; i++) {
1923 if (!strcmp(value, module->rev[i].date)) {
1924 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1925 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
1926 }
1927 }
1928
1929 LY_TREE_FOR(node->child, child) {
1930 if (!strcmp(child->name, "description")) {
1931 if (module->rev[module->rev_size].dsc) {
1932 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
1933 goto error;
1934 }
Radek Krejci0af13872015-05-30 11:50:52 +02001935 module->rev[module->rev_size].dsc = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02001936 if (!module->rev[module->rev_size].dsc) {
1937 goto error;
1938 }
1939 } else if (!strcmp(child->name, "reference")) {
1940 if (module->rev[module->rev_size].ref) {
1941 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
1942 goto error;
1943 }
Radek Krejci0af13872015-05-30 11:50:52 +02001944 module->rev[module->rev_size].ref = read_yin_text(ctx, child);
Radek Krejcice7fb782015-05-29 16:52:34 +02001945 if (!module->rev[module->rev_size].ref) {
1946 goto error;
1947 }
1948 } else {
1949 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1950 goto error;
1951 }
1952 }
1953
1954 /* keep the latest revision at position 0 */
1955 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
1956 /* switch their position */
1957 value = strdup(module->rev[0].date);
1958 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
1959 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
1960 free((char*)value);
1961
1962 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
1963 value = module->rev[0].dsc;
1964 module->rev[0].dsc = module->rev[module->rev_size].dsc;
1965 module->rev[module->rev_size].dsc = value;
1966 }
1967
1968 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
1969 value = module->rev[0].ref;
1970 module->rev[0].ref = module->rev[module->rev_size].ref;
1971 module->rev[module->rev_size].ref = value;
1972 }
1973 }
1974
Radek Krejciefaeba32015-05-27 14:30:57 +02001975 module->rev_size++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001976 } else if (!strcmp(node->name, "typedef")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001977 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
1978 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02001979
1980 if (r) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001981 goto error;
1982 }
Radek Krejci6793db02015-05-22 17:49:54 +02001983 } else if (!strcmp(node->name, "identity")) {
Radek Krejciefaeba32015-05-27 14:30:57 +02001984 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
1985 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02001986
1987 if (r) {
Radek Krejci6793db02015-05-22 17:49:54 +02001988 goto error;
1989 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001990 }
1991
1992 lyxml_free_elem(ctx, node);
1993 }
1994
1995 /* last part - process data nodes */
1996 LY_TREE_FOR_SAFE(root.child, next, node) {
1997
1998 if (!strcmp(node->name, "container")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02001999 mnode = read_yin_container(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002000 } else if (!strcmp(node->name, "leaf-list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002001 mnode = read_yin_leaflist(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002002 } else if (!strcmp(node->name, "leaf")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002003 mnode = read_yin_leaf(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002004 } else if (!strcmp(node->name, "list")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002005 mnode = read_yin_list(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002006 } else if (!strcmp(node->name, "choice")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002007 mnode = read_yin_choice(module, NULL, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002008 } else if (!strcmp(node->name, "grouping")) {
Radek Krejci25d782a2015-05-22 15:03:23 +02002009 mnode = read_yin_grouping(module, NULL, node);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02002010 } else if (!strcmp(node->name, "uses")) {
2011 mnode = read_yin_uses(module, NULL, node, 1);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002012 } else {
Radek Krejci25d782a2015-05-22 15:03:23 +02002013 /* TODO error */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002014 continue;
2015 }
2016 lyxml_free_elem(ctx, node);
2017
Radek Krejci25d782a2015-05-22 15:03:23 +02002018 if (!mnode) {
2019 goto error;
2020 }
2021
2022 /* include data element */
2023 if (module->data) {
2024 module->data->prev->next = mnode;
2025 mnode->prev = module->data->prev;
2026 module->data->prev = mnode;
2027 } else {
2028 module->data = mnode;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002029 }
2030 }
2031
Radek Krejciefaeba32015-05-27 14:30:57 +02002032 return EXIT_SUCCESS;
2033
2034error:
2035 /* cleanup */
2036 while (root.child) {
2037 lyxml_free_elem(module->ctx, root.child);
2038 }
2039
2040 return EXIT_FAILURE;
2041}
2042
2043struct ly_submodule *yin_read_submodule(struct ly_module *module, const char *data)
2044{
2045 struct lyxml_elem *yin;
Radek Krejci3045cf32015-05-28 10:58:52 +02002046 struct ly_submodule *submodule = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02002047 const char *value;
2048
Radek Krejci812b10a2015-05-28 16:48:25 +02002049 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02002050
2051 yin = lyxml_read(module->ctx, data, 0);
2052 if (!yin) {
2053 return NULL;
2054 }
2055
2056 /* check root element */
2057 if (!yin->name || strcmp(yin->name, "submodule")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002058 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002059 goto error;
2060 }
2061
Radek Krejci0af13872015-05-30 11:50:52 +02002062 GETVAL(value, yin, "name");
2063 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002064 goto error;
2065 }
2066
2067 submodule = calloc(1, sizeof *submodule);
2068 if (!submodule) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002069 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002070 goto error;
2071 }
2072
2073 submodule->ctx = module->ctx;
2074 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
Radek Krejcice7fb782015-05-29 16:52:34 +02002075 submodule->type = 1;
Radek Krejciefaeba32015-05-27 14:30:57 +02002076
Radek Krejci3045cf32015-05-28 10:58:52 +02002077 LOGVRB("reading submodule %s", submodule->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002078 if (read_sub_module((struct ly_module *)submodule, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002079 goto error;
2080 }
2081
2082 /* cleanup */
2083 lyxml_free_elem(module->ctx, yin);
2084
Radek Krejci3045cf32015-05-28 10:58:52 +02002085 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002086
2087 return submodule;
2088
2089error:
2090 /* cleanup */
2091 lyxml_free_elem(module->ctx, yin);
2092 ly_submodule_free(submodule);
2093
2094 return NULL;
2095}
2096
2097struct ly_module *yin_read_module(struct ly_ctx *ctx, const char *data)
2098{
2099 struct lyxml_elem *yin;
2100 struct ly_module *module = NULL, **newlist = NULL;
2101 const char *value;
2102 int i;
2103
2104 yin = lyxml_read(ctx, data, 0);
2105 if (!yin) {
2106 return NULL;
2107 }
2108
2109 /* check root element */
2110 if (!yin->name || strcmp(yin->name, "module")) {
Radek Krejci3045cf32015-05-28 10:58:52 +02002111 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02002112 goto error;
2113 }
2114
Radek Krejci0af13872015-05-30 11:50:52 +02002115 GETVAL(value, yin, "name");
2116 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002117 goto error;
2118 }
2119
2120 module = calloc(1, sizeof *module);
2121 if (!module) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002122 LOGMEM;
Radek Krejciefaeba32015-05-27 14:30:57 +02002123 goto error;
2124 }
2125
2126 module->ctx = ctx;
2127 module->name = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02002128 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02002129
Radek Krejci3045cf32015-05-28 10:58:52 +02002130 LOGVRB("reading module %s", module->name);
Radek Krejci0af13872015-05-30 11:50:52 +02002131 if (read_sub_module(module, yin)) {
Radek Krejciefaeba32015-05-27 14:30:57 +02002132 goto error;
2133 }
2134
Radek Krejcida04f4a2015-05-21 12:54:09 +02002135 /* add to the context's list of modules */
2136 if (ctx->models.used == ctx->models.size) {
2137 newlist = realloc(ctx->models.list, ctx->models.size * 2);
2138 if (!newlist) {
Radek Krejci812b10a2015-05-28 16:48:25 +02002139 LOGMEM;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002140 goto error;
2141 }
2142 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
2143 newlist[i] = NULL;
2144 }
2145 ctx->models.size *= 2;
2146 ctx->models.list = newlist;
2147 }
Radek Krejcif6e5e182015-05-27 17:18:07 +02002148 for (i = 0; ctx->models.list[i]; i++) {
Radek Krejcice7fb782015-05-29 16:52:34 +02002149 /* check name (name/revision) and namespace uniqueness */
Radek Krejcif6e5e182015-05-27 17:18:07 +02002150 if (!strcmp(ctx->models.list[i]->name, module->name)) {
2151 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
2152 /* both data models are same, with no revision specified */
Radek Krejci3045cf32015-05-28 10:58:52 +02002153 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.", module->name);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002154 goto error;
2155 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
2156 /* one of the models does not have a revision, so they differs */
2157 continue;
2158 } else {
2159 /* both models have a revision statement which we have to
2160 * compare, revision at position 0 is the last revision
2161 */
2162 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
2163 /* we have the same modules */
Radek Krejci3045cf32015-05-28 10:58:52 +02002164 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name, module->rev[0].date);
Radek Krejcif6e5e182015-05-27 17:18:07 +02002165 goto error;
2166 }
2167 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002168 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
2169 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
2170 ctx->models.list[i]->name, module->name, module->ns);
2171 goto error;
Radek Krejcif6e5e182015-05-27 17:18:07 +02002172 }
2173 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002174 ctx->models.list[i] = module;
2175 ctx->models.used++;
2176
2177 /* cleanup */
2178 lyxml_free_elem(ctx, yin);
2179
Radek Krejci3045cf32015-05-28 10:58:52 +02002180 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002181
2182 return module;
2183
2184error:
2185 /* cleanup */
Radek Krejcida04f4a2015-05-21 12:54:09 +02002186 lyxml_free_elem(ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02002187 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002188
2189 return NULL;
2190}