blob: c512d05c8c9e37f6c8c0a4c0faaa9aaeed1f2cba [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 Krejci6e4ffbb2015-06-16 10:34:41 +020041 LY_IDENT_FEATURE,
42 LY_IDENT_IDENTITY,
43 LY_IDENT_TYPE,
44 LY_IDENT_NODE,
45 LY_IDENT_NAME,
46 LY_IDENT_PREFIX
Radek Krejcice7fb782015-05-29 16:52:34 +020047};
48
Radek Krejciefdd0ce2015-05-26 16:48:29 +020049#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejcida04f4a2015-05-21 12:54:09 +020050
Radek Krejcice7fb782015-05-29 16:52:34 +020051#define GETVAL(value, node, arg) \
52 value = lyxml_get_attr(node, arg, NULL); \
53 if (!value) { \
54 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
55 goto error; \
56 }
57
Radek Krejcib388c152015-06-04 17:03:03 +020058#define OPT_IDENT 0x01
59#define OPT_CONFIG 0x02
60#define OPT_MODULE 0x04
61#define OPT_INHERIT 0x08
62static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
63
Radek Krejci74705112015-06-05 10:25:44 +020064struct mnode_list {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020065 struct ly_mnode *mnode;
66 struct mnode_list *next;
67 unsigned int line;
Radek Krejci74705112015-06-05 10:25:44 +020068};
69
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020070static struct ly_mnode *read_yin_choice(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
71 int resolve, struct mnode_list **unres);
72static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
73 int resolve, struct mnode_list **unres);
74static struct ly_mnode *read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
75 int resolve);
76static struct ly_mnode *read_yin_container(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
77 int resolve, struct mnode_list **unres);
78static struct ly_mnode *read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
79 int resolve);
80static struct ly_mnode *read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
81 int resolve);
82static struct ly_mnode *read_yin_list(struct ly_module *module,struct ly_mnode *parent, struct lyxml_elem *yin,
83 int resolve, struct mnode_list **unres);
84static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
85 int resolve, struct mnode_list **unres);
86static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
87 int resolve, struct mnode_list **unres);
Radek Krejci74705112015-06-05 10:25:44 +020088
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020089static int
90dup_typedef_check(const char *type, struct ly_tpdf *tpdf, int size)
Radek Krejcieac35532015-05-31 19:09:15 +020091{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020092 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020093
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 for (i = 0; i < size; i++) {
95 if (!strcmp(type, tpdf[i].name)) {
96 /* name collision */
97 return EXIT_FAILURE;
98 }
99 }
Radek Krejcieac35532015-05-31 19:09:15 +0200100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200101 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200102}
103
Radek Krejcib05774c2015-06-18 13:52:59 +0200104
105static int
106dup_feature_check(const char *id, struct ly_module *module)
107{
108 int i;
109
110 for (i = 0; i < module->features_size; i++) {
111 if (!strcmp(id, module->features[i].name)) {
112 return EXIT_FAILURE;
113 }
114 }
115}
116
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200117static int
118dup_prefix_check(const char *prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200119{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200120 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200121
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200122 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
123 return EXIT_FAILURE;
124 }
125 for (i = 0; i < module->imp_size; i++) {
126 if (!strcmp(module->imp[i].prefix, prefix)) {
127 return EXIT_FAILURE;
128 }
129 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200131 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200132}
133
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200134static int
135check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
136 struct ly_module *module, struct ly_mnode *parent)
Radek Krejcice7fb782015-05-29 16:52:34 +0200137{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200138 int i;
139 int size;
140 struct ly_tpdf *tpdf;
141 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200142
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200143 assert(id);
Radek Krejcice7fb782015-05-29 16:52:34 +0200144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200145 /* check id syntax */
146 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
147 LOGVAL(VE_INID, line, id, "invalid start character");
148 return EXIT_FAILURE;
149 }
150 for (i = 1; id[i]; i++) {
151 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
152 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
153 LOGVAL(VE_INID, line, id, "invalid character");
154 return EXIT_FAILURE;
155 }
156 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200157
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200158 if (i > 64) {
159 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
160 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200162 switch (type) {
163 case LY_IDENT_NAME:
164 /* check uniqueness of the node within its siblings */
165 if (!parent) {
166 break;
167 }
Radek Krejcib4cf2022015-06-03 14:40:05 +0200168
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200169 LY_TREE_FOR(parent->child, mnode) {
170 if (mnode->name == id) {
171 LOGVAL(VE_INID, line, id, "name duplication");
172 return EXIT_FAILURE;
173 }
174 }
175 break;
176 case LY_IDENT_TYPE:
177 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200178
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200179 /* check collision with the built-in types */
180 if (!strcmp(id, "binary") || !strcmp(id, "bits") ||
181 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
182 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
183 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
184 !strcmp(id, "int8") || !strcmp(id, "int16") ||
185 !strcmp(id, "int32") || !strcmp(id, "int64") ||
186 !strcmp(id, "leafref") || !strcmp(id, "string") ||
187 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
188 !strcmp(id, "uint32") || !strcmp(id, "uint64") || !strcmp(id, "union")) {
189 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
190 return EXIT_FAILURE;
191 }
Radek Krejcieac35532015-05-31 19:09:15 +0200192
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200193 /* check locally scoped typedefs (avoid name shadowing) */
194 for (; parent; parent = parent->parent) {
195 switch (parent->nodetype) {
196 case LY_NODE_CONTAINER:
197 size = ((struct ly_mnode_container *)parent)->tpdf_size;
198 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
199 break;
200 case LY_NODE_LIST:
201 size = ((struct ly_mnode_list *)parent)->tpdf_size;
202 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
203 break;
204 case LY_NODE_GROUPING:
205 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
206 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
207 break;
208 default:
209 continue;
210 }
Radek Krejcieac35532015-05-31 19:09:15 +0200211
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200212 if (dup_typedef_check(id, tpdf, size)) {
213 LOGVAL(VE_DUPID, line, "typedef", id);
214 return EXIT_FAILURE;
215 }
216 }
Radek Krejcieac35532015-05-31 19:09:15 +0200217
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200218 /* check top-level names */
219 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
220 LOGVAL(VE_DUPID, line, "typedef", id);
221 return EXIT_FAILURE;
222 }
Radek Krejcieac35532015-05-31 19:09:15 +0200223
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200224 /* check submodule's top-level names */
225 for (i = 0; i < module->inc_size; i++) {
226 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
227 LOGVAL(VE_DUPID, line, "typedef", id);
228 return EXIT_FAILURE;
229 }
230 }
Radek Krejcieac35532015-05-31 19:09:15 +0200231
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200232 /* check top-level names in the main module */
233 if (module->type) {
234 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
235 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
236 LOGVAL(VE_DUPID, line, "typedef", id);
237 return EXIT_FAILURE;
238 }
239 }
Radek Krejcieac35532015-05-31 19:09:15 +0200240
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200241 break;
242 case LY_IDENT_PREFIX:
243 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200245 if (module->type) {
246 /* go to the main module */
247 module = ((struct ly_submodule *)module)->belongsto;
248 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200249
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200250 /* check the main module itself */
251 if (dup_prefix_check(id, module)) {
252 LOGVAL(VE_DUPID, line, "prefix", id);
253 return EXIT_FAILURE;
254 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200255
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200256 /* and all its submodules */
257 for (i = 0; i < module->inc_size; i++) {
258 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
259 LOGVAL(VE_DUPID, line, "prefix", id);
260 return EXIT_FAILURE;
261 }
262 }
263 break;
Radek Krejcib05774c2015-06-18 13:52:59 +0200264 case LY_IDENT_FEATURE:
265 assert(module);
266
267 /* check feature name uniqness*/
268 if (module->type) {
269 /* check the main module */
270 module = ((struct ly_submodule *)module)->belongsto;
271 }
272
273 /* check features in the main module */
274 if (dup_feature_check(id, module)) {
275 LOGVAL(VE_DUPID, line, "feature", id);
276 return EXIT_FAILURE;
277 }
278
279 /* and all its submodules */
280 for (i = 0; i < module->inc_size; i++) {
281 if (dup_feature_check(id, (struct ly_module *)module->inc[i].submodule)) {
282 LOGVAL(VE_DUPID, line, "feature", id);
283 return EXIT_FAILURE;
284 }
285 }
286 break;
287
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200288 default:
289 /* no check required */
290 break;
291 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200292
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200293 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200294}
295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200296static int
297check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
298 const char *name, int len)
Radek Krejci345ad742015-06-03 11:04:18 +0200299{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200300 char *dup = NULL;
301 int j;
Radek Krejci345ad742015-06-03 11:04:18 +0200302
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200303 /* existence */
304 if (!key) {
305 if (name[len] != '\0') {
306 dup = strdup(name);
307 dup[len] = '\0';
308 name = dup;
309 }
310 LOGVAL(VE_KEY_MISS, line, name);
311 free(dup);
312 return EXIT_FAILURE;
313 }
Radek Krejci345ad742015-06-03 11:04:18 +0200314
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200315 /* uniqueness */
316 for (j = index - 1; j >= 0; j--) {
317 if (list[index] == list[j]) {
318 LOGVAL(VE_KEY_DUP, line, key->name);
319 return EXIT_FAILURE;
320 }
321 }
Radek Krejci345ad742015-06-03 11:04:18 +0200322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200323 /* key is a leaf */
324 if (key->nodetype != LY_NODE_LEAF) {
325 LOGVAL(VE_KEY_NLEAF, line, key->name);
326 return EXIT_FAILURE;
327 }
Radek Krejci345ad742015-06-03 11:04:18 +0200328
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200329 /* type of the leaf is not built-in empty */
330 if (key->type.base == LY_TYPE_EMPTY) {
331 LOGVAL(VE_KEY_TYPE, line, key->name);
332 return EXIT_FAILURE;
333 }
Radek Krejci345ad742015-06-03 11:04:18 +0200334
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200335 /* config attribute is the same as of the list */
336 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
337 LOGVAL(VE_KEY_CONFIG, line, key->name);
338 return EXIT_FAILURE;
339 }
Radek Krejci345ad742015-06-03 11:04:18 +0200340
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200341 return EXIT_SUCCESS;
Radek Krejci345ad742015-06-03 11:04:18 +0200342}
343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200344static int
Radek Krejci3de29a72015-06-16 15:23:03 +0200345check_mandatory(struct ly_mnode *mnode)
346{
347 struct ly_mnode *child;
348
349 assert(mnode);
350
351 if (mnode->flags & LY_NODE_MAND_TRUE) {
352 return EXIT_FAILURE;
353 }
354
Radek Krejcifd0bb0a2015-06-18 13:18:24 +0200355 if (mnode->nodetype == LY_NODE_CASE || mnode->nodetype == LY_NODE_CHOICE) {
356 LY_TREE_FOR(mnode->child, child) {
357 if (check_mandatory(child)) {
358 return EXIT_FAILURE;
359 }
Radek Krejci3de29a72015-06-16 15:23:03 +0200360 }
361 }
362
363 return EXIT_SUCCESS;
364}
365
366static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200367check_default(struct ly_type *type, const char *value)
Radek Krejcieac35532015-05-31 19:09:15 +0200368{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200369 /* TODO - RFC 6020, sec. 7.3.4 */
370 (void)type;
371 (void)value;
372 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200373}
374
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200375static int
376check_date(const char *date, unsigned int line)
Radek Krejcice7fb782015-05-29 16:52:34 +0200377{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200378 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200379
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200380 assert(date);
Radek Krejcice7fb782015-05-29 16:52:34 +0200381
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200382 if (strlen(date) != LY_REV_SIZE - 1) {
383 goto error;
384 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200385
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200386 for (i = 0; i < LY_REV_SIZE - 1; i++) {
387 if (i == 4 || i == 7) {
388 if (date[i] != '-') {
389 goto error;
390 }
391 } else if (!isdigit(date[i])) {
392 goto error;
393 }
394 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200396 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200397
398error:
399
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200400 LOGVAL(VE_INDATE, line, date);
401 return EXIT_FAILURE;
Radek Krejcice7fb782015-05-29 16:52:34 +0200402}
403
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200404static const char *
405read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200406{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200407 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200408
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200409 /* there should be <text> child */
410 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
411 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
412 } else if (node->child->content) {
413 len = strlen(node->child->content);
414 return lydict_insert(ctx, node->child->content, len);
415 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200416
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200417 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
418 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200419}
420
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200421static struct ly_tpdf *
422find_superior_type(const char *name, struct ly_module *module, struct ly_mnode *parent)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200423{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200424 int i, j, found = 0;
425 int prefix_len = 0;
426 const char *qname;
427 struct ly_tpdf *tpdf;
428 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200429
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200430 qname = strchr(name, ':');
Radek Krejcida04f4a2015-05-21 12:54:09 +0200431
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200432 if (!qname) {
433 /* no prefix, try built-in types */
434 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
435 if (!strcmp(ly_types[i].def->name, name)) {
436 return ly_types[i].def;
437 }
438 }
439 qname = name;
440 } else {
441 /* set qname to correct position after colon */
442 prefix_len = qname - name;
443 qname++;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200444
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200445 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
446 /* prefix refers to the current module, ignore it */
447 prefix_len = 0;
448 }
449 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200450
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200451 if (!prefix_len && parent) {
452 /* search in local typedefs */
453 while (parent) {
454 switch (parent->nodetype) {
455 case LY_NODE_CONTAINER:
456 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
457 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
458 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200459
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200460 case LY_NODE_LIST:
461 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
462 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
463 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200464
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200465 case LY_NODE_GROUPING:
466 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
467 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
468 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200469
Radek Krejci3cf9e222015-06-18 11:37:50 +0200470 /* TODO add rpc, notification, input, output */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200471 default:
472 parent = parent->parent;
473 continue;
474 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200475
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200476 for (i = 0; i < tpdf_size; i++) {
477 if (!strcmp(tpdf[i].name, qname)) {
478 return &tpdf[i];
479 }
480 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200481
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200482 parent = parent->parent;
483 }
484 } else if (prefix_len) {
485 /* get module where to search */
486 for (i = 0; i < module->imp_size; i++) {
487 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
488 module = module->imp[i].module;
489 found = 1;
490 break;
491 }
492 }
493 if (!found) {
494 return NULL;
495 }
496 }
497
498 /* search in top level typedefs */
499 for (i = 0; i < module->tpdf_size; i++) {
500 if (!strcmp(module->tpdf[i].name, qname)) {
501 return &module->tpdf[i];
502 }
503 }
504
505 /* search in submodules */
506 for (i = 0; i < module->inc_size; i++) {
507 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
508 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
509 return &module->inc[i].submodule->tpdf[j];
510 }
511 }
512 }
513
514 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200515}
516
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200517static struct ly_ident *
518find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
Radek Krejciefaeba32015-05-27 14:30:57 +0200519{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200520 unsigned int i;
521 struct ly_ident *base_iter;
522 struct ly_ident_der *der;
Radek Krejciefaeba32015-05-27 14:30:57 +0200523
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200524 for (i = 0; i < module->ident_size; i++) {
525 if (!strcmp(basename, module->ident[i].name)) {
526 /* we are done */
Radek Krejciefaeba32015-05-27 14:30:57 +0200527
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200528 if (!ident) {
529 /* just search for type, so do not modify anything, just return
530 * the base identity pointer
531 */
532 return &module->ident[i];
533 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200534
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200535 /* we are resolving identity definition, so now update structures */
536 ident->base = base_iter = &module->ident[i];
Radek Krejciefaeba32015-05-27 14:30:57 +0200537
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200538 while (base_iter) {
539 for (der = base_iter->der; der && der->next; der = der->next);
540 if (der) {
541 der->next = malloc(sizeof *der);
542 der = der->next;
543 } else {
544 ident->base->der = der = malloc(sizeof *der);
545 }
546 der->next = NULL;
547 der->ident = ident;
Radek Krejciefaeba32015-05-27 14:30:57 +0200548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200549 base_iter = base_iter->base;
550 }
551 return ident->base;
552 }
553 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200555 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200556}
557
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200558static struct ly_ident *
559find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200560{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200561 const char *name;
562 int prefix_len = 0;
563 int i, found = 0;
564 struct ly_ident *result;
565 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200567 basename = lyxml_get_attr(node, "name", NULL);
568 if (!basename) {
569 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
570 return NULL;
571 }
Radek Krejci04581c62015-05-22 21:24:00 +0200572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200573 /* search for the base identity */
574 name = strchr(basename, ':');
575 if (name) {
576 /* set name to correct position after colon */
577 prefix_len = name - basename;
578 name++;
Radek Krejci04581c62015-05-22 21:24:00 +0200579
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200580 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
581 /* prefix refers to the current module, ignore it */
582 prefix_len = 0;
583 }
584 } else {
585 name = basename;
586 }
Radek Krejci04581c62015-05-22 21:24:00 +0200587
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200588 if (prefix_len) {
589 /* get module where to search */
590 for (i = 0; i < module->imp_size; i++) {
591 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
592 && !module->imp[i].prefix[prefix_len]) {
593 module = module->imp[i].module;
594 found = 1;
595 break;
596 }
597 }
598 if (!found) {
599 /* identity refers unknown data model */
600 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
601 return NULL;
602 }
603 } else {
604 /* search in submodules */
605 for (i = 0; i < module->inc_size; i++) {
606 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
607 if (result) {
608 return result;
609 }
610 }
611 }
Radek Krejci04581c62015-05-22 21:24:00 +0200612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200613 /* search in the identified module */
614 result = find_base_ident_sub(module, ident, name);
615 if (!result) {
616 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
617 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200619 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200620}
621
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200622static int
623fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
Radek Krejci04581c62015-05-22 21:24:00 +0200624{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200625 struct lyxml_elem *node, *next;
Radek Krejci04581c62015-05-22 21:24:00 +0200626
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200627 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
628 return EXIT_FAILURE;
629 }
Radek Krejci04581c62015-05-22 21:24:00 +0200630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200631 LY_TREE_FOR_SAFE(yin->child, next, node) {
632 if (!strcmp(node->name, "base")) {
633 if (ident->base) {
634 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
635 return EXIT_FAILURE;
636 }
637 if (!find_base_ident(module, ident, node)) {
638 return EXIT_FAILURE;
639 }
640 } else {
641 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
642 return EXIT_FAILURE;
643 }
Radek Krejci04581c62015-05-22 21:24:00 +0200644
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200645 lyxml_free_elem(module->ctx, node);
646 }
Radek Krejci04581c62015-05-22 21:24:00 +0200647
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200648 return EXIT_SUCCESS;
Radek Krejci04581c62015-05-22 21:24:00 +0200649}
650
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200651static int
652fill_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 +0200653{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200654 const char *value, *delim;
655 struct lyxml_elem *next, *node, root;
656 int i, j, r;
657 int64_t v, v_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200658
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200659 /* init */
660 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +0200661
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200662 GETVAL(value, yin, "name")
663 delim = strchr(value, ':');
664 if (delim) {
665 type->prefix = lydict_insert(module->ctx, value, delim - value);
666 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200667
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200668 type->der = find_superior_type(value, module, parent);
669 if (!type->der) {
670 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
671 goto error;
672 }
673 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200674
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200675 switch (type->base) {
676 case LY_TYPE_BINARY:
677 /* TODO length, 9.4.4
678 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
679 * hodnoty se musi vejit do 64b, podelementy
680 */
681 break;
Radek Krejci04581c62015-05-22 21:24:00 +0200682
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200683 case LY_TYPE_BITS:
684 /* TODO bit, 9.7.4
685 * 1..n, nerekurzivni, stringy s podelementy */
686 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200687
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200688 case LY_TYPE_DEC64:
689 /* TODO fraction-digits, 9.3.4
690 * - MUST, 1, nerekurzivni, hodnota 1-18 */
691 /* TODO range, 9.2.4
692 * - optional, 0..1, rekurzivne - omezuje, string, podelementy*/
693 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200694
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200695 case LY_TYPE_ENUM:
696 /* RFC 6020 9.6 */
Radek Krejci25d782a2015-05-22 15:03:23 +0200697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200698 /* get enum specification, at least one must be present */
699 LY_TREE_FOR_SAFE(yin->child, next, node) {
700 if (!strcmp(node->name, "enum")) {
701 lyxml_unlink_elem(node);
702 lyxml_add_child(&root, node);
703 type->info.enums.count++;
704 }
705 }
706 if (yin->child) {
707 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
708 goto error;
709 }
710 if (!type->info.enums.count) {
711 if (type->der->type.der) {
712 /* this is just a derived type with no enum specified */
713 break;
714 }
715 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
716 goto error;
717 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200719 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
720 for (i = v = 0; root.child; i++) {
721 r = read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], root.child, OPT_IDENT);
722 if (r) {
723 type->info.enums.count = i + 1;
724 goto error;
725 }
726 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
727 value = type->info.enums.list[i].name;
728 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
729 LOGVAL(VE_ENUM_WS, LOGLINE(root.child), value);
730 type->info.enums.count = i + 1;
731 goto error;
732 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200734 /* check the name uniqueness */
735 for (j = 0; j < i; j++) {
736 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
737 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(root.child), type->info.enums.list[i].name);
738 type->info.enums.count = i + 1;
739 goto error;
740 }
741 }
Radek Krejci04581c62015-05-22 21:24:00 +0200742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200743 node = root.child->child;
744 if (node && !strcmp(node->name, "value")) {
745 value = lyxml_get_attr(node, "value", NULL);
746 v_ = strtol(value, NULL, 10);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200747
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200748 /* range check */
749 if (v_ < INT32_MIN || v_ > INT32_MAX) {
750 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
751 type->info.enums.count = i + 1;
752 goto error;
753 }
754 type->info.enums.list[i].value = v_;
755
756 /* keep the highest enum value for automatic increment */
757 if (type->info.enums.list[i].value > v) {
758 v = type->info.enums.list[i].value;
759 v++;
760 } else {
761 /* check that the value is unique */
762 for (j = 0; j < i; j++) {
763 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
764 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value,
765 type->info.enums.list[i].name);
766 type->info.enums.count = i + 1;
767 goto error;
768 }
769 }
770 }
771 } else {
772 /* assign value automatically */
773 if (v > INT32_MAX) {
774 LOGVAL(VE_INARG, LOGLINE(root.child), "2147483648", "enum/value");
775 type->info.enums.count = i + 1;
776 goto error;
777 }
778 type->info.enums.list[i].value = v;
779 v++;
780 }
781 lyxml_free_elem(module->ctx, root.child);
782 }
783 break;
784
785 case LY_TYPE_IDENT:
786 /* RFC 6020 9.10 */
787
788 /* get base specification, exactly one must be present */
789 if (!yin->child) {
790 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
791 goto error;
792 }
793 if (strcmp(yin->child->name, "base")) {
794 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
795 goto error;
796 }
797 if (yin->child->next) {
798 LOGVAL(VE_INSTMT, LOGLINE(yin->child->next), yin->child->next->name);
799 goto error;
800 }
801 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
802 if (!type->info.ident.ref) {
803 return EXIT_FAILURE;
804 }
805 break;
806
807 case LY_TYPE_INST:
808 /* TODO require-instance, 9.13.2
809 * - 0..1, true/false */
810 break;
811
812 case LY_TYPE_INT8:
813 case LY_TYPE_INT16:
814 case LY_TYPE_INT32:
815 case LY_TYPE_INT64:
816 case LY_TYPE_UINT8:
817 case LY_TYPE_UINT16:
818 case LY_TYPE_UINT32:
819 case LY_TYPE_UINT64:
820 /* TODO range, 9.2.4
821 * - optional, 0..1, i rekurzivne - omezuje, string, podelementy*/
822 break;
823
824 case LY_TYPE_LEAFREF:
825 /* TODO path, 9.9.2
826 * - 1, nerekurzivni, string */
827 break;
828
829 case LY_TYPE_STRING:
830 /* TODO length, 9.4.4
831 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
832 * pattern, 9.4.6
833 * - optional, 0..n, rekurzivni - rozsiruje, string, podelementy */
834 break;
835
836 case LY_TYPE_UNION:
837 /* TODO type, 7.4
838 * - 1..n, nerekurzivni, resp rekurzivni pro union ale bez vazby na predky, nesmi byt empty nebo leafref */
839 break;
840
841 default:
842 /* nothing needed :
843 * LY_TYPE_BOOL, LY_TYPE_EMPTY
844 */
845 break;
846 }
847
848 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +0200849
850error:
851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200852 LY_TREE_FOR_SAFE(root.child, next, node) {
853 lyxml_free_elem(module->ctx, node);
854 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200855
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200856 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200857}
858
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200859static int
860fill_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 +0200861{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200862 const char *value;
863 struct lyxml_elem *node, *next;
864 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200865
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200866 GETVAL(value, yin, "name");
867 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
868 goto error;
869 }
870 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +0200871
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200872 /* generic part - status, description, reference */
873 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
874 goto error;
875 }
Radek Krejcieac35532015-05-31 19:09:15 +0200876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200877 LY_TREE_FOR_SAFE(yin->child, next, node) {
878 if (!strcmp(node->name, "type")) {
879 if (tpdf->type.der) {
880 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
881 goto error;
882 }
883 r = fill_yin_type(module, parent, node, &tpdf->type);
884 } else if (!strcmp(node->name, "default")) {
885 if (tpdf->dflt) {
886 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
887 goto error;
888 }
889 GETVAL(value, node, "value");
890 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
891 } else if (!strcmp(node->name, "units")) {
892 if (tpdf->units) {
893 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
894 goto error;
895 }
896 GETVAL(value, node, "name");
897 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
898 } else {
899 LOGVAL(VE_INSTMT, LOGLINE(node), value);
900 r = 1;
901 }
902 lyxml_free_elem(module->ctx, node);
903 if (r) {
904 goto error;
905 }
906 }
Radek Krejci25d782a2015-05-22 15:03:23 +0200907
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200908 /* check mandatory value */
909 if (!tpdf->type.der) {
910 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
911 goto error;
912 }
Radek Krejcieac35532015-05-31 19:09:15 +0200913
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200914 /* check default value */
915 if (check_default(&tpdf->type, tpdf->dflt)) {
916 goto error;
917 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200918
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200919 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200920
921error:
922
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200923 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200924}
925
Radek Krejci3cf9e222015-06-18 11:37:50 +0200926static struct ly_feature *
927resolve_feature(const char *name, struct ly_module *module, unsigned int line)
928{
929 const char *prefix;
930 unsigned int prefix_len = 0;
931 int i, j, found = 0;
932
933 assert(name);
934 assert(module);
935
936 /* check prefix */
937 prefix = name;
938 name = strchr(prefix, ':');
939 if (name) {
940 /* there is prefix */
941 prefix_len = name - prefix;
942 name++;
943
944 /* check whether the prefix points to the current module */
945 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
946 /* then ignore prefix and works as there is no prefix */
947 prefix_len = 0;
948 }
949 } else {
950 /* no prefix, set pointers correctly */
951 name = prefix;
952 }
953
954 if (prefix_len) {
955 /* search in imported modules */
956 for (i = 0; i < module->imp_size; i++) {
957 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
958 module = module->imp[i].module;
959 found = 1;
960 break;
961 }
962 }
963 if (!found) {
964 /* identity refers unknown data model */
965 LOGVAL(VE_INPREFIX, line, prefix);
966 return NULL;
967 }
968 } else {
969 /* search in submodules */
970 for (i = 0; i < module->inc_size; i++) {
971 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
972 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
973 return &(module->inc[i].submodule->features[j]);
974 }
975 }
976 }
977 }
978
979 /* search in the identified module */
980 for (j = 0; j < module->features_size; j++) {
981 if (!strcmp(name, module->features[j].name)) {
982 return &module->features[j];
983 }
984 }
985
986 /* not found */
987 return NULL;
988}
989
990static int
991fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
992{
993 const char *value;
994 struct lyxml_elem *child, *next;
995 int c = 0;
996
Radek Krejcib05774c2015-06-18 13:52:59 +0200997 GETVAL(value, yin, "name");
998 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
999 goto error;
1000 }
1001 f->name = lydict_insert(ctx, value, strlen(value));
1002
1003 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001004 goto error;
1005 }
1006
1007 LY_TREE_FOR_SAFE(yin->child, next, child) {
1008 if (!strcmp(child->name, "if-feature")) {
1009 c++;
1010 } else {
1011 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1012 goto error;
1013 }
1014 }
1015
1016 if (c) {
1017 f->features = calloc(c, sizeof *f->features);
1018 }
1019
1020 LY_TREE_FOR_SAFE(yin->child, next, child) {
1021 GETVAL(value, child, "name");
1022 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1023 if (!f->features[f->features_size]) {
1024 goto error;
1025 }
1026 f->features_size++;
1027 }
1028
1029 /* tmp TODO remove */
1030 f->flags |= LY_NODE_FENABLED;
1031
1032 return EXIT_SUCCESS;
1033
1034error:
1035
1036 return EXIT_FAILURE;
1037}
1038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001039static int
1040fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
Radek Krejci800af702015-06-02 13:46:01 +02001041{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001042 struct lyxml_elem *child, *next;
1043 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001044
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001045 GETVAL(value, yin, "condition");
1046 must->cond = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001047
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001048 LY_TREE_FOR_SAFE(yin->child, next, child) {
1049 if (!strcmp(child->name, "description")) {
1050 if (must->dsc) {
1051 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1052 goto error;
1053 }
1054 must->dsc = read_yin_subnode(module->ctx, child, "text");
1055 if (!must->dsc) {
1056 goto error;
1057 }
1058 } else if (!strcmp(child->name, "reference")) {
1059 if (must->ref) {
1060 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1061 goto error;
1062 }
1063 must->ref = read_yin_subnode(module->ctx, child, "text");
1064 if (!must->ref) {
1065 goto error;
1066 }
1067 } else if (!strcmp(child->name, "error-app-tag")) {
1068 if (must->eapptag) {
1069 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1070 goto error;
1071 }
1072 must->eapptag = read_yin_subnode(module->ctx, child, "value");
1073 if (!must->eapptag) {
1074 goto error;
1075 }
1076 } else if (!strcmp(child->name, "error-message")) {
1077 if (must->emsg) {
1078 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1079 goto error;
1080 }
1081 must->emsg = read_yin_subnode(module->ctx, child, "value");
1082 if (!must->emsg) {
1083 goto error;
1084 }
1085 } else {
1086 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1087 goto error;
1088 }
Radek Krejci800af702015-06-02 13:46:01 +02001089
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001090 lyxml_free_elem(module->ctx, child);
1091 }
Radek Krejci800af702015-06-02 13:46:01 +02001092
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001093 return EXIT_SUCCESS;
Radek Krejci800af702015-06-02 13:46:01 +02001094
1095error:
1096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001097 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001098}
1099
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001100static int
1101fill_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 +02001102{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001103 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001104 struct lyxml_elem *next, *child;
1105 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02001106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001107 GETVAL(value, yin, "target-node");
1108 aug->target_name = lydict_insert(module->ctx, value, 0);
1109 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02001110
Radek Krejci3cf9e222015-06-18 11:37:50 +02001111 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, 0)) {
1112 goto error;
1113 }
1114
1115 LY_TREE_FOR_SAFE(yin->child, next, child) {
1116 if (!strcmp(child->name, "if-feature")) {
1117 c++;
1118 /* TODO when */
1119
1120 /* check allowed sub-statements */
1121 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
1122 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
1123 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
1124 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1125 goto error;
1126 }
1127 }
1128
1129 if (c) {
1130 aug->features = calloc(c, sizeof *aug->features);
1131 }
1132
1133 LY_TREE_FOR_SAFE(yin->child, next, child) {
1134 if (!strcmp(child->name, "if-feature")) {
1135 GETVAL(value, child, "name");
1136 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
1137 if (!aug->features[aug->features_size]) {
1138 goto error;
1139 }
1140 aug->features_size++;
1141 } else {
1142 /* keep the data nodes */
1143 continue;
1144 }
1145
1146 lyxml_free_elem(module->ctx, child);
1147 }
1148
1149 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001150 * when we will have the target node
1151 */
1152 lyxml_unlink_elem(yin);
1153 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02001154
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001155 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02001156
1157error:
1158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001159 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02001160}
1161
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001162static int
1163fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02001164{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001165 struct lyxml_elem *sub, *next;
1166 const char *value;
1167 char *endptr;
1168 int f_mand = 0, f_min = 0, f_max = 0;
1169 int c_must = 0;
1170 int r;
1171 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001173 GETVAL(value, yin, "target-node");
1174 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02001175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001176 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
1177 goto error;
1178 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001180 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1181 /* limited applicability */
1182 if (!strcmp(sub->name, "default")) {
1183 /* leaf or choice */
1184 if (rfn->mod.dflt) {
1185 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1186 goto error;
1187 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001188
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001189 /* check possibility of statements combination */
1190 if (rfn->target_type) {
1191 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
1192 if (!rfn->target_type) {
1193 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1194 goto error;
1195 }
1196 } else {
1197 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
1198 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001199
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001200 GETVAL(value, sub, "value");
1201 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
1202 } else if (!strcmp(sub->name, "mandatory")) {
1203 /* leaf, choice or anyxml */
1204 if (f_mand) {
1205 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1206 goto error;
1207 }
1208 /* just checking the flags in leaf is not sufficient, we would allow
1209 * multiple mandatory statements with the "false" value
1210 */
1211 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001212
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001213 /* check possibility of statements combination */
1214 if (rfn->target_type) {
1215 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
1216 if (!rfn->target_type) {
1217 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1218 goto error;
1219 }
1220 } else {
1221 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
1222 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001223
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001224 GETVAL(value, sub, "value");
1225 if (!strcmp(value, "true")) {
1226 rfn->flags |= LY_NODE_MAND_TRUE;
1227 } else if (!strcmp(value, "false")) {
1228 rfn->flags |= LY_NODE_MAND_FALSE;
1229 } else {
1230 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1231 goto error;
1232 }
1233 } else if (!strcmp(sub->name, "min-elements")) {
1234 /* list or leaf-list */
1235 if (f_min) {
1236 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1237 goto error;
1238 }
1239 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001240
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001241 /* check possibility of statements combination */
1242 if (rfn->target_type) {
1243 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1244 if (!rfn->target_type) {
1245 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1246 goto error;
1247 }
1248 } else {
1249 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1250 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001251
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001252 GETVAL(value, sub, "value");
1253 while (isspace(value[0])) {
1254 value++;
1255 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001256
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001257 /* convert it to uint32_t */
1258 errno = 0;
1259 endptr = NULL;
1260 val = strtoul(value, &endptr, 10);
1261 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1262 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1263 goto error;
1264 }
1265 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001266
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001267 /* magic - bit 3 in flags means min set */
1268 rfn->flags |= 0x04;
1269 } else if (!strcmp(sub->name, "max-elements")) {
1270 /* list or leaf-list */
1271 if (f_max) {
1272 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1273 goto error;
1274 }
1275 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001276
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001277 /* check possibility of statements combination */
1278 if (rfn->target_type) {
1279 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
1280 if (!rfn->target_type) {
1281 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1282 goto error;
1283 }
1284 } else {
1285 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
1286 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001287
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001288 GETVAL(value, sub, "value");
1289 while (isspace(value[0])) {
1290 value++;
1291 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001292
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001293 /* convert it to uint32_t */
1294 errno = 0;
1295 endptr = NULL;
1296 val = strtoul(value, &endptr, 10);
1297 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
1298 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1299 goto error;
1300 }
1301 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001302
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001303 /* magic - bit 4 in flags means min set */
1304 rfn->flags |= 0x08;
1305 } else if (!strcmp(sub->name, "presence")) {
1306 /* container */
1307 if (rfn->mod.presence) {
1308 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1309 goto error;
1310 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001311
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001312 /* check possibility of statements combination */
1313 if (rfn->target_type) {
1314 rfn->target_type &= LY_NODE_CONTAINER;
1315 if (!rfn->target_type) {
1316 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1317 goto error;
1318 }
1319 } else {
1320 rfn->target_type = LY_NODE_CONTAINER;
1321 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001322
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001323 GETVAL(value, sub, "value");
1324 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
1325 } else if (!strcmp(sub->name, "must")) {
1326 /* leaf-list, list, container or anyxml */
1327 /* check possibility of statements combination */
1328 if (rfn->target_type) {
1329 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
1330 if (!rfn->target_type) {
1331 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
1332 goto error;
1333 }
1334 } else {
1335 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
1336 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001337
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001338 c_must++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001340 } else {
1341 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1342 goto error;
1343 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001344
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001345 lyxml_free_elem(module->ctx, sub);
1346 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001347
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001348 /* process nodes with cardinality of 0..n */
1349 if (c_must) {
1350 rfn->must = calloc(c_must, sizeof *rfn->must);
1351 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001352
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001353 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1354 if (!strcmp(sub->name, "must")) {
1355 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
1356 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001357
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001358 if (r) {
1359 goto error;
1360 }
1361 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001362
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001363 lyxml_free_elem(module->ctx, sub);
1364 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02001365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001366 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001367
1368error:
1369
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001370 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02001371}
1372
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001373static int
1374fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02001375{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001376 struct lyxml_elem *child;
1377 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001378
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001379 LY_TREE_FOR(yin->child, child) {
1380 if (!strcmp(child->name, "prefix")) {
1381 GETVAL(value, child, "value");
1382 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
1383 goto error;
1384 }
1385 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
1386 } else if (!strcmp(child->name, "revision-date")) {
1387 if (imp->rev[0]) {
1388 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1389 goto error;
1390 }
1391 GETVAL(value, child, "date");
1392 if (check_date(value, LOGLINE(child))) {
1393 goto error;
1394 }
1395 memcpy(imp->rev, value, LY_REV_SIZE - 1);
1396 } else {
1397 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1398 goto error;
1399 }
1400 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001401
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001402 /* check mandatory information */
1403 if (!imp->prefix) {
1404 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
1405 goto error;
1406 }
Radek Krejcice7fb782015-05-29 16:52:34 +02001407
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001408 GETVAL(value, yin, "module");
1409 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
1410 if (!imp->module) {
1411 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
1412 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1413 goto error;
1414 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001415
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001416 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001417
1418error:
1419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001420 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001421}
1422
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001423static int
1424fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02001425{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001426 struct lyxml_elem *child;
1427 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02001428
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001429 LY_TREE_FOR(yin->child, child) {
1430 if (!strcmp(child->name, "revision-date")) {
1431 if (inc->rev[0]) {
1432 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
1433 goto error;
1434 }
1435 GETVAL(value, child, "date");
1436 if (check_date(value, LOGLINE(child))) {
1437 goto error;
1438 }
1439 memcpy(inc->rev, value, LY_REV_SIZE - 1);
1440 } else {
1441 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1442 goto error;
1443 }
1444 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001445
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001446 GETVAL(value, yin, "module");
1447 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL);
1448 if (!inc->submodule) {
1449 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
1450 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1451 goto error;
1452 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001453
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001454 /* check that belongs-to corresponds */
1455 if (module->type) {
1456 module = ((struct ly_submodule *)module)->belongsto;
1457 }
1458 if (inc->submodule->belongsto != module) {
1459 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
1460 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
1461 goto error;
1462 }
Radek Krejciefaeba32015-05-27 14:30:57 +02001463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001464 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02001465
1466error:
1467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001468 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02001469}
1470
Radek Krejcida04f4a2015-05-21 12:54:09 +02001471/*
1472 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02001473 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02001474 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02001475 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001476static int
1477read_yin_common(struct ly_module *module, struct ly_mnode *parent,
1478 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001479{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001480 const char *value;
1481 struct lyxml_elem *sub, *next;
1482 struct ly_ctx *const ctx = module->ctx;
1483 int r = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001484
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001485 if (opt & OPT_MODULE) {
1486 mnode->module = module;
1487 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001488
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001489 if (opt & OPT_IDENT) {
1490 GETVAL(value, xmlnode, "name");
1491 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
1492 goto error;
1493 }
1494 mnode->name = lydict_insert(ctx, value, strlen(value));
1495 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001496
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001497 /* process local parameters */
1498 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
1499 if (!strcmp(sub->name, "description")) {
1500 if (mnode->dsc) {
1501 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1502 goto error;
1503 }
1504 mnode->dsc = read_yin_subnode(ctx, sub, "text");
1505 if (!mnode->dsc) {
1506 r = 1;
1507 }
1508 } else if (!strcmp(sub->name, "reference")) {
1509 if (mnode->ref) {
1510 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1511 goto error;
1512 }
1513 mnode->ref = read_yin_subnode(ctx, sub, "text");
1514 if (!mnode->ref) {
1515 r = 1;
1516 }
1517 } else if (!strcmp(sub->name, "status")) {
1518 if (mnode->flags & LY_NODE_STATUS_MASK) {
1519 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1520 goto error;
1521 }
1522 GETVAL(value, sub, "value");
1523 if (!strcmp(value, "current")) {
1524 mnode->flags |= LY_NODE_STATUS_CURR;
1525 } else if (!strcmp(value, "deprecated")) {
1526 mnode->flags |= LY_NODE_STATUS_DEPRC;
1527 } else if (!strcmp(value, "obsolete")) {
1528 mnode->flags |= LY_NODE_STATUS_OBSLT;
1529 } else {
1530 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1531 r = 1;
1532 }
1533 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
1534 if (mnode->flags & LY_NODE_CONFIG_MASK) {
1535 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
1536 goto error;
1537 }
1538 GETVAL(value, sub, "value");
1539 if (!strcmp(value, "false")) {
1540 mnode->flags |= LY_NODE_CONFIG_R;
1541 } else if (!strcmp(value, "true")) {
1542 mnode->flags |= LY_NODE_CONFIG_W;
1543 } else {
1544 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1545 r = 1;
1546 }
1547 } else {
1548 /* skip the lyxml_free_elem */
1549 continue;
1550 }
1551 lyxml_free_elem(ctx, sub);
1552 if (r) {
1553 goto error;
1554 }
1555 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001557 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
1558 /* get config flag from parent */
1559 if (parent) {
1560 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1561 } else {
1562 /* default config is true */
1563 mnode->flags |= LY_NODE_CONFIG_W;
1564 }
1565 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001566
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001567 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001568
1569error:
1570
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001571 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001572}
1573
Radek Krejcib4cf2022015-06-03 14:40:05 +02001574/* additional check in case statement - the child must be unique across
1575 * all other case names and its data children
1576 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001577static int
1578check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001579{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001580 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001581
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001582 if (new->nodetype == LY_NODE_CHOICE) {
1583 /* we have nested choice in case, so we need recursion */
1584 LY_TREE_FOR(new->child, mnode) {
1585 if (mnode->nodetype == LY_NODE_CASE) {
1586 LY_TREE_FOR(mnode->child, submnode) {
1587 if (check_branch_id(parent, submnode, new, line)) {
1588 return EXIT_FAILURE;
1589 }
1590 }
1591 } else if (check_branch_id(parent, mnode, new, line)) {
1592 return EXIT_FAILURE;
1593 }
1594 }
1595 } else {
1596 LY_TREE_FOR(parent->child, mnode) {
1597 if (mnode == excl) {
1598 continue;
1599 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001601 if (!strcmp(new->name, mnode->name)) {
1602 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1603 return EXIT_FAILURE;
1604 }
1605 if (mnode->nodetype == LY_NODE_CASE) {
1606 LY_TREE_FOR(mnode->child, submnode) {
1607 if (!strcmp(new->name, submnode->name)) {
1608 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
1609 return EXIT_FAILURE;
1610 }
1611 }
1612 }
1613 }
1614 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001615
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001616 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001617}
1618
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001619static struct ly_mnode *
1620read_yin_case(struct ly_module *module,
1621 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02001622{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001623 struct lyxml_elem *sub, *next;
1624 struct ly_mnode_case *mcase;
1625 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001626 int c_ftrs = 0;
1627 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001628
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001629 mcase = calloc(1, sizeof *mcase);
1630 mcase->nodetype = LY_NODE_CASE;
1631 mcase->prev = (struct ly_mnode *)mcase;
1632 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001633
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001634 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT)) {
1635 goto error;
1636 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001637
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001638 /* process choice's specific children */
1639 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1640 if (!strcmp(sub->name, "container")) {
1641 mnode = read_yin_container(module, retval, sub, resolve, unres);
1642 } else if (!strcmp(sub->name, "leaf-list")) {
1643 mnode = read_yin_leaflist(module, retval, sub, resolve);
1644 } else if (!strcmp(sub->name, "leaf")) {
1645 mnode = read_yin_leaf(module, retval, sub, resolve);
1646 } else if (!strcmp(sub->name, "list")) {
1647 mnode = read_yin_list(module, retval, sub, resolve, unres);
1648 } else if (!strcmp(sub->name, "uses")) {
1649 mnode = read_yin_uses(module, retval, sub, resolve, unres);
1650 } else if (!strcmp(sub->name, "choice")) {
1651 mnode = read_yin_choice(module, retval, sub, resolve, unres);
1652 } else if (!strcmp(sub->name, "anyxml")) {
1653 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02001654 } else if (!strcmp(sub->name, "if-feature")) {
1655 c_ftrs++;
1656
1657 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
1658 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001659#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001660 } else {
1661 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1662 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001663#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001664 } else {
1665 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001666#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001667 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001669 if (!mnode) {
1670 goto error;
1671 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
1672 goto error;
1673 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001674
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001675 mnode = NULL;
1676 lyxml_free_elem(module->ctx, sub);
1677 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001678
Radek Krejci3cf9e222015-06-18 11:37:50 +02001679 if (c_ftrs) {
1680 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
1681 }
1682 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1683 GETVAL(value, sub, "name");
1684 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
1685 if (!mcase->features[mcase->features_size]) {
1686 goto error;
1687 }
1688 mcase->features_size++;
1689 lyxml_free_elem(module->ctx, sub);
1690 }
1691
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001692 /* inherit config flag */
1693 if (parent) {
1694 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
1695 } else {
1696 /* default config is true */
1697 retval->flags |= LY_NODE_CONFIG_W;
1698 }
Radek Krejcib388c152015-06-04 17:03:03 +02001699
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001700 /* insert the node into the schema tree */
1701 if (ly_mnode_addchild(parent, retval)) {
1702 goto error;
1703 }
Radek Krejcib7155b52015-06-10 17:03:01 +02001704
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001705 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001706
1707error:
1708
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001709 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02001710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001711 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001712}
1713
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001714static struct ly_mnode *
1715read_yin_choice(struct ly_module *module,
1716 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001717{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001718 struct lyxml_elem *sub, *next;
1719 struct ly_ctx *const ctx = module->ctx;
1720 struct ly_mnode *retval, *mnode = NULL;
1721 struct ly_mnode_choice *choice;
1722 const char *value;
1723 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001724 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001725
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001726 choice = calloc(1, sizeof *choice);
1727 choice->nodetype = LY_NODE_CHOICE;
1728 choice->prev = (struct ly_mnode *)choice;
1729 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001730
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001731 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
1732 goto error;
1733 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001734
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001735 /* process choice's specific children */
1736 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1737 if (!strcmp(sub->name, "container")) {
1738 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
1739 goto error;
1740 }
1741 } else if (!strcmp(sub->name, "leaf-list")) {
1742 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
1743 goto error;
1744 }
1745 } else if (!strcmp(sub->name, "leaf")) {
1746 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
1747 goto error;
1748 }
1749 } else if (!strcmp(sub->name, "list")) {
1750 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
1751 goto error;
1752 }
1753 } else if (!strcmp(sub->name, "case")) {
1754 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
1755 goto error;
1756 }
1757 } else if (!strcmp(sub->name, "anyxml")) {
1758 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
1759 goto error;
1760 }
1761 } else if (!strcmp(sub->name, "default")) {
1762 if (dflt_str) {
1763 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1764 goto error;
1765 }
1766 GETVAL(value, sub, "value");
1767 dflt_str = strdup(value);
1768 } else if (!strcmp(sub->name, "mandatory")) {
1769 if (f_mand) {
1770 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1771 goto error;
1772 }
1773 /* just checking the flags in leaf is not sufficient, we would allow
1774 * multiple mandatory statements with the "false" value
1775 */
1776 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001777
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001778 GETVAL(value, sub, "value");
1779 if (!strcmp(value, "true")) {
1780 choice->flags |= LY_NODE_MAND_TRUE;
1781 } else if (strcmp(value, "false")) {
1782 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1783 goto error;
1784 } /* else false is the default value, so we can ignore it */
Radek Krejci3cf9e222015-06-18 11:37:50 +02001785 } else if (!strcmp(sub->name, "if-feature")) {
1786 c_ftrs++;
1787
1788 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
1789 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001790#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001791 } else {
1792 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1793 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001794#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001795 } else {
1796 continue;
Radek Krejcib4cf2022015-06-03 14:40:05 +02001797#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001798 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001800 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
1801 goto error;
1802 }
1803 mnode = NULL;
1804 lyxml_free_elem(ctx, sub);
1805 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001806
Radek Krejci3cf9e222015-06-18 11:37:50 +02001807 if (c_ftrs) {
1808 choice->features = calloc(c_ftrs, sizeof *choice->features);
1809 }
1810
1811 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1812 GETVAL(value, sub, "name");
1813 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
1814 if (!choice->features[choice->features_size]) {
1815 goto error;
1816 }
1817 choice->features_size++;
1818 lyxml_free_elem(ctx, sub);
1819 }
1820
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001821 /* check - default is prohibited in combination with mandatory */
1822 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
1823 LOGVAL(VE_SPEC, LOGLINE(yin),
1824 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
1825 goto error;
1826 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02001827
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001828 /* link default with the case */
1829 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02001830 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001831 if (!choice->dflt) {
1832 /* default branch not found */
1833 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
1834 goto error;
1835 }
1836 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001837
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001838 /* insert the node into the schema tree */
1839 if (parent && ly_mnode_addchild(parent, retval)) {
1840 goto error;
1841 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001842
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001843 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02001844
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001845 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001846
1847error:
1848
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001849 ly_mnode_free(retval);
1850 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02001851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001852 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001853}
1854
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001855static struct ly_mnode *
1856read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02001857{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001858 struct ly_mnode *retval;
1859 struct ly_mnode_leaf *anyxml;
1860 struct lyxml_elem *sub, *next;
1861 const char *value;
1862 int r;
1863 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001864 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02001865
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001866 anyxml = calloc(1, sizeof *anyxml);
1867 anyxml->nodetype = LY_NODE_ANYXML;
1868 anyxml->prev = (struct ly_mnode *)anyxml;
1869 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02001870
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001871 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
1872 goto error;
1873 }
Radek Krejci863c2852015-06-03 15:47:11 +02001874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001875 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1876 if (!strcmp(sub->name, "mandatory")) {
1877 if (f_mand) {
1878 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1879 goto error;
1880 }
1881 /* just checking the flags in leaf is not sufficient, we would allow
1882 * multiple mandatory statements with the "false" value
1883 */
1884 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02001885
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001886 GETVAL(value, sub, "value");
1887 if (!strcmp(value, "true")) {
1888 anyxml->flags |= LY_NODE_MAND_TRUE;
1889 } else if (strcmp(value, "false")) {
1890 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
1891 goto error;
1892 }
1893 /* else false is the default value, so we can ignore it */
1894 lyxml_free_elem(module->ctx, sub);
1895 } else if (!strcmp(sub->name, "must")) {
1896 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001897 } else if (!strcmp(sub->name, "if-feature")) {
1898 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02001899
1900#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001901 } else {
1902 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
1903 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02001904#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001905 } else {
1906 continue;
Radek Krejci863c2852015-06-03 15:47:11 +02001907#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001908 }
1909 }
Radek Krejci863c2852015-06-03 15:47:11 +02001910
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001911 /* middle part - process nodes with cardinality of 0..n */
1912 if (c_must) {
1913 anyxml->must = calloc(c_must, sizeof *anyxml->must);
1914 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001915 if (c_ftrs) {
1916 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
1917 }
Radek Krejci863c2852015-06-03 15:47:11 +02001918
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001919 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1920 if (!strcmp(sub->name, "must")) {
1921 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
1922 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02001923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001924 if (r) {
1925 goto error;
1926 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02001927 } else if (!strcmp(sub->name, "must")) {
1928 GETVAL(value, sub, "name");
1929 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
1930 if (!anyxml->features[anyxml->features_size]) {
1931 goto error;
1932 }
1933 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001934 }
Radek Krejci863c2852015-06-03 15:47:11 +02001935
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001936 lyxml_free_elem(module->ctx, sub);
1937 }
Radek Krejci863c2852015-06-03 15:47:11 +02001938
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001939 if (parent && ly_mnode_addchild(parent, retval)) {
1940 goto error;
1941 }
Radek Krejci863c2852015-06-03 15:47:11 +02001942
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001943 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02001944
1945error:
1946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001947 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02001948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001949 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02001950}
1951
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001952static struct ly_mnode *
1953read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001954{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001955 struct ly_mnode *retval;
1956 struct ly_mnode_leaf *leaf;
1957 struct lyxml_elem *sub, *next;
1958 const char *value;
1959 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02001960 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001961
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001962 leaf = calloc(1, sizeof *leaf);
1963 leaf->nodetype = LY_NODE_LEAF;
1964 leaf->prev = (struct ly_mnode *)leaf;
1965 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001966
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001967 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
1968 goto error;
1969 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001971 LY_TREE_FOR_SAFE(yin->child, next, sub) {
1972 if (!strcmp(sub->name, "type")) {
1973 if (leaf->type.der) {
1974 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1975 goto error;
1976 }
1977 if (fill_yin_type(module, parent, sub, &leaf->type)) {
1978 goto error;
1979 }
1980 } else if (!strcmp(sub->name, "default")) {
1981 if (leaf->dflt) {
1982 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1983 goto error;
1984 }
1985 GETVAL(value, sub, "value");
1986 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
1987 } else if (!strcmp(sub->name, "units")) {
1988 if (leaf->units) {
1989 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1990 goto error;
1991 }
1992 GETVAL(value, sub, "name");
1993 leaf->units = lydict_insert(module->ctx, value, strlen(value));
1994 } else if (!strcmp(sub->name, "mandatory")) {
1995 if (f_mand) {
1996 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
1997 goto error;
1998 }
1999 /* just checking the flags in leaf is not sufficient, we would allow
2000 * multiple mandatory statements with the "false" value
2001 */
2002 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02002003
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002004 GETVAL(value, sub, "value");
2005 if (!strcmp(value, "true")) {
2006 leaf->flags |= LY_NODE_MAND_TRUE;
2007 } else if (strcmp(value, "false")) {
2008 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2009 goto error;
2010 } /* else false is the default value, so we can ignore it */
2011 } else if (!strcmp(sub->name, "must")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002012 c_must++; /* else false is the default value, so we can ignore it */
2013 } else if (!strcmp(sub->name, "if-feature")) {
2014 c_ftrs++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002016 /* skip element free at the end of the loop */
2017 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002018#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002019 } else {
2020 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2021 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02002022#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002023 } else {
2024 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002025#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002026 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002027
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002028 lyxml_free_elem(module->ctx, sub);
2029 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002031 /* check mandatory parameters */
2032 if (!leaf->type.der) {
2033 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2034 goto error;
2035 }
2036 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
2037 goto error;
2038 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002039
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002040 /* middle part - process nodes with cardinality of 0..n */
2041 if (c_must) {
2042 leaf->must = calloc(c_must, sizeof *leaf->must);
2043 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002044 if (c_ftrs) {
2045 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
2046 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002047
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002048 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2049 if (!strcmp(sub->name, "must")) {
2050 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
2051 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02002052
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002053 if (r) {
2054 goto error;
2055 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002056 } else if (!strcmp(sub->name, "if-feature")) {
2057 GETVAL(value, sub, "name");
2058 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
2059 if (!leaf->features[leaf->features_size]) {
2060 goto error;
2061 }
2062 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002063 }
Radek Krejci4c31f122015-06-02 14:51:22 +02002064
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002065 lyxml_free_elem(module->ctx, sub);
2066 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002067
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002068 if (parent && ly_mnode_addchild(parent, retval)) {
2069 goto error;
2070 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002071
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002072 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002073
2074error:
2075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002076 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002078 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002079}
2080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002081static struct ly_mnode *
2082read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002083{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002084 struct ly_mnode *retval;
2085 struct ly_mnode_leaflist *llist;
2086 struct lyxml_elem *sub, *next;
2087 const char *value;
2088 char *endptr;
2089 unsigned long val;
2090 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002091 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002092 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002093
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002094 llist = calloc(1, sizeof *llist);
2095 llist->nodetype = LY_NODE_LEAFLIST;
2096 llist->prev = (struct ly_mnode *)llist;
2097 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002098
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002099 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2100 goto error;
2101 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002103 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2104 if (!strcmp(sub->name, "type")) {
2105 if (llist->type.der) {
2106 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2107 goto error;
2108 }
2109 if (fill_yin_type(module, parent, sub, &llist->type)) {
2110 goto error;
2111 }
2112 } else if (!strcmp(sub->name, "units")) {
2113 if (llist->units) {
2114 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2115 goto error;
2116 }
2117 GETVAL(value, sub, "name");
2118 llist->units = lydict_insert(module->ctx, value, strlen(value));
2119 } else if (!strcmp(sub->name, "ordered-by")) {
2120 if (f_ordr) {
2121 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2122 goto error;
2123 }
2124 /* just checking the flags in llist is not sufficient, we would
2125 * allow multiple ordered-by statements with the "system" value
2126 */
2127 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002128
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002129 if (llist->flags & LY_NODE_CONFIG_R) {
2130 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2131 * state data
2132 */
2133 lyxml_free_elem(module->ctx, sub);
2134 continue;
2135 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002137 GETVAL(value, sub, "value");
2138 if (!strcmp(value, "user")) {
2139 llist->flags |= LY_NODE_USERORDERED;
2140 } else if (strcmp(value, "system")) {
2141 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2142 goto error;
2143 } /* else system is the default value, so we can ignore it */
2144 } else if (!strcmp(sub->name, "must")) {
2145 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002146 } else if (!strcmp(sub->name, "if-feature")) {
2147 c_ftrs++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002149 /* skip element free at the end of the loop */
2150 continue;
2151 } else if (!strcmp(sub->name, "min-elements")) {
2152 if (f_min) {
2153 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2154 goto error;
2155 }
2156 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002157
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002158 GETVAL(value, sub, "value");
2159 while (isspace(value[0])) {
2160 value++;
2161 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002163 /* convert it to uint32_t */
2164 errno = 0;
2165 endptr = NULL;
2166 val = strtoul(value, &endptr, 10);
2167 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2168 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2169 goto error;
2170 }
2171 llist->min = (uint32_t) val;
2172 } else if (!strcmp(sub->name, "max-elements")) {
2173 if (f_max) {
2174 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2175 goto error;
2176 }
2177 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002178
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002179 GETVAL(value, sub, "value");
2180 while (isspace(value[0])) {
2181 value++;
2182 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002183
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002184 /* convert it to uint32_t */
2185 errno = 0;
2186 endptr = NULL;
2187 val = strtoul(value, &endptr, 10);
2188 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2189 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2190 goto error;
2191 }
2192 llist->max = (uint32_t) val;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002193
Radek Krejci1e3f8902015-06-03 11:00:11 +02002194#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002195 } else {
2196 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2197 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02002198#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002199 } else {
2200 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002201#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002202 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002204 lyxml_free_elem(module->ctx, sub);
2205 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002207 /* check constraints */
2208 if (!llist->type.der) {
2209 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
2210 goto error;
2211 }
2212 if (llist->max && llist->min > llist->max) {
2213 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2214 goto error;
2215 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002217 /* middle part - process nodes with cardinality of 0..n */
2218 if (c_must) {
2219 llist->must = calloc(c_must, sizeof *llist->must);
2220 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002221 if (c_ftrs) {
2222 llist->features = calloc(c_ftrs, sizeof *llist->features);
2223 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002224
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002225 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2226 if (!strcmp(sub->name, "must")) {
2227 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
2228 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002230 if (r) {
2231 goto error;
2232 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002233 } else if (!strcmp(sub->name, "if-feature")) {
2234 GETVAL(value, sub, "name");
2235 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
2236 if (!llist->features[llist->features_size]) {
2237 goto error;
2238 }
2239 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002240 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02002241
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002242 lyxml_free_elem(module->ctx, sub);
2243 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002244
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002245 if (parent && ly_mnode_addchild(parent, retval)) {
2246 goto error;
2247 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002248
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002249 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002250
2251error:
2252
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002253 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002254
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002255 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002256}
2257
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002258static struct ly_mnode *
2259read_yin_list(struct ly_module *module,
2260 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002261{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002262 struct ly_mnode *retval, *mnode;
2263 struct ly_mnode_list *list;
2264 struct ly_unique *uniq_s;
2265 struct lyxml_elem *sub, *next, root, uniq;
2266 int i, r;
2267 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002268 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002269 int f_ordr = 0, f_max = 0, f_min = 0;
2270 const char *key_str = NULL, *uniq_str, *value;
2271 char *auxs;
2272 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002273
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002274 /* init */
2275 memset(&root, 0, sizeof root);
2276 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02002277
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002278 list = calloc(1, sizeof *list);
2279 list->nodetype = LY_NODE_LIST;
2280 list->prev = (struct ly_mnode *)list;
2281 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002283 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2284 goto error;
2285 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002287 /* process list's specific children */
2288 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2289 /* data statements */
2290 if (!strcmp(sub->name, "container") ||
2291 !strcmp(sub->name, "leaf-list") ||
2292 !strcmp(sub->name, "leaf") ||
2293 !strcmp(sub->name, "list") ||
2294 !strcmp(sub->name, "choice") ||
2295 !strcmp(sub->name, "uses") ||
2296 !strcmp(sub->name, "grouping") ||
2297 !strcmp(sub->name, "anyxml")) {
2298 lyxml_unlink_elem(sub);
2299 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002300
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002301 /* array counters */
2302 } else if (!strcmp(sub->name, "key")) {
2303 /* check cardinality 0..1 */
2304 if (list->keys_size) {
2305 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
2306 goto error;
2307 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002309 /* count the number of keys */
2310 GETVAL(value, sub, "value");
2311 key_str = value;
2312 while ((value = strpbrk(value, " \t\n"))) {
2313 list->keys_size++;
2314 while (isspace(*value)) {
2315 value++;
2316 }
2317 }
2318 list->keys_size++;
2319 list->keys = calloc(list->keys_size, sizeof *list->keys);
2320 } else if (!strcmp(sub->name, "unique")) {
2321 c_uniq++;
2322 lyxml_unlink_elem(sub);
2323 lyxml_add_child(&uniq, sub);
2324 } else if (!strcmp(sub->name, "typedef")) {
2325 c_tpdf++;
2326 } else if (!strcmp(sub->name, "must")) {
2327 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002328 } else if (!strcmp(sub->name, "if-feature")) {
2329 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02002330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002331 /* optional stetments */
2332 } else if (!strcmp(sub->name, "ordered-by")) {
2333 if (f_ordr) {
2334 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2335 goto error;
2336 }
2337 /* just checking the flags in llist is not sufficient, we would
2338 * allow multiple ordered-by statements with the "system" value
2339 */
2340 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002342 if (list->flags & LY_NODE_CONFIG_R) {
2343 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
2344 * state data
2345 */
2346 lyxml_free_elem(module->ctx, sub);
2347 continue;
2348 }
Radek Krejci345ad742015-06-03 11:04:18 +02002349
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002350 GETVAL(value, sub, "value");
2351 if (!strcmp(value, "user")) {
2352 list->flags |= LY_NODE_USERORDERED;
2353 } else if (strcmp(value, "system")) {
2354 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2355 goto error;
2356 }
2357 /* else system is the default value, so we can ignore it */
2358 lyxml_free_elem(module->ctx, sub);
2359 } else if (!strcmp(sub->name, "min-elements")) {
2360 if (f_min) {
2361 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2362 goto error;
2363 }
2364 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002366 GETVAL(value, sub, "value");
2367 while (isspace(value[0])) {
2368 value++;
2369 }
Radek Krejci345ad742015-06-03 11:04:18 +02002370
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002371 /* convert it to uint32_t */
2372 errno = 0;
2373 auxs = NULL;
2374 val = strtoul(value, &auxs, 10);
2375 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
2376 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2377 goto error;
2378 }
2379 list->min = (uint32_t) val;
2380 lyxml_free_elem(module->ctx, sub);
2381 } else if (!strcmp(sub->name, "max-elements")) {
2382 if (f_max) {
2383 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2384 goto error;
2385 }
2386 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02002387
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002388 GETVAL(value, sub, "value");
2389 while (isspace(value[0])) {
2390 value++;
2391 }
Radek Krejci345ad742015-06-03 11:04:18 +02002392
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002393 /* convert it to uint32_t */
2394 errno = 0;
2395 auxs = NULL;
2396 val = strtoul(value, &auxs, 10);
2397 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2398 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2399 goto error;
2400 }
2401 list->max = (uint32_t) val;
2402 lyxml_free_elem(module->ctx, sub);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002403#if 0
2404 } else {
2405 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2406 goto error;
2407#else
2408 } else {
2409 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002410 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002411#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002412 }
Radek Krejci345ad742015-06-03 11:04:18 +02002413
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002414 /* check - if list is configuration, key statement is mandatory */
2415 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
2416 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
2417 goto error;
2418 }
2419 if (list->max && list->min > list->max) {
2420 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
2421 goto error;
2422 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002424 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2425 if (c_tpdf) {
2426 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
2427 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002428 if (c_must) {
2429 list->must = calloc(c_must, sizeof *list->must);
2430 }
2431 if (c_ftrs) {
2432 list->features = calloc(c_ftrs, sizeof *list->features);
2433 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002434 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2435 if (!strcmp(sub->name, "typedef")) {
2436 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
2437 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002438
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002439 if (r) {
2440 goto error;
2441 }
2442 lyxml_free_elem(module->ctx, sub);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002443 } else if (!strcmp(sub->name, "if-feature")) {
2444 GETVAL(value, sub, "name");
2445 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
2446 if (!list->features[list->features_size]) {
2447 goto error;
2448 }
2449 list->features_size++;
2450 } else if (!strcmp(sub->name, "must")) {
2451 r = fill_yin_must(module, sub, &list->must[list->must_size]);
2452 list->must_size++;
2453
2454 if (r) {
2455 goto error;
2456 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002457 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002458 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002459 }
Radek Krejci25d782a2015-05-22 15:03:23 +02002460
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002461 /* last part - process data nodes */
2462 LY_TREE_FOR_SAFE(root.child, next, sub) {
2463 if (!strcmp(sub->name, "container")) {
2464 mnode = read_yin_container(module, retval, sub, resolve, unres);
2465 } else if (!strcmp(sub->name, "leaf-list")) {
2466 mnode = read_yin_leaflist(module, retval, sub, resolve);
2467 } else if (!strcmp(sub->name, "leaf")) {
2468 mnode = read_yin_leaf(module, retval, sub, resolve);
2469 } else if (!strcmp(sub->name, "list")) {
2470 mnode = read_yin_list(module, retval, sub, resolve, unres);
2471 } else if (!strcmp(sub->name, "choice")) {
2472 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2473 } else if (!strcmp(sub->name, "uses")) {
2474 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2475 } else if (!strcmp(sub->name, "grouping")) {
2476 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2477 } else if (!strcmp(sub->name, "anyxml")) {
2478 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002479 }
2480 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002481
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002482 if (!mnode) {
2483 goto error;
2484 }
2485 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002486
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002487 if (parent && ly_mnode_addchild(parent, retval)) {
2488 goto error;
2489 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002490
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002491 if (!key_str) {
2492 /* config false list without a key */
2493 return retval;
2494 }
Radek Krejci812b10a2015-05-28 16:48:25 +02002495
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002496 /* link key leafs into the list structure and check all constraints */
2497 for (i = 0; i < list->keys_size; i++) {
2498 /* get the key name */
2499 if ((value = strpbrk(key_str, " \t\n"))) {
2500 len = value - key_str;
2501 while (isspace(*value)) {
2502 value++;
2503 }
2504 } else {
2505 len = strlen(key_str);
2506 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02002507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002508 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02002509
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002510 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
2511 goto error;
2512 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002513
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002514 /* prepare for next iteration */
2515 while (value && isspace(*value)) {
2516 value++;
2517 }
2518 key_str = value;
2519 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02002520
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002521 /* process unique statements */
2522 if (c_uniq) {
2523 list->unique = calloc(c_uniq, sizeof *list->unique);
2524 }
2525 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
2526 /* count the number of unique values */
2527 GETVAL(value, sub, "tag");
2528 uniq_str = value;
2529 uniq_s = &list->unique[list->unique_size];
2530 while ((value = strpbrk(value, " \t\n"))) {
2531 uniq_s->leafs_size++;
2532 while (isspace(*value)) {
2533 value++;
2534 }
2535 }
2536 uniq_s->leafs_size++;
2537 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
2538 list->unique_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02002539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002540 /* interconnect unique values with the leafs */
2541 for (i = 0; i < uniq_s->leafs_size; i++) {
2542 if ((value = strpbrk(uniq_str, " \t\n"))) {
2543 len = value - uniq_str;
2544 while (isspace(*value)) {
2545 value++;
2546 }
2547 } else {
2548 len = strlen(uniq_str);
2549 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002550
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002551 uniq_s->leafs[i] = find_leaf(retval, uniq_str, len);
2552 if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
2553 goto error;
2554 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002555
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002556 /* prepare for next iteration */
2557 while (value && isspace(*value)) {
2558 value++;
2559 }
2560 uniq_str = value;
2561 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002562
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002563 lyxml_free_elem(module->ctx, sub);
2564 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02002565
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002566 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002567
2568error:
2569
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002570 ly_mnode_free(retval);
2571 while (root.child) {
2572 lyxml_free_elem(module->ctx, root.child);
2573 }
2574 while (uniq.child) {
2575 lyxml_free_elem(module->ctx, uniq.child);
2576 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002578 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002579}
2580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002581static struct ly_mnode *
2582read_yin_container(struct ly_module *module,
2583 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002584{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002585 struct lyxml_elem *sub, *next, root;
2586 struct ly_mnode *mnode = NULL;
2587 struct ly_mnode *retval;
2588 struct ly_mnode_container *cont;
2589 const char *value;
2590 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002591 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002593 /* init */
2594 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02002595
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002596 cont = calloc(1, sizeof *cont);
2597 cont->nodetype = LY_NODE_CONTAINER;
2598 cont->prev = (struct ly_mnode *)cont;
2599 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002600
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002601 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | (resolve ? OPT_INHERIT : 0))) {
2602 goto error;
2603 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002604
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002605 /* process container's specific children */
2606 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2607 if (!strcmp(sub->name, "presence")) {
2608 if (cont->presence) {
2609 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2610 goto error;
2611 }
2612 GETVAL(value, sub, "value");
2613 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02002614
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002615 lyxml_free_elem(module->ctx, sub);
Radek Krejci4c31f122015-06-02 14:51:22 +02002616
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002617 /* data statements */
2618 } else if (!strcmp(sub->name, "container") ||
2619 !strcmp(sub->name, "leaf-list") ||
2620 !strcmp(sub->name, "leaf") ||
2621 !strcmp(sub->name, "list") ||
2622 !strcmp(sub->name, "choice") ||
2623 !strcmp(sub->name, "uses") ||
2624 !strcmp(sub->name, "grouping") ||
2625 !strcmp(sub->name, "anyxml")) {
2626 lyxml_unlink_elem(sub);
2627 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002628
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002629 /* array counters */
2630 } else if (!strcmp(sub->name, "typedef")) {
2631 c_tpdf++;
2632 } else if (!strcmp(sub->name, "must")) {
2633 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002634 } else if (!strcmp(sub->name, "if-feature")) {
2635 c_ftrs++;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002636#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002637 } else {
2638 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2639 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02002640#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002641 } else {
2642 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02002643#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002644 }
2645 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002646
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002647 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2648 if (c_tpdf) {
2649 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
2650 }
2651 if (c_must) {
2652 cont->must = calloc(c_must, sizeof *cont->must);
2653 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002654 if (c_ftrs) {
2655 cont->features = calloc(c_ftrs, sizeof *cont->features);
2656 }
Radek Krejci800af702015-06-02 13:46:01 +02002657
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002658 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2659 if (!strcmp(sub->name, "typedef")) {
2660 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size]);
2661 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002663 if (r) {
2664 goto error;
2665 }
2666 } else if (!strcmp(sub->name, "must")) {
2667 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
2668 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02002669
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002670 if (r) {
2671 goto error;
2672 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002673 } else if (!strcmp(sub->name, "if-feature")) {
2674 GETVAL(value, sub, "name");
2675 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
2676 if (!cont->features[cont->features_size]) {
2677 goto error;
2678 }
2679 cont->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002680 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002682 lyxml_free_elem(module->ctx, sub);
2683 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002684
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002685 /* last part - process data nodes */
2686 LY_TREE_FOR_SAFE(root.child, next, sub) {
2687 if (!strcmp(sub->name, "container")) {
2688 mnode = read_yin_container(module, retval, sub, resolve, unres);
2689 } else if (!strcmp(sub->name, "leaf-list")) {
2690 mnode = read_yin_leaflist(module, retval, sub, resolve);
2691 } else if (!strcmp(sub->name, "leaf")) {
2692 mnode = read_yin_leaf(module, retval, sub, resolve);
2693 } else if (!strcmp(sub->name, "list")) {
2694 mnode = read_yin_list(module, retval, sub, resolve, unres);
2695 } else if (!strcmp(sub->name, "choice")) {
2696 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2697 } else if (!strcmp(sub->name, "uses")) {
2698 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2699 } else if (!strcmp(sub->name, "grouping")) {
2700 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2701 } else if (!strcmp(sub->name, "anyxml")) {
2702 mnode = read_yin_anyxml(module, retval, sub, resolve);
2703 }
2704 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002705
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002706 if (!mnode) {
2707 goto error;
2708 }
2709 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002711 if (parent && ly_mnode_addchild(parent, retval)) {
2712 goto error;
2713 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002715 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002716
2717error:
2718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002719 ly_mnode_free(retval);
2720 while (root.child) {
2721 lyxml_free_elem(module->ctx, root.child);
2722 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002723
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002724 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002725}
2726
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002727static struct ly_mnode *
2728read_yin_grouping(struct ly_module *module,
2729 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002730{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002731 struct lyxml_elem *sub, *next, root;
2732 struct ly_mnode *mnode = NULL;
2733 struct ly_mnode *retval;
2734 struct ly_mnode_grp *grp;
2735 int r;
2736 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002738 /* init */
2739 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02002740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002741 grp = calloc(1, sizeof *grp);
2742 grp->nodetype = LY_NODE_GROUPING;
2743 grp->prev = (struct ly_mnode *)grp;
2744 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002745
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002746 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE)) {
2747 goto error;
2748 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002750 LY_TREE_FOR_SAFE(node->child, next, sub) {
2751 /* data statements */
2752 if (!strcmp(sub->name, "container") ||
2753 !strcmp(sub->name, "leaf-list") ||
2754 !strcmp(sub->name, "leaf") ||
2755 !strcmp(sub->name, "list") ||
2756 !strcmp(sub->name, "choice") ||
2757 !strcmp(sub->name, "uses") ||
2758 !strcmp(sub->name, "grouping") ||
2759 !strcmp(sub->name, "anyxml")) {
2760 lyxml_unlink_elem(sub);
2761 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002762
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002763 /* array counters */
2764 } else if (!strcmp(sub->name, "typedef")) {
2765 c_tpdf++;
2766 } else {
2767 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2768 goto error;
2769 }
2770 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002771
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002772 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2773 if (c_tpdf) {
2774 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
2775 }
2776 LY_TREE_FOR_SAFE(node->child, next, sub) {
2777 if (!strcmp(sub->name, "typedef")) {
2778 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size]);
2779 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02002780
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002781 if (r) {
2782 goto error;
2783 }
2784 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002785
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002786 lyxml_free_elem(module->ctx, sub);
2787 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002788
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002789 /* last part - process data nodes */
2790 LY_TREE_FOR_SAFE(root.child, next, sub) {
2791 if (!strcmp(sub->name, "container")) {
2792 mnode = read_yin_container(module, retval, sub, resolve, unres);
2793 } else if (!strcmp(sub->name, "leaf-list")) {
2794 mnode = read_yin_leaflist(module, retval, sub, resolve);
2795 } else if (!strcmp(sub->name, "leaf")) {
2796 mnode = read_yin_leaf(module, retval, sub, resolve);
2797 } else if (!strcmp(sub->name, "list")) {
2798 mnode = read_yin_list(module, retval, sub, resolve, unres);
2799 } else if (!strcmp(sub->name, "choice")) {
2800 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2801 } else if (!strcmp(sub->name, "uses")) {
2802 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2803 } else if (!strcmp(sub->name, "grouping")) {
2804 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2805 } else if (!strcmp(sub->name, "anyxml")) {
2806 mnode = read_yin_anyxml(module, retval, sub, resolve);
2807 }
2808 lyxml_free_elem(module->ctx, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02002809
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002810 if (!mnode) {
2811 goto error;
2812 }
2813 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002815 if (parent && ly_mnode_addchild(parent, retval)) {
2816 goto error;
2817 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002819 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002820
2821error:
2822
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002823 ly_mnode_free(retval);
2824 while (root.child) {
2825 lyxml_free_elem(module->ctx, root.child);
2826 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002827
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002828 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002829}
2830
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002831static struct ly_mnode *
2832read_yin_input_output(struct ly_module *module,
2833 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02002834{
Radek Krejcie0674f82015-06-15 13:58:51 +02002835 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02002836 struct ly_mnode *mnode = NULL;
2837 struct ly_mnode *retval;
2838 struct ly_mnode_input_output *inout;
2839 int r;
2840 int c_tpdf = 0;
2841
Radek Krejcie0674f82015-06-15 13:58:51 +02002842 /* init */
2843 memset(&root, 0, sizeof root);
2844
Michal Vasko38d01f72015-06-15 09:41:06 +02002845 inout = calloc(1, sizeof *inout);
2846
2847 if (!strcmp(yin->name, "input")) {
2848 inout->nodetype = LY_NODE_INPUT;
2849 } else if (!strcmp(yin->name, "output")) {
2850 inout->nodetype = LY_NODE_OUTPUT;
2851 } else {
2852 assert(0);
2853 }
2854
2855 inout->prev = (struct ly_mnode *)inout;
2856 retval = (struct ly_mnode *)inout;
2857
Michal Vaskoebeac942015-06-15 12:11:50 +02002858 if (read_yin_common(module, parent, retval, yin, OPT_MODULE)) {
2859 goto error;
2860 }
2861
Michal Vasko38d01f72015-06-15 09:41:06 +02002862 /* data statements */
2863 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2864 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002865 !strcmp(sub->name, "leaf-list") ||
2866 !strcmp(sub->name, "leaf") ||
2867 !strcmp(sub->name, "list") ||
2868 !strcmp(sub->name, "choice") ||
2869 !strcmp(sub->name, "uses") ||
2870 !strcmp(sub->name, "grouping") ||
2871 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02002872 lyxml_unlink_elem(sub);
2873 lyxml_add_child(&root, sub);
2874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002875 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02002876 } else if (!strcmp(sub->name, "typedef")) {
2877 c_tpdf++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002878#if 0
Michal Vasko38d01f72015-06-15 09:41:06 +02002879 } else {
2880 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2881 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002882#else
Michal Vasko38d01f72015-06-15 09:41:06 +02002883 } else {
2884 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002885#endif
Michal Vasko38d01f72015-06-15 09:41:06 +02002886 }
2887 }
2888
2889 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2890 if (c_tpdf) {
2891 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
2892 }
2893
2894 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2895 if (!strcmp(sub->name, "typedef")) {
2896 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size]);
2897 inout->tpdf_size++;
2898
2899 if (r) {
2900 goto error;
2901 }
2902 }
2903
2904 lyxml_free_elem(module->ctx, sub);
2905 }
2906
2907 /* last part - process data nodes */
2908 LY_TREE_FOR_SAFE(root.child, next, sub) {
2909 if (!strcmp(sub->name, "container")) {
2910 mnode = read_yin_container(module, retval, sub, resolve, unres);
2911 } else if (!strcmp(sub->name, "leaf-list")) {
2912 mnode = read_yin_leaflist(module, retval, sub, resolve);
2913 } else if (!strcmp(sub->name, "leaf")) {
2914 mnode = read_yin_leaf(module, retval, sub, resolve);
2915 } else if (!strcmp(sub->name, "list")) {
2916 mnode = read_yin_list(module, retval, sub, resolve, unres);
2917 } else if (!strcmp(sub->name, "choice")) {
2918 mnode = read_yin_choice(module, retval, sub, resolve, unres);
2919 } else if (!strcmp(sub->name, "uses")) {
2920 mnode = read_yin_uses(module, retval, sub, resolve, unres);
2921 } else if (!strcmp(sub->name, "grouping")) {
2922 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
2923 } else if (!strcmp(sub->name, "anyxml")) {
2924 mnode = read_yin_anyxml(module, retval, sub, resolve);
2925 }
2926 lyxml_free_elem(module->ctx, sub);
2927
2928 if (!mnode) {
2929 goto error;
2930 }
2931 }
2932
2933 if (parent && ly_mnode_addchild(parent, retval)) {
2934 goto error;
2935 }
2936
2937 return retval;
2938
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002939error:
Michal Vasko38d01f72015-06-15 09:41:06 +02002940
2941 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02002942 while (root.child) {
2943 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02002944 }
2945
2946 return NULL;
2947}
2948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002949static struct ly_mnode *
2950read_yin_notif(struct ly_module *module,
2951 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02002952{
Michal Vaskoc6551b32015-06-16 10:51:43 +02002953 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02002954 struct ly_mnode *mnode = NULL;
2955 struct ly_mnode *retval;
2956 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002957 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02002958 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002959 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02002960
Michal Vaskoc6551b32015-06-16 10:51:43 +02002961 memset(&root, 0, sizeof root);
2962
Michal Vasko0ea41032015-06-16 08:53:55 +02002963 notif = calloc(1, sizeof *notif);
2964 notif->nodetype = LY_NODE_NOTIF;
2965 notif->prev = (struct ly_mnode *)notif;
2966 retval = (struct ly_mnode *)notif;
2967
2968 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
2969 goto error;
2970 }
2971
2972 /* process rpc's specific children */
2973 LY_TREE_FOR_SAFE(yin->child, next, sub) {
2974 /* data statements */
2975 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002976 !strcmp(sub->name, "leaf-list") ||
2977 !strcmp(sub->name, "leaf") ||
2978 !strcmp(sub->name, "list") ||
2979 !strcmp(sub->name, "choice") ||
2980 !strcmp(sub->name, "uses") ||
2981 !strcmp(sub->name, "grouping") ||
2982 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02002983 lyxml_unlink_elem(sub);
2984 lyxml_add_child(&root, sub);
2985
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002986 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02002987 } else if (!strcmp(sub->name, "typedef")) {
2988 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002989 } else if (!strcmp(sub->name, "if-feature")) {
2990 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02002991 } else {
2992 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2993 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02002994 }
2995 }
2996
2997 /* middle part - process nodes with cardinality of 0..n except the data nodes */
2998 if (c_tpdf) {
2999 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
3000 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003001 if (c_ftrs) {
3002 notif->features = calloc(c_ftrs, sizeof *notif->features);
3003 }
Michal Vasko0ea41032015-06-16 08:53:55 +02003004
3005 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3006 if (!strcmp(sub->name, "typedef")) {
3007 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size]);
3008 notif->tpdf_size++;
3009
3010 if (r) {
3011 goto error;
3012 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003013 } else if (!strcmp(sub->name, "typedef")) {
3014 GETVAL(value, sub, "name");
3015 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
3016 if (!notif->features[notif->features_size]) {
3017 goto error;
3018 }
3019 notif->features_size++;
Michal Vasko0ea41032015-06-16 08:53:55 +02003020 }
3021
3022 lyxml_free_elem(module->ctx, sub);
3023 }
3024
3025 /* last part - process data nodes */
3026 LY_TREE_FOR_SAFE(root.child, next, sub) {
3027 if (!strcmp(sub->name, "container")) {
3028 mnode = read_yin_container(module, retval, sub, resolve, unres);
3029 } else if (!strcmp(sub->name, "leaf-list")) {
3030 mnode = read_yin_leaflist(module, retval, sub, resolve);
3031 } else if (!strcmp(sub->name, "leaf")) {
3032 mnode = read_yin_leaf(module, retval, sub, resolve);
3033 } else if (!strcmp(sub->name, "list")) {
3034 mnode = read_yin_list(module, retval, sub, resolve, unres);
3035 } else if (!strcmp(sub->name, "choice")) {
3036 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3037 } else if (!strcmp(sub->name, "uses")) {
3038 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3039 } else if (!strcmp(sub->name, "grouping")) {
3040 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3041 } else if (!strcmp(sub->name, "anyxml")) {
3042 mnode = read_yin_anyxml(module, retval, sub, resolve);
3043 }
3044 lyxml_free_elem(module->ctx, sub);
3045
3046 if (!mnode) {
3047 goto error;
3048 }
3049 }
3050
3051 if (parent && ly_mnode_addchild(parent, retval)) {
3052 goto error;
3053 }
3054
3055 return retval;
3056
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003057error:
Michal Vasko0ea41032015-06-16 08:53:55 +02003058
3059 ly_mnode_free(retval);
3060 while (root.child) {
3061 lyxml_free_elem(module->ctx, root.child);
3062 }
3063
3064 return NULL;
3065}
3066
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003067static struct ly_mnode *
3068read_yin_rpc(struct ly_module *module,
3069 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct mnode_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02003070{
Radek Krejcie0674f82015-06-15 13:58:51 +02003071 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02003072 struct ly_mnode *mnode = NULL;
3073 struct ly_mnode *retval;
3074 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003075 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02003076 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003077 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02003078
Radek Krejcie0674f82015-06-15 13:58:51 +02003079 /* init */
3080 memset(&root, 0, sizeof root);
3081
Michal Vasko38d01f72015-06-15 09:41:06 +02003082 rpc = calloc(1, sizeof *rpc);
3083 rpc->nodetype = LY_NODE_RPC;
3084 rpc->prev = (struct ly_mnode *)rpc;
3085 retval = (struct ly_mnode *)rpc;
3086
3087 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE)) {
3088 goto error;
3089 }
3090
3091 /* process rpc's specific children */
3092 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3093 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003094 if (rpc->child
3095 && (rpc->child->nodetype == LY_NODE_INPUT
3096 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003097 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3098 goto error;
3099 }
3100 lyxml_unlink_elem(sub);
3101 lyxml_add_child(&root, sub);
3102 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003103 if (rpc->child
3104 && (rpc->child->nodetype == LY_NODE_INPUT
3105 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02003106 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3107 goto error;
3108 }
3109 lyxml_unlink_elem(sub);
3110 lyxml_add_child(&root, sub);
3111
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003112 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02003113 } else if (!strcmp(sub->name, "grouping")) {
3114 lyxml_unlink_elem(sub);
3115 lyxml_add_child(&root, sub);
3116
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003117 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02003118 } else if (!strcmp(sub->name, "typedef")) {
3119 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003120 } else if (!strcmp(sub->name, "if-feature")) {
3121 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003122 } else {
3123 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3124 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02003125 }
3126 }
3127
3128 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3129 if (c_tpdf) {
3130 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
3131 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003132 if (c_ftrs) {
3133 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
3134 }
Michal Vasko38d01f72015-06-15 09:41:06 +02003135
3136 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3137 if (!strcmp(sub->name, "typedef")) {
3138 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size]);
3139 rpc->tpdf_size++;
3140
3141 if (r) {
3142 goto error;
3143 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003144 } else if (!strcmp(sub->name, "if-feature")) {
3145 GETVAL(value, sub, "name");
3146 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
3147 if (!rpc->features[rpc->features_size]) {
3148 goto error;
3149 }
3150 rpc->features_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02003151 }
3152
3153 lyxml_free_elem(module->ctx, sub);
3154 }
3155
3156 /* last part - process data nodes */
3157 LY_TREE_FOR_SAFE(root.child, next, sub) {
3158 if (!strcmp(sub->name, "grouping")) {
3159 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3160 } else if (!strcmp(sub->name, "input")) {
3161 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3162 } else if (!strcmp(sub->name, "output")) {
3163 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
3164 }
3165 lyxml_free_elem(module->ctx, sub);
3166
3167 if (!mnode) {
3168 goto error;
3169 }
3170 }
3171
3172 if (parent && ly_mnode_addchild(parent, retval)) {
3173 goto error;
3174 }
3175
3176 return retval;
3177
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003178error:
Michal Vasko38d01f72015-06-15 09:41:06 +02003179
3180 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02003181 while (root.child) {
3182 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02003183 }
3184
3185 return NULL;
3186}
3187
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003188static int
3189find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003190{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003191 struct ly_module *searchmod = NULL, *module = uses->module;
3192 struct ly_mnode *mnode, *mnode_aux;
3193 const char *name;
3194 int prefix_len = 0;
3195 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003196
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003197 /* get referenced grouping */
3198 name = strchr(uses->name, ':');
3199 if (!name) {
3200 /* no prefix, search in local tree */
3201 name = uses->name;
3202 } else {
3203 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003204
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003205 /* set name to correct position after colon */
3206 prefix_len = name - uses->name;
3207 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003208
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003209 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3210 /* prefix refers to the current module, ignore it */
3211 prefix_len = 0;
3212 }
3213 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003214
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003215 /* search */
3216 if (prefix_len) {
3217 /* in top-level groupings of some other module */
3218 for (i = 0; i < module->imp_size; i++) {
3219 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
3220 && !module->imp[i].prefix[prefix_len]) {
3221 searchmod = module->imp[i].module;
3222 break;
3223 }
3224 }
3225 if (!searchmod) {
3226 /* uses refers unknown data model */
3227 LOGVAL(VE_INPREFIX, line, name);
3228 return EXIT_FAILURE;
3229 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003230
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003231 LY_TREE_FOR(searchmod->data, mnode) {
3232 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3233 uses->grp = (struct ly_mnode_grp *)mnode;
3234 return EXIT_SUCCESS;
3235 }
3236 }
3237 } else {
3238 /* in local tree hierarchy */
3239 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
3240 LY_TREE_FOR(mnode_aux->child, mnode) {
3241 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3242 uses->grp = (struct ly_mnode_grp *)mnode;
3243 return EXIT_SUCCESS;
3244 }
3245 }
3246 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003248 /* search in top level of the current module */
3249 LY_TREE_FOR(module->data, mnode) {
3250 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3251 uses->grp = (struct ly_mnode_grp *)mnode;
3252 return EXIT_SUCCESS;
3253 }
3254 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003255
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003256 /* search in top-level of included modules */
3257 for (i = 0; i < module->inc_size; i++) {
3258 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
3259 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
3260 uses->grp = (struct ly_mnode_grp *)mnode;
3261 return EXIT_SUCCESS;
3262 }
3263 }
3264 }
3265 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02003266
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003267 /* not found, but no explicit error occured */
3268 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02003269}
3270
Radek Krejcif5be10f2015-06-16 13:29:36 +02003271static int
3272resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
3273{
3274 struct lyxml_elem *yin, *next, *sub;
3275 struct ly_mnode *mnode;
3276
3277 assert(module);
3278
3279 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003280 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02003281 if (!aug->target) {
3282 LOGVAL(VE_INARG, line, aug->target, "uses");
3283 return EXIT_FAILURE;
3284 }
3285
3286 if (!aug->child) {
3287 /* nothing to do */
3288 return EXIT_SUCCESS;
3289 }
3290
3291 yin = (struct lyxml_elem *)aug->child;
3292
3293 if (read_yin_common(module, aug->target, (struct ly_mnode *)aug, yin, OPT_CONFIG)) {
3294 return EXIT_FAILURE;
3295 }
3296
3297 LY_TREE_FOR_SAFE(yin->child, next, sub) {
3298 if (!strcmp(sub->name, "container")) {
3299 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
3300 } else if (!strcmp(sub->name, "leaf-list")) {
3301 mnode = read_yin_leaflist(module, aug->target, sub, 1);
3302 } else if (!strcmp(sub->name, "leaf")) {
3303 mnode = read_yin_leaf(module, aug->target, sub, 1);
3304 } else if (!strcmp(sub->name, "list")) {
3305 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
3306 } else if (!strcmp(sub->name, "uses")) {
3307 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
3308 } else if (!strcmp(sub->name, "choice")) {
3309 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3310 } else if (!strcmp(sub->name, "case")) {
3311 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
3312 } else if (!strcmp(sub->name, "anyxml")) {
3313 mnode = read_yin_anyxml(module, aug->target, sub, 1);
3314#if 0
3315 } else {
3316 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02003317 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003318#else
3319 } else {
3320 continue;
3321#endif
3322 }
3323
3324 if (!mnode) {
3325 return EXIT_FAILURE;
3326 }
Radek Krejci3de29a72015-06-16 15:23:03 +02003327 /* check for mandatory nodes - if the target node is in another module
3328 * the added nodes cannot be mandatory
3329 */
3330 if (check_mandatory(mnode)) {
3331 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
3332 return EXIT_FAILURE;
3333 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003334
3335 lyxml_free_elem(module->ctx, sub);
3336
3337 /* the parent pointer will point to the augment node, but all
3338 * siblings pointers and possibly the child node in target does
3339 * not know about the augment and follow the standard schema tree
3340 * structure
3341 */
3342 mnode->parent = (struct ly_mnode *)aug;
3343 mnode = NULL;
3344 }
3345
3346 lyxml_free_elem(module->ctx, yin);
3347 aug->child = NULL;
3348
3349 return EXIT_SUCCESS;
3350}
3351
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003352int
3353resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02003354{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003355 struct ly_ctx *ctx;
3356 struct ly_mnode *mnode = NULL, *mnode_aux;
3357 struct ly_refine *rfn;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003358 struct ly_must *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003359 int i, j;
3360 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02003361
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003362 /* copy the data nodes from grouping into the uses context */
3363 LY_TREE_FOR(uses->grp->child, mnode) {
3364 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
3365 if (!mnode_aux) {
3366 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
3367 return EXIT_FAILURE;
3368 }
3369 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
3370 ly_mnode_free(mnode_aux);
3371 return EXIT_FAILURE;
3372 }
3373 }
3374 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02003375
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003376 /* apply refines */
3377 for (i = 0; i < uses->refine_size; i++) {
3378 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02003379 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003380 if (!mnode) {
3381 LOGVAL(VE_INARG, line, rfn->target, "uses");
3382 return EXIT_FAILURE;
3383 }
Radek Krejci106efc02015-06-10 14:36:27 +02003384
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003385 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
3386 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
3387 return EXIT_FAILURE;
3388 }
Radek Krejci106efc02015-06-10 14:36:27 +02003389
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003390 /* description on any nodetype */
3391 if (rfn->dsc) {
3392 lydict_remove(ctx, mnode->dsc);
3393 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
3394 }
Radek Krejci106efc02015-06-10 14:36:27 +02003395
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003396 /* reference on any nodetype */
3397 if (rfn->ref) {
3398 lydict_remove(ctx, mnode->ref);
3399 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
3400 }
Radek Krejci106efc02015-06-10 14:36:27 +02003401
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003402 /* config on any nodetype */
3403 if (rfn->flags & LY_NODE_CONFIG_MASK) {
3404 mnode->flags &= ~LY_NODE_CONFIG_MASK;
3405 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
3406 }
Radek Krejci106efc02015-06-10 14:36:27 +02003407
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003408 /* default value ... */
3409 if (rfn->mod.dflt) {
3410 if (mnode->nodetype == LY_NODE_LEAF) {
3411 /* leaf */
3412 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
3413 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3414 } else if (mnode->nodetype == LY_NODE_CHOICE) {
3415 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02003416 ((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 +02003417 if (!((struct ly_mnode_choice *)mnode)->dflt) {
3418 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
3419 return EXIT_FAILURE;
3420 }
3421 }
3422 }
Radek Krejci106efc02015-06-10 14:36:27 +02003423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003424 /* mandatory on leaf, anyxml or choice */
3425 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
3426 if (rfn->flags & LY_NODE_MAND_FALSE) {
3427 /* erase mandatory true flag, we don't use false flag in schema nodes */
3428 mnode->flags &= ~LY_NODE_MAND_TRUE;
3429 } else if (rfn->flags & LY_NODE_MAND_TRUE) {
3430 /* set mandatory true flag */
3431 mnode->flags |= LY_NODE_MAND_TRUE;
3432 }
3433 }
Radek Krejci106efc02015-06-10 14:36:27 +02003434
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003435 /* presence on container */
3436 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
3437 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
3438 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
3439 }
Radek Krejci106efc02015-06-10 14:36:27 +02003440
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003441 /* min/max-elements on list or leaf-list */
3442 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
3443 /* magic - bit 3 in flags means min set, bit 4 says max set */
3444 if (rfn->flags & 0x04) {
3445 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
3446 }
3447 if (rfn->flags & 0x08) {
3448 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
3449 }
3450 }
Radek Krejci106efc02015-06-10 14:36:27 +02003451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003452 /* must in leaf, leaf-list, list, container or anyxml */
3453 if (rfn->must_size) {
3454 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
3455 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
3456 if (!newmust) {
3457 LOGMEM;
3458 return EXIT_FAILURE;
3459 }
3460 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
3461 newmust[j].cond = lydict_insert(ctx, rfn->must[i].cond, 0);
3462 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3463 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3464 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3465 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
3466 }
Radek Krejci106efc02015-06-10 14:36:27 +02003467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003468 ((struct ly_mnode_leaf *)mnode)->must = newmust;
3469 ((struct ly_mnode_leaf *)mnode)->must_size = size;
3470 }
3471 }
Radek Krejci106efc02015-06-10 14:36:27 +02003472
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003473 /* apply augments */
3474 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02003475 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003476 goto error;
3477 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003478 }
Radek Krejci106efc02015-06-10 14:36:27 +02003479
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003480 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02003481
3482error:
3483
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003484 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02003485}
Radek Krejci74705112015-06-05 10:25:44 +02003486
3487/*
3488 * resolve - referenced grouping should be bounded to the namespace (resolved)
3489 * only when uses does not appear in grouping. In a case of grouping's uses,
3490 * we just get information but we do not apply augment or refine to it.
3491 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003492static struct ly_mnode *
3493read_yin_uses(struct ly_module *module,
3494 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct mnode_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02003495{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003496 struct lyxml_elem *sub, *next;
3497 struct ly_mnode *retval;
3498 struct ly_mnode_uses *uses;
3499 struct mnode_list *unres_new;
3500 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003501 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003502 int r;
Radek Krejci74705112015-06-05 10:25:44 +02003503
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003504 uses = calloc(1, sizeof *uses);
3505 uses->nodetype = LY_NODE_USES;
3506 uses->prev = (struct ly_mnode *)uses;
3507 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02003508
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003509 GETVAL(value, node, "name");
3510 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02003511
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003512 if (read_yin_common(module, parent, retval, node, OPT_MODULE | (resolve ? OPT_INHERIT : 0))) {
3513 goto error;
3514 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003515
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003516 /* get other properties of uses */
3517 LY_TREE_FOR_SAFE(node->child, next, sub) {
3518 if (!strcmp(sub->name, "refine")) {
3519 c_ref++;
3520 } else if (!strcmp(sub->name, "augment")) {
3521 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003522 } else if (!strcmp(sub->name, "if-feature")) {
3523 c_aug++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02003524#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003525 } else {
3526 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3527 goto error;
Radek Krejcifac63ba2015-06-10 14:48:40 +02003528#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003529 } else {
3530 lyxml_free_elem(module->ctx, sub);
Radek Krejci3bde87f2015-06-05 16:51:58 +02003531#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003532 }
3533 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003534
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003535 /* process properties with cardinality 0..n */
3536 if (c_ref) {
3537 uses->refine = calloc(c_ref, sizeof *uses->refine);
3538 }
3539 if (c_aug) {
3540 uses->augment = calloc(c_aug, sizeof *uses->augment);
3541 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003542 if (c_ftrs) {
3543 uses->features = calloc(c_ftrs, sizeof *uses->features);
3544 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003546 LY_TREE_FOR_SAFE(node->child, next, sub) {
3547 if (!strcmp(sub->name, "refine")) {
3548 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
3549 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003550 lyxml_free_elem(module->ctx, sub);
3551 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003552 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
3553 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003554 } else if (!strcmp(sub->name, "if-feature")) {
3555 GETVAL(value, sub, "name");
3556 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
3557 if (!uses->features[uses->features_size]) {
3558 goto error;
3559 }
3560 uses->features_size++;
3561 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003562 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003563
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003564 if (r) {
3565 goto error;
3566 }
3567 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02003568
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003569 if (find_grouping(parent, uses, LOGLINE(node))) {
3570 goto error;
3571 }
3572 if (!uses->grp) {
3573 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
3574 unres_new = calloc(1, sizeof *unres_new);
3575 if (*unres) {
3576 unres_new->next = *unres;
3577 }
3578 unres_new->mnode = retval;
3579 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02003580
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003581 /* put it at the beginning of the unresolved list */
3582 *unres = unres_new;
3583 }
Radek Krejci74705112015-06-05 10:25:44 +02003584
Radek Krejci368c38f2015-06-15 15:09:55 +02003585 if (parent && ly_mnode_addchild(parent, retval)) {
3586 goto error;
3587 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003588
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003589 if (resolve) {
3590 /* inherit config flag */
3591 if (parent) {
3592 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
3593 } else {
3594 /* default config is true */
3595 retval->flags |= LY_NODE_CONFIG_W;
3596 }
3597 }
Radek Krejcib388c152015-06-04 17:03:03 +02003598
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003599 if (resolve && uses->grp) {
3600 /* copy the data nodes from grouping into the uses context */
3601 if (resolve_uses(uses, LOGLINE(node))) {
3602 goto error;
3603 }
3604 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003605
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003606 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003607
3608error:
3609
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003610 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003611
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003612 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02003613}
3614
Radek Krejciefaeba32015-05-27 14:30:57 +02003615/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003616static int
3617read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003618{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003619 struct ly_ctx *ctx = module->ctx;
3620 struct ly_submodule *submodule = (struct ly_submodule *)module;
3621 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
3622 struct ly_mnode *mnode = NULL;
3623 struct mnode_list *unres = NULL, *unres_next; /* unresolved uses */
3624 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003625 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02003626 int i;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003627 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003628 /* counters */
3629 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003630
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003631 /* init */
3632 memset(&root, 0, sizeof root);
3633 memset(&grps, 0, sizeof grps);
3634 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02003635 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02003636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003637 /*
3638 * in the first run, we process elements with cardinality of 1 or 0..1 and
3639 * count elements with cardinality 0..n. Data elements (choices, containers,
3640 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
3641 * need have all top-level and groupings already prepared at that time. In
3642 * the middle loop, we process other elements with carinality of 0..n since
3643 * we need to allocate arrays to store them.
3644 */
3645 LY_TREE_FOR_SAFE(yin->child, next, node) {
3646 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
3647 lyxml_free_elem(ctx, node);
3648 continue;
3649 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003650
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003651 if (!module->type && !strcmp(node->name, "namespace")) {
3652 if (module->ns) {
3653 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3654 goto error;
3655 }
3656 GETVAL(value, node, "uri");
3657 module->ns = lydict_insert(ctx, value, strlen(value));
3658 lyxml_free_elem(ctx, node);
3659 } else if (!module->type && !strcmp(node->name, "prefix")) {
3660 if (module->prefix) {
3661 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3662 goto error;
3663 }
3664 GETVAL(value, node, "value");
3665 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
3666 goto error;
3667 }
3668 module->prefix = lydict_insert(ctx, value, strlen(value));
3669 lyxml_free_elem(ctx, node);
3670 } else if (module->type && !strcmp(node->name, "belongs-to")) {
3671 if (belongsto_flag) {
3672 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3673 goto error;
3674 }
3675 belongsto_flag = 1;
3676 GETVAL(value, node, "module");
3677 while (submodule->belongsto->type) {
3678 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
3679 }
3680 if (value != submodule->belongsto->name) {
3681 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
3682 goto error;
3683 }
Radek Krejcif3886932015-06-04 17:36:06 +02003684
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003685 /* get the prefix substatement, start with checks */
3686 if (!node->child) {
3687 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
3688 goto error;
3689 } else if (strcmp(node->child->name, "prefix")) {
3690 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
3691 goto error;
3692 } else if (node->child->next) {
3693 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
3694 goto error;
3695 }
3696 /* and now finally get the value */
3697 GETVAL(value, node->child, "value");
3698 /* check here differs from a generic prefix check, since this prefix
3699 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02003700 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003701 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
3702 goto error;
3703 }
3704 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02003705
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003706 /* we are done with belongs-to */
3707 lyxml_free_elem(ctx, node);
3708 } else if (!strcmp(node->name, "import")) {
3709 c_imp++;
3710 } else if (!strcmp(node->name, "revision")) {
3711 c_rev++;
3712 } else if (!strcmp(node->name, "typedef")) {
3713 c_tpdf++;
3714 } else if (!strcmp(node->name, "identity")) {
3715 c_ident++;
3716 } else if (!strcmp(node->name, "include")) {
3717 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02003718 } else if (!strcmp(node->name, "augment")) {
3719 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003720 } else if (!strcmp(node->name, "feature")) {
3721 c_ftrs++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003723 /* data statements */
3724 } else if (!strcmp(node->name, "container") ||
3725 !strcmp(node->name, "leaf-list") ||
3726 !strcmp(node->name, "leaf") ||
3727 !strcmp(node->name, "list") ||
3728 !strcmp(node->name, "choice") ||
3729 !strcmp(node->name, "uses") ||
3730 !strcmp(node->name, "anyxml")) {
3731 lyxml_unlink_elem(node);
3732 lyxml_add_child(&root, node);
3733 } else if (!strcmp(node->name, "grouping")) {
3734 /* keep groupings separated and process them before other data statements */
3735 lyxml_unlink_elem(node);
3736 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003737
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003738 /* optional statements */
3739 } else if (!strcmp(node->name, "description")) {
3740 if (module->dsc) {
3741 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3742 goto error;
3743 }
3744 module->dsc = read_yin_subnode(ctx, node, "text");
3745 lyxml_free_elem(ctx, node);
3746 if (!module->dsc) {
3747 goto error;
3748 }
3749 } else if (!strcmp(node->name, "reference")) {
3750 if (module->ref) {
3751 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3752 goto error;
3753 }
3754 module->ref = read_yin_subnode(ctx, node, "text");
3755 lyxml_free_elem(ctx, node);
3756 if (!module->ref) {
3757 goto error;
3758 }
3759 } else if (!strcmp(node->name, "organization")) {
3760 if (module->org) {
3761 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3762 goto error;
3763 }
3764 module->org = read_yin_subnode(ctx, node, "text");
3765 lyxml_free_elem(ctx, node);
3766 if (!module->org) {
3767 goto error;
3768 }
3769 } else if (!strcmp(node->name, "contact")) {
3770 if (module->contact) {
3771 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3772 goto error;
3773 }
3774 module->contact = read_yin_subnode(ctx, node, "text");
3775 lyxml_free_elem(ctx, node);
3776 if (!module->contact) {
3777 goto error;
3778 }
3779 } else if (!strcmp(node->name, "yang-version")) {
3780 /* TODO: support YANG 1.1 ? */
3781 if (module->version) {
3782 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
3783 goto error;
3784 }
3785 GETVAL(value, node, "value");
3786 if (strcmp(value, "1")) {
3787 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
3788 goto error;
3789 }
3790 module->version = 1;
3791 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02003792
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003793 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02003794 } else if (!strcmp(node->name, "rpc")) {
3795 lyxml_unlink_elem(node);
3796 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02003797 } else if (!strcmp(node->name, "notification")) {
3798 lyxml_unlink_elem(node);
3799 lyxml_add_child(&notifs, node);
Radek Krejci1e3f8902015-06-03 11:00:11 +02003800#if 0
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003801 } else {
3802 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
3803 goto error;
Radek Krejci8eaf9bd2015-06-04 11:05:18 +02003804#else
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003805 } else {
3806 continue;
Radek Krejci1e3f8902015-06-03 11:00:11 +02003807#endif
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003808 }
3809 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003810
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003811 if (!submodule) {
3812 /* check for mandatory statements */
3813 if (!module->ns) {
3814 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
3815 goto error;
3816 }
3817 if (!module->prefix) {
3818 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
3819 goto error;
3820 }
3821 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02003822
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003823 /* allocate arrays for elements with cardinality of 0..n */
3824 if (c_imp) {
3825 module->imp = calloc(c_imp, sizeof *module->imp);
3826 }
3827 if (c_rev) {
3828 module->rev = calloc(c_rev, sizeof *module->rev);
3829 }
3830 if (c_tpdf) {
3831 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
3832 }
3833 if (c_ident) {
3834 module->ident = calloc(c_ident, sizeof *module->ident);
3835 }
3836 if (c_inc) {
3837 module->inc = calloc(c_inc, sizeof *module->inc);
3838 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003839 if (c_aug) {
3840 module->augment = calloc(c_aug, sizeof *module->augment);
3841 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003842 if (c_ftrs) {
3843 module->features = calloc(c_ftrs, sizeof *module->features);
3844 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003845
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003846 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3847 LY_TREE_FOR_SAFE(yin->child, next, node) {
3848 if (!strcmp(node->name, "import")) {
3849 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
3850 module->imp_size++;
3851 if (r) {
3852 goto error;
3853 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003854
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003855 /* check duplicities in imported modules */
3856 for (i = 0; i < module->imp_size - 1; i++) {
3857 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
3858 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
3859 goto error;
3860 }
3861 }
3862 } else if (!strcmp(node->name, "include")) {
3863 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
3864 module->inc_size++;
3865 if (r) {
3866 goto error;
3867 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003868
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003869 /* check duplications in include submodules */
3870 for (i = 0; i < module->inc_size - 1; i++) {
3871 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
3872 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
3873 module->inc[i].submodule->name);
3874 goto error;
3875 }
3876 }
3877 } else if (!strcmp(node->name, "revision")) {
3878 GETVAL(value, node, "date");
3879 if (check_date(value, LOGLINE(node))) {
3880 goto error;
3881 }
3882 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
3883 /* check uniqueness of the revision date - not required by RFC */
3884 for (i = 0; i < module->rev_size; i++) {
3885 if (!strcmp(value, module->rev[i].date)) {
3886 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
3887 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
3888 }
3889 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003891 LY_TREE_FOR(node->child, child) {
3892 if (!strcmp(child->name, "description")) {
3893 if (module->rev[module->rev_size].dsc) {
3894 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
3895 goto error;
3896 }
3897 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
3898 if (!module->rev[module->rev_size].dsc) {
3899 goto error;
3900 }
3901 } else if (!strcmp(child->name, "reference")) {
3902 if (module->rev[module->rev_size].ref) {
3903 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
3904 goto error;
3905 }
3906 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
3907 if (!module->rev[module->rev_size].ref) {
3908 goto error;
3909 }
3910 } else {
3911 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
3912 goto error;
3913 }
3914 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003915
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003916 /* keep the latest revision at position 0 */
3917 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
3918 /* switch their position */
3919 value = strdup(module->rev[0].date);
3920 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
3921 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
3922 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02003923
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003924 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
3925 value = module->rev[0].dsc;
3926 module->rev[0].dsc = module->rev[module->rev_size].dsc;
3927 module->rev[module->rev_size].dsc = value;
3928 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003929
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003930 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
3931 value = module->rev[0].ref;
3932 module->rev[0].ref = module->rev[module->rev_size].ref;
3933 module->rev[module->rev_size].ref = value;
3934 }
3935 }
Radek Krejcice7fb782015-05-29 16:52:34 +02003936
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003937 module->rev_size++;
3938 } else if (!strcmp(node->name, "typedef")) {
3939 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size]);
3940 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02003941
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003942 if (r) {
3943 goto error;
3944 }
3945 } else if (!strcmp(node->name, "identity")) {
3946 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
3947 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02003948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003949 if (r) {
3950 goto error;
3951 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003952 } else if (!strcmp(node->name, "feature")) {
3953 r = fill_yin_feature(module, node, &module->features[module->features_size]);
3954 module->features_size++;
3955
3956 if (r) {
3957 goto error;
3958 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02003959 } else if (!strcmp(node->name, "augment")) {
3960 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
3961 module->augment_size++;
3962
3963 if (r) {
3964 goto error;
3965 }
3966
3967 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
3968 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003969 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003971 lyxml_free_elem(ctx, node);
3972 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003973
Radek Krejcif5be10f2015-06-16 13:29:36 +02003974 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003975 * refer to them
3976 */
3977 LY_TREE_FOR_SAFE(grps.child, next, node) {
3978 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
3979 lyxml_free_elem(ctx, node);
Radek Krejci74705112015-06-05 10:25:44 +02003980
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003981 if (!mnode) {
3982 goto error;
3983 }
Radek Krejci74705112015-06-05 10:25:44 +02003984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003985 /* include data element */
3986 if (module->data) {
3987 module->data->prev->next = mnode;
3988 mnode->prev = module->data->prev;
3989 module->data->prev = mnode;
3990 } else {
3991 module->data = mnode;
3992 }
3993 }
3994 while (unres) {
3995 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
3996 goto error;
3997 }
3998 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
3999 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4000 goto error;
4001 }
4002 unres_next = unres->next;
4003 free(unres);
4004 unres = unres_next;
4005 }
Radek Krejci74705112015-06-05 10:25:44 +02004006
Radek Krejcif5be10f2015-06-16 13:29:36 +02004007 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004008 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02004009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004010 if (!strcmp(node->name, "container")) {
4011 mnode = read_yin_container(module, NULL, node, 1, &unres);
4012 } else if (!strcmp(node->name, "leaf-list")) {
4013 mnode = read_yin_leaflist(module, NULL, node, 1);
4014 } else if (!strcmp(node->name, "leaf")) {
4015 mnode = read_yin_leaf(module, NULL, node, 1);
4016 } else if (!strcmp(node->name, "list")) {
4017 mnode = read_yin_list(module, NULL, node, 1, &unres);
4018 } else if (!strcmp(node->name, "choice")) {
4019 mnode = read_yin_choice(module, NULL, node, 1, &unres);
4020 } else if (!strcmp(node->name, "uses")) {
4021 mnode = read_yin_uses(module, NULL, node, 1, &unres);
4022 } else if (!strcmp(node->name, "anyxml")) {
4023 mnode = read_yin_anyxml(module, NULL, node, 1);
4024 }
4025 lyxml_free_elem(ctx, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004026
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004027 if (!mnode) {
4028 goto error;
4029 }
Radek Krejci25d782a2015-05-22 15:03:23 +02004030
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004031 /* include data element */
4032 if (module->data) {
4033 module->data->prev->next = mnode;
4034 mnode->prev = module->data->prev;
4035 module->data->prev = mnode;
4036 } else {
4037 module->data = mnode;
4038 }
4039 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004040
4041 /* ... rpcs ... */
4042 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
4043 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
4044 lyxml_free_elem(ctx, node);
4045
4046 if (!mnode) {
4047 goto error;
4048 }
4049
4050 /* include rpc element */
4051 if (module->rpc) {
4052 module->rpc->prev->next = mnode;
4053 mnode->prev = module->rpc->prev;
4054 module->rpc->prev = mnode;
4055 } else {
4056 module->rpc = mnode;
4057 }
4058 }
4059
4060 /* ... and notifications */
4061 LY_TREE_FOR_SAFE(notifs.child, next, node) {
4062 mnode = read_yin_notif(module, NULL, node, 0, &unres);
4063 lyxml_free_elem(ctx, node);
4064
4065 if (!mnode) {
4066 goto error;
4067 }
4068
4069 /* include notification element */
4070 if (module->notif) {
4071 module->notif->prev->next = mnode;
4072 mnode->prev = module->notif->prev;
4073 module->notif->prev = mnode;
4074 } else {
4075 module->notif = mnode;
4076 }
4077 }
4078
4079 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004080 while (unres) {
4081 /* find referenced grouping */
4082 if (find_grouping(unres->mnode->parent, (struct ly_mnode_uses *)unres->mnode, unres->line)) {
4083 goto error;
4084 }
4085 if (!((struct ly_mnode_uses *)unres->mnode)->grp) {
4086 LOGVAL(VE_INARG, unres->line, unres->mnode->name, "uses");
4087 goto error;
4088 }
Radek Krejci74705112015-06-05 10:25:44 +02004089
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004090 /* resolve uses by copying grouping content under the uses */
4091 if (resolve_uses((struct ly_mnode_uses *)unres->mnode, unres->line)) {
4092 goto error;
4093 }
Radek Krejci74705112015-06-05 10:25:44 +02004094
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004095 unres_next = unres->next;
4096 free(unres);
4097 unres = unres_next;
4098 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004099
Radek Krejcif5be10f2015-06-16 13:29:36 +02004100 /* and finally apply augments */
4101 for (i = 0; i < module->augment_size; i++) {
4102 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004103 goto error;
4104 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004105 }
4106
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004107 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02004108
4109error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004110 /* cleanup */
4111 while (root.child) {
4112 lyxml_free_elem(module->ctx, root.child);
4113 }
4114 while (grps.child) {
4115 lyxml_free_elem(module->ctx, grps.child);
4116 }
4117 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004118 lyxml_free_elem(module->ctx, rpcs.child);
4119 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004121 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02004122}
4123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004124struct ly_submodule *
4125yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004126{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004127 struct lyxml_elem *yin;
4128 struct ly_submodule *submodule = NULL;
4129 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02004130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004131 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02004132
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004133 yin = lyxml_read(module->ctx, data, 0);
4134 if (!yin) {
4135 return NULL;
4136 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004137
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004138 /* check root element */
4139 if (!yin->name || strcmp(yin->name, "submodule")) {
4140 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4141 goto error;
4142 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004144 GETVAL(value, yin, "name");
4145 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4146 goto error;
4147 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004149 submodule = calloc(1, sizeof *submodule);
4150 if (!submodule) {
4151 LOGMEM;
4152 goto error;
4153 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004154
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004155 submodule->ctx = module->ctx;
4156 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
4157 submodule->type = 1;
4158 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02004159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004160 LOGVRB("reading submodule %s", submodule->name);
4161 if (read_sub_module((struct ly_module *)submodule, yin)) {
4162 goto error;
4163 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004164
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004165 /* cleanup */
4166 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02004167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004168 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02004169
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004170 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02004171
4172error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004173 /* cleanup */
4174 lyxml_free_elem(module->ctx, yin);
4175 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02004176
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004177 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02004178}
4179
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004180struct ly_module *
4181yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02004182{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004183 struct lyxml_elem *yin;
4184 struct ly_module *module = NULL, **newlist = NULL;
4185 const char *value;
4186 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02004187
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004188 yin = lyxml_read(ctx, data, 0);
4189 if (!yin) {
4190 return NULL;
4191 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004192
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004193 /* check root element */
4194 if (!yin->name || strcmp(yin->name, "module")) {
4195 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
4196 goto error;
4197 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004198
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004199 GETVAL(value, yin, "name");
4200 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
4201 goto error;
4202 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004204 module = calloc(1, sizeof *module);
4205 if (!module) {
4206 LOGMEM;
4207 goto error;
4208 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004209
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004210 module->ctx = ctx;
4211 module->name = lydict_insert(ctx, value, strlen(value));
4212 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02004213
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004214 LOGVRB("reading module %s", module->name);
4215 if (read_sub_module(module, yin)) {
4216 goto error;
4217 }
Radek Krejciefaeba32015-05-27 14:30:57 +02004218
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004219 /* add to the context's list of modules */
4220 if (ctx->models.used == ctx->models.size) {
4221 newlist = realloc(ctx->models.list, ctx->models.size * 2);
4222 if (!newlist) {
4223 LOGMEM;
4224 goto error;
4225 }
4226 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
4227 newlist[i] = NULL;
4228 }
4229 ctx->models.size *= 2;
4230 ctx->models.list = newlist;
4231 }
4232 for (i = 0; ctx->models.list[i]; i++) {
4233 /* check name (name/revision) and namespace uniqueness */
4234 if (!strcmp(ctx->models.list[i]->name, module->name)) {
4235 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
4236 /* both data models are same, with no revision specified */
4237 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
4238 module->name);
4239 goto error;
4240 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
4241 /* one of the models does not have a revision, so they differs */
4242 continue;
4243 } else {
4244 /* both models have a revision statement which we have to
4245 * compare, revision at position 0 is the last revision
4246 */
4247 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
4248 /* we have the same modules */
4249 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
4250 module->rev[0].date);
4251 goto error;
4252 }
4253 }
4254 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
4255 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
4256 ctx->models.list[i]->name, module->name, module->ns);
4257 goto error;
4258 }
4259 }
4260 ctx->models.list[i] = module;
4261 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004262
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004263 /* cleanup */
4264 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004265
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004266 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004267
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004268 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004269
4270error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004271 /* cleanup */
4272 lyxml_free_elem(ctx, yin);
4273 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004274
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004275 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004276}