blob: 7dce2d8d23daefb2d0665ffd8b58e42755f9b5ee [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 {
Radek Krejci994b6f62015-06-18 16:47:27 +020041 LY_IDENT_SIMPLE, /* only syntax rules */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020042 LY_IDENT_FEATURE,
43 LY_IDENT_IDENTITY,
44 LY_IDENT_TYPE,
45 LY_IDENT_NODE,
Radek Krejci994b6f62015-06-18 16:47:27 +020046 LY_IDENT_NAME, /* uniqueness across the siblings */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020047 LY_IDENT_PREFIX
Radek Krejcice7fb782015-05-29 16:52:34 +020048};
49
Radek Krejciefdd0ce2015-05-26 16:48:29 +020050#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020051
Radek Krejcice7fb782015-05-29 16:52:34 +020052#define GETVAL(value, node, arg) \
53 value = lyxml_get_attr(node, arg, NULL); \
54 if (!value) { \
55 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
56 goto error; \
57 }
58
Radek Krejcib388c152015-06-04 17:03:03 +020059#define OPT_IDENT 0x01
60#define OPT_CONFIG 0x02
61#define OPT_MODULE 0x04
62#define OPT_INHERIT 0x08
63static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
64
Radek Krejci74705112015-06-05 10:25:44 +020065struct mnode_list {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020066 struct ly_mnode *mnode;
67 struct mnode_list *next;
68 unsigned int line;
Radek Krejci74705112015-06-05 10:25:44 +020069};
70
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020071static struct ly_mnode *read_yin_choice(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
72 int resolve, struct mnode_list **unres);
73static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
74 int resolve, struct mnode_list **unres);
75static struct ly_mnode *read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
76 int resolve);
77static struct ly_mnode *read_yin_container(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
78 int resolve, struct mnode_list **unres);
79static struct ly_mnode *read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
80 int resolve);
81static struct ly_mnode *read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
82 int resolve);
83static struct ly_mnode *read_yin_list(struct ly_module *module,struct ly_mnode *parent, struct lyxml_elem *yin,
84 int resolve, struct mnode_list **unres);
85static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
86 int resolve, struct mnode_list **unres);
87static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
88 int resolve, struct mnode_list **unres);
Radek Krejcib0af6ba2015-06-18 15:01:03 +020089static struct ly_when *read_yin_when(struct ly_module *module,struct lyxml_elem *yin);
Radek Krejci74705112015-06-05 10:25:44 +020090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091static int
92dup_typedef_check(const char *type, struct ly_tpdf *tpdf, int size)
Radek Krejcieac35532015-05-31 19:09:15 +020093{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020095
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020096 for (i = 0; i < size; i++) {
97 if (!strcmp(type, tpdf[i].name)) {
98 /* name collision */
99 return EXIT_FAILURE;
100 }
101 }
Radek Krejcieac35532015-05-31 19:09:15 +0200102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200104}
105
Radek Krejcib05774c2015-06-18 13:52:59 +0200106
107static int
108dup_feature_check(const char *id, struct ly_module *module)
109{
110 int i;
111
112 for (i = 0; i < module->features_size; i++) {
113 if (!strcmp(id, module->features[i].name)) {
114 return EXIT_FAILURE;
115 }
116 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +0200117
118 return EXIT_SUCCESS;
Radek Krejcib05774c2015-06-18 13:52:59 +0200119}
120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200121static int
122dup_prefix_check(const char *prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200123{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200124 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200125
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
127 return EXIT_FAILURE;
128 }
129 for (i = 0; i < module->imp_size; i++) {
130 if (!strcmp(module->imp[i].prefix, prefix)) {
131 return EXIT_FAILURE;
132 }
133 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200134
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200135 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200136}
137
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200138static int
139check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
140 struct ly_module *module, struct ly_mnode *parent)
Radek Krejcice7fb782015-05-29 16:52:34 +0200141{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200142 int i;
143 int size;
144 struct ly_tpdf *tpdf;
145 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200147 assert(id);
Radek Krejcice7fb782015-05-29 16:52:34 +0200148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200149 /* check id syntax */
150 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
151 LOGVAL(VE_INID, line, id, "invalid start character");
152 return EXIT_FAILURE;
153 }
154 for (i = 1; id[i]; i++) {
155 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
156 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
157 LOGVAL(VE_INID, line, id, "invalid character");
158 return EXIT_FAILURE;
159 }
160 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200162 if (i > 64) {
163 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
164 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 switch (type) {
167 case LY_IDENT_NAME:
168 /* check uniqueness of the node within its siblings */
169 if (!parent) {
170 break;
171 }
Radek Krejcib4cf2022015-06-03 14:40:05 +0200172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200173 LY_TREE_FOR(parent->child, mnode) {
174 if (mnode->name == id) {
175 LOGVAL(VE_INID, line, id, "name duplication");
176 return EXIT_FAILURE;
177 }
178 }
179 break;
180 case LY_IDENT_TYPE:
181 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200182
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200183 /* check collision with the built-in types */
184 if (!strcmp(id, "binary") || !strcmp(id, "bits") ||
185 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
186 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
187 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
188 !strcmp(id, "int8") || !strcmp(id, "int16") ||
189 !strcmp(id, "int32") || !strcmp(id, "int64") ||
190 !strcmp(id, "leafref") || !strcmp(id, "string") ||
191 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
192 !strcmp(id, "uint32") || !strcmp(id, "uint64") || !strcmp(id, "union")) {
193 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
194 return EXIT_FAILURE;
195 }
Radek Krejcieac35532015-05-31 19:09:15 +0200196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200197 /* check locally scoped typedefs (avoid name shadowing) */
198 for (; parent; parent = parent->parent) {
199 switch (parent->nodetype) {
200 case LY_NODE_CONTAINER:
201 size = ((struct ly_mnode_container *)parent)->tpdf_size;
202 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
203 break;
204 case LY_NODE_LIST:
205 size = ((struct ly_mnode_list *)parent)->tpdf_size;
206 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
207 break;
208 case LY_NODE_GROUPING:
209 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
210 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
211 break;
212 default:
213 continue;
214 }
Radek Krejcieac35532015-05-31 19:09:15 +0200215
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200216 if (dup_typedef_check(id, tpdf, size)) {
217 LOGVAL(VE_DUPID, line, "typedef", id);
218 return EXIT_FAILURE;
219 }
220 }
Radek Krejcieac35532015-05-31 19:09:15 +0200221
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200222 /* check top-level names */
223 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
224 LOGVAL(VE_DUPID, line, "typedef", id);
225 return EXIT_FAILURE;
226 }
Radek Krejcieac35532015-05-31 19:09:15 +0200227
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200228 /* check submodule's top-level names */
229 for (i = 0; i < module->inc_size; i++) {
230 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
231 LOGVAL(VE_DUPID, line, "typedef", id);
232 return EXIT_FAILURE;
233 }
234 }
Radek Krejcieac35532015-05-31 19:09:15 +0200235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200236 /* check top-level names in the main module */
237 if (module->type) {
238 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
239 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
240 LOGVAL(VE_DUPID, line, "typedef", id);
241 return EXIT_FAILURE;
242 }
243 }
Radek Krejcieac35532015-05-31 19:09:15 +0200244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200245 break;
246 case LY_IDENT_PREFIX:
247 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200249 if (module->type) {
250 /* go to the main module */
251 module = ((struct ly_submodule *)module)->belongsto;
252 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200253
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200254 /* check the main module itself */
255 if (dup_prefix_check(id, module)) {
256 LOGVAL(VE_DUPID, line, "prefix", id);
257 return EXIT_FAILURE;
258 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200260 /* and all its submodules */
261 for (i = 0; i < module->inc_size; i++) {
262 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
263 LOGVAL(VE_DUPID, line, "prefix", id);
264 return EXIT_FAILURE;
265 }
266 }
267 break;
Radek Krejcib05774c2015-06-18 13:52:59 +0200268 case LY_IDENT_FEATURE:
269 assert(module);
270
271 /* check feature name uniqness*/
Radek Krejci49babf32015-06-18 13:56:17 +0200272 /* check features in the current module */
Radek Krejcib05774c2015-06-18 13:52:59 +0200273 if (dup_feature_check(id, module)) {
274 LOGVAL(VE_DUPID, line, "feature", id);
275 return EXIT_FAILURE;
276 }
277
278 /* and all its submodules */
279 for (i = 0; i < module->inc_size; i++) {
280 if (dup_feature_check(id, (struct ly_module *)module->inc[i].submodule)) {
281 LOGVAL(VE_DUPID, line, "feature", id);
282 return EXIT_FAILURE;
283 }
284 }
285 break;
286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200287 default:
288 /* no check required */
289 break;
290 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200292 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200293}
294
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200295static int
296check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
297 const char *name, int len)
Radek Krejci345ad742015-06-03 11:04:18 +0200298{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200299 char *dup = NULL;
300 int j;
Radek Krejci345ad742015-06-03 11:04:18 +0200301
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200302 /* existence */
303 if (!key) {
304 if (name[len] != '\0') {
305 dup = strdup(name);
306 dup[len] = '\0';
307 name = dup;
308 }
309 LOGVAL(VE_KEY_MISS, line, name);
310 free(dup);
311 return EXIT_FAILURE;
312 }
Radek Krejci345ad742015-06-03 11:04:18 +0200313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200314 /* uniqueness */
315 for (j = index - 1; j >= 0; j--) {
316 if (list[index] == list[j]) {
317 LOGVAL(VE_KEY_DUP, line, key->name);
318 return EXIT_FAILURE;
319 }
320 }
Radek Krejci345ad742015-06-03 11:04:18 +0200321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200322 /* key is a leaf */
323 if (key->nodetype != LY_NODE_LEAF) {
324 LOGVAL(VE_KEY_NLEAF, line, key->name);
325 return EXIT_FAILURE;
326 }
Radek Krejci345ad742015-06-03 11:04:18 +0200327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200328 /* type of the leaf is not built-in empty */
329 if (key->type.base == LY_TYPE_EMPTY) {
330 LOGVAL(VE_KEY_TYPE, line, key->name);
331 return EXIT_FAILURE;
332 }
Radek Krejci345ad742015-06-03 11:04:18 +0200333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200334 /* config attribute is the same as of the list */
335 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
336 LOGVAL(VE_KEY_CONFIG, line, key->name);
337 return EXIT_FAILURE;
338 }
Radek Krejci345ad742015-06-03 11:04:18 +0200339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200340 return EXIT_SUCCESS;
Radek Krejci345ad742015-06-03 11:04:18 +0200341}
342
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200343static int
Radek Krejci3de29a72015-06-16 15:23:03 +0200344check_mandatory(struct ly_mnode *mnode)
345{
346 struct ly_mnode *child;
347
348 assert(mnode);
349
350 if (mnode->flags & LY_NODE_MAND_TRUE) {
351 return EXIT_FAILURE;
352 }
353
Radek Krejcifd0bb0a2015-06-18 13:18:24 +0200354 if (mnode->nodetype == LY_NODE_CASE || mnode->nodetype == LY_NODE_CHOICE) {
355 LY_TREE_FOR(mnode->child, child) {
356 if (check_mandatory(child)) {
357 return EXIT_FAILURE;
358 }
Radek Krejci3de29a72015-06-16 15:23:03 +0200359 }
360 }
361
362 return EXIT_SUCCESS;
363}
364
365static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200366check_default(struct ly_type *type, const char *value)
Radek Krejcieac35532015-05-31 19:09:15 +0200367{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200368 /* TODO - RFC 6020, sec. 7.3.4 */
369 (void)type;
370 (void)value;
371 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200372}
373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200374static int
375check_date(const char *date, unsigned int line)
Radek Krejcice7fb782015-05-29 16:52:34 +0200376{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200377 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200378
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200379 assert(date);
Radek Krejcice7fb782015-05-29 16:52:34 +0200380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200381 if (strlen(date) != LY_REV_SIZE - 1) {
382 goto error;
383 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200385 for (i = 0; i < LY_REV_SIZE - 1; i++) {
386 if (i == 4 || i == 7) {
387 if (date[i] != '-') {
388 goto error;
389 }
390 } else if (!isdigit(date[i])) {
391 goto error;
392 }
393 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200394
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200395 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200396
397error:
398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200399 LOGVAL(VE_INDATE, line, date);
400 return EXIT_FAILURE;
Radek Krejcice7fb782015-05-29 16:52:34 +0200401}
402
Radek Krejci41726f92015-06-19 13:11:05 +0200403static int
404check_length(const char *expr, struct ly_type *type, unsigned int line)
405{
406 const char *c = expr;
407 char *tail;
408 uint64_t limit = 0, n;
409 int flg = 1; /* first run flag */
410
411 assert(expr);
412
413 /* TODO check compatibility with the restriction defined on type from which this type is derived,
414 * it will be the same function to check that the value from instance data respect the restriction */
415 (void)type;
416
417lengthpart:
418
419 while (isspace(*c)) {
420 c++;
421 }
422
423 /* lower boundary or explicit number */
424 if (!strncmp(c, "max", 3)) {
425max:
426 c += 3;
427 while (isspace(*c)) {
428 c++;
429 }
430 if (*c != '\0') {
431 goto error;
432 }
433
434 return EXIT_SUCCESS;
435
436 } else if (!strncmp(c, "min", 3)) {
437 if (!flg) {
438 /* min cannot be used elsewhere than in the first length-part */
439 goto error;
440 } else {
441 flg = 0;
442 /* remember value/lower boundary */
443 limit = 0;
444 }
445 c += 3;
446 while (isspace(*c)) {
447 c++;
448 }
449
450 if (*c == '|') {
451 c++;
452 /* process next length-parth */
453 goto lengthpart;
454 } else if (*c == '\0') {
455 return EXIT_SUCCESS;
456 } else if (!strncmp(c, "..", 2)) {
457upper:
458 c += 2;
459 while (isspace(*c)) {
460 c++;
461 }
462 if (*c == '\0') {
463 goto error;
464 }
465
466 /* upper boundary */
467 if (!strncmp(c, "max", 3)) {
468 goto max;
469 }
470
471 if (!isdigit(*c)) {
472 goto error;
473 }
474
475 n = strtol(c, &tail, 10);
476 c = tail;
477 while (isspace(*c)) {
478 c++;
479 }
480 if (n <= limit) {
481 goto error;
482 }
483 if (*c == '\0') {
484 return EXIT_SUCCESS;
485 } else if (*c == '|') {
486 c++;
487 /* remember the uppre boundary for check in next part */
488 limit = n;
489 /* process next length-parth */
490 goto lengthpart;
491 } else {
492 goto error;
493 }
494 } else {
495 goto error;
496 }
497
498 } else if (isdigit(*c)) {
499 /* number */
500 n = strtol(c, &tail, 10);
501 c = tail;
502 while (isspace(*c)) {
503 c++;
504 }
505 /* skip limit check in first length-part check */
506 if (!flg && n <= limit) {
507 goto error;
508 }
509 flg = 0;
510 limit = n;
511
512 if (*c == '|') {
513 c++;
514 /* process next length-parth */
515 goto lengthpart;
516 } else if (*c == '\0') {
517 return EXIT_SUCCESS;
518 } else if (!strncmp(c, "..", 2)) {
519 goto upper;
520 }
521 } /* else error */
522
523error:
524
525 LOGVAL(VE_INARG, line, expr, "length");
526 return EXIT_FAILURE;
527}
528
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200529static const char *
530read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200531{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200532 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200534 /* there should be <text> child */
535 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
536 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
537 } else if (node->child->content) {
538 len = strlen(node->child->content);
539 return lydict_insert(ctx, node->child->content, len);
540 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200542 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
543 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200544}
545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200546static struct ly_tpdf *
547find_superior_type(const char *name, struct ly_module *module, struct ly_mnode *parent)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200548{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200549 int i, j, found = 0;
550 int prefix_len = 0;
551 const char *qname;
552 struct ly_tpdf *tpdf;
553 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200555 qname = strchr(name, ':');
Radek Krejcida04f4a2015-05-21 12:54:09 +0200556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200557 if (!qname) {
558 /* no prefix, try built-in types */
559 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
560 if (!strcmp(ly_types[i].def->name, name)) {
561 return ly_types[i].def;
562 }
563 }
564 qname = name;
565 } else {
566 /* set qname to correct position after colon */
567 prefix_len = qname - name;
568 qname++;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200570 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
571 /* prefix refers to the current module, ignore it */
572 prefix_len = 0;
573 }
574 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200575
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200576 if (!prefix_len && parent) {
577 /* search in local typedefs */
578 while (parent) {
579 switch (parent->nodetype) {
580 case LY_NODE_CONTAINER:
581 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
582 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
583 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200584
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200585 case LY_NODE_LIST:
586 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
587 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
588 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200589
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200590 case LY_NODE_GROUPING:
591 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
592 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
593 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200594
Radek Krejci3cf9e222015-06-18 11:37:50 +0200595 /* TODO add rpc, notification, input, output */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200596 default:
597 parent = parent->parent;
598 continue;
599 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200601 for (i = 0; i < tpdf_size; i++) {
602 if (!strcmp(tpdf[i].name, qname)) {
603 return &tpdf[i];
604 }
605 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200607 parent = parent->parent;
608 }
609 } else if (prefix_len) {
610 /* get module where to search */
611 for (i = 0; i < module->imp_size; i++) {
612 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
613 module = module->imp[i].module;
614 found = 1;
615 break;
616 }
617 }
618 if (!found) {
619 return NULL;
620 }
621 }
622
623 /* search in top level typedefs */
624 for (i = 0; i < module->tpdf_size; i++) {
625 if (!strcmp(module->tpdf[i].name, qname)) {
626 return &module->tpdf[i];
627 }
628 }
629
630 /* search in submodules */
631 for (i = 0; i < module->inc_size; i++) {
632 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
633 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
634 return &module->inc[i].submodule->tpdf[j];
635 }
636 }
637 }
638
639 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200640}
641
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200642static struct ly_ident *
643find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
Radek Krejciefaeba32015-05-27 14:30:57 +0200644{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200645 unsigned int i;
646 struct ly_ident *base_iter;
647 struct ly_ident_der *der;
Radek Krejciefaeba32015-05-27 14:30:57 +0200648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200649 for (i = 0; i < module->ident_size; i++) {
650 if (!strcmp(basename, module->ident[i].name)) {
651 /* we are done */
Radek Krejciefaeba32015-05-27 14:30:57 +0200652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200653 if (!ident) {
654 /* just search for type, so do not modify anything, just return
655 * the base identity pointer
656 */
657 return &module->ident[i];
658 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200660 /* we are resolving identity definition, so now update structures */
661 ident->base = base_iter = &module->ident[i];
Radek Krejciefaeba32015-05-27 14:30:57 +0200662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200663 while (base_iter) {
664 for (der = base_iter->der; der && der->next; der = der->next);
665 if (der) {
666 der->next = malloc(sizeof *der);
667 der = der->next;
668 } else {
669 ident->base->der = der = malloc(sizeof *der);
670 }
671 der->next = NULL;
672 der->ident = ident;
Radek Krejciefaeba32015-05-27 14:30:57 +0200673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200674 base_iter = base_iter->base;
675 }
676 return ident->base;
677 }
678 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200679
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200680 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200681}
682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200683static struct ly_ident *
684find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200685{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200686 const char *name;
687 int prefix_len = 0;
688 int i, found = 0;
689 struct ly_ident *result;
690 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200692 basename = lyxml_get_attr(node, "name", NULL);
693 if (!basename) {
694 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
695 return NULL;
696 }
Radek Krejci04581c62015-05-22 21:24:00 +0200697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200698 /* search for the base identity */
699 name = strchr(basename, ':');
700 if (name) {
701 /* set name to correct position after colon */
702 prefix_len = name - basename;
703 name++;
Radek Krejci04581c62015-05-22 21:24:00 +0200704
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200705 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
706 /* prefix refers to the current module, ignore it */
707 prefix_len = 0;
708 }
709 } else {
710 name = basename;
711 }
Radek Krejci04581c62015-05-22 21:24:00 +0200712
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200713 if (prefix_len) {
714 /* get module where to search */
715 for (i = 0; i < module->imp_size; i++) {
716 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
717 && !module->imp[i].prefix[prefix_len]) {
718 module = module->imp[i].module;
719 found = 1;
720 break;
721 }
722 }
723 if (!found) {
724 /* identity refers unknown data model */
725 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
726 return NULL;
727 }
728 } else {
729 /* search in submodules */
730 for (i = 0; i < module->inc_size; i++) {
731 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
732 if (result) {
733 return result;
734 }
735 }
736 }
Radek Krejci04581c62015-05-22 21:24:00 +0200737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200738 /* search in the identified module */
739 result = find_base_ident_sub(module, ident, name);
740 if (!result) {
741 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
742 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200743
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200744 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200745}
746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200747static int
748fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
Radek Krejci04581c62015-05-22 21:24:00 +0200749{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200750 struct lyxml_elem *node, *next;
Radek Krejci04581c62015-05-22 21:24:00 +0200751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200752 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
753 return EXIT_FAILURE;
754 }
Radek Krejci04581c62015-05-22 21:24:00 +0200755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200756 LY_TREE_FOR_SAFE(yin->child, next, node) {
757 if (!strcmp(node->name, "base")) {
758 if (ident->base) {
759 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
760 return EXIT_FAILURE;
761 }
762 if (!find_base_ident(module, ident, node)) {
763 return EXIT_FAILURE;
764 }
765 } else {
766 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
767 return EXIT_FAILURE;
768 }
Radek Krejci04581c62015-05-22 21:24:00 +0200769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200770 lyxml_free_elem(module->ctx, node);
771 }
Radek Krejci04581c62015-05-22 21:24:00 +0200772
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200773 return EXIT_SUCCESS;
Radek Krejci04581c62015-05-22 21:24:00 +0200774}
775
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200776static int
Radek Krejci0bd5db42015-06-19 13:30:07 +0200777read_restr_substmt(struct ly_ctx *ctx, struct ly_restr *restr, struct lyxml_elem *yin)
Radek Krejci41726f92015-06-19 13:11:05 +0200778{
779 struct lyxml_elem *next, *child;
Radek Krejci461d1622015-06-30 14:06:28 +0200780 const char *value;
Radek Krejci41726f92015-06-19 13:11:05 +0200781
782 LY_TREE_FOR_SAFE(yin->child, next, child) {
783 if (!strcmp(child->name, "description")) {
784 if (restr->dsc) {
785 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
786 return EXIT_FAILURE;
787 }
788 restr->dsc = read_yin_subnode(ctx, child, "text");
789 if (!restr->dsc) {
790 return EXIT_FAILURE;
791 }
792 } else if (!strcmp(child->name, "reference")) {
793 if (restr->ref) {
794 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
795 return EXIT_FAILURE;
796 }
797 restr->ref = read_yin_subnode(ctx, child, "text");
798 if (!restr->ref) {
799 return EXIT_FAILURE;
800 }
801 } else if (!strcmp(child->name, "error-app-tag")) {
802 if (restr->eapptag) {
803 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
804 return EXIT_FAILURE;
805 }
Radek Krejci461d1622015-06-30 14:06:28 +0200806 GETVAL(value, yin, "value");
807 restr->eapptag = lydict_insert(ctx, value, 0);
Radek Krejci41726f92015-06-19 13:11:05 +0200808 } else if (!strcmp(child->name, "error-message")) {
809 if (restr->emsg) {
810 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
811 return EXIT_FAILURE;
812 }
813 restr->emsg = read_yin_subnode(ctx, child, "value");
814 if (!restr->emsg) {
815 return EXIT_FAILURE;
816 }
817 } else {
818 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
819 return EXIT_FAILURE;
820 }
821
822 lyxml_free_elem(ctx, child);
823 }
824
825 return EXIT_SUCCESS;
Michal Vaskoc8ef47f2015-06-29 14:56:19 +0200826
827error:
828 return EXIT_FAILURE;
Radek Krejci41726f92015-06-19 13:11:05 +0200829}
830
831static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200832fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200833{
Radek Krejcif2860132015-06-20 12:37:20 +0200834 const char *value, *delim, *name;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200835 struct lyxml_elem *next, *node;
Radek Krejcif2860132015-06-20 12:37:20 +0200836 struct ly_restr **restr;
Radek Krejci994b6f62015-06-18 16:47:27 +0200837 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200838 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200839 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200840
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200841 GETVAL(value, yin, "name")
842 delim = strchr(value, ':');
843 if (delim) {
844 type->prefix = lydict_insert(module->ctx, value, delim - value);
845 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200846
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200847 type->der = find_superior_type(value, module, parent);
848 if (!type->der) {
849 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
850 goto error;
851 }
852 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200853
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200854 switch (type->base) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200855 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200856 /* RFC 6020 9.7.4 - bit */
857
858 /* get bit specifications, at least one must be present */
859 LY_TREE_FOR_SAFE(yin->child, next, node) {
860 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200861 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200862 } else {
863 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
864 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200865 }
866 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200867 if (!type->info.bits.count) {
868 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +0200869 /* this is just a derived type with no bit specified/required */
Radek Krejci994b6f62015-06-18 16:47:27 +0200870 break;
871 }
872 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
873 goto error;
874 }
875
876 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci5fbc9162015-06-19 14:11:11 +0200877 for (i = p = 0; yin->child; i++) {
878 GETVAL(value, yin->child, "name");
879 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200880 goto error;
881 }
882 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +0200883 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], yin->child, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200884 type->info.bits.count = i + 1;
885 goto error;
886 }
887
888 /* check the name uniqueness */
889 for (j = 0; j < i; j++) {
890 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200891 LOGVAL(VE_BITS_DUPNAME, LOGLINE(yin->child), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200892 type->info.bits.count = i + 1;
893 goto error;
894 }
895 }
896
Radek Krejci5fbc9162015-06-19 14:11:11 +0200897 node = yin->child->child;
Radek Krejci994b6f62015-06-18 16:47:27 +0200898 if (node && !strcmp(node->name, "position")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +0200899 GETVAL(value, node, "value");
Radek Krejci994b6f62015-06-18 16:47:27 +0200900 p_ = strtol(value, NULL, 10);
901
902 /* range check */
903 if (p_ < 0 || p_ > UINT32_MAX) {
904 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
905 type->info.bits.count = i + 1;
906 goto error;
907 }
908 type->info.bits.bit[i].pos = (uint32_t)p_;
909
910 /* keep the highest enum value for automatic increment */
911 if (type->info.bits.bit[i].pos > p) {
912 p = type->info.bits.bit[i].pos;
913 p++;
914 } else {
915 /* check that the value is unique */
916 for (j = 0; j < i; j++) {
917 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
918 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
919 type->info.bits.count = i + 1;
920 goto error;
921 }
922 }
923 }
924 } else {
925 /* assign value automatically */
926 if (p > UINT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +0200927 LOGVAL(VE_INARG, LOGLINE(yin->child), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +0200928 type->info.bits.count = i + 1;
929 goto error;
930 }
931 type->info.bits.bit[i].pos = (uint32_t)p;
932 p++;
933 }
Radek Krejci5fbc9162015-06-19 14:11:11 +0200934 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci994b6f62015-06-18 16:47:27 +0200935 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200936 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200937
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200938 case LY_TYPE_DEC64:
Radek Krejcif9401c32015-06-26 16:47:36 +0200939 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
940 LY_TREE_FOR_SAFE(yin->child, next, node) {
941 if (!strcmp(node->name, "range")) {
942 if (type->info.dec64.range) {
943 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
944 goto error;
945 }
946
947 GETVAL(value, node, "value");
948 if (check_length(value, type, LOGLINE(node))) {
949 goto error;
950 }
951 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
952 type->info.dec64.range->expr = lydict_insert(module->ctx, value, 0);
953
954 /* get possible substatements */
955 if (read_restr_substmt(module->ctx, type->info.dec64.range, node)) {
956 goto error;
957 }
958 } else if (!strcmp(node->name, "fraction-digits")) {
959 if (type->info.dec64.dig) {
960 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
961 goto error;
962 }
963 GETVAL(value, node, "value");
964 v = strtol(value, NULL, 10);
965
966 /* range check */
967 if (v < 1 || v > 18) {
968 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
969 goto error;
970 }
971 type->info.dec64.dig = (uint8_t)v;
972 } else {
973 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
974 goto error;
975 }
976 lyxml_free_elem(module->ctx, node);
977 }
978
979 /* mandatory sub-statement(s) check */
980 if (!type->info.dec64.dig && !type->der->type.der) {
981 /* decimal64 type directly derived from built-in type requires fraction-digits */
982 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "fraction-digits", "type");
983 goto error;
984 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200985 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200986
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200987 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +0200988 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +0200989
Radek Krejci994b6f62015-06-18 16:47:27 +0200990 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200991 LY_TREE_FOR_SAFE(yin->child, next, node) {
992 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200993 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200994 } else {
995 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
996 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200997 }
998 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200999 if (!type->info.enums.count) {
1000 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001001 /* this is just a derived type with no enum specified/required */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001002 break;
1003 }
1004 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
1005 goto error;
1006 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001007
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001008 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci5fbc9162015-06-19 14:11:11 +02001009 for (i = v = 0; yin->child; i++) {
1010 GETVAL(value, yin->child, "name");
1011 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(yin->child), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001012 goto error;
1013 }
1014 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci5fbc9162015-06-19 14:11:11 +02001015 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], yin->child, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001016 type->info.enums.count = i + 1;
1017 goto error;
1018 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001019
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001020 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1021 value = type->info.enums.list[i].name;
1022 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001023 LOGVAL(VE_ENUM_WS, LOGLINE(yin->child), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001024 type->info.enums.count = i + 1;
1025 goto error;
1026 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001027
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001028 /* check the name uniqueness */
1029 for (j = 0; j < i; j++) {
1030 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001031 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(yin->child), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001032 type->info.enums.count = i + 1;
1033 goto error;
1034 }
1035 }
Radek Krejci04581c62015-05-22 21:24:00 +02001036
Radek Krejci5fbc9162015-06-19 14:11:11 +02001037 node = yin->child->child;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001038 if (node && !strcmp(node->name, "value")) {
Radek Krejci3e7b6182015-06-19 14:25:20 +02001039 GETVAL(value, node, "value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001040 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001041
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001042 /* range check */
1043 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1044 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1045 type->info.enums.count = i + 1;
1046 goto error;
1047 }
1048 type->info.enums.list[i].value = v_;
1049
1050 /* keep the highest enum value for automatic increment */
1051 if (type->info.enums.list[i].value > v) {
1052 v = type->info.enums.list[i].value;
1053 v++;
1054 } else {
1055 /* check that the value is unique */
1056 for (j = 0; j < i; j++) {
1057 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001058 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value, type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001059 type->info.enums.count = i + 1;
1060 goto error;
1061 }
1062 }
1063 }
1064 } else {
1065 /* assign value automatically */
1066 if (v > INT32_MAX) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001067 LOGVAL(VE_INARG, LOGLINE(yin->child), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001068 type->info.enums.count = i + 1;
1069 goto error;
1070 }
1071 type->info.enums.list[i].value = v;
1072 v++;
1073 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001074 lyxml_free_elem(module->ctx, yin->child);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001075 }
1076 break;
1077
1078 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001079 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001080
1081 /* get base specification, exactly one must be present */
1082 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001083 if (type->der->type.der) {
1084 /* this is just a derived type with no base specified/required */
1085 break;
1086 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001087 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1088 goto error;
1089 }
1090 if (strcmp(yin->child->name, "base")) {
1091 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1092 goto error;
1093 }
1094 if (yin->child->next) {
1095 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
1096 goto error;
1097 }
1098 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1099 if (!type->info.ident.ref) {
1100 return EXIT_FAILURE;
1101 }
1102 break;
1103
1104 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001105 /* RFC 6020 9.13.2 - require-instance */
1106 LY_TREE_FOR_SAFE(yin->child, next, node) {
1107 if (!strcmp(node->name, "require-instance")) {
1108 if (type->info.inst.req) {
1109 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1110 goto error;
1111 }
1112 GETVAL(value, node, "value");
1113 if (strcmp(value, "true")) {
1114 type->info.inst.req = 1;
1115 } else if (strcmp(value, "false")) {
1116 type->info.inst.req = -1;
1117 } else {
1118 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1119 goto error;
1120 }
1121 } else {
1122 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1123 goto error;
1124 }
1125 lyxml_free_elem(module->ctx, node);
1126 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001127 break;
1128
Radek Krejcif2860132015-06-20 12:37:20 +02001129 case LY_TYPE_BINARY:
1130 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001131 case LY_TYPE_INT8:
1132 case LY_TYPE_INT16:
1133 case LY_TYPE_INT32:
1134 case LY_TYPE_INT64:
1135 case LY_TYPE_UINT8:
1136 case LY_TYPE_UINT16:
1137 case LY_TYPE_UINT32:
1138 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001139 /* RFC 6020 9.2.4 - range */
1140
1141 /* length and range are actually the same restriction, so process
1142 * them by this common code, we just need to differ the name and
1143 * structure where the information will be stored
1144 */
1145 if (type->base == LY_TYPE_BINARY) {
1146 restr = &type->info.binary.length;
1147 name = "length";
1148 } else {
1149 restr = &type->info.num.range;
1150 name = "range";
1151 }
1152
1153 LY_TREE_FOR_SAFE(yin->child, next, node) {
1154 if (!strcmp(node->name, name)) {
1155 if (*restr) {
1156 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1157 goto error;
1158 }
1159
1160 GETVAL(value, node, "value");
1161 if (check_length(value, type, LOGLINE(node))) {
1162 goto error;
1163 }
1164 *restr = calloc(1, sizeof **restr);
1165 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1166
1167 /* get possible substatements */
1168 if (read_restr_substmt(module->ctx, *restr, node)) {
1169 goto error;
1170 }
1171 } else {
1172 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1173 goto error;
1174 }
1175 lyxml_free_elem(module->ctx, node);
1176 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001177 break;
1178
1179 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001180 /* RFC 6020 9.9.2 - path */
1181 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001182 if (type->der->type.der) {
1183 /* this is just a derived type with no path specified/required */
1184 break;
1185 }
Radek Krejcidc4c1412015-06-19 15:39:54 +02001186 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1187 goto error;
1188 }
1189 LY_TREE_FOR_SAFE(yin->child, next, node) {
1190 if (!strcmp(node->name, "path")) {
1191 if (type->info.lref.path) {
1192 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1193 goto error;
1194 }
1195
1196 GETVAL(value, node, "value");
1197 /* TODO
1198 * it would be nice to perform here a check that target is leaf or leaf-list,
Radek Krejcic63c9b02015-06-26 16:51:31 +02001199 * but schema is not finished yet and path can point almost to anywhere, so
Radek Krejcidc4c1412015-06-19 15:39:54 +02001200 * we will have to check the path at the end of parsing the schema.
1201 */
1202 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1203 } else {
1204 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1205 goto error;
1206 }
1207 lyxml_free_elem(module->ctx, node);
1208 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001209 break;
1210
1211 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001212 /* RFC 6020 9.4.4 - length */
1213 /* RFC 6020 9.4.6 - pattern */
1214 LY_TREE_FOR_SAFE(yin->child, next, node) {
1215 if (!strcmp(node->name, "length")) {
1216 if (type->info.str.length) {
1217 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1218 goto error;
1219 }
1220
1221 GETVAL(value, node, "value");
1222 if (check_length(value, type, LOGLINE(node))) {
1223 goto error;
1224 }
1225 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1226 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1227
Radek Krejci5fbc9162015-06-19 14:11:11 +02001228 /* get possible sub-statements */
1229 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001230 goto error;
1231 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001232 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001233 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001234 type->info.str.pat_count++;
Radek Krejci3733a802015-06-19 13:43:21 +02001235 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001236 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001237 goto error;
1238 }
1239 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001240 /* store patterns in array */
1241 if (type->info.str.pat_count) {
1242 type->info.str.patterns = calloc(type->info.str.pat_count, sizeof *type->info.str.patterns);
1243 for (i = 0; yin->child; i++) {
1244 GETVAL(value, yin->child, "value");
1245 type->info.str.patterns[i].expr = lydict_insert(module->ctx, value, 0);
1246
1247 /* get possible sub-statements */
1248 if (read_restr_substmt(module->ctx, &type->info.str.patterns[i], yin->child)) {
1249 goto error;
1250 }
1251 lyxml_free_elem(module->ctx, yin->child);
1252 }
1253 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001254 break;
1255
1256 case LY_TYPE_UNION:
1257 /* TODO type, 7.4
1258 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
1259 break;
1260
1261 default:
Radek Krejci6e328cd2015-06-26 16:24:11 +02001262 /* no sub-statement allowed in:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001263 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1264 */
Radek Krejci6e328cd2015-06-26 16:24:11 +02001265 if (yin->child) {
1266 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1267 goto error;
1268 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001269 break;
1270 }
1271
1272 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001273
1274error:
1275
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001276 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001277}
1278
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001279static int
1280fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_tpdf *tpdf)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001281{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001282 const char *value;
1283 struct lyxml_elem *node, *next;
1284 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001285
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001286 GETVAL(value, yin, "name");
1287 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1288 goto error;
1289 }
1290 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001291
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001292 /* generic part - status, description, reference */
1293 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1294 goto error;
1295 }
Radek Krejcieac35532015-05-31 19:09:15 +02001296
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001297 LY_TREE_FOR_SAFE(yin->child, next, node) {
1298 if (!strcmp(node->name, "type")) {
1299 if (tpdf->type.der) {
1300 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1301 goto error;
1302 }
1303 r = fill_yin_type(module, parent, node, &tpdf->type);
1304 } else if (!strcmp(node->name, "default")) {
1305 if (tpdf->dflt) {
1306 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1307 goto error;
1308 }
1309 GETVAL(value, node, "value");
1310 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1311 } else if (!strcmp(node->name, "units")) {
1312 if (tpdf->units) {
1313 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1314 goto error;
1315 }
1316 GETVAL(value, node, "name");
1317 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1318 } else {
1319 LOGVAL(VE_INSTMT, LOGLINE(node), value);
1320 r = 1;
1321 }
1322 lyxml_free_elem(module->ctx, node);
1323 if (r) {
1324 goto error;
1325 }
1326 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001328 /* check mandatory value */
1329 if (!tpdf->type.der) {
1330 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1331 goto error;
1332 }
Radek Krejcieac35532015-05-31 19:09:15 +02001333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001334 /* check default value */
1335 if (check_default(&tpdf->type, tpdf->dflt)) {
1336 goto error;
1337 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001338
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001339 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001340
1341error:
1342
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001343 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001344}
1345
Radek Krejci3cf9e222015-06-18 11:37:50 +02001346static struct ly_feature *
1347resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1348{
1349 const char *prefix;
1350 unsigned int prefix_len = 0;
1351 int i, j, found = 0;
1352
1353 assert(name);
1354 assert(module);
1355
1356 /* check prefix */
1357 prefix = name;
1358 name = strchr(prefix, ':');
1359 if (name) {
1360 /* there is prefix */
1361 prefix_len = name - prefix;
1362 name++;
1363
1364 /* check whether the prefix points to the current module */
1365 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1366 /* then ignore prefix and works as there is no prefix */
1367 prefix_len = 0;
1368 }
1369 } else {
1370 /* no prefix, set pointers correctly */
1371 name = prefix;
1372 }
1373
1374 if (prefix_len) {
1375 /* search in imported modules */
1376 for (i = 0; i < module->imp_size; i++) {
1377 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1378 module = module->imp[i].module;
1379 found = 1;
1380 break;
1381 }
1382 }
1383 if (!found) {
1384 /* identity refers unknown data model */
1385 LOGVAL(VE_INPREFIX, line, prefix);
1386 return NULL;
1387 }
1388 } else {
1389 /* search in submodules */
1390 for (i = 0; i < module->inc_size; i++) {
1391 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1392 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1393 return &(module->inc[i].submodule->features[j]);
1394 }
1395 }
1396 }
1397 }
1398
1399 /* search in the identified module */
1400 for (j = 0; j < module->features_size; j++) {
1401 if (!strcmp(name, module->features[j].name)) {
1402 return &module->features[j];
1403 }
1404 }
1405
1406 /* not found */
1407 return NULL;
1408}
1409
1410static int
1411fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1412{
1413 const char *value;
1414 struct lyxml_elem *child, *next;
1415 int c = 0;
1416
Radek Krejcib05774c2015-06-18 13:52:59 +02001417 GETVAL(value, yin, "name");
1418 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1419 goto error;
1420 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001421 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcib05774c2015-06-18 13:52:59 +02001422
Radek Krejci7e97c352015-06-19 16:26:34 +02001423 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, OPT_MODULE)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001424 goto error;
1425 }
1426
1427 LY_TREE_FOR_SAFE(yin->child, next, child) {
1428 if (!strcmp(child->name, "if-feature")) {
1429 c++;
1430 } else {
1431 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1432 goto error;
1433 }
1434 }
1435
1436 if (c) {
1437 f->features = calloc(c, sizeof *f->features);
1438 }
1439
1440 LY_TREE_FOR_SAFE(yin->child, next, child) {
1441 GETVAL(value, child, "name");
1442 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1443 if (!f->features[f->features_size]) {
1444 goto error;
1445 }
1446 f->features_size++;
1447 }
1448
Radek Krejci3cf9e222015-06-18 11:37:50 +02001449 return EXIT_SUCCESS;
1450
1451error:
1452
1453 return EXIT_FAILURE;
1454}
1455
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001456static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001457fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001458{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001459 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001460
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001461 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001462 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001463
Radek Krejci41726f92015-06-19 13:11:05 +02001464 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001465
Radek Krejci41726f92015-06-19 13:11:05 +02001466error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001468 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001469}
1470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001471static int
Radek Krejcieb00f512015-07-01 16:44:58 +02001472parse_unique(struct ly_mnode *parent, struct lyxml_elem *node, struct ly_unique *uniq_s)
1473{
1474 const char *value;
Radek Krejcie82ce862015-07-01 16:49:39 +02001475 char *uniq_str = NULL, *uniq_val, *start;
Radek Krejcieb00f512015-07-01 16:44:58 +02001476 int i, j;
1477
1478 /* count the number of unique values */
1479 GETVAL(value, node, "tag");
1480 uniq_val = uniq_str = strdup(value);
1481 uniq_s->leafs_size = 0;
1482 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1483 uniq_s->leafs_size++;
1484 while (isspace(*uniq_val)) {
1485 uniq_val++;
1486 }
1487 }
1488 uniq_s->leafs_size++;
1489 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1490
1491 /* interconnect unique values with the leafs */
1492 uniq_val = uniq_str;
1493 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1494 start = uniq_val;
1495 if ((uniq_val = strpbrk(start, " \t\n"))) {
1496 *uniq_val = '\0'; /* add terminating NULL byte */
1497 uniq_val++;
1498 while (isspace(*uniq_val)) {
1499 uniq_val++;
1500 }
1501 } /* else only one nodeid present/left already NULL byte terminated */
1502
1503 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LY_NODE_USES);
1504 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LY_NODE_LEAF) {
1505 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1506 if (!uniq_s->leafs[i]) {
1507 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
1508 } else {
1509 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
1510 }
1511 goto error;
1512 }
1513
1514 for (j = 0; j < i; j++) {
1515 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
1516 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1517 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
1518 goto error;
1519 }
1520 }
1521 }
1522
1523 free(uniq_str);
1524 return EXIT_SUCCESS;
1525
1526error:
1527
1528 free(uniq_s->leafs);
1529 free(uniq_str);
1530
1531 return EXIT_FAILURE;
1532}
1533
1534/*
1535 * type: 0 - min, 1 - max
1536 */
1537static int
1538deviate_minmax(struct ly_mnode *target, struct lyxml_elem *node, struct ly_deviate *d, int type)
1539{
1540 const char *value;
1541 char *endptr;
1542 unsigned long val;
1543 uint32_t *ui32val;
1544
1545 /* check target node type */
1546 if (target->nodetype == LY_NODE_LEAFLIST) {
1547 if (type) {
1548 ui32val = &((struct ly_mnode_leaflist *)target)->max;
1549 } else {
1550 ui32val = &((struct ly_mnode_leaflist *)target)->min;
1551 }
1552 } else if (target->nodetype == LY_NODE_LIST) {
1553 if (type) {
1554 ui32val = &((struct ly_mnode_list *)target)->max;
1555 } else {
1556 ui32val = &((struct ly_mnode_list *)target)->min;
1557 }
1558 } else {
1559 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1560 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", node->name);
1561 goto error;
1562 }
1563
1564 GETVAL(value, node, "value");
1565 while (isspace(value[0])) {
1566 value++;
1567 }
1568
1569 /* convert it to uint32_t */
1570 errno = 0;
1571 endptr = NULL;
1572 val = strtoul(value, &endptr, 10);
1573 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1574 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1575 goto error;
1576 }
1577 if (type) {
1578 d->max = (uint32_t)val;
1579 } else {
1580 d->min = (uint32_t)val;
1581 }
1582
1583 if (d->mod == LY_DEVIATE_ADD) {
1584 /* check that there is no current value */
1585 if (*ui32val) {
1586 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1587 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1588 goto error;
1589 }
1590 }
1591
1592 if (d->mod == LY_DEVIATE_DEL) {
1593 /* check values */
1594 if ((uint32_t)val != *ui32val) {
1595 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1596 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1597 goto error;
1598 }
1599 /* remove current min-elements value of the target */
1600 *ui32val = 0;
1601 } else { /* add (already checked) and replace */
1602 /* set new value specified in deviation */
1603 *ui32val = (uint32_t)val;
1604 }
1605
1606 return EXIT_SUCCESS;
1607
1608error:
1609
1610 return EXIT_FAILURE;
1611}
1612
1613static int
1614fill_yin_deviation(struct ly_module *module, struct lyxml_elem *yin, struct ly_deviation *dev)
1615{
1616 const char *value, **stritem;
1617 struct lyxml_elem *next, *child, *develem;
1618 int c_dev = 0, c_must, c_uniq;
1619 int f_min = 0; /* flags */
1620 int i, j;
1621 struct ly_deviate *d;
1622 struct ly_mnode *mnode;
1623 struct ly_mnode_choice *choice;
1624 struct ly_mnode_leaf *leaf;
1625 struct ly_mnode_list *list;
1626 struct ly_type *t;
1627 uint8_t *trg_must_size;
1628 struct ly_restr **trg_must;
1629
1630 GETVAL(value, yin, "target-node");
1631 dev->target_name = lydict_insert(module->ctx, value, 0);
1632
1633 /* resolve target node */
1634 dev->target = resolve_schema_nodeid(dev->target_name, NULL, module, LY_NODE_AUGMENT);
1635 if (!dev->target) {
1636 LOGVAL(VE_INARG, LOGLINE(yin), dev->target_name, yin->name);
1637 goto error;
1638 }
1639 if (dev->target->module == module) {
1640 LOGVAL(VE_SPEC, LOGLINE(yin), "Deviating own module is not allowed.");
1641 goto error;
1642 }
1643 /* mark the target module as deviated */
1644 dev->target->module->deviated = 1;
1645
1646 LY_TREE_FOR_SAFE(yin->child, next, child) {
1647 if (!strcmp(child->name, "description")) {
1648 if (dev->dsc) {
1649 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1650 goto error;
1651 }
1652 dev->dsc = read_yin_subnode(module->ctx, child, "text");
1653 if (!dev->dsc) {
1654 goto error;
1655 }
1656 } else if (!strcmp(child->name, "reference")) {
1657 if (dev->ref) {
1658 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1659 goto error;
1660 }
1661 dev->ref = read_yin_subnode(module->ctx, child, "text");
1662 if (!dev->ref) {
1663 goto error;
1664 }
1665 } else if (!strcmp(child->name, "deviate")) {
1666 c_dev++;
1667
1668 /* skip lyxml_free_elem() at the end of the loop, node will be
1669 * further processed later
1670 */
1671 continue;
1672 } else {
1673 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1674 goto error;
1675 }
1676
1677 lyxml_free_elem(module->ctx, child);
1678 }
1679
1680 if (c_dev) {
1681 dev->deviate = calloc(c_dev, sizeof *dev->deviate);
1682 }
1683
1684 LY_TREE_FOR(yin->child, develem) {
1685 /* init */
1686 f_min = 0;
1687 c_must = 0;
1688 c_uniq = 0;
1689
1690 /* get deviation type */
1691 GETVAL(value, develem, "value");
1692 if (!strcmp(value, "not-supported")) {
1693 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_NO;
1694 /* no property expected in this case */
1695 if (develem->child) {
1696 LOGVAL(VE_INSTMT, LOGLINE(develem->child), develem->child->name);
1697 goto error;
1698 }
1699
Radek Krejci5b917642015-07-02 09:03:13 +02001700 /* and neither any other deviate statement is expected,
1701 * not-supported deviation must be the only deviation of the target
1702 */
1703 if (dev->deviate_size || develem->next) {
1704 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1705 LOGVAL(VE_SPEC, 0, "\"not-supported\" deviation cannot be combined with any other deviation.");
1706 goto error;
1707 }
1708
1709
Radek Krejcieb00f512015-07-01 16:44:58 +02001710 /* remove target node */
1711 ly_mnode_free(dev->target);
Radek Krejci5b917642015-07-02 09:03:13 +02001712 dev->target = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001713
Radek Krejci5b917642015-07-02 09:03:13 +02001714 dev->deviate_size = 1;
1715 return EXIT_SUCCESS;
Radek Krejcieb00f512015-07-01 16:44:58 +02001716 } else if (!strcmp(value, "add")) {
1717 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_ADD;
1718 } else if (!strcmp(value, "replace")) {
1719 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_RPL;
1720 } else if (!strcmp(value, "delete")) {
1721 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_DEL;
1722 } else {
1723 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1724 goto error;
1725 }
1726 d = &dev->deviate[dev->deviate_size];
1727
1728 /* process deviation properties */
1729 LY_TREE_FOR_SAFE(develem->child, next, child) {
1730 if (!strcmp(child->name, "config")) {
1731 if (d->flags & LY_NODE_CONFIG_MASK) {
1732 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1733 goto error;
1734 }
1735
1736 /* for we deviate from RFC 6020 and allow config property even it is/is not
1737 * specified in the target explicitly since config property inherits. So we expect
1738 * that config is specified in every node. But for delete, we check that the value
1739 * is the same as here in deviation
1740 */
1741 GETVAL(value, child, "value");
1742 if (!strcmp(value, "false")) {
1743 d->flags |= LY_NODE_CONFIG_R;
1744 } else if (!strcmp(value, "true")) {
1745 d->flags |= LY_NODE_CONFIG_W;
1746 } else {
1747 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1748 goto error;
1749 }
1750
1751 if (d->mod == LY_DEVIATE_DEL) {
1752 /* check values */
1753 if ((d->flags & LY_NODE_CONFIG_MASK) != (dev->target->flags & LY_NODE_CONFIG_MASK)) {
1754 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1755 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1756 goto error;
1757 }
1758 /* remove current config value of the target ... */
1759 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1760
1761 /* ... and inherit config value from the target's parent */
1762 if (dev->target->parent) {
1763 dev->target->flags |= dev->target->parent->flags & LY_NODE_CONFIG_MASK;
1764 } else {
1765 /* default config is true */
1766 dev->target->flags |= LY_NODE_CONFIG_W;
1767 }
1768 } else { /* add and replace are the same in this case */
1769 /* remove current config value of the target ... */
1770 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1771
1772 /* ... and replace it with the value specified in deviation */
1773 dev->target->flags |= d->flags & LY_NODE_CONFIG_MASK;
1774 }
1775 } else if (!strcmp(child->name, "default")) {
1776 if (d->dflt) {
1777 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1778 goto error;
1779 }
1780 GETVAL(value, child, "value");
1781 d->dflt = lydict_insert(module->ctx, value, 0);
1782
1783 if (dev->target->nodetype == LY_NODE_CHOICE) {
1784 choice = (struct ly_mnode_choice *)dev->target;
1785
1786 if (d->mod == LY_DEVIATE_ADD) {
1787 /* check that there is no current value */
1788 if (choice->dflt) {
1789 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1790 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1791 goto error;
1792 }
1793 }
1794
1795 mnode = resolve_schema_nodeid(d->dflt, (struct ly_mnode *)choice, choice->module, LY_NODE_CHOICE);
1796 if (d->mod == LY_DEVIATE_DEL) {
1797 if (!choice->dflt || choice->dflt != mnode) {
1798 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1799 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1800 goto error;
1801 }
1802 } else { /* add (already checked) and replace */
1803 choice->dflt = mnode;
1804 if (!choice->dflt) {
1805 /* default branch not found */
1806 LOGVAL(VE_INARG, LOGLINE(yin), value, "default");
1807 goto error;
1808 }
1809 }
1810 } else if (dev->target->nodetype == LY_NODE_LEAF) {
1811 leaf = (struct ly_mnode_leaf *)dev->target;
1812
1813 if (d->mod == LY_DEVIATE_ADD) {
1814 /* check that there is no current value */
1815 if (leaf->dflt) {
1816 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1817 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1818 goto error;
1819 }
1820 }
1821
1822 if (d->mod == LY_DEVIATE_DEL) {
1823 if (!leaf->dflt || leaf->dflt != d->dflt) {
1824 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1825 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1826 goto error;
1827 }
1828 /* remove value */
1829 lydict_remove(leaf->module->ctx, leaf->dflt);
1830 leaf->dflt = NULL;
1831 } else { /* add (already checked) and replace */
1832 /* remove value */
1833 lydict_remove(leaf->module->ctx, leaf->dflt);
1834
1835 /* set new value */
1836 leaf->dflt = lydict_insert(leaf->module->ctx, d->dflt, 0);
1837 }
1838 } else {
1839 /* invalid target for default value */
1840 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1841 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1842 goto error;
1843 }
1844 } else if (!strcmp(child->name, "mandatory")) {
1845 if (d->flags & LY_NODE_MAND_MASK) {
1846 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1847 goto error;
1848 }
1849
1850 /* check target node type */
1851 if (!(dev->target->nodetype &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML))) {
1852 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1853 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1854 goto error;
1855 }
1856
1857 GETVAL(value, child, "value");
1858 if (!strcmp(value, "false")) {
1859 d->flags |= LY_NODE_MAND_FALSE;
1860 } else if (!strcmp(value, "true")) {
1861 d->flags |= LY_NODE_MAND_TRUE;
1862 } else {
1863 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1864 goto error;
1865 }
1866
1867 if (d->mod == LY_DEVIATE_ADD) {
1868 /* check that there is no current value */
1869 if (dev->target->flags & LY_NODE_MAND_MASK) {
1870 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1871 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1872 goto error;
1873 }
1874 }
1875
1876 if (d->mod == LY_DEVIATE_DEL) {
1877 /* check values */
1878 if ((d->flags & LY_NODE_MAND_MASK) != (dev->target->flags & LY_NODE_MAND_MASK)) {
1879 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1880 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1881 goto error;
1882 }
1883 /* remove current mandatory value of the target */
1884 dev->target->flags &= ~LY_NODE_MAND_MASK;
1885 } else { /* add (already checked) and replace */
1886 /* remove current mandatory value of the target ... */
1887 dev->target->flags &= ~LY_NODE_MAND_MASK;
1888
1889 /* ... and replace it with the value specified in deviation */
1890 dev->target->flags |= d->flags & LY_NODE_MAND_MASK;
1891 }
1892 } else if (!strcmp(child->name, "min-elements")) {
1893 if (f_min) {
1894 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1895 goto error;
1896 }
1897 f_min = 1;
1898
1899 if (deviate_minmax(dev->target, child, d, 0)) {
1900 goto error;
1901 }
1902 } else if (!strcmp(child->name, "max-elements")) {
1903 if (d->max) {
1904 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1905 goto error;
1906 }
1907
1908 if (deviate_minmax(dev->target, child, d, 1)) {
1909 goto error;
1910 }
1911 } else if (!strcmp(child->name, "must")) {
1912 c_must++;
1913
1914 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
1915 continue;
1916 } else if (!strcmp(child->name, "type")) {
1917 if (d->type) {
1918 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1919 goto error;
1920 }
1921
1922 /* check target node type */
1923 if (dev->target->nodetype == LY_NODE_LEAF) {
1924 t = &((struct ly_mnode_leaf *)dev->target)->type;
1925 } else if (dev->target->nodetype == LY_NODE_LEAFLIST) {
1926 t = &((struct ly_mnode_leaflist *)dev->target)->type;
1927 } else {
1928 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1929 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1930 goto error;
1931 }
1932
1933 if (d->mod == LY_DEVIATE_ADD) {
1934 /* not allowed, type is always present at the target */
1935 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1936 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1937 goto error;
1938 } else if (d->mod == LY_DEVIATE_DEL) {
1939 /* not allowed, type cannot be deleted from the target */
1940 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1941 LOGVAL(VE_SPEC, 0, "Deleteing type from the target is not allowed.");
1942 goto error;
1943 }
1944
1945 /* replace */
1946 /* remove current units value of the target ... */
1947 ly_type_free(dev->target->module->ctx, t);
1948
1949 /* ... and replace it with the value specified in deviation */
1950 if (fill_yin_type(module, dev->target, child, t)) {
1951 goto error;
1952 }
1953 d->type = t;
1954 } else if (!strcmp(child->name, "unique")) {
1955 c_uniq++;
1956
1957 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
1958 continue;
1959 } else if (!strcmp(child->name, "units")) {
1960 if (d->units) {
1961 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1962 goto error;
1963 }
1964
1965 /* check target node type */
1966 if (dev->target->nodetype == LY_NODE_LEAFLIST) {
1967 stritem = &((struct ly_mnode_leaflist *)dev->target)->units;
1968 } else if (dev->target->nodetype == LY_NODE_LEAF) {
1969 stritem = &((struct ly_mnode_leaf *)dev->target)->units;
1970 } else {
1971 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1972 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
1973 goto error;
1974 }
1975
1976 /* get units value */
1977 GETVAL(value, child, "name");
1978 d->units = lydict_insert(module->ctx, value, 0);
1979
1980 /* apply to target */
1981 if (d->mod == LY_DEVIATE_ADD) {
1982 /* check that there is no current value */
1983 if (*stritem) {
1984 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1985 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1986 goto error;
1987 }
1988 }
1989
1990 if (d->mod == LY_DEVIATE_DEL) {
1991 /* check values */
1992 if (*stritem != d->units) {
1993 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1994 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1995 goto error;
1996 }
1997 /* remove current units value of the target */
1998 lydict_remove(dev->target->module->ctx, *stritem);
1999 } else { /* add (already checked) and replace */
2000 /* remove current units value of the target ... */
2001 lydict_remove(dev->target->module->ctx, *stritem);
2002
2003 /* ... and replace it with the value specified in deviation */
2004 *stritem = lydict_insert(module->ctx, value, 0);
2005 }
2006 } else {
2007 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2008 goto error;
2009 }
2010
2011 lyxml_free_elem(module->ctx, child);
2012 }
2013
2014 if (c_must) {
2015 /* check target node type */
2016 switch (dev->target->nodetype) {
2017 case LY_NODE_LEAF:
2018 trg_must = &((struct ly_mnode_leaf *)dev->target)->must;
2019 trg_must_size = &((struct ly_mnode_leaf *)dev->target)->must_size;
2020 break;
2021 case LY_NODE_CONTAINER:
2022 trg_must = &((struct ly_mnode_container *)dev->target)->must;
2023 trg_must_size = &((struct ly_mnode_container *)dev->target)->must_size;
2024 break;
2025 case LY_NODE_LEAFLIST:
2026 trg_must = &((struct ly_mnode_leaflist *)dev->target)->must;
2027 trg_must_size = &((struct ly_mnode_leaflist *)dev->target)->must_size;
2028 break;
2029 case LY_NODE_LIST:
2030 trg_must = &((struct ly_mnode_list *)dev->target)->must;
2031 trg_must_size = &((struct ly_mnode_list *)dev->target)->must_size;
2032 break;
2033 case LY_NODE_ANYXML:
2034 trg_must = &((struct ly_mnode_anyxml *)dev->target)->must;
2035 trg_must_size = &((struct ly_mnode_anyxml *)dev->target)->must_size;
2036 break;
2037 default:
2038 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2039 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2040 goto error;
2041 }
2042
2043 if (d->mod == LY_DEVIATE_RPL) {
2044 /* remove target's musts and allocate new array for it */
2045 if (!*trg_must) {
2046 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2047 LOGVAL(VE_SPEC, 0, "Property \"must\" to replace does not exists in target.");
2048 goto error;
2049 }
2050
2051 for (i = 0; i < list->must_size; i++) {
2052 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2053 }
2054 free(*trg_must);
2055 *trg_must = d->must = calloc(c_must, sizeof *d->must);
2056 d->must_size = c_must;
2057 *trg_must_size = 0;
2058 } else if (d->mod == LY_DEVIATE_ADD) {
2059 /* reallocate the must array of the target */
2060 d->must = realloc(*trg_must, (c_must + *trg_must_size) * sizeof *d->must);
2061 *trg_must = d->must;
2062 d->must = &(*trg_must[*trg_must_size]);
2063 d->must_size = c_must;
2064 } else { /* LY_DEVIATE_DEL */
2065 d->must = calloc(c_must, sizeof *d->must);
2066 }
2067 }
2068 if (c_uniq) {
2069 /* check target node type */
2070 if (dev->target->nodetype != LY_NODE_LIST) {
2071 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2072 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2073 goto error;
2074 }
2075
2076 list = (struct ly_mnode_list *)dev->target;
2077 if (d->mod == LY_DEVIATE_RPL) {
2078 /* remove target's unique and allocate new array for it */
2079 if (!list->unique) {
2080 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2081 LOGVAL(VE_SPEC, 0, "Property \"unique\" to replace does not exists in target.");
2082 goto error;
2083 }
2084
2085 for (i = 0; i < list->unique_size; i++) {
2086 free(list->unique[i].leafs);
2087 }
2088 free(list->unique);
2089 list->unique = d->unique = calloc(c_uniq, sizeof *d->unique);
2090 d->unique_size = c_uniq;
2091 list->unique_size = 0;
2092 } else if (d->mod == LY_DEVIATE_ADD) {
2093 /* reallocate the unique array of the target */
2094 d->unique = realloc(list->unique, (c_uniq + list->unique_size) * sizeof *d->unique);
2095 list->unique = d->unique;
2096 d->unique = &list->unique[list->unique_size];
2097 d->unique_size = c_uniq;
2098 } else { /* LY_DEVIATE_DEL */
2099 d->unique = calloc(c_uniq, sizeof *d->unique);
2100 }
2101 }
2102
2103 /* process deviation properties with 0..n cardinality */
2104 LY_TREE_FOR_SAFE(develem->child, next, child) {
2105 if (!strcmp(child->name, "must")) {
2106 if (d->mod == LY_DEVIATE_DEL) {
2107 if (fill_yin_must(module, child, &d->must[d->must_size])) {
2108 goto error;
2109 }
2110
2111 /* find must to delete, we are ok with just matching conditions */
2112 for (i = 0; i < *trg_must_size; i++) {
2113 if (d->must[d->must_size].expr == (*trg_must)[i].expr) {
2114 /* we have a match, free the must structure ... */
2115 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2116 /* ... and maintain the array */
2117 (*trg_must_size)--;
2118 if (i != *trg_must_size) {
2119 (*trg_must)[i].expr = (*trg_must)[*trg_must_size].expr;
2120 (*trg_must)[i].dsc = (*trg_must)[*trg_must_size].dsc;
2121 (*trg_must)[i].ref = (*trg_must)[*trg_must_size].ref;
2122 (*trg_must)[i].eapptag = (*trg_must)[*trg_must_size].eapptag;
2123 (*trg_must)[i].emsg = (*trg_must)[*trg_must_size].emsg;
2124 }
2125 if (!(*trg_must_size)) {
2126 free(*trg_must);
2127 *trg_must = NULL;
2128 } else {
2129 (*trg_must)[*trg_must_size].expr = NULL;
2130 (*trg_must)[*trg_must_size].dsc = NULL;
2131 (*trg_must)[*trg_must_size].ref = NULL;
2132 (*trg_must)[*trg_must_size].eapptag = NULL;
2133 (*trg_must)[*trg_must_size].emsg = NULL;
2134 }
2135
2136 i = -1; /* set match flag */
2137 break;
2138 }
2139 }
2140 d->must_size++;
2141 if (i != -1) {
2142 /* no match found */
2143 LOGVAL(VE_INARG, LOGLINE(child), d->must[d->must_size - 1].expr, child->name);
2144 LOGVAL(VE_SPEC, 0, "Value does not match any must from the target.");
2145 goto error;
2146 }
2147 } else { /* replace or add */
2148 if (fill_yin_must(dev->target->module, child, &((*trg_must)[*trg_must_size]))) {
2149 goto error;
2150 }
2151 (*trg_must_size)++;
2152 }
2153 } else if (!strcmp(child->name, "unique")) {
2154 if (d->mod == LY_DEVIATE_DEL) {
2155 if (parse_unique(dev->target, child, &d->unique[d->unique_size])) {
2156 goto error;
2157 }
2158
2159 /* find unique structures to delete */
2160 for (i = 0; i < list->unique_size; i++) {
2161 if (list->unique[i].leafs_size != d->unique[d->unique_size].leafs_size) {
2162 continue;
2163 }
2164
2165 for (j = 0; j < d->unique[d->unique_size].leafs_size; j++) {
2166 if (list->unique[i].leafs[j] != d->unique[d->unique_size].leafs[j]) {
2167 break;
2168 }
2169 }
2170
2171 if (j == d->unique[d->unique_size].leafs_size) {
2172 /* we have a match, free the unique structure ... */
2173 free(list->unique[i].leafs);
2174 /* ... and maintain the array */
2175 list->unique_size--;
2176 if (i != list->unique_size) {
2177 list->unique[i].leafs_size = list->unique[list->unique_size].leafs_size;
2178 list->unique[i].leafs = list->unique[list->unique_size].leafs;
2179 }
2180
2181 if (!list->unique_size) {
2182 free(list->unique);
2183 list->unique = NULL;
2184 } else {
2185 list->unique[list->unique_size].leafs_size = 0;
2186 list->unique[list->unique_size].leafs = NULL;
2187 }
2188
2189 i = -1; /* set match flag */
2190 break;
2191 }
2192 }
2193
2194 d->unique_size++;
2195 if (i != -1) {
2196 /* no match found */
2197 LOGVAL(VE_INARG, LOGLINE(child), lyxml_get_attr(child, "tag", NULL), child->name);
2198 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2199 goto error;
2200 }
2201 } else { /* replace or add */
2202 if (parse_unique(dev->target, child, &list->unique[list->unique_size])) {
2203 goto error;
2204 }
2205 list->unique_size++;
2206 }
2207 }
2208 lyxml_free_elem(module->ctx, child);
2209 }
Radek Krejci5b917642015-07-02 09:03:13 +02002210
2211 dev->deviate_size++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002212 }
2213
Radek Krejcieb00f512015-07-01 16:44:58 +02002214 return EXIT_SUCCESS;
2215
2216error:
2217
2218 if (dev->deviate) {
2219 for (i = 0; i < dev->deviate_size; i++) {
2220 lydict_remove(module->ctx, dev->deviate[i].dflt);
2221 lydict_remove(module->ctx, dev->deviate[i].units);
2222
2223 if (dev->deviate[i].mod == LY_DEVIATE_DEL) {
2224 for (j = 0; j < dev->deviate[i].must_size; j++) {
2225 ly_restr_free(module->ctx, &dev->deviate[i].must[j]);
2226 }
2227 free(dev->deviate[i].must);
2228
2229 for (j = 0; j < dev->deviate[i].unique_size; j++) {
2230 free(dev->deviate[i].unique[j].leafs);
2231 }
2232 free(dev->deviate[i].unique);
2233 }
2234 }
2235 free(dev->deviate);
2236 }
2237
2238 return EXIT_FAILURE;
2239}
2240
2241static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002242fill_yin_augment(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_augment *aug)
Radek Krejci106efc02015-06-10 14:36:27 +02002243{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002244 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002245 struct lyxml_elem *next, *child;
2246 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02002247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002248 GETVAL(value, yin, "target-node");
2249 aug->target_name = lydict_insert(module->ctx, value, 0);
2250 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02002251
Radek Krejci3cf9e222015-06-18 11:37:50 +02002252 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
2253 goto error;
2254 }
2255
2256 LY_TREE_FOR_SAFE(yin->child, next, child) {
2257 if (!strcmp(child->name, "if-feature")) {
2258 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002259 } else if (!strcmp(child->name, "when")) {
2260 if (aug->when) {
2261 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2262 goto error;
2263 }
2264
2265 aug->when = read_yin_when(module, child);
2266 lyxml_free_elem(module->ctx, child);
2267
2268 if (!aug->when) {
2269 goto error;
2270 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002271
2272 /* check allowed sub-statements */
2273 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
2274 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
2275 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
2276 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2277 goto error;
2278 }
2279 }
2280
2281 if (c) {
2282 aug->features = calloc(c, sizeof *aug->features);
2283 }
2284
2285 LY_TREE_FOR_SAFE(yin->child, next, child) {
2286 if (!strcmp(child->name, "if-feature")) {
2287 GETVAL(value, child, "name");
2288 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
2289 if (!aug->features[aug->features_size]) {
2290 goto error;
2291 }
2292 aug->features_size++;
2293 } else {
2294 /* keep the data nodes */
2295 continue;
2296 }
2297
2298 lyxml_free_elem(module->ctx, child);
2299 }
2300
2301 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002302 * when we will have the target node
2303 */
2304 lyxml_unlink_elem(yin);
2305 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02002306
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002307 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02002308
2309error:
2310
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002311 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02002312}
2313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002314static int
2315fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02002316{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002317 struct lyxml_elem *sub, *next;
2318 const char *value;
2319 char *endptr;
2320 int f_mand = 0, f_min = 0, f_max = 0;
2321 int c_must = 0;
2322 int r;
2323 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002324
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002325 GETVAL(value, yin, "target-node");
2326 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02002327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002328 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
2329 goto error;
2330 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002331
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002332 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2333 /* limited applicability */
2334 if (!strcmp(sub->name, "default")) {
2335 /* leaf or choice */
2336 if (rfn->mod.dflt) {
2337 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2338 goto error;
2339 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002341 /* check possibility of statements combination */
2342 if (rfn->target_type) {
2343 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
2344 if (!rfn->target_type) {
2345 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2346 goto error;
2347 }
2348 } else {
2349 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
2350 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002351
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002352 GETVAL(value, sub, "value");
2353 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
2354 } else if (!strcmp(sub->name, "mandatory")) {
2355 /* leaf, choice or anyxml */
2356 if (f_mand) {
2357 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2358 goto error;
2359 }
2360 /* just checking the flags in leaf is not sufficient, we would allow
2361 * multiple mandatory statements with the "false" value
2362 */
2363 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002364
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002365 /* check possibility of statements combination */
2366 if (rfn->target_type) {
2367 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
2368 if (!rfn->target_type) {
2369 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2370 goto error;
2371 }
2372 } else {
2373 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
2374 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002375
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002376 GETVAL(value, sub, "value");
2377 if (!strcmp(value, "true")) {
2378 rfn->flags |= LY_NODE_MAND_TRUE;
2379 } else if (!strcmp(value, "false")) {
2380 rfn->flags |= LY_NODE_MAND_FALSE;
2381 } else {
2382 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2383 goto error;
2384 }
2385 } else if (!strcmp(sub->name, "min-elements")) {
2386 /* list or leaf-list */
2387 if (f_min) {
2388 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2389 goto error;
2390 }
2391 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002392
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002393 /* check possibility of statements combination */
2394 if (rfn->target_type) {
2395 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2396 if (!rfn->target_type) {
2397 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2398 goto error;
2399 }
2400 } else {
2401 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2402 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002403
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002404 GETVAL(value, sub, "value");
2405 while (isspace(value[0])) {
2406 value++;
2407 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002408
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002409 /* convert it to uint32_t */
2410 errno = 0;
2411 endptr = NULL;
2412 val = strtoul(value, &endptr, 10);
2413 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2414 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2415 goto error;
2416 }
2417 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002418
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002419 /* magic - bit 3 in flags means min set */
2420 rfn->flags |= 0x04;
2421 } else if (!strcmp(sub->name, "max-elements")) {
2422 /* list or leaf-list */
2423 if (f_max) {
2424 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2425 goto error;
2426 }
2427 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002428
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002429 /* check possibility of statements combination */
2430 if (rfn->target_type) {
2431 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2432 if (!rfn->target_type) {
2433 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2434 goto error;
2435 }
2436 } else {
2437 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2438 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002439
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002440 GETVAL(value, sub, "value");
2441 while (isspace(value[0])) {
2442 value++;
2443 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002444
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002445 /* convert it to uint32_t */
2446 errno = 0;
2447 endptr = NULL;
2448 val = strtoul(value, &endptr, 10);
2449 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2450 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2451 goto error;
2452 }
2453 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002454
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002455 /* magic - bit 4 in flags means min set */
2456 rfn->flags |= 0x08;
2457 } else if (!strcmp(sub->name, "presence")) {
2458 /* container */
2459 if (rfn->mod.presence) {
2460 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2461 goto error;
2462 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002464 /* check possibility of statements combination */
2465 if (rfn->target_type) {
2466 rfn->target_type &= LY_NODE_CONTAINER;
2467 if (!rfn->target_type) {
2468 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2469 goto error;
2470 }
2471 } else {
2472 rfn->target_type = LY_NODE_CONTAINER;
2473 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002475 GETVAL(value, sub, "value");
2476 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
2477 } else if (!strcmp(sub->name, "must")) {
2478 /* leaf-list, list, container or anyxml */
2479 /* check possibility of statements combination */
2480 if (rfn->target_type) {
2481 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
2482 if (!rfn->target_type) {
2483 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2484 goto error;
2485 }
2486 } else {
2487 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
2488 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002490 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002491
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002492 } else {
2493 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2494 goto error;
2495 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002496
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002497 lyxml_free_elem(module->ctx, sub);
2498 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002499
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002500 /* process nodes with cardinality of 0..n */
2501 if (c_must) {
2502 rfn->must = calloc(c_must, sizeof *rfn->must);
2503 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002504
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002505 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2506 if (!strcmp(sub->name, "must")) {
2507 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
2508 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002509
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002510 if (r) {
2511 goto error;
2512 }
2513 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002514
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002515 lyxml_free_elem(module->ctx, sub);
2516 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002518 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002519
2520error:
2521
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002522 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002523}
2524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002525static int
2526fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02002527{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002528 struct lyxml_elem *child;
2529 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002531 LY_TREE_FOR(yin->child, child) {
2532 if (!strcmp(child->name, "prefix")) {
2533 GETVAL(value, child, "value");
2534 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
2535 goto error;
2536 }
2537 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
2538 } else if (!strcmp(child->name, "revision-date")) {
2539 if (imp->rev[0]) {
2540 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2541 goto error;
2542 }
2543 GETVAL(value, child, "date");
2544 if (check_date(value, LOGLINE(child))) {
2545 goto error;
2546 }
2547 memcpy(imp->rev, value, LY_REV_SIZE - 1);
2548 } else {
2549 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2550 goto error;
2551 }
2552 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002553
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002554 /* check mandatory information */
2555 if (!imp->prefix) {
2556 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
2557 goto error;
2558 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002559
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002560 GETVAL(value, yin, "module");
2561 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
2562 if (!imp->module) {
2563 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
2564 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2565 goto error;
2566 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002567
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002568 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002569
2570error:
2571
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002572 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002573}
2574
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002575static int
2576fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02002577{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002578 struct lyxml_elem *child;
2579 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002581 LY_TREE_FOR(yin->child, child) {
2582 if (!strcmp(child->name, "revision-date")) {
2583 if (inc->rev[0]) {
2584 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2585 goto error;
2586 }
2587 GETVAL(value, child, "date");
2588 if (check_date(value, LOGLINE(child))) {
2589 goto error;
2590 }
2591 memcpy(inc->rev, value, LY_REV_SIZE - 1);
2592 } else {
2593 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2594 goto error;
2595 }
2596 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002597
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002598 GETVAL(value, yin, "module");
2599 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
2600 if (!inc->submodule) {
2601 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
2602 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2603 goto error;
2604 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002606 /* check that belongs-to corresponds */
2607 if (module->type) {
2608 module = ((struct ly_submodule *)module)->belongsto;
2609 }
2610 if (inc->submodule->belongsto != module) {
2611 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2612 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
2613 goto error;
2614 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002615
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002616 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002617
2618error:
2619
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002620 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002621}
2622
Radek Krejcida04f4a2015-05-21 12:54:09 +02002623/*
2624 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02002625 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02002626 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02002627 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002628static int
2629read_yin_common(struct ly_module *module, struct ly_mnode *parent,
2630 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002631{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002632 const char *value;
2633 struct lyxml_elem *sub, *next;
2634 struct ly_ctx *const ctx = module->ctx;
2635 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002637 if (opt & OPT_MODULE) {
2638 mnode->module = module;
2639 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002640
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002641 if (opt & OPT_IDENT) {
2642 GETVAL(value, xmlnode, "name");
2643 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
2644 goto error;
2645 }
2646 mnode->name = lydict_insert(ctx, value, strlen(value));
2647 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002649 /* process local parameters */
2650 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
2651 if (!strcmp(sub->name, "description")) {
2652 if (mnode->dsc) {
2653 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2654 goto error;
2655 }
2656 mnode->dsc = read_yin_subnode(ctx, sub, "text");
2657 if (!mnode->dsc) {
2658 r = 1;
2659 }
2660 } else if (!strcmp(sub->name, "reference")) {
2661 if (mnode->ref) {
2662 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2663 goto error;
2664 }
2665 mnode->ref = read_yin_subnode(ctx, sub, "text");
2666 if (!mnode->ref) {
2667 r = 1;
2668 }
2669 } else if (!strcmp(sub->name, "status")) {
2670 if (mnode->flags & LY_NODE_STATUS_MASK) {
2671 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2672 goto error;
2673 }
2674 GETVAL(value, sub, "value");
2675 if (!strcmp(value, "current")) {
2676 mnode->flags |= LY_NODE_STATUS_CURR;
2677 } else if (!strcmp(value, "deprecated")) {
2678 mnode->flags |= LY_NODE_STATUS_DEPRC;
2679 } else if (!strcmp(value, "obsolete")) {
2680 mnode->flags |= LY_NODE_STATUS_OBSLT;
2681 } else {
2682 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2683 r = 1;
2684 }
2685 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
2686 if (mnode->flags & LY_NODE_CONFIG_MASK) {
2687 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2688 goto error;
2689 }
2690 GETVAL(value, sub, "value");
2691 if (!strcmp(value, "false")) {
2692 mnode->flags |= LY_NODE_CONFIG_R;
2693 } else if (!strcmp(value, "true")) {
2694 mnode->flags |= LY_NODE_CONFIG_W;
2695 } else {
2696 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2697 r = 1;
2698 }
2699 } else {
2700 /* skip the lyxml_free_elem */
2701 continue;
2702 }
2703 lyxml_free_elem(ctx, sub);
2704 if (r) {
2705 goto error;
2706 }
2707 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002708
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002709 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
2710 /* get config flag from parent */
2711 if (parent) {
2712 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2713 } else {
2714 /* default config is true */
2715 mnode->flags |= LY_NODE_CONFIG_W;
2716 }
2717 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002719 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02002720
2721error:
2722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002723 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002724}
2725
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002726static struct ly_when *
2727read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
2728{
Radek Krejci53ebfb12015-06-19 09:35:59 +02002729 struct ly_when *retval = NULL;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002730 struct lyxml_elem *next, *child;
2731 const char *value;
2732
2733 retval = calloc(1, sizeof *retval);
2734
2735 GETVAL(value, yin, "condition");
2736 retval->cond = lydict_insert(module->ctx, value, 0);
2737
2738 LY_TREE_FOR_SAFE(yin->child, next, child) {
2739 if (!strcmp(child->name, "description")) {
2740 if (retval->dsc) {
2741 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2742 goto error;
2743 }
2744 retval->dsc = read_yin_subnode(module->ctx, child, "text");
2745 if (!retval->dsc) {
2746 goto error;
2747 }
2748 } else if (!strcmp(child->name, "reference")) {
2749 if (retval->ref) {
2750 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2751 goto error;
2752 }
2753 retval->ref = read_yin_subnode(module->ctx, child, "text");
2754 if (!retval->ref) {
2755 goto error;
2756 }
2757 } else {
2758 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2759 goto error;
2760 }
2761
2762 lyxml_free_elem(module->ctx, child);
2763 }
2764
2765 return retval;
2766
2767error:
2768
Radek Krejci53ebfb12015-06-19 09:35:59 +02002769 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002770 return NULL;
2771}
2772
Radek Krejcib4cf2022015-06-03 14:40:05 +02002773/* additional check in case statement - the child must be unique across
2774 * all other case names and its data children
2775 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002776static int
2777check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002778{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002779 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002780
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002781 if (new->nodetype == LY_NODE_CHOICE) {
2782 /* we have nested choice in case, so we need recursion */
2783 LY_TREE_FOR(new->child, mnode) {
2784 if (mnode->nodetype == LY_NODE_CASE) {
2785 LY_TREE_FOR(mnode->child, submnode) {
2786 if (check_branch_id(parent, submnode, new, line)) {
2787 return EXIT_FAILURE;
2788 }
2789 }
2790 } else if (check_branch_id(parent, mnode, new, line)) {
2791 return EXIT_FAILURE;
2792 }
2793 }
2794 } else {
2795 LY_TREE_FOR(parent->child, mnode) {
2796 if (mnode == excl) {
2797 continue;
2798 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002800 if (!strcmp(new->name, mnode->name)) {
2801 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2802 return EXIT_FAILURE;
2803 }
2804 if (mnode->nodetype == LY_NODE_CASE) {
2805 LY_TREE_FOR(mnode->child, submnode) {
2806 if (!strcmp(new->name, submnode->name)) {
2807 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
2808 return EXIT_FAILURE;
2809 }
2810 }
2811 }
2812 }
2813 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002815 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002816}
2817
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002818static struct ly_mnode *
2819read_yin_case(struct ly_module *module,
2820 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02002821{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002822 struct lyxml_elem *sub, *next;
2823 struct ly_mnode_case *mcase;
2824 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002825 int c_ftrs = 0;
2826 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002827
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002828 mcase = calloc(1, sizeof *mcase);
2829 mcase->nodetype = LY_NODE_CASE;
2830 mcase->prev = (struct ly_mnode *)mcase;
2831 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002832
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002833 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
2834 goto error;
2835 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002836
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002837 /* process choice's specific children */
2838 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2839 if (!strcmp(sub->name, "container")) {
2840 mnode = read_yin_container(module, retval, sub, resolve, unres);
2841 } else if (!strcmp(sub->name, "leaf-list")) {
2842 mnode = read_yin_leaflist(module, retval, sub, resolve);
2843 } else if (!strcmp(sub->name, "leaf")) {
2844 mnode = read_yin_leaf(module, retval, sub, resolve);
2845 } else if (!strcmp(sub->name, "list")) {
2846 mnode = read_yin_list(module, retval, sub, resolve, unres);
2847 } else if (!strcmp(sub->name, "uses")) {
2848 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2849 } else if (!strcmp(sub->name, "choice")) {
2850 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2851 } else if (!strcmp(sub->name, "anyxml")) {
2852 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002853 } else if (!strcmp(sub->name, "if-feature")) {
2854 c_ftrs++;
2855
2856 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
2857 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002858 } else if (!strcmp(sub->name, "when")) {
2859 if (mcase->when) {
2860 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2861 goto error;
2862 }
2863
2864 mcase->when = read_yin_when(module, sub);
2865 if (!mcase->when) {
2866 goto error;
2867 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002868 } else {
2869 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2870 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002871 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002872
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002873 if (!mnode) {
2874 goto error;
2875 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
2876 goto error;
2877 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002878
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002879 mnode = NULL;
2880 lyxml_free_elem(module->ctx, sub);
2881 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02002882
Radek Krejci3cf9e222015-06-18 11:37:50 +02002883 if (c_ftrs) {
2884 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
2885 }
2886 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2887 GETVAL(value, sub, "name");
2888 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
2889 if (!mcase->features[mcase->features_size]) {
2890 goto error;
2891 }
2892 mcase->features_size++;
2893 lyxml_free_elem(module->ctx, sub);
2894 }
2895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002896 /* inherit config flag */
2897 if (parent) {
2898 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2899 } else {
2900 /* default config is true */
2901 retval->flags |= LY_NODE_CONFIG_W;
2902 }
Radek Krejcib388c152015-06-04 17:03:03 +02002903
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002904 /* insert the node into the schema tree */
2905 if (ly_mnode_addchild(parent, retval)) {
2906 goto error;
2907 }
Radek Krejcib7155b52015-06-10 17:03:01 +02002908
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002909 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002910
2911error:
2912
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002913 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02002914
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002915 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002916}
2917
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002918static struct ly_mnode *
2919read_yin_choice(struct ly_module *module,
2920 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002921{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002922 struct lyxml_elem *sub, *next;
2923 struct ly_ctx *const ctx = module->ctx;
2924 struct ly_mnode *retval, *mnode = NULL;
2925 struct ly_mnode_choice *choice;
2926 const char *value;
2927 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002928 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002929
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002930 choice = calloc(1, sizeof *choice);
2931 choice->nodetype = LY_NODE_CHOICE;
2932 choice->prev = (struct ly_mnode *)choice;
2933 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002935 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2936 goto error;
2937 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002938
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002939 /* process choice's specific children */
2940 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2941 if (!strcmp(sub->name, "container")) {
2942 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
2943 goto error;
2944 }
2945 } else if (!strcmp(sub->name, "leaf-list")) {
2946 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
2947 goto error;
2948 }
2949 } else if (!strcmp(sub->name, "leaf")) {
2950 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
2951 goto error;
2952 }
2953 } else if (!strcmp(sub->name, "list")) {
2954 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
2955 goto error;
2956 }
2957 } else if (!strcmp(sub->name, "case")) {
2958 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
2959 goto error;
2960 }
2961 } else if (!strcmp(sub->name, "anyxml")) {
2962 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
2963 goto error;
2964 }
2965 } else if (!strcmp(sub->name, "default")) {
2966 if (dflt_str) {
2967 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2968 goto error;
2969 }
2970 GETVAL(value, sub, "value");
2971 dflt_str = strdup(value);
2972 } else if (!strcmp(sub->name, "mandatory")) {
2973 if (f_mand) {
2974 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2975 goto error;
2976 }
2977 /* just checking the flags in leaf is not sufficient, we would allow
2978 * multiple mandatory statements with the "false" value
2979 */
2980 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02002981
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002982 GETVAL(value, sub, "value");
2983 if (!strcmp(value, "true")) {
2984 choice->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02002985 } else if (!strcmp(value, "false")) {
2986 choice->flags |= LY_NODE_MAND_FALSE;
2987 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002988 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2989 goto error;
2990 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002991 } else if (!strcmp(sub->name, "when")) {
2992 if (choice->when) {
2993 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2994 goto error;
2995 }
2996
2997 choice->when = read_yin_when(module, sub);
2998 if (!choice->when) {
2999 goto error;
3000 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003001 } else if (!strcmp(sub->name, "if-feature")) {
3002 c_ftrs++;
3003
3004 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
3005 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003006 } else {
3007 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3008 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003009 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003010
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003011 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
3012 goto error;
3013 }
3014 mnode = NULL;
3015 lyxml_free_elem(ctx, sub);
3016 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003017
Radek Krejci3cf9e222015-06-18 11:37:50 +02003018 if (c_ftrs) {
3019 choice->features = calloc(c_ftrs, sizeof *choice->features);
3020 }
3021
3022 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3023 GETVAL(value, sub, "name");
3024 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
3025 if (!choice->features[choice->features_size]) {
3026 goto error;
3027 }
3028 choice->features_size++;
3029 lyxml_free_elem(ctx, sub);
3030 }
3031
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003032 /* check - default is prohibited in combination with mandatory */
3033 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
3034 LOGVAL(VE_SPEC, LOGLINE(yin),
3035 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
3036 goto error;
3037 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003039 /* link default with the case */
3040 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02003041 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003042 if (!choice->dflt) {
3043 /* default branch not found */
3044 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
3045 goto error;
3046 }
3047 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003048
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003049 /* insert the node into the schema tree */
3050 if (parent && ly_mnode_addchild(parent, retval)) {
3051 goto error;
3052 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003053
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003054 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02003055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003056 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003057
3058error:
3059
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003060 ly_mnode_free(retval);
3061 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003062
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003063 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003064}
3065
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003066static struct ly_mnode *
3067read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02003068{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003069 struct ly_mnode *retval;
3070 struct ly_mnode_leaf *anyxml;
3071 struct lyxml_elem *sub, *next;
3072 const char *value;
3073 int r;
3074 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003075 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02003076
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003077 anyxml = calloc(1, sizeof *anyxml);
3078 anyxml->nodetype = LY_NODE_ANYXML;
3079 anyxml->prev = (struct ly_mnode *)anyxml;
3080 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02003081
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003082 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3083 goto error;
3084 }
Radek Krejci863c2852015-06-03 15:47:11 +02003085
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003086 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3087 if (!strcmp(sub->name, "mandatory")) {
3088 if (f_mand) {
3089 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3090 goto error;
3091 }
3092 /* just checking the flags in leaf is not sufficient, we would allow
3093 * multiple mandatory statements with the "false" value
3094 */
3095 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02003096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003097 GETVAL(value, sub, "value");
3098 if (!strcmp(value, "true")) {
3099 anyxml->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003100 } else if (!strcmp(value, "false")) {
3101 anyxml->flags |= LY_NODE_MAND_FALSE;
3102 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003103 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3104 goto error;
3105 }
3106 /* else false is the default value, so we can ignore it */
3107 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003108 } else if (!strcmp(sub->name, "when")) {
3109 if (anyxml->when) {
3110 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3111 goto error;
3112 }
3113
3114 anyxml->when = read_yin_when(module, sub);
3115 lyxml_free_elem(module->ctx, sub);
3116
3117 if (!anyxml->when) {
3118 goto error;
3119 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003120 } else if (!strcmp(sub->name, "must")) {
3121 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003122 } else if (!strcmp(sub->name, "if-feature")) {
3123 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02003124
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003125 } else {
3126 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3127 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003128 }
3129 }
Radek Krejci863c2852015-06-03 15:47:11 +02003130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003131 /* middle part - process nodes with cardinality of 0..n */
3132 if (c_must) {
3133 anyxml->must = calloc(c_must, sizeof *anyxml->must);
3134 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003135 if (c_ftrs) {
3136 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
3137 }
Radek Krejci863c2852015-06-03 15:47:11 +02003138
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003139 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3140 if (!strcmp(sub->name, "must")) {
3141 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
3142 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02003143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003144 if (r) {
3145 goto error;
3146 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003147 } else if (!strcmp(sub->name, "must")) {
3148 GETVAL(value, sub, "name");
3149 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
3150 if (!anyxml->features[anyxml->features_size]) {
3151 goto error;
3152 }
3153 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003154 }
Radek Krejci863c2852015-06-03 15:47:11 +02003155
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003156 lyxml_free_elem(module->ctx, sub);
3157 }
Radek Krejci863c2852015-06-03 15:47:11 +02003158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003159 if (parent && ly_mnode_addchild(parent, retval)) {
3160 goto error;
3161 }
Radek Krejci863c2852015-06-03 15:47:11 +02003162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003163 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02003164
3165error:
3166
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003167 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02003168
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003169 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02003170}
3171
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003172static struct ly_mnode *
3173read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003174{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003175 struct ly_mnode *retval;
3176 struct ly_mnode_leaf *leaf;
3177 struct lyxml_elem *sub, *next;
3178 const char *value;
3179 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003180 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003181
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003182 leaf = calloc(1, sizeof *leaf);
3183 leaf->nodetype = LY_NODE_LEAF;
3184 leaf->prev = (struct ly_mnode *)leaf;
3185 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003186
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003187 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3188 goto error;
3189 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003190
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003191 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3192 if (!strcmp(sub->name, "type")) {
3193 if (leaf->type.der) {
3194 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3195 goto error;
3196 }
3197 if (fill_yin_type(module, parent, sub, &leaf->type)) {
3198 goto error;
3199 }
3200 } else if (!strcmp(sub->name, "default")) {
3201 if (leaf->dflt) {
3202 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3203 goto error;
3204 }
3205 GETVAL(value, sub, "value");
3206 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
3207 } else if (!strcmp(sub->name, "units")) {
3208 if (leaf->units) {
3209 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3210 goto error;
3211 }
3212 GETVAL(value, sub, "name");
3213 leaf->units = lydict_insert(module->ctx, value, strlen(value));
3214 } else if (!strcmp(sub->name, "mandatory")) {
3215 if (f_mand) {
3216 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3217 goto error;
3218 }
3219 /* just checking the flags in leaf is not sufficient, we would allow
3220 * multiple mandatory statements with the "false" value
3221 */
3222 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02003223
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003224 GETVAL(value, sub, "value");
3225 if (!strcmp(value, "true")) {
3226 leaf->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003227 } else if (!strcmp(value, "false")) {
3228 leaf->flags |= LY_NODE_MAND_FALSE;
3229 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003230 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3231 goto error;
3232 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003233 } else if (!strcmp(sub->name, "when")) {
3234 if (leaf->when) {
3235 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3236 goto error;
3237 }
3238
3239 leaf->when = read_yin_when(module, sub);
3240 if (!leaf->when) {
3241 goto error;
3242 }
3243
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003244 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003245 c_must++; /* else false is the default value, so we can ignore it */
3246 } else if (!strcmp(sub->name, "if-feature")) {
3247 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003249 /* skip element free at the end of the loop */
3250 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003251 } else {
3252 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3253 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003254 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003255
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003256 lyxml_free_elem(module->ctx, sub);
3257 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003258
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003259 /* check mandatory parameters */
3260 if (!leaf->type.der) {
3261 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3262 goto error;
3263 }
3264 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
3265 goto error;
3266 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003267
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003268 /* middle part - process nodes with cardinality of 0..n */
3269 if (c_must) {
3270 leaf->must = calloc(c_must, sizeof *leaf->must);
3271 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003272 if (c_ftrs) {
3273 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
3274 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003275
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003276 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3277 if (!strcmp(sub->name, "must")) {
3278 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
3279 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003280
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003281 if (r) {
3282 goto error;
3283 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003284 } else if (!strcmp(sub->name, "if-feature")) {
3285 GETVAL(value, sub, "name");
3286 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
3287 if (!leaf->features[leaf->features_size]) {
3288 goto error;
3289 }
3290 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003291 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003292
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003293 lyxml_free_elem(module->ctx, sub);
3294 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003296 if (parent && ly_mnode_addchild(parent, retval)) {
3297 goto error;
3298 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003300 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003301
3302error:
3303
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003304 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003305
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003306 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003307}
3308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003309static struct ly_mnode *
3310read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003311{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003312 struct ly_mnode *retval;
3313 struct ly_mnode_leaflist *llist;
3314 struct lyxml_elem *sub, *next;
3315 const char *value;
3316 char *endptr;
3317 unsigned long val;
3318 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003319 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003320 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003321
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003322 llist = calloc(1, sizeof *llist);
3323 llist->nodetype = LY_NODE_LEAFLIST;
3324 llist->prev = (struct ly_mnode *)llist;
3325 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003327 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3328 goto error;
3329 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003331 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3332 if (!strcmp(sub->name, "type")) {
3333 if (llist->type.der) {
3334 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3335 goto error;
3336 }
3337 if (fill_yin_type(module, parent, sub, &llist->type)) {
3338 goto error;
3339 }
3340 } else if (!strcmp(sub->name, "units")) {
3341 if (llist->units) {
3342 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3343 goto error;
3344 }
3345 GETVAL(value, sub, "name");
3346 llist->units = lydict_insert(module->ctx, value, strlen(value));
3347 } else if (!strcmp(sub->name, "ordered-by")) {
3348 if (f_ordr) {
3349 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3350 goto error;
3351 }
3352 /* just checking the flags in llist is not sufficient, we would
3353 * allow multiple ordered-by statements with the "system" value
3354 */
3355 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003356
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003357 if (llist->flags & LY_NODE_CONFIG_R) {
3358 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3359 * state data
3360 */
3361 lyxml_free_elem(module->ctx, sub);
3362 continue;
3363 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003364
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003365 GETVAL(value, sub, "value");
3366 if (!strcmp(value, "user")) {
3367 llist->flags |= LY_NODE_USERORDERED;
3368 } else if (strcmp(value, "system")) {
3369 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3370 goto error;
3371 } /* else system is the default value, so we can ignore it */
3372 } else if (!strcmp(sub->name, "must")) {
3373 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003374 } else if (!strcmp(sub->name, "if-feature")) {
3375 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003376
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003377 /* skip element free at the end of the loop */
3378 continue;
3379 } else if (!strcmp(sub->name, "min-elements")) {
3380 if (f_min) {
3381 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3382 goto error;
3383 }
3384 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003385
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003386 GETVAL(value, sub, "value");
3387 while (isspace(value[0])) {
3388 value++;
3389 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003391 /* convert it to uint32_t */
3392 errno = 0;
3393 endptr = NULL;
3394 val = strtoul(value, &endptr, 10);
3395 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
3396 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3397 goto error;
3398 }
3399 llist->min = (uint32_t) val;
3400 } else if (!strcmp(sub->name, "max-elements")) {
3401 if (f_max) {
3402 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3403 goto error;
3404 }
3405 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003406
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003407 GETVAL(value, sub, "value");
3408 while (isspace(value[0])) {
3409 value++;
3410 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003411
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003412 /* convert it to uint32_t */
3413 errno = 0;
3414 endptr = NULL;
3415 val = strtoul(value, &endptr, 10);
3416 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3417 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3418 goto error;
3419 }
3420 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003421 } else if (!strcmp(sub->name, "when")) {
3422 if (llist->when) {
3423 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3424 goto error;
3425 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003426
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003427 llist->when = read_yin_when(module, sub);
3428 if (!llist->when) {
3429 goto error;
3430 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003431 } else {
3432 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3433 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003434 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003435
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003436 lyxml_free_elem(module->ctx, sub);
3437 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003438
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003439 /* check constraints */
3440 if (!llist->type.der) {
3441 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3442 goto error;
3443 }
3444 if (llist->max && llist->min > llist->max) {
3445 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3446 goto error;
3447 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003449 /* middle part - process nodes with cardinality of 0..n */
3450 if (c_must) {
3451 llist->must = calloc(c_must, sizeof *llist->must);
3452 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003453 if (c_ftrs) {
3454 llist->features = calloc(c_ftrs, sizeof *llist->features);
3455 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003456
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003457 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3458 if (!strcmp(sub->name, "must")) {
3459 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
3460 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003461
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003462 if (r) {
3463 goto error;
3464 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003465 } else if (!strcmp(sub->name, "if-feature")) {
3466 GETVAL(value, sub, "name");
3467 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
3468 if (!llist->features[llist->features_size]) {
3469 goto error;
3470 }
3471 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003472 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003473
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003474 lyxml_free_elem(module->ctx, sub);
3475 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003476
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003477 if (parent && ly_mnode_addchild(parent, retval)) {
3478 goto error;
3479 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003481 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003482
3483error:
3484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003485 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003486
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003487 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003488}
3489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003490static struct ly_mnode *
3491read_yin_list(struct ly_module *module,
3492 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003493{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003494 struct ly_mnode *retval, *mnode;
3495 struct ly_mnode_list *list;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003496 struct lyxml_elem *sub, *next, root, uniq;
3497 int i, r;
3498 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003499 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003500 int f_ordr = 0, f_max = 0, f_min = 0;
Radek Krejcieb00f512015-07-01 16:44:58 +02003501 const char *key_str = NULL, *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003502 char *auxs;
3503 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003504
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003505 /* init */
3506 memset(&root, 0, sizeof root);
3507 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02003508
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003509 list = calloc(1, sizeof *list);
3510 list->nodetype = LY_NODE_LIST;
3511 list->prev = (struct ly_mnode *)list;
3512 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003513
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003514 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3515 goto error;
3516 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003518 /* process list's specific children */
3519 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3520 /* data statements */
3521 if (!strcmp(sub->name, "container") ||
3522 !strcmp(sub->name, "leaf-list") ||
3523 !strcmp(sub->name, "leaf") ||
3524 !strcmp(sub->name, "list") ||
3525 !strcmp(sub->name, "choice") ||
3526 !strcmp(sub->name, "uses") ||
3527 !strcmp(sub->name, "grouping") ||
3528 !strcmp(sub->name, "anyxml")) {
3529 lyxml_unlink_elem(sub);
3530 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003531
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003532 /* array counters */
3533 } else if (!strcmp(sub->name, "key")) {
3534 /* check cardinality 0..1 */
3535 if (list->keys_size) {
3536 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
3537 goto error;
3538 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003540 /* count the number of keys */
3541 GETVAL(value, sub, "value");
3542 key_str = value;
3543 while ((value = strpbrk(value, " \t\n"))) {
3544 list->keys_size++;
3545 while (isspace(*value)) {
3546 value++;
3547 }
3548 }
3549 list->keys_size++;
3550 list->keys = calloc(list->keys_size, sizeof *list->keys);
3551 } else if (!strcmp(sub->name, "unique")) {
3552 c_uniq++;
3553 lyxml_unlink_elem(sub);
3554 lyxml_add_child(&uniq, sub);
3555 } else if (!strcmp(sub->name, "typedef")) {
3556 c_tpdf++;
3557 } else if (!strcmp(sub->name, "must")) {
3558 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003559 } else if (!strcmp(sub->name, "if-feature")) {
3560 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02003561
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003562 /* optional stetments */
3563 } else if (!strcmp(sub->name, "ordered-by")) {
3564 if (f_ordr) {
3565 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3566 goto error;
3567 }
3568 /* just checking the flags in llist is not sufficient, we would
3569 * allow multiple ordered-by statements with the "system" value
3570 */
3571 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003573 if (list->flags & LY_NODE_CONFIG_R) {
3574 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3575 * state data
3576 */
3577 lyxml_free_elem(module->ctx, sub);
3578 continue;
3579 }
Radek Krejci345ad742015-06-03 11:04:18 +02003580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003581 GETVAL(value, sub, "value");
3582 if (!strcmp(value, "user")) {
3583 list->flags |= LY_NODE_USERORDERED;
3584 } else if (strcmp(value, "system")) {
3585 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3586 goto error;
3587 }
3588 /* else system is the default value, so we can ignore it */
3589 lyxml_free_elem(module->ctx, sub);
3590 } else if (!strcmp(sub->name, "min-elements")) {
3591 if (f_min) {
3592 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3593 goto error;
3594 }
3595 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003596
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003597 GETVAL(value, sub, "value");
3598 while (isspace(value[0])) {
3599 value++;
3600 }
Radek Krejci345ad742015-06-03 11:04:18 +02003601
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003602 /* convert it to uint32_t */
3603 errno = 0;
3604 auxs = NULL;
3605 val = strtoul(value, &auxs, 10);
3606 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
3607 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3608 goto error;
3609 }
3610 list->min = (uint32_t) val;
3611 lyxml_free_elem(module->ctx, sub);
3612 } else if (!strcmp(sub->name, "max-elements")) {
3613 if (f_max) {
3614 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3615 goto error;
3616 }
3617 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003619 GETVAL(value, sub, "value");
3620 while (isspace(value[0])) {
3621 value++;
3622 }
Radek Krejci345ad742015-06-03 11:04:18 +02003623
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003624 /* convert it to uint32_t */
3625 errno = 0;
3626 auxs = NULL;
3627 val = strtoul(value, &auxs, 10);
3628 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3629 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3630 goto error;
3631 }
3632 list->max = (uint32_t) val;
3633 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003634 } else if (!strcmp(sub->name, "when")) {
3635 if (list->when) {
3636 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3637 goto error;
3638 }
3639
3640 list->when = read_yin_when(module, sub);
3641 lyxml_free_elem(module->ctx, sub);
3642
3643 if (!list->when) {
3644 goto error;
3645 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003646 } else {
3647 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3648 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003649 }
3650 }
Radek Krejci345ad742015-06-03 11:04:18 +02003651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003652 /* check - if list is configuration, key statement is mandatory */
3653 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
3654 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
3655 goto error;
3656 }
3657 if (list->max && list->min > list->max) {
3658 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3659 goto error;
3660 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003661
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003662 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3663 if (c_tpdf) {
3664 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
3665 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003666 if (c_must) {
3667 list->must = calloc(c_must, sizeof *list->must);
3668 }
3669 if (c_ftrs) {
3670 list->features = calloc(c_ftrs, sizeof *list->features);
3671 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003672 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3673 if (!strcmp(sub->name, "typedef")) {
3674 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
3675 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02003676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003677 if (r) {
3678 goto error;
3679 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003680 } else if (!strcmp(sub->name, "if-feature")) {
3681 GETVAL(value, sub, "name");
3682 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
3683 if (!list->features[list->features_size]) {
3684 goto error;
3685 }
3686 list->features_size++;
3687 } else if (!strcmp(sub->name, "must")) {
3688 r = fill_yin_must(module, sub, &list->must[list->must_size]);
3689 list->must_size++;
3690
3691 if (r) {
3692 goto error;
3693 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003694 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003695 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003696 }
Radek Krejci25d782a2015-05-22 15:03:23 +02003697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003698 /* last part - process data nodes */
3699 LY_TREE_FOR_SAFE(root.child, next, sub) {
3700 if (!strcmp(sub->name, "container")) {
3701 mnode = read_yin_container(module, retval, sub, resolve, unres);
3702 } else if (!strcmp(sub->name, "leaf-list")) {
3703 mnode = read_yin_leaflist(module, retval, sub, resolve);
3704 } else if (!strcmp(sub->name, "leaf")) {
3705 mnode = read_yin_leaf(module, retval, sub, resolve);
3706 } else if (!strcmp(sub->name, "list")) {
3707 mnode = read_yin_list(module, retval, sub, resolve, unres);
3708 } else if (!strcmp(sub->name, "choice")) {
3709 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3710 } else if (!strcmp(sub->name, "uses")) {
3711 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3712 } else if (!strcmp(sub->name, "grouping")) {
3713 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3714 } else if (!strcmp(sub->name, "anyxml")) {
3715 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003716 }
3717 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003719 if (!mnode) {
3720 goto error;
3721 }
3722 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003723
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003724 if (parent && ly_mnode_addchild(parent, retval)) {
3725 goto error;
3726 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003728 if (!key_str) {
3729 /* config false list without a key */
3730 return retval;
3731 }
Radek Krejci812b10a2015-05-28 16:48:25 +02003732
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003733 /* link key leafs into the list structure and check all constraints */
3734 for (i = 0; i < list->keys_size; i++) {
3735 /* get the key name */
3736 if ((value = strpbrk(key_str, " \t\n"))) {
3737 len = value - key_str;
3738 while (isspace(*value)) {
3739 value++;
3740 }
3741 } else {
3742 len = strlen(key_str);
3743 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02003744
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003745 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02003746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003747 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
3748 goto error;
3749 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003750
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003751 /* prepare for next iteration */
3752 while (value && isspace(*value)) {
3753 value++;
3754 }
3755 key_str = value;
3756 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003757
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003758 /* process unique statements */
3759 if (c_uniq) {
3760 list->unique = calloc(c_uniq, sizeof *list->unique);
3761 }
3762 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
Radek Krejcieb00f512015-07-01 16:44:58 +02003763 if (parse_unique(retval, sub, &list->unique[list->unique_size++])) {
3764 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003765 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003766
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003767 lyxml_free_elem(module->ctx, sub);
3768 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003770 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003771
3772error:
3773
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003774 ly_mnode_free(retval);
3775 while (root.child) {
3776 lyxml_free_elem(module->ctx, root.child);
3777 }
3778 while (uniq.child) {
3779 lyxml_free_elem(module->ctx, uniq.child);
3780 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003781
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003782 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003783}
3784
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003785static struct ly_mnode *
3786read_yin_container(struct ly_module *module,
3787 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003788{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003789 struct lyxml_elem *sub, *next, root;
3790 struct ly_mnode *mnode = NULL;
3791 struct ly_mnode *retval;
3792 struct ly_mnode_container *cont;
3793 const char *value;
3794 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003795 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003796
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003797 /* init */
3798 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003800 cont = calloc(1, sizeof *cont);
3801 cont->nodetype = LY_NODE_CONTAINER;
3802 cont->prev = (struct ly_mnode *)cont;
3803 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003804
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003805 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
3806 goto error;
3807 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003808
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003809 /* process container's specific children */
3810 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3811 if (!strcmp(sub->name, "presence")) {
3812 if (cont->presence) {
3813 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3814 goto error;
3815 }
3816 GETVAL(value, sub, "value");
3817 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02003818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003819 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003820 } else if (!strcmp(sub->name, "when")) {
3821 if (cont->when) {
3822 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3823 goto error;
3824 }
3825
3826 cont->when = read_yin_when(module, sub);
3827 lyxml_free_elem(module->ctx, sub);
3828
3829 if (!cont->when) {
3830 goto error;
3831 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003832
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003833 /* data statements */
3834 } else if (!strcmp(sub->name, "container") ||
3835 !strcmp(sub->name, "leaf-list") ||
3836 !strcmp(sub->name, "leaf") ||
3837 !strcmp(sub->name, "list") ||
3838 !strcmp(sub->name, "choice") ||
3839 !strcmp(sub->name, "uses") ||
3840 !strcmp(sub->name, "grouping") ||
3841 !strcmp(sub->name, "anyxml")) {
3842 lyxml_unlink_elem(sub);
3843 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003845 /* array counters */
3846 } else if (!strcmp(sub->name, "typedef")) {
3847 c_tpdf++;
3848 } else if (!strcmp(sub->name, "must")) {
3849 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003850 } else if (!strcmp(sub->name, "if-feature")) {
3851 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003852 } else {
3853 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3854 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003855 }
3856 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003857
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003858 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3859 if (c_tpdf) {
3860 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
3861 }
3862 if (c_must) {
3863 cont->must = calloc(c_must, sizeof *cont->must);
3864 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003865 if (c_ftrs) {
3866 cont->features = calloc(c_ftrs, sizeof *cont->features);
3867 }
Radek Krejci800af702015-06-02 13:46:01 +02003868
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003869 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3870 if (!strcmp(sub->name, "typedef")) {
3871 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
3872 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003873
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003874 if (r) {
3875 goto error;
3876 }
3877 } else if (!strcmp(sub->name, "must")) {
3878 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
3879 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02003880
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003881 if (r) {
3882 goto error;
3883 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003884 } else if (!strcmp(sub->name, "if-feature")) {
3885 GETVAL(value, sub, "name");
3886 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
3887 if (!cont->features[cont->features_size]) {
3888 goto error;
3889 }
3890 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003891 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003892
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003893 lyxml_free_elem(module->ctx, sub);
3894 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003895
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003896 /* last part - process data nodes */
3897 LY_TREE_FOR_SAFE(root.child, next, sub) {
3898 if (!strcmp(sub->name, "container")) {
3899 mnode = read_yin_container(module, retval, sub, resolve, unres);
3900 } else if (!strcmp(sub->name, "leaf-list")) {
3901 mnode = read_yin_leaflist(module, retval, sub, resolve);
3902 } else if (!strcmp(sub->name, "leaf")) {
3903 mnode = read_yin_leaf(module, retval, sub, resolve);
3904 } else if (!strcmp(sub->name, "list")) {
3905 mnode = read_yin_list(module, retval, sub, resolve, unres);
3906 } else if (!strcmp(sub->name, "choice")) {
3907 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3908 } else if (!strcmp(sub->name, "uses")) {
3909 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3910 } else if (!strcmp(sub->name, "grouping")) {
3911 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3912 } else if (!strcmp(sub->name, "anyxml")) {
3913 mnode = read_yin_anyxml(module, retval, sub, resolve);
3914 }
3915 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003916
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003917 if (!mnode) {
3918 goto error;
3919 }
3920 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003921
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003922 if (parent && ly_mnode_addchild(parent, retval)) {
3923 goto error;
3924 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003925
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003926 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003927
3928error:
3929
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003930 ly_mnode_free(retval);
3931 while (root.child) {
3932 lyxml_free_elem(module->ctx, root.child);
3933 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003935 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003936}
3937
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003938static struct ly_mnode *
3939read_yin_grouping(struct ly_module *module,
3940 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003941{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003942 struct lyxml_elem *sub, *next, root;
3943 struct ly_mnode *mnode = NULL;
3944 struct ly_mnode *retval;
3945 struct ly_mnode_grp *grp;
3946 int r;
3947 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003949 /* init */
3950 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02003951
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003952 grp = calloc(1, sizeof *grp);
3953 grp->nodetype = LY_NODE_GROUPING;
3954 grp->prev = (struct ly_mnode *)grp;
3955 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003956
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003957 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
3958 goto error;
3959 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003960
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003961 LY_TREE_FOR_SAFE(node->child, next, sub) {
3962 /* data statements */
3963 if (!strcmp(sub->name, "container") ||
3964 !strcmp(sub->name, "leaf-list") ||
3965 !strcmp(sub->name, "leaf") ||
3966 !strcmp(sub->name, "list") ||
3967 !strcmp(sub->name, "choice") ||
3968 !strcmp(sub->name, "uses") ||
3969 !strcmp(sub->name, "grouping") ||
3970 !strcmp(sub->name, "anyxml")) {
3971 lyxml_unlink_elem(sub);
3972 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003973
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003974 /* array counters */
3975 } else if (!strcmp(sub->name, "typedef")) {
3976 c_tpdf++;
3977 } else {
3978 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3979 goto error;
3980 }
3981 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003982
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003983 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3984 if (c_tpdf) {
3985 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
3986 }
3987 LY_TREE_FOR_SAFE(node->child, next, sub) {
3988 if (!strcmp(sub->name, "typedef")) {
3989 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
3990 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003991
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003992 if (r) {
3993 goto error;
3994 }
3995 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003996
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003997 lyxml_free_elem(module->ctx, sub);
3998 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003999
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004000 /* last part - process data nodes */
4001 LY_TREE_FOR_SAFE(root.child, next, sub) {
4002 if (!strcmp(sub->name, "container")) {
4003 mnode = read_yin_container(module, retval, sub, resolve, unres);
4004 } else if (!strcmp(sub->name, "leaf-list")) {
4005 mnode = read_yin_leaflist(module, retval, sub, resolve);
4006 } else if (!strcmp(sub->name, "leaf")) {
4007 mnode = read_yin_leaf(module, retval, sub, resolve);
4008 } else if (!strcmp(sub->name, "list")) {
4009 mnode = read_yin_list(module, retval, sub, resolve, unres);
4010 } else if (!strcmp(sub->name, "choice")) {
4011 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4012 } else if (!strcmp(sub->name, "uses")) {
4013 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4014 } else if (!strcmp(sub->name, "grouping")) {
4015 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4016 } else if (!strcmp(sub->name, "anyxml")) {
4017 mnode = read_yin_anyxml(module, retval, sub, resolve);
4018 }
4019 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004020
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004021 if (!mnode) {
4022 goto error;
4023 }
4024 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004026 if (parent && ly_mnode_addchild(parent, retval)) {
4027 goto error;
4028 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004029
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004030 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004031
4032error:
4033
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004034 ly_mnode_free(retval);
4035 while (root.child) {
4036 lyxml_free_elem(module->ctx, root.child);
4037 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004039 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004040}
4041
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004042static struct ly_mnode *
4043read_yin_input_output(struct ly_module *module,
4044 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004045{
Radek Krejcie0674f82015-06-15 13:58:51 +02004046 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004047 struct ly_mnode *mnode = NULL;
4048 struct ly_mnode *retval;
4049 struct ly_mnode_input_output *inout;
4050 int r;
4051 int c_tpdf = 0;
4052
Radek Krejcie0674f82015-06-15 13:58:51 +02004053 /* init */
4054 memset(&root, 0, sizeof root);
4055
Michal Vasko38d01f72015-06-15 09:41:06 +02004056 inout = calloc(1, sizeof *inout);
4057
4058 if (!strcmp(yin->name, "input")) {
4059 inout->nodetype = LY_NODE_INPUT;
4060 } else if (!strcmp(yin->name, "output")) {
4061 inout->nodetype = LY_NODE_OUTPUT;
4062 } else {
4063 assert(0);
4064 }
4065
4066 inout->prev = (struct ly_mnode *)inout;
4067 retval = (struct ly_mnode *)inout;
4068
Michal Vaskoebeac942015-06-15 12:11:50 +02004069 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
4070 goto error;
4071 }
4072
Michal Vasko38d01f72015-06-15 09:41:06 +02004073 /* data statements */
4074 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4075 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004076 !strcmp(sub->name, "leaf-list") ||
4077 !strcmp(sub->name, "leaf") ||
4078 !strcmp(sub->name, "list") ||
4079 !strcmp(sub->name, "choice") ||
4080 !strcmp(sub->name, "uses") ||
4081 !strcmp(sub->name, "grouping") ||
4082 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004083 lyxml_unlink_elem(sub);
4084 lyxml_add_child(&root, sub);
4085
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004086 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004087 } else if (!strcmp(sub->name, "typedef")) {
4088 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004089#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02004090 } else {
4091 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4092 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004093#else
Michal Vasko38d01f72015-06-15 09:41:06 +02004094 } else {
4095 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004096#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02004097 }
4098 }
4099
4100 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4101 if (c_tpdf) {
4102 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
4103 }
4104
4105 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4106 if (!strcmp(sub->name, "typedef")) {
4107 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
4108 inout->tpdf_size++;
4109
4110 if (r) {
4111 goto error;
4112 }
4113 }
4114
4115 lyxml_free_elem(module->ctx, sub);
4116 }
4117
4118 /* last part - process data nodes */
4119 LY_TREE_FOR_SAFE(root.child, next, sub) {
4120 if (!strcmp(sub->name, "container")) {
4121 mnode = read_yin_container(module, retval, sub, resolve, unres);
4122 } else if (!strcmp(sub->name, "leaf-list")) {
4123 mnode = read_yin_leaflist(module, retval, sub, resolve);
4124 } else if (!strcmp(sub->name, "leaf")) {
4125 mnode = read_yin_leaf(module, retval, sub, resolve);
4126 } else if (!strcmp(sub->name, "list")) {
4127 mnode = read_yin_list(module, retval, sub, resolve, unres);
4128 } else if (!strcmp(sub->name, "choice")) {
4129 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4130 } else if (!strcmp(sub->name, "uses")) {
4131 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4132 } else if (!strcmp(sub->name, "grouping")) {
4133 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4134 } else if (!strcmp(sub->name, "anyxml")) {
4135 mnode = read_yin_anyxml(module, retval, sub, resolve);
4136 }
4137 lyxml_free_elem(module->ctx, sub);
4138
4139 if (!mnode) {
4140 goto error;
4141 }
4142 }
4143
4144 if (parent && ly_mnode_addchild(parent, retval)) {
4145 goto error;
4146 }
4147
4148 return retval;
4149
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004150error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004151
4152 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004153 while (root.child) {
4154 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004155 }
4156
4157 return NULL;
4158}
4159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004160static struct ly_mnode *
4161read_yin_notif(struct ly_module *module,
4162 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02004163{
Michal Vaskoc6551b32015-06-16 10:51:43 +02004164 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02004165 struct ly_mnode *mnode = NULL;
4166 struct ly_mnode *retval;
4167 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004168 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02004169 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004170 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02004171
Michal Vaskoc6551b32015-06-16 10:51:43 +02004172 memset(&root, 0, sizeof root);
4173
Michal Vasko0ea41032015-06-16 08:53:55 +02004174 notif = calloc(1, sizeof *notif);
4175 notif->nodetype = LY_NODE_NOTIF;
4176 notif->prev = (struct ly_mnode *)notif;
4177 retval = (struct ly_mnode *)notif;
4178
4179 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
4180 goto error;
4181 }
4182
4183 /* process rpc's specific children */
4184 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4185 /* data statements */
4186 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004187 !strcmp(sub->name, "leaf-list") ||
4188 !strcmp(sub->name, "leaf") ||
4189 !strcmp(sub->name, "list") ||
4190 !strcmp(sub->name, "choice") ||
4191 !strcmp(sub->name, "uses") ||
4192 !strcmp(sub->name, "grouping") ||
4193 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004194 lyxml_unlink_elem(sub);
4195 lyxml_add_child(&root, sub);
4196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004197 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02004198 } else if (!strcmp(sub->name, "typedef")) {
4199 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004200 } else if (!strcmp(sub->name, "if-feature")) {
4201 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004202 } else {
4203 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4204 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02004205 }
4206 }
4207
4208 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4209 if (c_tpdf) {
4210 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
4211 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004212 if (c_ftrs) {
4213 notif->features = calloc(c_ftrs, sizeof *notif->features);
4214 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004215
4216 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4217 if (!strcmp(sub->name, "typedef")) {
4218 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
4219 notif->tpdf_size++;
4220
4221 if (r) {
4222 goto error;
4223 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004224 } else if (!strcmp(sub->name, "typedef")) {
4225 GETVAL(value, sub, "name");
4226 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
4227 if (!notif->features[notif->features_size]) {
4228 goto error;
4229 }
4230 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004231 }
4232
4233 lyxml_free_elem(module->ctx, sub);
4234 }
4235
4236 /* last part - process data nodes */
4237 LY_TREE_FOR_SAFE(root.child, next, sub) {
4238 if (!strcmp(sub->name, "container")) {
4239 mnode = read_yin_container(module, retval, sub, resolve, unres);
4240 } else if (!strcmp(sub->name, "leaf-list")) {
4241 mnode = read_yin_leaflist(module, retval, sub, resolve);
4242 } else if (!strcmp(sub->name, "leaf")) {
4243 mnode = read_yin_leaf(module, retval, sub, resolve);
4244 } else if (!strcmp(sub->name, "list")) {
4245 mnode = read_yin_list(module, retval, sub, resolve, unres);
4246 } else if (!strcmp(sub->name, "choice")) {
4247 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4248 } else if (!strcmp(sub->name, "uses")) {
4249 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4250 } else if (!strcmp(sub->name, "grouping")) {
4251 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4252 } else if (!strcmp(sub->name, "anyxml")) {
4253 mnode = read_yin_anyxml(module, retval, sub, resolve);
4254 }
4255 lyxml_free_elem(module->ctx, sub);
4256
4257 if (!mnode) {
4258 goto error;
4259 }
4260 }
4261
4262 if (parent && ly_mnode_addchild(parent, retval)) {
4263 goto error;
4264 }
4265
4266 return retval;
4267
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004268error:
Michal Vasko0ea41032015-06-16 08:53:55 +02004269
4270 ly_mnode_free(retval);
4271 while (root.child) {
4272 lyxml_free_elem(module->ctx, root.child);
4273 }
4274
4275 return NULL;
4276}
4277
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004278static struct ly_mnode *
4279read_yin_rpc(struct ly_module *module,
4280 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004281{
Radek Krejcie0674f82015-06-15 13:58:51 +02004282 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004283 struct ly_mnode *mnode = NULL;
4284 struct ly_mnode *retval;
4285 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004286 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02004287 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004288 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02004289
Radek Krejcie0674f82015-06-15 13:58:51 +02004290 /* init */
4291 memset(&root, 0, sizeof root);
4292
Michal Vasko38d01f72015-06-15 09:41:06 +02004293 rpc = calloc(1, sizeof *rpc);
4294 rpc->nodetype = LY_NODE_RPC;
4295 rpc->prev = (struct ly_mnode *)rpc;
4296 retval = (struct ly_mnode *)rpc;
4297
4298 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
4299 goto error;
4300 }
4301
4302 /* process rpc's specific children */
4303 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4304 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004305 if (rpc->child
4306 && (rpc->child->nodetype == LY_NODE_INPUT
4307 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004308 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4309 goto error;
4310 }
4311 lyxml_unlink_elem(sub);
4312 lyxml_add_child(&root, sub);
4313 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004314 if (rpc->child
4315 && (rpc->child->nodetype == LY_NODE_INPUT
4316 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004317 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4318 goto error;
4319 }
4320 lyxml_unlink_elem(sub);
4321 lyxml_add_child(&root, sub);
4322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004323 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02004324 } else if (!strcmp(sub->name, "grouping")) {
4325 lyxml_unlink_elem(sub);
4326 lyxml_add_child(&root, sub);
4327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004328 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004329 } else if (!strcmp(sub->name, "typedef")) {
4330 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004331 } else if (!strcmp(sub->name, "if-feature")) {
4332 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004333 } else {
4334 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4335 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004336 }
4337 }
4338
4339 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4340 if (c_tpdf) {
4341 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
4342 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004343 if (c_ftrs) {
4344 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
4345 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004346
4347 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4348 if (!strcmp(sub->name, "typedef")) {
4349 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
4350 rpc->tpdf_size++;
4351
4352 if (r) {
4353 goto error;
4354 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004355 } else if (!strcmp(sub->name, "if-feature")) {
4356 GETVAL(value, sub, "name");
4357 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
4358 if (!rpc->features[rpc->features_size]) {
4359 goto error;
4360 }
4361 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004362 }
4363
4364 lyxml_free_elem(module->ctx, sub);
4365 }
4366
4367 /* last part - process data nodes */
4368 LY_TREE_FOR_SAFE(root.child, next, sub) {
4369 if (!strcmp(sub->name, "grouping")) {
4370 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4371 } else if (!strcmp(sub->name, "input")) {
4372 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4373 } else if (!strcmp(sub->name, "output")) {
4374 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4375 }
4376 lyxml_free_elem(module->ctx, sub);
4377
4378 if (!mnode) {
4379 goto error;
4380 }
4381 }
4382
4383 if (parent && ly_mnode_addchild(parent, retval)) {
4384 goto error;
4385 }
4386
4387 return retval;
4388
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004389error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004390
4391 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004392 while (root.child) {
4393 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004394 }
4395
4396 return NULL;
4397}
4398
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004399static int
4400find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004401{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004402 struct ly_module *searchmod = NULL, *module = uses->module;
4403 struct ly_mnode *mnode, *mnode_aux;
4404 const char *name;
4405 int prefix_len = 0;
4406 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004407
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004408 /* get referenced grouping */
4409 name = strchr(uses->name, ':');
4410 if (!name) {
4411 /* no prefix, search in local tree */
4412 name = uses->name;
4413 } else {
4414 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004415
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004416 /* set name to correct position after colon */
4417 prefix_len = name - uses->name;
4418 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004420 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
4421 /* prefix refers to the current module, ignore it */
4422 prefix_len = 0;
4423 }
4424 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004425
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004426 /* search */
4427 if (prefix_len) {
4428 /* in top-level groupings of some other module */
4429 for (i = 0; i < module->imp_size; i++) {
4430 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
4431 && !module->imp[i].prefix[prefix_len]) {
4432 searchmod = module->imp[i].module;
4433 break;
4434 }
4435 }
4436 if (!searchmod) {
4437 /* uses refers unknown data model */
4438 LOGVAL(VE_INPREFIX, line, name);
4439 return EXIT_FAILURE;
4440 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004441
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004442 LY_TREE_FOR(searchmod->data, mnode) {
4443 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4444 uses->grp = (struct ly_mnode_grp *)mnode;
4445 return EXIT_SUCCESS;
4446 }
4447 }
4448 } else {
4449 /* in local tree hierarchy */
4450 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
4451 LY_TREE_FOR(mnode_aux->child, mnode) {
4452 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4453 uses->grp = (struct ly_mnode_grp *)mnode;
4454 return EXIT_SUCCESS;
4455 }
4456 }
4457 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004458
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004459 /* search in top level of the current module */
4460 LY_TREE_FOR(module->data, mnode) {
4461 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4462 uses->grp = (struct ly_mnode_grp *)mnode;
4463 return EXIT_SUCCESS;
4464 }
4465 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004466
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004467 /* search in top-level of included modules */
4468 for (i = 0; i < module->inc_size; i++) {
4469 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
4470 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4471 uses->grp = (struct ly_mnode_grp *)mnode;
4472 return EXIT_SUCCESS;
4473 }
4474 }
4475 }
4476 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004477
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004478 /* not found, but no explicit error occured */
4479 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02004480}
4481
Radek Krejcif5be10f2015-06-16 13:29:36 +02004482static int
4483resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
4484{
4485 struct lyxml_elem *yin, *next, *sub;
4486 struct ly_mnode *mnode;
4487
4488 assert(module);
4489
4490 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004491 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004492 if (!aug->target) {
4493 LOGVAL(VE_INARG, line, aug->target, "uses");
4494 return EXIT_FAILURE;
4495 }
4496
4497 if (!aug->child) {
4498 /* nothing to do */
4499 return EXIT_SUCCESS;
4500 }
4501
4502 yin = (struct lyxml_elem *)aug->child;
4503
4504 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
4505 return EXIT_FAILURE;
4506 }
4507
4508 LY_TREE_FOR_SAFE(yin->child, next, sub) {
4509 if (!strcmp(sub->name, "container")) {
4510 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
4511 } else if (!strcmp(sub->name, "leaf-list")) {
4512 mnode = read_yin_leaflist(module, aug->target, sub, 1);
4513 } else if (!strcmp(sub->name, "leaf")) {
4514 mnode = read_yin_leaf(module, aug->target, sub, 1);
4515 } else if (!strcmp(sub->name, "list")) {
4516 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
4517 } else if (!strcmp(sub->name, "uses")) {
4518 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
4519 } else if (!strcmp(sub->name, "choice")) {
4520 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4521 } else if (!strcmp(sub->name, "case")) {
4522 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4523 } else if (!strcmp(sub->name, "anyxml")) {
4524 mnode = read_yin_anyxml(module, aug->target, sub, 1);
4525#if 0
4526 } else {
4527 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02004528 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004529#else
4530 } else {
4531 continue;
4532#endif
4533 }
4534
4535 if (!mnode) {
4536 return EXIT_FAILURE;
4537 }
Radek Krejci3de29a72015-06-16 15:23:03 +02004538 /* check for mandatory nodes - if the target node is in another module
4539 * the added nodes cannot be mandatory
4540 */
4541 if (check_mandatory(mnode)) {
4542 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
4543 return EXIT_FAILURE;
4544 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004545
4546 lyxml_free_elem(module->ctx, sub);
4547
4548 /* the parent pointer will point to the augment node, but all
4549 * siblings pointers and possibly the child node in target does
4550 * not know about the augment and follow the standard schema tree
4551 * structure
4552 */
4553 mnode->parent = (struct ly_mnode *)aug;
4554 mnode = NULL;
4555 }
4556
4557 lyxml_free_elem(module->ctx, yin);
4558 aug->child = NULL;
4559
4560 return EXIT_SUCCESS;
4561}
4562
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004563int
4564resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02004565{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004566 struct ly_ctx *ctx;
4567 struct ly_mnode *mnode = NULL, *mnode_aux;
4568 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02004569 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004570 int i, j;
4571 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02004572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004573 /* copy the data nodes from grouping into the uses context */
4574 LY_TREE_FOR(uses->grp->child, mnode) {
4575 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
4576 if (!mnode_aux) {
4577 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
4578 return EXIT_FAILURE;
4579 }
4580 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
4581 ly_mnode_free(mnode_aux);
4582 return EXIT_FAILURE;
4583 }
4584 }
4585 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02004586
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004587 /* apply refines */
4588 for (i = 0; i < uses->refine_size; i++) {
4589 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02004590 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004591 if (!mnode) {
4592 LOGVAL(VE_INARG, line, rfn->target, "uses");
4593 return EXIT_FAILURE;
4594 }
Radek Krejci106efc02015-06-10 14:36:27 +02004595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004596 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
4597 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
4598 return EXIT_FAILURE;
4599 }
Radek Krejci106efc02015-06-10 14:36:27 +02004600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004601 /* description on any nodetype */
4602 if (rfn->dsc) {
4603 lydict_remove(ctx, mnode->dsc);
4604 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
4605 }
Radek Krejci106efc02015-06-10 14:36:27 +02004606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004607 /* reference on any nodetype */
4608 if (rfn->ref) {
4609 lydict_remove(ctx, mnode->ref);
4610 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
4611 }
Radek Krejci106efc02015-06-10 14:36:27 +02004612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004613 /* config on any nodetype */
4614 if (rfn->flags & LY_NODE_CONFIG_MASK) {
4615 mnode->flags &= ~LY_NODE_CONFIG_MASK;
4616 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
4617 }
Radek Krejci106efc02015-06-10 14:36:27 +02004618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004619 /* default value ... */
4620 if (rfn->mod.dflt) {
4621 if (mnode->nodetype == LY_NODE_LEAF) {
4622 /* leaf */
4623 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
4624 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
4625 } else if (mnode->nodetype == LY_NODE_CHOICE) {
4626 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004627 ((struct ly_mnode_choice *)mnode)->dflt = resolve_schema_nodeid(rfn->mod.dflt, mnode, mnode->module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004628 if (!((struct ly_mnode_choice *)mnode)->dflt) {
4629 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
4630 return EXIT_FAILURE;
4631 }
4632 }
4633 }
Radek Krejci106efc02015-06-10 14:36:27 +02004634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004635 /* mandatory on leaf, anyxml or choice */
Radek Krejcieb00f512015-07-01 16:44:58 +02004636 if (rfn->flags & LY_NODE_MAND_MASK) {
4637 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
4638 /* remove current value */
4639 mnode->flags &= ~LY_NODE_MAND_MASK;
4640
4641 /* set new value */
4642 mnode->flags |= (rfn->flags & LY_NODE_MAND_MASK);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004643 }
4644 }
Radek Krejci106efc02015-06-10 14:36:27 +02004645
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004646 /* presence on container */
4647 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
4648 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
4649 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
4650 }
Radek Krejci106efc02015-06-10 14:36:27 +02004651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004652 /* min/max-elements on list or leaf-list */
4653 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
4654 /* magic - bit 3 in flags means min set, bit 4 says max set */
4655 if (rfn->flags & 0x04) {
4656 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
4657 }
4658 if (rfn->flags & 0x08) {
4659 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
4660 }
4661 }
Radek Krejci106efc02015-06-10 14:36:27 +02004662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004663 /* must in leaf, leaf-list, list, container or anyxml */
4664 if (rfn->must_size) {
4665 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
4666 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
4667 if (!newmust) {
4668 LOGMEM;
4669 return EXIT_FAILURE;
4670 }
4671 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02004672 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004673 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
4674 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
4675 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
4676 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
4677 }
Radek Krejci106efc02015-06-10 14:36:27 +02004678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004679 ((struct ly_mnode_leaf *)mnode)->must = newmust;
4680 ((struct ly_mnode_leaf *)mnode)->must_size = size;
4681 }
4682 }
Radek Krejci106efc02015-06-10 14:36:27 +02004683
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004684 /* apply augments */
4685 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004686 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004687 goto error;
4688 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004689 }
Radek Krejci106efc02015-06-10 14:36:27 +02004690
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004691 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02004692
4693error:
4694
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004695 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02004696}
Radek Krejci74705112015-06-05 10:25:44 +02004697
4698/*
4699 * resolve - referenced grouping should be bounded to the namespace (resolved)
4700 * only when uses does not appear in grouping. In a case of grouping's uses,
4701 * we just get information but we do not apply augment or refine to it.
4702 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004703static struct ly_mnode *
4704read_yin_uses(struct ly_module *module,
4705 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02004706{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004707 struct lyxml_elem *sub, *next;
4708 struct ly_mnode *retval;
4709 struct ly_mnode_uses *uses;
4710 struct mnode_list *unres_new;
4711 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004712 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004713 int r;
Radek Krejci74705112015-06-05 10:25:44 +02004714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004715 uses = calloc(1, sizeof *uses);
4716 uses->nodetype = LY_NODE_USES;
4717 uses->prev = (struct ly_mnode *)uses;
4718 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02004719
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004720 GETVAL(value, node, "name");
4721 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02004722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004723 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
4724 goto error;
4725 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004726
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004727 /* get other properties of uses */
4728 LY_TREE_FOR_SAFE(node->child, next, sub) {
4729 if (!strcmp(sub->name, "refine")) {
4730 c_ref++;
4731 } else if (!strcmp(sub->name, "augment")) {
4732 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004733 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02004734 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02004735 } else if (!strcmp(sub->name, "when")) {
4736 if (uses->when) {
4737 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
4738 goto error;
4739 }
4740
4741 uses->when = read_yin_when(module, sub);
4742 lyxml_free_elem(module->ctx, sub);
4743
4744 if (!uses->when) {
4745 goto error;
4746 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004747 } else {
4748 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4749 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004750 }
4751 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004752
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004753 /* process properties with cardinality 0..n */
4754 if (c_ref) {
4755 uses->refine = calloc(c_ref, sizeof *uses->refine);
4756 }
4757 if (c_aug) {
4758 uses->augment = calloc(c_aug, sizeof *uses->augment);
4759 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004760 if (c_ftrs) {
4761 uses->features = calloc(c_ftrs, sizeof *uses->features);
4762 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004763
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004764 LY_TREE_FOR_SAFE(node->child, next, sub) {
4765 if (!strcmp(sub->name, "refine")) {
4766 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
4767 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004768 lyxml_free_elem(module->ctx, sub);
4769 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004770 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
4771 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004772 } else if (!strcmp(sub->name, "if-feature")) {
4773 GETVAL(value, sub, "name");
4774 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
4775 if (!uses->features[uses->features_size]) {
4776 goto error;
4777 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02004778 r = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004779 uses->features_size++;
4780 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004781 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004782
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004783 if (r) {
4784 goto error;
4785 }
4786 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02004787
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004788 if (find_grouping(parent, uses, LOGLINE(node))) {
4789 goto error;
4790 }
4791 if (!uses->grp) {
4792 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
4793 unres_new = calloc(1, sizeof *unres_new);
4794 if (*unres) {
4795 unres_new->next = *unres;
4796 }
4797 unres_new->mnode = retval;
4798 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02004799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004800 /* put it at the beginning of the unresolved list */
4801 *unres = unres_new;
4802 }
Radek Krejci74705112015-06-05 10:25:44 +02004803
Radek Krejci368c38f2015-06-15 15:09:55 +02004804 if (parent && ly_mnode_addchild(parent, retval)) {
4805 goto error;
4806 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004807
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004808 if (resolve) {
4809 /* inherit config flag */
4810 if (parent) {
4811 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
4812 } else {
4813 /* default config is true */
4814 retval->flags |= LY_NODE_CONFIG_W;
4815 }
4816 }
Radek Krejcib388c152015-06-04 17:03:03 +02004817
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004818 if (resolve && uses->grp) {
4819 /* copy the data nodes from grouping into the uses context */
4820 if (resolve_uses(uses, LOGLINE(node))) {
4821 goto error;
4822 }
4823 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004824
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004825 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004826
4827error:
4828
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004829 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004830
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004831 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004832}
4833
Radek Krejciefaeba32015-05-27 14:30:57 +02004834/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004835static int
4836read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004837{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004838 struct ly_ctx *ctx = module->ctx;
4839 struct ly_submodule *submodule = (struct ly_submodule *)module;
4840 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
4841 struct ly_mnode *mnode = NULL;
4842 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
4843 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004844 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02004845 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004846 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004847 /* counters */
Radek Krejcieb00f512015-07-01 16:44:58 +02004848 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0, c_dev = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004849
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004850 /* init */
4851 memset(&root, 0, sizeof root);
4852 memset(&grps, 0, sizeof grps);
4853 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02004854 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02004855
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004856 /*
4857 * in the first run, we process elements with cardinality of 1 or 0..1 and
4858 * count elements with cardinality 0..n. Data elements (choices, containers,
4859 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
4860 * need have all top-level and groupings already prepared at that time. In
4861 * the middle loop, we process other elements with carinality of 0..n since
4862 * we need to allocate arrays to store them.
4863 */
4864 LY_TREE_FOR_SAFE(yin->child, next, node) {
4865 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
4866 lyxml_free_elem(ctx, node);
4867 continue;
4868 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004869
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004870 if (!module->type && !strcmp(node->name, "namespace")) {
4871 if (module->ns) {
4872 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4873 goto error;
4874 }
4875 GETVAL(value, node, "uri");
4876 module->ns = lydict_insert(ctx, value, strlen(value));
4877 lyxml_free_elem(ctx, node);
4878 } else if (!module->type && !strcmp(node->name, "prefix")) {
4879 if (module->prefix) {
4880 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4881 goto error;
4882 }
4883 GETVAL(value, node, "value");
4884 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
4885 goto error;
4886 }
4887 module->prefix = lydict_insert(ctx, value, strlen(value));
4888 lyxml_free_elem(ctx, node);
4889 } else if (module->type && !strcmp(node->name, "belongs-to")) {
4890 if (belongsto_flag) {
4891 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4892 goto error;
4893 }
4894 belongsto_flag = 1;
4895 GETVAL(value, node, "module");
4896 while (submodule->belongsto->type) {
4897 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
4898 }
4899 if (value != submodule->belongsto->name) {
4900 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
4901 goto error;
4902 }
Radek Krejcif3886932015-06-04 17:36:06 +02004903
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004904 /* get the prefix substatement, start with checks */
4905 if (!node->child) {
4906 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
4907 goto error;
4908 } else if (strcmp(node->child->name, "prefix")) {
4909 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
4910 goto error;
4911 } else if (node->child->next) {
4912 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
4913 goto error;
4914 }
4915 /* and now finally get the value */
4916 GETVAL(value, node->child, "value");
4917 /* check here differs from a generic prefix check, since this prefix
4918 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02004919 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004920 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
4921 goto error;
4922 }
4923 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02004924
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004925 /* we are done with belongs-to */
4926 lyxml_free_elem(ctx, node);
Radek Krejcieb00f512015-07-01 16:44:58 +02004927
4928 /* counters (statements with n..1 cardinality) */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004929 } else if (!strcmp(node->name, "import")) {
4930 c_imp++;
4931 } else if (!strcmp(node->name, "revision")) {
4932 c_rev++;
4933 } else if (!strcmp(node->name, "typedef")) {
4934 c_tpdf++;
4935 } else if (!strcmp(node->name, "identity")) {
4936 c_ident++;
4937 } else if (!strcmp(node->name, "include")) {
4938 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004939 } else if (!strcmp(node->name, "augment")) {
4940 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004941 } else if (!strcmp(node->name, "feature")) {
4942 c_ftrs++;
Radek Krejcieb00f512015-07-01 16:44:58 +02004943 } else if (!strcmp(node->name, "deviation")) {
4944 c_dev++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004945
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004946 /* data statements */
4947 } else if (!strcmp(node->name, "container") ||
4948 !strcmp(node->name, "leaf-list") ||
4949 !strcmp(node->name, "leaf") ||
4950 !strcmp(node->name, "list") ||
4951 !strcmp(node->name, "choice") ||
4952 !strcmp(node->name, "uses") ||
4953 !strcmp(node->name, "anyxml")) {
4954 lyxml_unlink_elem(node);
4955 lyxml_add_child(&root, node);
4956 } else if (!strcmp(node->name, "grouping")) {
4957 /* keep groupings separated and process them before other data statements */
4958 lyxml_unlink_elem(node);
4959 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004960
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004961 /* optional statements */
4962 } else if (!strcmp(node->name, "description")) {
4963 if (module->dsc) {
4964 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4965 goto error;
4966 }
4967 module->dsc = read_yin_subnode(ctx, node, "text");
4968 lyxml_free_elem(ctx, node);
4969 if (!module->dsc) {
4970 goto error;
4971 }
4972 } else if (!strcmp(node->name, "reference")) {
4973 if (module->ref) {
4974 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4975 goto error;
4976 }
4977 module->ref = read_yin_subnode(ctx, node, "text");
4978 lyxml_free_elem(ctx, node);
4979 if (!module->ref) {
4980 goto error;
4981 }
4982 } else if (!strcmp(node->name, "organization")) {
4983 if (module->org) {
4984 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4985 goto error;
4986 }
4987 module->org = read_yin_subnode(ctx, node, "text");
4988 lyxml_free_elem(ctx, node);
4989 if (!module->org) {
4990 goto error;
4991 }
4992 } else if (!strcmp(node->name, "contact")) {
4993 if (module->contact) {
4994 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
4995 goto error;
4996 }
4997 module->contact = read_yin_subnode(ctx, node, "text");
4998 lyxml_free_elem(ctx, node);
4999 if (!module->contact) {
5000 goto error;
5001 }
5002 } else if (!strcmp(node->name, "yang-version")) {
5003 /* TODO: support YANG 1.1 ? */
5004 if (module->version) {
5005 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5006 goto error;
5007 }
5008 GETVAL(value, node, "value");
5009 if (strcmp(value, "1")) {
5010 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
5011 goto error;
5012 }
5013 module->version = 1;
5014 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02005015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005016 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02005017 } else if (!strcmp(node->name, "rpc")) {
5018 lyxml_unlink_elem(node);
5019 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02005020 } else if (!strcmp(node->name, "notification")) {
5021 lyxml_unlink_elem(node);
5022 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02005023#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005024 } else {
5025 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
5026 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02005027#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005028 } else {
5029 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02005030#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005031 }
5032 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005033
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005034 if (!submodule) {
5035 /* check for mandatory statements */
5036 if (!module->ns) {
5037 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
5038 goto error;
5039 }
5040 if (!module->prefix) {
5041 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
5042 goto error;
5043 }
5044 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02005045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005046 /* allocate arrays for elements with cardinality of 0..n */
5047 if (c_imp) {
5048 module->imp = calloc(c_imp, sizeof *module->imp);
5049 }
5050 if (c_rev) {
5051 module->rev = calloc(c_rev, sizeof *module->rev);
5052 }
5053 if (c_tpdf) {
5054 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
5055 }
5056 if (c_ident) {
5057 module->ident = calloc(c_ident, sizeof *module->ident);
5058 }
5059 if (c_inc) {
5060 module->inc = calloc(c_inc, sizeof *module->inc);
5061 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005062 if (c_aug) {
5063 module->augment = calloc(c_aug, sizeof *module->augment);
5064 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005065 if (c_ftrs) {
5066 module->features = calloc(c_ftrs, sizeof *module->features);
5067 }
Radek Krejcieb00f512015-07-01 16:44:58 +02005068 if (c_dev) {
5069 module->deviation = calloc(c_dev, sizeof *module->deviation);
5070 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005071
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005072 /* middle part - process nodes with cardinality of 0..n except the data nodes */
5073 LY_TREE_FOR_SAFE(yin->child, next, node) {
5074 if (!strcmp(node->name, "import")) {
5075 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
5076 module->imp_size++;
5077 if (r) {
5078 goto error;
5079 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005081 /* check duplicities in imported modules */
5082 for (i = 0; i < module->imp_size - 1; i++) {
5083 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
5084 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
5085 goto error;
5086 }
5087 }
5088 } else if (!strcmp(node->name, "include")) {
5089 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
5090 module->inc_size++;
5091 if (r) {
5092 goto error;
5093 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005094
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005095 /* check duplications in include submodules */
5096 for (i = 0; i < module->inc_size - 1; i++) {
5097 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
5098 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
5099 module->inc[i].submodule->name);
5100 goto error;
5101 }
5102 }
5103 } else if (!strcmp(node->name, "revision")) {
5104 GETVAL(value, node, "date");
5105 if (check_date(value, LOGLINE(node))) {
5106 goto error;
5107 }
5108 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5109 /* check uniqueness of the revision date - not required by RFC */
5110 for (i = 0; i < module->rev_size; i++) {
5111 if (!strcmp(value, module->rev[i].date)) {
5112 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5113 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
5114 }
5115 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005116
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005117 LY_TREE_FOR(node->child, child) {
5118 if (!strcmp(child->name, "description")) {
5119 if (module->rev[module->rev_size].dsc) {
5120 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5121 goto error;
5122 }
5123 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
5124 if (!module->rev[module->rev_size].dsc) {
5125 goto error;
5126 }
5127 } else if (!strcmp(child->name, "reference")) {
5128 if (module->rev[module->rev_size].ref) {
5129 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5130 goto error;
5131 }
5132 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
5133 if (!module->rev[module->rev_size].ref) {
5134 goto error;
5135 }
5136 } else {
5137 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
5138 goto error;
5139 }
5140 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005141
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005142 /* keep the latest revision at position 0 */
5143 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
5144 /* switch their position */
5145 value = strdup(module->rev[0].date);
5146 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
5147 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5148 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02005149
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005150 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
5151 value = module->rev[0].dsc;
5152 module->rev[0].dsc = module->rev[module->rev_size].dsc;
5153 module->rev[module->rev_size].dsc = value;
5154 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005155
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005156 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
5157 value = module->rev[0].ref;
5158 module->rev[0].ref = module->rev[module->rev_size].ref;
5159 module->rev[module->rev_size].ref = value;
5160 }
5161 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005163 module->rev_size++;
5164 } else if (!strcmp(node->name, "typedef")) {
5165 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
5166 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02005167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005168 if (r) {
5169 goto error;
5170 }
5171 } else if (!strcmp(node->name, "identity")) {
5172 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
5173 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02005174
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005175 if (r) {
5176 goto error;
5177 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005178 } else if (!strcmp(node->name, "feature")) {
5179 r = fill_yin_feature(module, node, &module->features[module->features_size]);
5180 module->features_size++;
5181
5182 if (r) {
5183 goto error;
5184 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005185 } else if (!strcmp(node->name, "augment")) {
5186 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
5187 module->augment_size++;
5188
5189 if (r) {
5190 goto error;
5191 }
5192
5193 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
5194 continue;
Radek Krejcieb00f512015-07-01 16:44:58 +02005195 } else if (!strcmp(node->name, "deviation")) {
5196 r = fill_yin_deviation(module, node, &module->deviation[module->deviation_size]);
5197 module->deviation_size++;
5198
5199 if (r) {
5200 goto error;
5201 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005202 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005204 lyxml_free_elem(ctx, node);
5205 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005206
Radek Krejcif5be10f2015-06-16 13:29:36 +02005207 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005208 * refer to them
5209 */
5210 LY_TREE_FOR_SAFE(grps.child, next, node) {
5211 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
5212 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02005213
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005214 if (!mnode) {
5215 goto error;
5216 }
Radek Krejci74705112015-06-05 10:25:44 +02005217
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005218 /* include data element */
5219 if (module->data) {
5220 module->data->prev->next = mnode;
5221 mnode->prev = module->data->prev;
5222 module->data->prev = mnode;
5223 } else {
5224 module->data = mnode;
5225 }
5226 }
5227 while (unres) {
5228 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
5229 goto error;
5230 }
5231 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
5232 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
5233 goto error;
5234 }
5235 unres_next = unres->next;
5236 free(unres);
5237 unres = unres_next;
5238 }
Radek Krejci74705112015-06-05 10:25:44 +02005239
Radek Krejcif5be10f2015-06-16 13:29:36 +02005240 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005241 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02005242
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005243 if (!strcmp(node->name, "container")) {
5244 mnode = read_yin_container(module, NULL, node, 1, &unres);
5245 } else if (!strcmp(node->name, "leaf-list")) {
5246 mnode = read_yin_leaflist(module, NULL, node, 1);
5247 } else if (!strcmp(node->name, "leaf")) {
5248 mnode = read_yin_leaf(module, NULL, node, 1);
5249 } else if (!strcmp(node->name, "list")) {
5250 mnode = read_yin_list(module, NULL, node, 1, &unres);
5251 } else if (!strcmp(node->name, "choice")) {
5252 mnode = read_yin_choice(module, NULL, node, 1, &unres);
5253 } else if (!strcmp(node->name, "uses")) {
5254 mnode = read_yin_uses(module, NULL, node, 1, &unres);
5255 } else if (!strcmp(node->name, "anyxml")) {
5256 mnode = read_yin_anyxml(module, NULL, node, 1);
5257 }
5258 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005259
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005260 if (!mnode) {
5261 goto error;
5262 }
Radek Krejci25d782a2015-05-22 15:03:23 +02005263
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005264 /* include data element */
5265 if (module->data) {
5266 module->data->prev->next = mnode;
5267 mnode->prev = module->data->prev;
5268 module->data->prev = mnode;
5269 } else {
5270 module->data = mnode;
5271 }
5272 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005273
5274 /* ... rpcs ... */
5275 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
5276 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
5277 lyxml_free_elem(ctx, node);
5278
5279 if (!mnode) {
5280 goto error;
5281 }
5282
5283 /* include rpc element */
5284 if (module->rpc) {
5285 module->rpc->prev->next = mnode;
5286 mnode->prev = module->rpc->prev;
5287 module->rpc->prev = mnode;
5288 } else {
5289 module->rpc = mnode;
5290 }
5291 }
5292
5293 /* ... and notifications */
5294 LY_TREE_FOR_SAFE(notifs.child, next, node) {
5295 mnode = read_yin_notif(module, NULL, node, 0, &unres);
5296 lyxml_free_elem(ctx, node);
5297
5298 if (!mnode) {
5299 goto error;
5300 }
5301
5302 /* include notification element */
5303 if (module->notif) {
5304 module->notif->prev->next = mnode;
5305 mnode->prev = module->notif->prev;
5306 module->notif->prev = mnode;
5307 } else {
5308 module->notif = mnode;
5309 }
5310 }
5311
5312 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005313 while (unres) {
5314 /* find referenced grouping */
5315 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
5316 goto error;
5317 }
5318 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
5319 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
5320 goto error;
5321 }
Radek Krejci74705112015-06-05 10:25:44 +02005322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005323 /* resolve uses by copying grouping content under the uses */
5324 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
5325 goto error;
5326 }
Radek Krejci74705112015-06-05 10:25:44 +02005327
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005328 unres_next = unres->next;
5329 free(unres);
5330 unres = unres_next;
5331 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005332
Radek Krejcif5be10f2015-06-16 13:29:36 +02005333 /* and finally apply augments */
5334 for (i = 0; i < module->augment_size; i++) {
5335 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005336 goto error;
5337 }
Michal Vasko0ea41032015-06-16 08:53:55 +02005338 }
5339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005340 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02005341
5342error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005343 /* cleanup */
5344 while (root.child) {
5345 lyxml_free_elem(module->ctx, root.child);
5346 }
5347 while (grps.child) {
5348 lyxml_free_elem(module->ctx, grps.child);
5349 }
5350 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005351 lyxml_free_elem(module->ctx, rpcs.child);
5352 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005353
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005354 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02005355}
5356
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005357struct ly_submodule *
5358yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005359{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005360 struct lyxml_elem *yin;
5361 struct ly_submodule *submodule = NULL;
5362 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02005363
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005364 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02005365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005366 yin = lyxml_read(module->ctx, data, 0);
5367 if (!yin) {
5368 return NULL;
5369 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005370
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005371 /* check root element */
5372 if (!yin->name || strcmp(yin->name, "submodule")) {
5373 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5374 goto error;
5375 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005376
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005377 GETVAL(value, yin, "name");
5378 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5379 goto error;
5380 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005381
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005382 submodule = calloc(1, sizeof *submodule);
5383 if (!submodule) {
5384 LOGMEM;
5385 goto error;
5386 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005387
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005388 submodule->ctx = module->ctx;
5389 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
5390 submodule->type = 1;
5391 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02005392
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005393 LOGVRB("reading submodule %s", submodule->name);
5394 if (read_sub_module((struct ly_module *)submodule, yin)) {
5395 goto error;
5396 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005397
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005398 /* cleanup */
5399 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02005400
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005401 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02005402
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005403 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02005404
5405error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005406 /* cleanup */
5407 lyxml_free_elem(module->ctx, yin);
5408 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02005409
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005410 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02005411}
5412
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005413struct ly_module *
5414yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005415{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005416 struct lyxml_elem *yin;
5417 struct ly_module *module = NULL, **newlist = NULL;
5418 const char *value;
5419 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02005420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005421 yin = lyxml_read(ctx, data, 0);
5422 if (!yin) {
5423 return NULL;
5424 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005425
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005426 /* check root element */
5427 if (!yin->name || strcmp(yin->name, "module")) {
5428 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5429 goto error;
5430 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005431
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005432 GETVAL(value, yin, "name");
5433 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5434 goto error;
5435 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005436
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005437 module = calloc(1, sizeof *module);
5438 if (!module) {
5439 LOGMEM;
5440 goto error;
5441 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005442
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005443 module->ctx = ctx;
5444 module->name = lydict_insert(ctx, value, strlen(value));
5445 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02005446
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005447 LOGVRB("reading module %s", module->name);
5448 if (read_sub_module(module, yin)) {
5449 goto error;
5450 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005452 /* add to the context's list of modules */
5453 if (ctx->models.used == ctx->models.size) {
5454 newlist = realloc(ctx->models.list, ctx->models.size * 2);
5455 if (!newlist) {
5456 LOGMEM;
5457 goto error;
5458 }
5459 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
5460 newlist[i] = NULL;
5461 }
5462 ctx->models.size *= 2;
5463 ctx->models.list = newlist;
5464 }
5465 for (i = 0; ctx->models.list[i]; i++) {
5466 /* check name (name/revision) and namespace uniqueness */
5467 if (!strcmp(ctx->models.list[i]->name, module->name)) {
5468 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
5469 /* both data models are same, with no revision specified */
5470 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
5471 module->name);
5472 goto error;
5473 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
5474 /* one of the models does not have a revision, so they differs */
5475 continue;
5476 } else {
5477 /* both models have a revision statement which we have to
5478 * compare, revision at position 0 is the last revision
5479 */
5480 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
5481 /* we have the same modules */
5482 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
5483 module->rev[0].date);
5484 goto error;
5485 }
5486 }
5487 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
5488 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
5489 ctx->models.list[i]->name, module->name, module->ns);
5490 goto error;
5491 }
5492 }
5493 ctx->models.list[i] = module;
5494 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005495
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005496 /* cleanup */
5497 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005498
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005499 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005500
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005501 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005502
5503error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005504 /* cleanup */
5505 lyxml_free_elem(ctx, yin);
5506 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005508 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005509}