blob: fbc45ff643f05f8b35014afeeab34ee148b62609 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file yin.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief YIN parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Radek Krejci812b10a2015-05-28 16:48:25 +020022#include <assert.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020023#include <ctype.h>
Radek Krejci8b4f23c2015-06-02 16:09:25 +020024#include <errno.h>
25#include <limits.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020026#include <stdint.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020027#include <stdlib.h>
28#include <string.h>
Radek Krejci25d782a2015-05-22 15:03:23 +020029#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020030
Radek Krejciefdd0ce2015-05-26 16:48:29 +020031#include "../libyang.h"
32#include "../common.h"
33#include "../context.h"
34#include "../dict.h"
35#include "../parser.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020036
Radek Krejciefdd0ce2015-05-26 16:48:29 +020037#include "../tree_internal.h"
38#include "../xml.h"
39
Radek Krejcice7fb782015-05-29 16:52:34 +020040enum LY_IDENT {
Radek Krejci994b6f62015-06-18 16:47:27 +020041 LY_IDENT_SIMPLE, /* only syntax rules */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020042 LY_IDENT_FEATURE,
43 LY_IDENT_IDENTITY,
44 LY_IDENT_TYPE,
45 LY_IDENT_NODE,
Radek Krejci994b6f62015-06-18 16:47:27 +020046 LY_IDENT_NAME, /* uniqueness across the siblings */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020047 LY_IDENT_PREFIX
Radek Krejcice7fb782015-05-29 16:52:34 +020048};
49
Radek Krejciefdd0ce2015-05-26 16:48:29 +020050#define LY_NSYIN "urn:ietf:params:xml:ns:yang:yin:1"
Radek Krejci6764bb32015-07-03 15:16:04 +020051#define LY_NSNACM "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
Radek Krejcida04f4a2015-05-21 12:54:09 +020052
Radek Krejcice7fb782015-05-29 16:52:34 +020053#define GETVAL(value, node, arg) \
54 value = lyxml_get_attr(node, arg, NULL); \
55 if (!value) { \
56 LOGVAL(VE_MISSARG, LOGLINE(node), arg, node->name); \
57 goto error; \
58 }
59
Radek Krejcib388c152015-06-04 17:03:03 +020060#define OPT_IDENT 0x01
61#define OPT_CONFIG 0x02
62#define OPT_MODULE 0x04
63#define OPT_INHERIT 0x08
Radek Krejci6764bb32015-07-03 15:16:04 +020064#define OPT_NACMEXT 0x10
Radek Krejcib388c152015-06-04 17:03:03 +020065static int read_yin_common(struct ly_module *, struct ly_mnode *, struct ly_mnode *, struct lyxml_elem *, int);
66
Radek Krejci8de7b0f2015-07-02 11:43:42 +020067struct obj_list {
68 void *obj;
69 struct obj_list *next;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020070 unsigned int line;
Radek Krejci74705112015-06-05 10:25:44 +020071};
72
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020073static struct ly_mnode *read_yin_choice(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020074 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020075static struct ly_mnode *read_yin_case(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020076 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020077static struct ly_mnode *read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
78 int resolve);
79static struct ly_mnode *read_yin_container(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020080 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020081static struct ly_mnode *read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
82 int resolve);
83static struct ly_mnode *read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin,
84 int resolve);
85static struct ly_mnode *read_yin_list(struct ly_module *module,struct ly_mnode *parent, struct lyxml_elem *yin,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020086 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020087static struct ly_mnode *read_yin_uses(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020088 int resolve, struct obj_list **unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020089static struct ly_mnode *read_yin_grouping(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *node,
Radek Krejci8de7b0f2015-07-02 11:43:42 +020090 int resolve, struct obj_list **unres);
Radek Krejcib0af6ba2015-06-18 15:01:03 +020091static struct ly_when *read_yin_when(struct ly_module *module,struct lyxml_elem *yin);
Radek Krejci74705112015-06-05 10:25:44 +020092
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020093static int
94dup_typedef_check(const char *type, struct ly_tpdf *tpdf, int size)
Radek Krejcieac35532015-05-31 19:09:15 +020095{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020096 int i;
Radek Krejcieac35532015-05-31 19:09:15 +020097
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020098 for (i = 0; i < size; i++) {
99 if (!strcmp(type, tpdf[i].name)) {
100 /* name collision */
101 return EXIT_FAILURE;
102 }
103 }
Radek Krejcieac35532015-05-31 19:09:15 +0200104
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200105 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200106}
107
Radek Krejcib05774c2015-06-18 13:52:59 +0200108
109static int
110dup_feature_check(const char *id, struct ly_module *module)
111{
112 int i;
113
114 for (i = 0; i < module->features_size; i++) {
115 if (!strcmp(id, module->features[i].name)) {
116 return EXIT_FAILURE;
117 }
118 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +0200119
120 return EXIT_SUCCESS;
Radek Krejcib05774c2015-06-18 13:52:59 +0200121}
122
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200123static int
124dup_prefix_check(const char *prefix, struct ly_module *module)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200125{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200127
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200128 if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
129 return EXIT_FAILURE;
130 }
131 for (i = 0; i < module->imp_size; i++) {
132 if (!strcmp(module->imp[i].prefix, prefix)) {
133 return EXIT_FAILURE;
134 }
135 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200137 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200138}
139
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200140static int
141check_identifier(const char *id, enum LY_IDENT type, unsigned int line,
142 struct ly_module *module, struct ly_mnode *parent)
Radek Krejcice7fb782015-05-29 16:52:34 +0200143{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200144 int i;
145 int size;
146 struct ly_tpdf *tpdf;
147 struct ly_mnode *mnode;
Radek Krejcice7fb782015-05-29 16:52:34 +0200148
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200149 assert(id);
Radek Krejcice7fb782015-05-29 16:52:34 +0200150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200151 /* check id syntax */
152 if (!(id[0] >= 'A' && id[0] <= 'Z') && !(id[0] >= 'a' && id[0] <= 'z') && id[0] != '_') {
153 LOGVAL(VE_INID, line, id, "invalid start character");
154 return EXIT_FAILURE;
155 }
156 for (i = 1; id[i]; i++) {
157 if (!(id[i] >= 'A' && id[i] <= 'Z') && !(id[i] >= 'a' && id[i] <= 'z')
158 && !(id[i] >= '0' && id[i] <= '9') && id[i] != '_' && id[i] != '-' && id[i] != '.') {
159 LOGVAL(VE_INID, line, id, "invalid character");
160 return EXIT_FAILURE;
161 }
162 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200163
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200164 if (i > 64) {
165 LOGWRN("Identifier \"%s\" is long, you should use something shorter.", id);
166 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200168 switch (type) {
169 case LY_IDENT_NAME:
170 /* check uniqueness of the node within its siblings */
171 if (!parent) {
172 break;
173 }
Radek Krejcib4cf2022015-06-03 14:40:05 +0200174
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200175 LY_TREE_FOR(parent->child, mnode) {
176 if (mnode->name == id) {
177 LOGVAL(VE_INID, line, id, "name duplication");
178 return EXIT_FAILURE;
179 }
180 }
181 break;
182 case LY_IDENT_TYPE:
183 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200184
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200185 /* check collision with the built-in types */
186 if (!strcmp(id, "binary") || !strcmp(id, "bits") ||
187 !strcmp(id, "boolean") || !strcmp(id, "decimal64") ||
188 !strcmp(id, "empty") || !strcmp(id, "enumeration") ||
189 !strcmp(id, "identityref") || !strcmp(id, "instance-identifier") ||
190 !strcmp(id, "int8") || !strcmp(id, "int16") ||
191 !strcmp(id, "int32") || !strcmp(id, "int64") ||
192 !strcmp(id, "leafref") || !strcmp(id, "string") ||
193 !strcmp(id, "uint8") || !strcmp(id, "uint16") ||
194 !strcmp(id, "uint32") || !strcmp(id, "uint64") || !strcmp(id, "union")) {
195 LOGVAL(VE_SPEC, line, "Typedef name duplicates built-in type.");
196 return EXIT_FAILURE;
197 }
Radek Krejcieac35532015-05-31 19:09:15 +0200198
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200199 /* check locally scoped typedefs (avoid name shadowing) */
200 for (; parent; parent = parent->parent) {
201 switch (parent->nodetype) {
202 case LY_NODE_CONTAINER:
203 size = ((struct ly_mnode_container *)parent)->tpdf_size;
204 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
205 break;
206 case LY_NODE_LIST:
207 size = ((struct ly_mnode_list *)parent)->tpdf_size;
208 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
209 break;
210 case LY_NODE_GROUPING:
211 size = ((struct ly_mnode_grp *)parent)->tpdf_size;
212 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
213 break;
214 default:
215 continue;
216 }
Radek Krejcieac35532015-05-31 19:09:15 +0200217
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200218 if (dup_typedef_check(id, tpdf, size)) {
219 LOGVAL(VE_DUPID, line, "typedef", id);
220 return EXIT_FAILURE;
221 }
222 }
Radek Krejcieac35532015-05-31 19:09:15 +0200223
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200224 /* check top-level names */
225 if (dup_typedef_check(id, module->tpdf, module->tpdf_size)) {
226 LOGVAL(VE_DUPID, line, "typedef", id);
227 return EXIT_FAILURE;
228 }
Radek Krejcieac35532015-05-31 19:09:15 +0200229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200230 /* check submodule's top-level names */
231 for (i = 0; i < module->inc_size; i++) {
232 if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
233 LOGVAL(VE_DUPID, line, "typedef", id);
234 return EXIT_FAILURE;
235 }
236 }
Radek Krejcieac35532015-05-31 19:09:15 +0200237
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200238 /* check top-level names in the main module */
239 if (module->type) {
240 if (dup_typedef_check(id, ((struct ly_submodule *)module)->belongsto->tpdf,
241 ((struct ly_submodule *)module)->belongsto->tpdf_size)) {
242 LOGVAL(VE_DUPID, line, "typedef", id);
243 return EXIT_FAILURE;
244 }
245 }
Radek Krejcieac35532015-05-31 19:09:15 +0200246
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200247 break;
248 case LY_IDENT_PREFIX:
249 assert(module);
Radek Krejcieac35532015-05-31 19:09:15 +0200250
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200251 if (module->type) {
252 /* go to the main module */
253 module = ((struct ly_submodule *)module)->belongsto;
254 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200255
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200256 /* check the main module itself */
257 if (dup_prefix_check(id, module)) {
258 LOGVAL(VE_DUPID, line, "prefix", id);
259 return EXIT_FAILURE;
260 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200261
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200262 /* and all its submodules */
263 for (i = 0; i < module->inc_size; i++) {
264 if (dup_prefix_check(id, (struct ly_module *)module->inc[i].submodule)) {
265 LOGVAL(VE_DUPID, line, "prefix", id);
266 return EXIT_FAILURE;
267 }
268 }
269 break;
Radek Krejcib05774c2015-06-18 13:52:59 +0200270 case LY_IDENT_FEATURE:
271 assert(module);
272
273 /* check feature name uniqness*/
Radek Krejci49babf32015-06-18 13:56:17 +0200274 /* check features in the current module */
Radek Krejcib05774c2015-06-18 13:52:59 +0200275 if (dup_feature_check(id, module)) {
276 LOGVAL(VE_DUPID, line, "feature", id);
277 return EXIT_FAILURE;
278 }
279
280 /* and all its submodules */
281 for (i = 0; i < module->inc_size; i++) {
282 if (dup_feature_check(id, (struct ly_module *)module->inc[i].submodule)) {
283 LOGVAL(VE_DUPID, line, "feature", id);
284 return EXIT_FAILURE;
285 }
286 }
287 break;
288
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200289 default:
290 /* no check required */
291 break;
292 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200293
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200294 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200295}
296
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200297static int
298check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
299 const char *name, int len)
Radek Krejci345ad742015-06-03 11:04:18 +0200300{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200301 char *dup = NULL;
302 int j;
Radek Krejci345ad742015-06-03 11:04:18 +0200303
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200304 /* existence */
305 if (!key) {
306 if (name[len] != '\0') {
307 dup = strdup(name);
308 dup[len] = '\0';
309 name = dup;
310 }
311 LOGVAL(VE_KEY_MISS, line, name);
312 free(dup);
313 return EXIT_FAILURE;
314 }
Radek Krejci345ad742015-06-03 11:04:18 +0200315
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200316 /* uniqueness */
317 for (j = index - 1; j >= 0; j--) {
318 if (list[index] == list[j]) {
319 LOGVAL(VE_KEY_DUP, line, key->name);
320 return EXIT_FAILURE;
321 }
322 }
Radek Krejci345ad742015-06-03 11:04:18 +0200323
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200324 /* key is a leaf */
325 if (key->nodetype != LY_NODE_LEAF) {
326 LOGVAL(VE_KEY_NLEAF, line, key->name);
327 return EXIT_FAILURE;
328 }
Radek Krejci345ad742015-06-03 11:04:18 +0200329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200330 /* type of the leaf is not built-in empty */
331 if (key->type.base == LY_TYPE_EMPTY) {
332 LOGVAL(VE_KEY_TYPE, line, key->name);
333 return EXIT_FAILURE;
334 }
Radek Krejci345ad742015-06-03 11:04:18 +0200335
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200336 /* config attribute is the same as of the list */
337 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
338 LOGVAL(VE_KEY_CONFIG, line, key->name);
339 return EXIT_FAILURE;
340 }
Radek Krejci345ad742015-06-03 11:04:18 +0200341
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200342 return EXIT_SUCCESS;
Radek Krejci345ad742015-06-03 11:04:18 +0200343}
344
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200345static int
Radek Krejci3de29a72015-06-16 15:23:03 +0200346check_mandatory(struct ly_mnode *mnode)
347{
348 struct ly_mnode *child;
349
350 assert(mnode);
351
352 if (mnode->flags & LY_NODE_MAND_TRUE) {
353 return EXIT_FAILURE;
354 }
355
Radek Krejcifd0bb0a2015-06-18 13:18:24 +0200356 if (mnode->nodetype == LY_NODE_CASE || mnode->nodetype == LY_NODE_CHOICE) {
357 LY_TREE_FOR(mnode->child, child) {
358 if (check_mandatory(child)) {
359 return EXIT_FAILURE;
360 }
Radek Krejci3de29a72015-06-16 15:23:03 +0200361 }
362 }
363
364 return EXIT_SUCCESS;
365}
366
367static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200368check_default(struct ly_type *type, const char *value)
Radek Krejcieac35532015-05-31 19:09:15 +0200369{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200370 /* TODO - RFC 6020, sec. 7.3.4 */
371 (void)type;
372 (void)value;
373 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +0200374}
375
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200376static int
377check_date(const char *date, unsigned int line)
Radek Krejcice7fb782015-05-29 16:52:34 +0200378{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200379 int i;
Radek Krejcice7fb782015-05-29 16:52:34 +0200380
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200381 assert(date);
Radek Krejcice7fb782015-05-29 16:52:34 +0200382
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200383 if (strlen(date) != LY_REV_SIZE - 1) {
384 goto error;
385 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200386
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200387 for (i = 0; i < LY_REV_SIZE - 1; i++) {
388 if (i == 4 || i == 7) {
389 if (date[i] != '-') {
390 goto error;
391 }
392 } else if (!isdigit(date[i])) {
393 goto error;
394 }
395 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200396
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200397 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +0200398
399error:
400
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200401 LOGVAL(VE_INDATE, line, date);
402 return EXIT_FAILURE;
Radek Krejcice7fb782015-05-29 16:52:34 +0200403}
404
Radek Krejci41726f92015-06-19 13:11:05 +0200405static int
406check_length(const char *expr, struct ly_type *type, unsigned int line)
407{
408 const char *c = expr;
409 char *tail;
410 uint64_t limit = 0, n;
411 int flg = 1; /* first run flag */
412
413 assert(expr);
414
415 /* TODO check compatibility with the restriction defined on type from which this type is derived,
416 * it will be the same function to check that the value from instance data respect the restriction */
417 (void)type;
418
419lengthpart:
420
421 while (isspace(*c)) {
422 c++;
423 }
424
425 /* lower boundary or explicit number */
426 if (!strncmp(c, "max", 3)) {
427max:
428 c += 3;
429 while (isspace(*c)) {
430 c++;
431 }
432 if (*c != '\0') {
433 goto error;
434 }
435
436 return EXIT_SUCCESS;
437
438 } else if (!strncmp(c, "min", 3)) {
439 if (!flg) {
440 /* min cannot be used elsewhere than in the first length-part */
441 goto error;
442 } else {
443 flg = 0;
444 /* remember value/lower boundary */
445 limit = 0;
446 }
447 c += 3;
448 while (isspace(*c)) {
449 c++;
450 }
451
452 if (*c == '|') {
453 c++;
454 /* process next length-parth */
455 goto lengthpart;
456 } else if (*c == '\0') {
457 return EXIT_SUCCESS;
458 } else if (!strncmp(c, "..", 2)) {
459upper:
460 c += 2;
461 while (isspace(*c)) {
462 c++;
463 }
464 if (*c == '\0') {
465 goto error;
466 }
467
468 /* upper boundary */
469 if (!strncmp(c, "max", 3)) {
470 goto max;
471 }
472
473 if (!isdigit(*c)) {
474 goto error;
475 }
476
477 n = strtol(c, &tail, 10);
478 c = tail;
479 while (isspace(*c)) {
480 c++;
481 }
482 if (n <= limit) {
483 goto error;
484 }
485 if (*c == '\0') {
486 return EXIT_SUCCESS;
487 } else if (*c == '|') {
488 c++;
489 /* remember the uppre boundary for check in next part */
490 limit = n;
491 /* process next length-parth */
492 goto lengthpart;
493 } else {
494 goto error;
495 }
496 } else {
497 goto error;
498 }
499
500 } else if (isdigit(*c)) {
501 /* number */
502 n = strtol(c, &tail, 10);
503 c = tail;
504 while (isspace(*c)) {
505 c++;
506 }
507 /* skip limit check in first length-part check */
508 if (!flg && n <= limit) {
509 goto error;
510 }
511 flg = 0;
512 limit = n;
513
514 if (*c == '|') {
515 c++;
516 /* process next length-parth */
517 goto lengthpart;
518 } else if (*c == '\0') {
519 return EXIT_SUCCESS;
520 } else if (!strncmp(c, "..", 2)) {
521 goto upper;
522 }
523 } /* else error */
524
525error:
526
527 LOGVAL(VE_INARG, line, expr, "length");
528 return EXIT_FAILURE;
529}
530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200531static const char *
532read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
Radek Krejcice7fb782015-05-29 16:52:34 +0200533{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200534 int len;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200536 /* there should be <text> child */
537 if (!node->child || !node->child->name || strcmp(node->child->name, name)) {
538 LOGWRN("Expected \"%s\" element in \"%s\" element.", name, node->name);
539 } else if (node->child->content) {
540 len = strlen(node->child->content);
541 return lydict_insert(ctx, node->child->content, len);
542 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200544 LOGVAL(VE_INARG, LOGLINE(node), name, node->name);
545 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200546}
547
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200548static struct ly_tpdf *
549find_superior_type(const char *name, struct ly_module *module, struct ly_mnode *parent)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200550{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200551 int i, j, found = 0;
552 int prefix_len = 0;
553 const char *qname;
554 struct ly_tpdf *tpdf;
555 int tpdf_size;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200556
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200557 qname = strchr(name, ':');
Radek Krejcida04f4a2015-05-21 12:54:09 +0200558
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200559 if (!qname) {
560 /* no prefix, try built-in types */
561 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
562 if (!strcmp(ly_types[i].def->name, name)) {
563 return ly_types[i].def;
564 }
565 }
566 qname = name;
567 } else {
568 /* set qname to correct position after colon */
569 prefix_len = qname - name;
570 qname++;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200571
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200572 if (!strncmp(name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
573 /* prefix refers to the current module, ignore it */
574 prefix_len = 0;
575 }
576 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200577
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200578 if (!prefix_len && parent) {
579 /* search in local typedefs */
580 while (parent) {
581 switch (parent->nodetype) {
582 case LY_NODE_CONTAINER:
583 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
584 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
585 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200586
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200587 case LY_NODE_LIST:
588 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
589 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
590 break;
Radek Krejci25d782a2015-05-22 15:03:23 +0200591
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200592 case LY_NODE_GROUPING:
593 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
594 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
595 break;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200596
Radek Krejci3cf9e222015-06-18 11:37:50 +0200597 /* TODO add rpc, notification, input, output */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200598 default:
599 parent = parent->parent;
600 continue;
601 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200602
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200603 for (i = 0; i < tpdf_size; i++) {
604 if (!strcmp(tpdf[i].name, qname)) {
605 return &tpdf[i];
606 }
607 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200608
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200609 parent = parent->parent;
610 }
611 } else if (prefix_len) {
612 /* get module where to search */
613 for (i = 0; i < module->imp_size; i++) {
614 if (!strncmp(module->imp[i].prefix, name, prefix_len) && !module->imp[i].prefix[prefix_len]) {
615 module = module->imp[i].module;
616 found = 1;
617 break;
618 }
619 }
620 if (!found) {
621 return NULL;
622 }
623 }
624
625 /* search in top level typedefs */
626 for (i = 0; i < module->tpdf_size; i++) {
627 if (!strcmp(module->tpdf[i].name, qname)) {
628 return &module->tpdf[i];
629 }
630 }
631
632 /* search in submodules */
633 for (i = 0; i < module->inc_size; i++) {
634 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
635 if (!strcmp(module->inc[i].submodule->tpdf[j].name, qname)) {
636 return &module->inc[i].submodule->tpdf[j];
637 }
638 }
639 }
640
641 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200642}
643
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200644static struct ly_ident *
645find_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
Radek Krejciefaeba32015-05-27 14:30:57 +0200646{
Michal Vasko4703e7d2015-07-03 09:21:07 +0200647 unsigned int i, j;
648 struct ly_ident *base_iter = NULL;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200649 struct ly_ident_der *der;
Radek Krejciefaeba32015-05-27 14:30:57 +0200650
Michal Vasko4703e7d2015-07-03 09:21:07 +0200651 /* search module */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200652 for (i = 0; i < module->ident_size; i++) {
653 if (!strcmp(basename, module->ident[i].name)) {
Radek Krejciefaeba32015-05-27 14:30:57 +0200654
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200655 if (!ident) {
656 /* just search for type, so do not modify anything, just return
657 * the base identity pointer
658 */
659 return &module->ident[i];
660 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200661
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200662 /* we are resolving identity definition, so now update structures */
663 ident->base = base_iter = &module->ident[i];
Radek Krejciefaeba32015-05-27 14:30:57 +0200664
Michal Vasko4703e7d2015-07-03 09:21:07 +0200665 break;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200666 }
667 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200668
Michal Vasko4703e7d2015-07-03 09:21:07 +0200669 /* search submodules */
670 if (!base_iter) {
671 for (j = 0; j < module->inc_size; j++) {
672 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
673 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
674
675 if (!ident) {
676 return &module->inc[j].submodule->ident[i];
677 }
678
679 ident->base = base_iter = &module->inc[j].submodule->ident[i];
680 break;
681 }
682 }
683 }
684 }
685
686 /* we found it somewhere */
687 if (base_iter) {
688 while (base_iter) {
689 for (der = base_iter->der; der && der->next; der = der->next);
690 if (der) {
691 der->next = malloc(sizeof *der);
692 der = der->next;
693 } else {
694 ident->base->der = der = malloc(sizeof *der);
695 }
696 der->next = NULL;
697 der->ident = ident;
698
699 base_iter = base_iter->base;
700 }
701 return ident->base;
702 }
703
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200704 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200705}
706
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200707static struct ly_ident *
708find_base_ident(struct ly_module *module, struct ly_ident *ident, struct lyxml_elem *node)
Radek Krejci04581c62015-05-22 21:24:00 +0200709{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200710 const char *name;
711 int prefix_len = 0;
712 int i, found = 0;
713 struct ly_ident *result;
714 const char *basename;
Radek Krejci04581c62015-05-22 21:24:00 +0200715
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200716 basename = lyxml_get_attr(node, "name", NULL);
717 if (!basename) {
718 LOGVAL(VE_MISSARG, LOGLINE(node), "name", "base");
719 return NULL;
720 }
Radek Krejci04581c62015-05-22 21:24:00 +0200721
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200722 /* search for the base identity */
723 name = strchr(basename, ':');
724 if (name) {
725 /* set name to correct position after colon */
726 prefix_len = name - basename;
727 name++;
Radek Krejci04581c62015-05-22 21:24:00 +0200728
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200729 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
730 /* prefix refers to the current module, ignore it */
731 prefix_len = 0;
732 }
733 } else {
734 name = basename;
735 }
Radek Krejci04581c62015-05-22 21:24:00 +0200736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200737 if (prefix_len) {
738 /* get module where to search */
739 for (i = 0; i < module->imp_size; i++) {
740 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
741 && !module->imp[i].prefix[prefix_len]) {
742 module = module->imp[i].module;
743 found = 1;
744 break;
745 }
746 }
747 if (!found) {
748 /* identity refers unknown data model */
749 LOGVAL(VE_INPREFIX, LOGLINE(node), basename);
750 return NULL;
751 }
752 } else {
753 /* search in submodules */
754 for (i = 0; i < module->inc_size; i++) {
755 result = find_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
756 if (result) {
757 return result;
758 }
759 }
760 }
Radek Krejci04581c62015-05-22 21:24:00 +0200761
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200762 /* search in the identified module */
763 result = find_base_ident_sub(module, ident, name);
764 if (!result) {
765 LOGVAL(VE_INARG, LOGLINE(node), basename, ident ? "identity" : "type");
766 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200767
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200768 return result;
Radek Krejci04581c62015-05-22 21:24:00 +0200769}
770
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200771static int
772fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
Radek Krejci04581c62015-05-22 21:24:00 +0200773{
Radek Krejci73adb602015-07-02 18:07:40 +0200774 struct lyxml_elem *node;
Radek Krejci04581c62015-05-22 21:24:00 +0200775
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200776 if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, OPT_IDENT | OPT_MODULE)) {
777 return EXIT_FAILURE;
778 }
Radek Krejci04581c62015-05-22 21:24:00 +0200779
Radek Krejci73adb602015-07-02 18:07:40 +0200780 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200781 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
782 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +0200783 continue;
784 }
785
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200786 if (!strcmp(node->name, "base")) {
787 if (ident->base) {
788 LOGVAL(VE_TOOMANY, LOGLINE(node), "base", "identity");
789 return EXIT_FAILURE;
790 }
791 if (!find_base_ident(module, ident, node)) {
792 return EXIT_FAILURE;
793 }
794 } else {
795 LOGVAL(VE_INSTMT, LOGLINE(node), node->name, "identity");
796 return EXIT_FAILURE;
797 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200798 }
Radek Krejci04581c62015-05-22 21:24:00 +0200799
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200800 return EXIT_SUCCESS;
Radek Krejci04581c62015-05-22 21:24:00 +0200801}
802
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200803static int
Radek Krejci0bd5db42015-06-19 13:30:07 +0200804read_restr_substmt(struct ly_ctx *ctx, struct ly_restr *restr, struct lyxml_elem *yin)
Radek Krejci41726f92015-06-19 13:11:05 +0200805{
Radek Krejci73adb602015-07-02 18:07:40 +0200806 struct lyxml_elem *child;
Radek Krejci461d1622015-06-30 14:06:28 +0200807 const char *value;
Radek Krejci41726f92015-06-19 13:11:05 +0200808
Radek Krejci73adb602015-07-02 18:07:40 +0200809 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200810 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
811 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +0200812 continue;
813 }
814
Radek Krejci41726f92015-06-19 13:11:05 +0200815 if (!strcmp(child->name, "description")) {
816 if (restr->dsc) {
817 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
818 return EXIT_FAILURE;
819 }
820 restr->dsc = read_yin_subnode(ctx, child, "text");
821 if (!restr->dsc) {
822 return EXIT_FAILURE;
823 }
824 } else if (!strcmp(child->name, "reference")) {
825 if (restr->ref) {
826 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
827 return EXIT_FAILURE;
828 }
829 restr->ref = read_yin_subnode(ctx, child, "text");
830 if (!restr->ref) {
831 return EXIT_FAILURE;
832 }
833 } else if (!strcmp(child->name, "error-app-tag")) {
834 if (restr->eapptag) {
835 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
836 return EXIT_FAILURE;
837 }
Radek Krejci461d1622015-06-30 14:06:28 +0200838 GETVAL(value, yin, "value");
839 restr->eapptag = lydict_insert(ctx, value, 0);
Radek Krejci41726f92015-06-19 13:11:05 +0200840 } else if (!strcmp(child->name, "error-message")) {
841 if (restr->emsg) {
842 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
843 return EXIT_FAILURE;
844 }
845 restr->emsg = read_yin_subnode(ctx, child, "value");
846 if (!restr->emsg) {
847 return EXIT_FAILURE;
848 }
849 } else {
850 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
851 return EXIT_FAILURE;
852 }
Radek Krejci41726f92015-06-19 13:11:05 +0200853 }
854
855 return EXIT_SUCCESS;
Michal Vaskoc8ef47f2015-06-29 14:56:19 +0200856
857error:
858 return EXIT_FAILURE;
Radek Krejci41726f92015-06-19 13:11:05 +0200859}
860
861static int
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200862fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200863{
Radek Krejcif2860132015-06-20 12:37:20 +0200864 const char *value, *delim, *name;
Radek Krejci5fbc9162015-06-19 14:11:11 +0200865 struct lyxml_elem *next, *node;
Radek Krejcif2860132015-06-20 12:37:20 +0200866 struct ly_restr **restr;
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200867 struct obj_list *unres_new;
Radek Krejci994b6f62015-06-18 16:47:27 +0200868 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200869 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200870 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200871
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200872 GETVAL(value, yin, "name");
873
874 if (!type->prefix) {
875 /* if we are trying to resolve unresolved type,
876 * prefix is already stored
877 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200878 delim = strchr(value, ':');
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200879 if (delim) {
880 type->prefix = lydict_insert(module->ctx, value, delim - value);
881 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200882 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200883
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200884 type->der = find_superior_type(value, module, parent);
885 if (!type->der) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200886 if (unres) {
887 /* store it for later resolving */
888 LOGVRB("Unresolved type of \"%s\" (line %d), trying to resolve it later", value, LOGLINE(yin));
889 unres_new = calloc(1, sizeof *unres_new);
890 if (*unres) {
891 unres_new->next = *unres;
892 }
893 /* keep XML data for later processing */
894 type->der = (struct ly_tpdf *)lyxml_dup_elem(module->ctx, yin, NULL, 1);
895
896 unres_new->obj = type;
897 unres_new->line = LOGLINE(yin);
898
899 /* put it at the beginning of the unresolved list */
900 *unres = unres_new;
901 return EXIT_SUCCESS;
902 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200903 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
904 goto error;
905 }
906 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200907
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200908 switch (type->base) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200909 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200910 /* RFC 6020 9.7.4 - bit */
911
912 /* get bit specifications, at least one must be present */
913 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200914 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
915 /* garbage */
916 lyxml_free_elem(module->ctx, node);
917 continue;
918 }
919
Radek Krejci994b6f62015-06-18 16:47:27 +0200920 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200921 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200922 } else {
923 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
924 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200925 }
926 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200927 if (!type->info.bits.count) {
928 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +0200929 /* this is just a derived type with no bit specified/required */
Radek Krejci994b6f62015-06-18 16:47:27 +0200930 break;
931 }
932 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
933 goto error;
934 }
935
936 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci73adb602015-07-02 18:07:40 +0200937 p = 0;
938 i = -1;
939 LY_TREE_FOR(yin->child, next) {
940 i++;
941
942 GETVAL(value, next, "name");
943 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(next), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200944 goto error;
945 }
946 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci73adb602015-07-02 18:07:40 +0200947 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], next, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200948 type->info.bits.count = i + 1;
949 goto error;
950 }
951
952 /* check the name uniqueness */
953 for (j = 0; j < i; j++) {
954 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci73adb602015-07-02 18:07:40 +0200955 LOGVAL(VE_BITS_DUPNAME, LOGLINE(next), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200956 type->info.bits.count = i + 1;
957 goto error;
958 }
959 }
960
Radek Krejci0d70c372015-07-02 16:23:10 +0200961 p_ = -1;
Radek Krejci73adb602015-07-02 18:07:40 +0200962 LY_TREE_FOR(next->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200963 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
964 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +0200965 continue;
Radek Krejci994b6f62015-06-18 16:47:27 +0200966 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200967
Radek Krejci0d70c372015-07-02 16:23:10 +0200968 if (!strcmp(node->name, "position")) {
969 GETVAL(value, node, "value");
970 p_ = strtol(value, NULL, 10);
971
972 /* range check */
973 if (p_ < 0 || p_ > UINT32_MAX) {
974 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
975 type->info.bits.count = i + 1;
976 goto error;
977 }
978 type->info.bits.bit[i].pos = (uint32_t)p_;
979
980 /* keep the highest enum value for automatic increment */
981 if (type->info.bits.bit[i].pos > p) {
982 p = type->info.bits.bit[i].pos;
983 p++;
984 } else {
985 /* check that the value is unique */
986 for (j = 0; j < i; j++) {
987 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
988 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
989 type->info.bits.count = i + 1;
990 goto error;
991 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200992 }
993 }
Radek Krejci0d70c372015-07-02 16:23:10 +0200994 } else {
Radek Krejci73adb602015-07-02 18:07:40 +0200995 LOGVAL(VE_INSTMT, LOGLINE(next), next->name);
Radek Krejci0d70c372015-07-02 16:23:10 +0200996 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200997 }
Radek Krejci0d70c372015-07-02 16:23:10 +0200998 }
999 if (p_ == -1) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001000 /* assign value automatically */
1001 if (p > UINT32_MAX) {
Radek Krejci73adb602015-07-02 18:07:40 +02001002 LOGVAL(VE_INARG, LOGLINE(next), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +02001003 type->info.bits.count = i + 1;
1004 goto error;
1005 }
1006 type->info.bits.bit[i].pos = (uint32_t)p;
1007 p++;
1008 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001009 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001010 break;
Radek Krejci25d782a2015-05-22 15:03:23 +02001011
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001012 case LY_TYPE_DEC64:
Radek Krejcif9401c32015-06-26 16:47:36 +02001013 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
Radek Krejci73adb602015-07-02 18:07:40 +02001014 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001015 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1016 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001017 continue;
1018 }
1019
Radek Krejcif9401c32015-06-26 16:47:36 +02001020 if (!strcmp(node->name, "range")) {
1021 if (type->info.dec64.range) {
1022 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1023 goto error;
1024 }
1025
1026 GETVAL(value, node, "value");
1027 if (check_length(value, type, LOGLINE(node))) {
1028 goto error;
1029 }
1030 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
1031 type->info.dec64.range->expr = lydict_insert(module->ctx, value, 0);
1032
1033 /* get possible substatements */
1034 if (read_restr_substmt(module->ctx, type->info.dec64.range, node)) {
1035 goto error;
1036 }
1037 } else if (!strcmp(node->name, "fraction-digits")) {
1038 if (type->info.dec64.dig) {
1039 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1040 goto error;
1041 }
1042 GETVAL(value, node, "value");
1043 v = strtol(value, NULL, 10);
1044
1045 /* range check */
1046 if (v < 1 || v > 18) {
1047 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1048 goto error;
1049 }
1050 type->info.dec64.dig = (uint8_t)v;
1051 } else {
1052 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1053 goto error;
1054 }
Radek Krejcif9401c32015-06-26 16:47:36 +02001055 }
1056
1057 /* mandatory sub-statement(s) check */
1058 if (!type->info.dec64.dig && !type->der->type.der) {
1059 /* decimal64 type directly derived from built-in type requires fraction-digits */
1060 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "fraction-digits", "type");
1061 goto error;
1062 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001063 break;
Radek Krejci25d782a2015-05-22 15:03:23 +02001064
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001065 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +02001066 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +02001067
Radek Krejci994b6f62015-06-18 16:47:27 +02001068 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001069 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001070 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1071 /* garbage */
1072 lyxml_free_elem(module->ctx, node);
1073 continue;
1074 }
1075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001076 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001077 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +02001078 } else {
1079 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1080 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001081 }
1082 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001083 if (!type->info.enums.count) {
1084 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001085 /* this is just a derived type with no enum specified/required */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001086 break;
1087 }
1088 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
1089 goto error;
1090 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001091
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001092 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci73adb602015-07-02 18:07:40 +02001093 v = 0;
1094 i = -1;
1095 LY_TREE_FOR(yin->child, next) {
1096 i++;
1097
1098 GETVAL(value, next, "name");
1099 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(next), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001100 goto error;
1101 }
1102 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci73adb602015-07-02 18:07:40 +02001103 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], next, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001104 type->info.enums.count = i + 1;
1105 goto error;
1106 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001107
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001108 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1109 value = type->info.enums.list[i].name;
1110 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci73adb602015-07-02 18:07:40 +02001111 LOGVAL(VE_ENUM_WS, LOGLINE(next), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001112 type->info.enums.count = i + 1;
1113 goto error;
1114 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001115
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001116 /* check the name uniqueness */
1117 for (j = 0; j < i; j++) {
1118 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci73adb602015-07-02 18:07:40 +02001119 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(next), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001120 type->info.enums.count = i + 1;
1121 goto error;
1122 }
1123 }
Radek Krejci04581c62015-05-22 21:24:00 +02001124
Radek Krejci0d70c372015-07-02 16:23:10 +02001125 v_ = -1;
Radek Krejci73adb602015-07-02 18:07:40 +02001126 LY_TREE_FOR(next->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001127 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1128 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001129 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001130 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001131
Radek Krejci0d70c372015-07-02 16:23:10 +02001132 if (!strcmp(node->name, "value")) {
1133 GETVAL(value, node, "value");
1134 v_ = strtol(value, NULL, 10);
1135
1136 /* range check */
1137 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1138 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1139 type->info.enums.count = i + 1;
1140 goto error;
1141 }
1142 type->info.enums.list[i].value = v_;
1143
1144 /* keep the highest enum value for automatic increment */
1145 if (type->info.enums.list[i].value > v) {
1146 v = type->info.enums.list[i].value;
1147 v++;
1148 } else {
1149 /* check that the value is unique */
1150 for (j = 0; j < i; j++) {
1151 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
1152 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value,
1153 type->info.enums.list[i].name);
1154 type->info.enums.count = i + 1;
1155 goto error;
1156 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001157 }
1158 }
Radek Krejci0d70c372015-07-02 16:23:10 +02001159 } else {
Radek Krejci73adb602015-07-02 18:07:40 +02001160 LOGVAL(VE_INSTMT, LOGLINE(next), next->name);
Radek Krejci0d70c372015-07-02 16:23:10 +02001161 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001162 }
Radek Krejci0d70c372015-07-02 16:23:10 +02001163 }
1164 if (v_ == -1) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001165 /* assign value automatically */
1166 if (v > INT32_MAX) {
Radek Krejci73adb602015-07-02 18:07:40 +02001167 LOGVAL(VE_INARG, LOGLINE(next), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001168 type->info.enums.count = i + 1;
1169 goto error;
1170 }
1171 type->info.enums.list[i].value = v;
1172 v++;
1173 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001174 }
1175 break;
1176
1177 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001178 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001179
1180 /* get base specification, exactly one must be present */
Radek Krejci0d70c372015-07-02 16:23:10 +02001181 LY_TREE_FOR_SAFE(yin->child, next, node) {
1182 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1183 /* garbage */
1184 lyxml_free_elem(module->ctx, node);
1185 continue;
1186 }
1187
1188 if (strcmp(yin->child->name, "base")) {
1189 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1190 goto error;
1191 }
1192 }
1193
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001194 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001195 if (type->der->type.der) {
1196 /* this is just a derived type with no base specified/required */
1197 break;
1198 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001199 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1200 goto error;
1201 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001202 if (yin->child->next) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001203 LOGVAL(VE_TOOMANY, LOGLINE(yin->child->next), yin->child->next->name, yin->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001204 goto error;
1205 }
1206 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1207 if (!type->info.ident.ref) {
1208 return EXIT_FAILURE;
1209 }
1210 break;
1211
1212 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001213 /* RFC 6020 9.13.2 - require-instance */
Radek Krejci73adb602015-07-02 18:07:40 +02001214 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001215 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1216 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001217 continue;
1218 }
1219
Radek Krejciaf351422015-06-19 14:49:38 +02001220 if (!strcmp(node->name, "require-instance")) {
1221 if (type->info.inst.req) {
1222 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1223 goto error;
1224 }
1225 GETVAL(value, node, "value");
1226 if (strcmp(value, "true")) {
1227 type->info.inst.req = 1;
1228 } else if (strcmp(value, "false")) {
1229 type->info.inst.req = -1;
1230 } else {
1231 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1232 goto error;
1233 }
1234 } else {
1235 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1236 goto error;
1237 }
Radek Krejciaf351422015-06-19 14:49:38 +02001238 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001239 break;
1240
Radek Krejcif2860132015-06-20 12:37:20 +02001241 case LY_TYPE_BINARY:
1242 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001243 case LY_TYPE_INT8:
1244 case LY_TYPE_INT16:
1245 case LY_TYPE_INT32:
1246 case LY_TYPE_INT64:
1247 case LY_TYPE_UINT8:
1248 case LY_TYPE_UINT16:
1249 case LY_TYPE_UINT32:
1250 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001251 /* RFC 6020 9.2.4 - range */
1252
1253 /* length and range are actually the same restriction, so process
1254 * them by this common code, we just need to differ the name and
1255 * structure where the information will be stored
1256 */
1257 if (type->base == LY_TYPE_BINARY) {
1258 restr = &type->info.binary.length;
1259 name = "length";
1260 } else {
1261 restr = &type->info.num.range;
1262 name = "range";
1263 }
1264
Radek Krejci73adb602015-07-02 18:07:40 +02001265 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001266 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1267 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001268 continue;
1269 }
1270
Radek Krejcif2860132015-06-20 12:37:20 +02001271 if (!strcmp(node->name, name)) {
1272 if (*restr) {
1273 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1274 goto error;
1275 }
1276
1277 GETVAL(value, node, "value");
1278 if (check_length(value, type, LOGLINE(node))) {
1279 goto error;
1280 }
1281 *restr = calloc(1, sizeof **restr);
1282 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1283
1284 /* get possible substatements */
1285 if (read_restr_substmt(module->ctx, *restr, node)) {
1286 goto error;
1287 }
1288 } else {
1289 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1290 goto error;
1291 }
Radek Krejcif2860132015-06-20 12:37:20 +02001292 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001293 break;
1294
1295 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001296 /* RFC 6020 9.9.2 - path */
Radek Krejci73adb602015-07-02 18:07:40 +02001297 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001298 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1299 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001300 continue;
1301 }
1302
Radek Krejcidc4c1412015-06-19 15:39:54 +02001303 if (!strcmp(node->name, "path")) {
1304 if (type->info.lref.path) {
1305 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1306 goto error;
1307 }
1308
1309 GETVAL(value, node, "value");
1310 /* TODO
1311 * it would be nice to perform here a check that target is leaf or leaf-list,
Radek Krejcic63c9b02015-06-26 16:51:31 +02001312 * but schema is not finished yet and path can point almost to anywhere, so
Radek Krejcidc4c1412015-06-19 15:39:54 +02001313 * we will have to check the path at the end of parsing the schema.
1314 */
1315 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1316 } else {
1317 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1318 goto error;
1319 }
Radek Krejci73adb602015-07-02 18:07:40 +02001320 }
1321
1322 if (!type->info.lref.path) {
1323 if (type->der->type.der) {
1324 /* this is just a derived type with no path specified/required */
1325 break;
1326 }
1327 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1328 goto error;
Radek Krejcidc4c1412015-06-19 15:39:54 +02001329 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001330 break;
1331
1332 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001333 /* RFC 6020 9.4.4 - length */
1334 /* RFC 6020 9.4.6 - pattern */
Radek Krejci73adb602015-07-02 18:07:40 +02001335 i = 0;
Radek Krejci3733a802015-06-19 13:43:21 +02001336 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001337 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1338 /* garbage */
1339 lyxml_free_elem(module->ctx, node);
1340 continue;
1341 }
1342
Radek Krejci3733a802015-06-19 13:43:21 +02001343 if (!strcmp(node->name, "length")) {
1344 if (type->info.str.length) {
1345 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1346 goto error;
1347 }
1348
1349 GETVAL(value, node, "value");
1350 if (check_length(value, type, LOGLINE(node))) {
1351 goto error;
1352 }
1353 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1354 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1355
Radek Krejci5fbc9162015-06-19 14:11:11 +02001356 /* get possible sub-statements */
1357 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001358 goto error;
1359 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001360 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001361 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci73adb602015-07-02 18:07:40 +02001362 i++;
Radek Krejci3733a802015-06-19 13:43:21 +02001363 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001364 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001365 goto error;
1366 }
1367 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001368 /* store patterns in array */
Radek Krejci73adb602015-07-02 18:07:40 +02001369 if (i) {
1370 type->info.str.patterns = calloc(i, sizeof *type->info.str.patterns);
1371 LY_TREE_FOR(yin->child, node) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001372 GETVAL(value, yin->child, "value");
Radek Krejci73adb602015-07-02 18:07:40 +02001373 type->info.str.patterns[type->info.str.pat_count].expr = lydict_insert(module->ctx, value, 0);
Radek Krejci5fbc9162015-06-19 14:11:11 +02001374
1375 /* get possible sub-statements */
Radek Krejci73adb602015-07-02 18:07:40 +02001376 if (read_restr_substmt(module->ctx, &type->info.str.patterns[type->info.str.pat_count], yin->child)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001377 goto error;
1378 }
Radek Krejci73adb602015-07-02 18:07:40 +02001379 type->info.str.pat_count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +02001380 }
1381 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001382 break;
1383
1384 case LY_TYPE_UNION:
Radek Krejcie4c366b2015-07-02 10:11:31 +02001385 /* RFC 6020 7.4 - type */
1386 /* count number of types in union */
1387 i = 0;
Radek Krejci0d70c372015-07-02 16:23:10 +02001388 LY_TREE_FOR_SAFE(yin->child, next, node) {
1389 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1390 /* garbage */
1391 lyxml_free_elem(module->ctx, node);
1392 continue;
1393 }
1394
Radek Krejcie4c366b2015-07-02 10:11:31 +02001395 if (!strcmp(node->name, "type")) {
1396 i++;
1397 } else {
1398 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1399 goto error;
1400 }
1401 }
1402
1403 if (!i) {
1404 if (type->der->type.der) {
1405 /* this is just a derived type with no base specified/required */
1406 break;
1407 }
1408 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", "(union) type");
1409 goto error;
1410 }
1411
1412 /* allocate array for union's types ... */
1413 type->info.uni.type = calloc(i, sizeof *type->info.uni.type);
1414 /* ... and fill the structures */
Radek Krejci73adb602015-07-02 18:07:40 +02001415 LY_TREE_FOR(yin->child, node) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001416 if (fill_yin_type(module, parent, node, &type->info.uni.type[type->info.uni.count], unres)) {
Radek Krejcie4c366b2015-07-02 10:11:31 +02001417 goto error;
1418 }
1419 type->info.uni.count++;
1420
1421 /* union's type cannot be empty or leafref */
1422 if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_EMPTY) {
1423 LOGVAL(VE_INARG, LOGLINE(node), "empty", node->name);
1424 goto error;
1425 } else if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_LEAFREF) {
1426 LOGVAL(VE_INARG, LOGLINE(node), "leafref", node->name);
1427 goto error;
1428 }
Radek Krejcie4c366b2015-07-02 10:11:31 +02001429 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001430 break;
1431
1432 default:
Radek Krejci6e328cd2015-06-26 16:24:11 +02001433 /* no sub-statement allowed in:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001434 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1435 */
Radek Krejci0d70c372015-07-02 16:23:10 +02001436 LY_TREE_FOR(yin->child, node) {
1437 if (node->ns && !strcmp(node->ns->value, LY_NSYIN)) {
1438 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1439 goto error;
1440 }
Radek Krejci6e328cd2015-06-26 16:24:11 +02001441 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001442 break;
1443 }
1444
1445 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001446
1447error:
1448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001449 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001450}
1451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001452static int
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001453fill_yin_typedef(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_tpdf *tpdf, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02001454{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001455 const char *value;
Radek Krejci73adb602015-07-02 18:07:40 +02001456 struct lyxml_elem *node;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001457
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001458 GETVAL(value, yin, "name");
1459 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1460 goto error;
1461 }
1462 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001463
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001464 /* generic part - status, description, reference */
1465 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1466 goto error;
1467 }
Radek Krejcieac35532015-05-31 19:09:15 +02001468
Radek Krejci73adb602015-07-02 18:07:40 +02001469 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001470 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1471 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001472 continue;
1473 }
1474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001475 if (!strcmp(node->name, "type")) {
1476 if (tpdf->type.der) {
1477 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1478 goto error;
1479 }
Radek Krejci73adb602015-07-02 18:07:40 +02001480 if (fill_yin_type(module, parent, node, &tpdf->type, unres)) {
1481 goto error;
1482 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001483 } else if (!strcmp(node->name, "default")) {
1484 if (tpdf->dflt) {
1485 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1486 goto error;
1487 }
1488 GETVAL(value, node, "value");
1489 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1490 } else if (!strcmp(node->name, "units")) {
1491 if (tpdf->units) {
1492 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1493 goto error;
1494 }
1495 GETVAL(value, node, "name");
1496 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1497 } else {
1498 LOGVAL(VE_INSTMT, LOGLINE(node), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001499 goto error;
1500 }
1501 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001502
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001503 /* check mandatory value */
1504 if (!tpdf->type.der) {
1505 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1506 goto error;
1507 }
Radek Krejcieac35532015-05-31 19:09:15 +02001508
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001509 /* check default value */
1510 if (check_default(&tpdf->type, tpdf->dflt)) {
1511 goto error;
1512 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001513
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001514 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001515
1516error:
1517
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001518 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001519}
1520
Radek Krejci3cf9e222015-06-18 11:37:50 +02001521static struct ly_feature *
1522resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1523{
1524 const char *prefix;
1525 unsigned int prefix_len = 0;
1526 int i, j, found = 0;
1527
1528 assert(name);
1529 assert(module);
1530
1531 /* check prefix */
1532 prefix = name;
1533 name = strchr(prefix, ':');
1534 if (name) {
1535 /* there is prefix */
1536 prefix_len = name - prefix;
1537 name++;
1538
1539 /* check whether the prefix points to the current module */
1540 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1541 /* then ignore prefix and works as there is no prefix */
1542 prefix_len = 0;
1543 }
1544 } else {
1545 /* no prefix, set pointers correctly */
1546 name = prefix;
1547 }
1548
1549 if (prefix_len) {
1550 /* search in imported modules */
1551 for (i = 0; i < module->imp_size; i++) {
1552 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1553 module = module->imp[i].module;
1554 found = 1;
1555 break;
1556 }
1557 }
1558 if (!found) {
1559 /* identity refers unknown data model */
1560 LOGVAL(VE_INPREFIX, line, prefix);
1561 return NULL;
1562 }
1563 } else {
1564 /* search in submodules */
1565 for (i = 0; i < module->inc_size; i++) {
1566 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1567 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1568 return &(module->inc[i].submodule->features[j]);
1569 }
1570 }
1571 }
1572 }
1573
1574 /* search in the identified module */
1575 for (j = 0; j < module->features_size; j++) {
1576 if (!strcmp(name, module->features[j].name)) {
1577 return &module->features[j];
1578 }
1579 }
1580
1581 /* not found */
1582 return NULL;
1583}
1584
1585static int
1586fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1587{
1588 const char *value;
1589 struct lyxml_elem *child, *next;
1590 int c = 0;
1591
Radek Krejcib05774c2015-06-18 13:52:59 +02001592 GETVAL(value, yin, "name");
1593 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1594 goto error;
1595 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001596 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci6a113852015-07-03 16:04:20 +02001597 f->module = module;
Radek Krejcib05774c2015-06-18 13:52:59 +02001598
Radek Krejci6a113852015-07-03 16:04:20 +02001599 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001600 goto error;
1601 }
1602
1603 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001604 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1605 /* garbage */
1606 lyxml_free_elem(module->ctx, child);
1607 continue;
1608 }
1609
Radek Krejci3cf9e222015-06-18 11:37:50 +02001610 if (!strcmp(child->name, "if-feature")) {
1611 c++;
1612 } else {
1613 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1614 goto error;
1615 }
1616 }
1617
1618 if (c) {
1619 f->features = calloc(c, sizeof *f->features);
1620 }
Radek Krejci73adb602015-07-02 18:07:40 +02001621 LY_TREE_FOR(yin->child, child) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001622 GETVAL(value, child, "name");
1623 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1624 if (!f->features[f->features_size]) {
1625 goto error;
1626 }
1627 f->features_size++;
1628 }
1629
Radek Krejci3cf9e222015-06-18 11:37:50 +02001630 return EXIT_SUCCESS;
1631
1632error:
1633
1634 return EXIT_FAILURE;
1635}
1636
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001637static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001638fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001639{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001640 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001641
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001642 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001643 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001644
Radek Krejci41726f92015-06-19 13:11:05 +02001645 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001646
Radek Krejci41726f92015-06-19 13:11:05 +02001647error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001648
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001649 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001650}
1651
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001652static int
Radek Krejcieb00f512015-07-01 16:44:58 +02001653parse_unique(struct ly_mnode *parent, struct lyxml_elem *node, struct ly_unique *uniq_s)
1654{
1655 const char *value;
Radek Krejcie82ce862015-07-01 16:49:39 +02001656 char *uniq_str = NULL, *uniq_val, *start;
Radek Krejcieb00f512015-07-01 16:44:58 +02001657 int i, j;
1658
1659 /* count the number of unique values */
1660 GETVAL(value, node, "tag");
1661 uniq_val = uniq_str = strdup(value);
1662 uniq_s->leafs_size = 0;
1663 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1664 uniq_s->leafs_size++;
1665 while (isspace(*uniq_val)) {
1666 uniq_val++;
1667 }
1668 }
1669 uniq_s->leafs_size++;
1670 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1671
1672 /* interconnect unique values with the leafs */
1673 uniq_val = uniq_str;
1674 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1675 start = uniq_val;
1676 if ((uniq_val = strpbrk(start, " \t\n"))) {
1677 *uniq_val = '\0'; /* add terminating NULL byte */
1678 uniq_val++;
1679 while (isspace(*uniq_val)) {
1680 uniq_val++;
1681 }
1682 } /* else only one nodeid present/left already NULL byte terminated */
1683
1684 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LY_NODE_USES);
1685 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LY_NODE_LEAF) {
1686 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1687 if (!uniq_s->leafs[i]) {
1688 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
1689 } else {
1690 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
1691 }
1692 goto error;
1693 }
1694
1695 for (j = 0; j < i; j++) {
1696 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
1697 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1698 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
1699 goto error;
1700 }
1701 }
1702 }
1703
1704 free(uniq_str);
1705 return EXIT_SUCCESS;
1706
1707error:
1708
1709 free(uniq_s->leafs);
1710 free(uniq_str);
1711
1712 return EXIT_FAILURE;
1713}
1714
1715/*
1716 * type: 0 - min, 1 - max
1717 */
1718static int
1719deviate_minmax(struct ly_mnode *target, struct lyxml_elem *node, struct ly_deviate *d, int type)
1720{
1721 const char *value;
1722 char *endptr;
1723 unsigned long val;
1724 uint32_t *ui32val;
1725
1726 /* check target node type */
1727 if (target->nodetype == LY_NODE_LEAFLIST) {
1728 if (type) {
1729 ui32val = &((struct ly_mnode_leaflist *)target)->max;
1730 } else {
1731 ui32val = &((struct ly_mnode_leaflist *)target)->min;
1732 }
1733 } else if (target->nodetype == LY_NODE_LIST) {
1734 if (type) {
1735 ui32val = &((struct ly_mnode_list *)target)->max;
1736 } else {
1737 ui32val = &((struct ly_mnode_list *)target)->min;
1738 }
1739 } else {
1740 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1741 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", node->name);
1742 goto error;
1743 }
1744
1745 GETVAL(value, node, "value");
1746 while (isspace(value[0])) {
1747 value++;
1748 }
1749
1750 /* convert it to uint32_t */
1751 errno = 0;
1752 endptr = NULL;
1753 val = strtoul(value, &endptr, 10);
1754 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1755 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1756 goto error;
1757 }
1758 if (type) {
1759 d->max = (uint32_t)val;
1760 } else {
1761 d->min = (uint32_t)val;
1762 }
1763
1764 if (d->mod == LY_DEVIATE_ADD) {
1765 /* check that there is no current value */
1766 if (*ui32val) {
1767 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1768 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1769 goto error;
1770 }
1771 }
1772
1773 if (d->mod == LY_DEVIATE_DEL) {
1774 /* check values */
1775 if ((uint32_t)val != *ui32val) {
1776 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1777 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1778 goto error;
1779 }
1780 /* remove current min-elements value of the target */
1781 *ui32val = 0;
1782 } else { /* add (already checked) and replace */
1783 /* set new value specified in deviation */
1784 *ui32val = (uint32_t)val;
1785 }
1786
1787 return EXIT_SUCCESS;
1788
1789error:
1790
1791 return EXIT_FAILURE;
1792}
1793
1794static int
1795fill_yin_deviation(struct ly_module *module, struct lyxml_elem *yin, struct ly_deviation *dev)
1796{
1797 const char *value, **stritem;
1798 struct lyxml_elem *next, *child, *develem;
1799 int c_dev = 0, c_must, c_uniq;
1800 int f_min = 0; /* flags */
1801 int i, j;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001802 struct ly_deviate *d = NULL;
1803 struct ly_mnode *mnode = NULL;
1804 struct ly_mnode_choice *choice = NULL;
1805 struct ly_mnode_leaf *leaf = NULL;
1806 struct ly_mnode_list *list = NULL;
1807 struct ly_type *t = NULL;
Radek Krejcie4c366b2015-07-02 10:11:31 +02001808 uint8_t *trg_must_size = NULL;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001809 struct ly_restr **trg_must = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001810
1811 GETVAL(value, yin, "target-node");
1812 dev->target_name = lydict_insert(module->ctx, value, 0);
1813
1814 /* resolve target node */
1815 dev->target = resolve_schema_nodeid(dev->target_name, NULL, module, LY_NODE_AUGMENT);
1816 if (!dev->target) {
1817 LOGVAL(VE_INARG, LOGLINE(yin), dev->target_name, yin->name);
1818 goto error;
1819 }
1820 if (dev->target->module == module) {
1821 LOGVAL(VE_SPEC, LOGLINE(yin), "Deviating own module is not allowed.");
1822 goto error;
1823 }
1824 /* mark the target module as deviated */
1825 dev->target->module->deviated = 1;
1826
1827 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001828 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1829 /* garbage */
1830 lyxml_free_elem(module->ctx, child);
1831 continue;
1832 }
1833
Radek Krejcieb00f512015-07-01 16:44:58 +02001834 if (!strcmp(child->name, "description")) {
1835 if (dev->dsc) {
1836 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1837 goto error;
1838 }
1839 dev->dsc = read_yin_subnode(module->ctx, child, "text");
1840 if (!dev->dsc) {
1841 goto error;
1842 }
1843 } else if (!strcmp(child->name, "reference")) {
1844 if (dev->ref) {
1845 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1846 goto error;
1847 }
1848 dev->ref = read_yin_subnode(module->ctx, child, "text");
1849 if (!dev->ref) {
1850 goto error;
1851 }
1852 } else if (!strcmp(child->name, "deviate")) {
1853 c_dev++;
1854
1855 /* skip lyxml_free_elem() at the end of the loop, node will be
1856 * further processed later
1857 */
1858 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02001859
Radek Krejcieb00f512015-07-01 16:44:58 +02001860 } else {
1861 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1862 goto error;
1863 }
1864
1865 lyxml_free_elem(module->ctx, child);
1866 }
1867
1868 if (c_dev) {
1869 dev->deviate = calloc(c_dev, sizeof *dev->deviate);
1870 }
1871
1872 LY_TREE_FOR(yin->child, develem) {
1873 /* init */
1874 f_min = 0;
1875 c_must = 0;
1876 c_uniq = 0;
1877
1878 /* get deviation type */
1879 GETVAL(value, develem, "value");
1880 if (!strcmp(value, "not-supported")) {
1881 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_NO;
1882 /* no property expected in this case */
1883 if (develem->child) {
1884 LOGVAL(VE_INSTMT, LOGLINE(develem->child), develem->child->name);
1885 goto error;
1886 }
1887
Radek Krejci5b917642015-07-02 09:03:13 +02001888 /* and neither any other deviate statement is expected,
1889 * not-supported deviation must be the only deviation of the target
1890 */
1891 if (dev->deviate_size || develem->next) {
1892 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1893 LOGVAL(VE_SPEC, 0, "\"not-supported\" deviation cannot be combined with any other deviation.");
1894 goto error;
1895 }
1896
1897
Radek Krejcieb00f512015-07-01 16:44:58 +02001898 /* remove target node */
1899 ly_mnode_free(dev->target);
Radek Krejci5b917642015-07-02 09:03:13 +02001900 dev->target = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001901
Radek Krejci5b917642015-07-02 09:03:13 +02001902 dev->deviate_size = 1;
1903 return EXIT_SUCCESS;
Radek Krejcieb00f512015-07-01 16:44:58 +02001904 } else if (!strcmp(value, "add")) {
1905 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_ADD;
1906 } else if (!strcmp(value, "replace")) {
1907 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_RPL;
1908 } else if (!strcmp(value, "delete")) {
1909 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_DEL;
1910 } else {
1911 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1912 goto error;
1913 }
1914 d = &dev->deviate[dev->deviate_size];
1915
1916 /* process deviation properties */
1917 LY_TREE_FOR_SAFE(develem->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001918 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1919 /* garbage */
1920 lyxml_free_elem(module->ctx, child);
1921 continue;
1922 }
1923
Radek Krejcieb00f512015-07-01 16:44:58 +02001924 if (!strcmp(child->name, "config")) {
1925 if (d->flags & LY_NODE_CONFIG_MASK) {
1926 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1927 goto error;
1928 }
1929
1930 /* for we deviate from RFC 6020 and allow config property even it is/is not
1931 * specified in the target explicitly since config property inherits. So we expect
1932 * that config is specified in every node. But for delete, we check that the value
1933 * is the same as here in deviation
1934 */
1935 GETVAL(value, child, "value");
1936 if (!strcmp(value, "false")) {
1937 d->flags |= LY_NODE_CONFIG_R;
1938 } else if (!strcmp(value, "true")) {
1939 d->flags |= LY_NODE_CONFIG_W;
1940 } else {
1941 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1942 goto error;
1943 }
1944
1945 if (d->mod == LY_DEVIATE_DEL) {
1946 /* check values */
1947 if ((d->flags & LY_NODE_CONFIG_MASK) != (dev->target->flags & LY_NODE_CONFIG_MASK)) {
1948 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1949 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1950 goto error;
1951 }
1952 /* remove current config value of the target ... */
1953 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1954
1955 /* ... and inherit config value from the target's parent */
1956 if (dev->target->parent) {
1957 dev->target->flags |= dev->target->parent->flags & LY_NODE_CONFIG_MASK;
1958 } else {
1959 /* default config is true */
1960 dev->target->flags |= LY_NODE_CONFIG_W;
1961 }
1962 } else { /* add and replace are the same in this case */
1963 /* remove current config value of the target ... */
1964 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1965
1966 /* ... and replace it with the value specified in deviation */
1967 dev->target->flags |= d->flags & LY_NODE_CONFIG_MASK;
1968 }
1969 } else if (!strcmp(child->name, "default")) {
1970 if (d->dflt) {
1971 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1972 goto error;
1973 }
1974 GETVAL(value, child, "value");
1975 d->dflt = lydict_insert(module->ctx, value, 0);
1976
1977 if (dev->target->nodetype == LY_NODE_CHOICE) {
1978 choice = (struct ly_mnode_choice *)dev->target;
1979
1980 if (d->mod == LY_DEVIATE_ADD) {
1981 /* check that there is no current value */
1982 if (choice->dflt) {
1983 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1984 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1985 goto error;
1986 }
1987 }
1988
1989 mnode = resolve_schema_nodeid(d->dflt, (struct ly_mnode *)choice, choice->module, LY_NODE_CHOICE);
1990 if (d->mod == LY_DEVIATE_DEL) {
1991 if (!choice->dflt || choice->dflt != mnode) {
1992 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1993 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1994 goto error;
1995 }
1996 } else { /* add (already checked) and replace */
1997 choice->dflt = mnode;
1998 if (!choice->dflt) {
1999 /* default branch not found */
2000 LOGVAL(VE_INARG, LOGLINE(yin), value, "default");
2001 goto error;
2002 }
2003 }
2004 } else if (dev->target->nodetype == LY_NODE_LEAF) {
2005 leaf = (struct ly_mnode_leaf *)dev->target;
2006
2007 if (d->mod == LY_DEVIATE_ADD) {
2008 /* check that there is no current value */
2009 if (leaf->dflt) {
2010 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2011 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2012 goto error;
2013 }
2014 }
2015
2016 if (d->mod == LY_DEVIATE_DEL) {
2017 if (!leaf->dflt || leaf->dflt != d->dflt) {
2018 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2019 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2020 goto error;
2021 }
2022 /* remove value */
2023 lydict_remove(leaf->module->ctx, leaf->dflt);
2024 leaf->dflt = NULL;
2025 } else { /* add (already checked) and replace */
2026 /* remove value */
2027 lydict_remove(leaf->module->ctx, leaf->dflt);
2028
2029 /* set new value */
2030 leaf->dflt = lydict_insert(leaf->module->ctx, d->dflt, 0);
2031 }
2032 } else {
2033 /* invalid target for default value */
2034 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2035 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2036 goto error;
2037 }
2038 } else if (!strcmp(child->name, "mandatory")) {
2039 if (d->flags & LY_NODE_MAND_MASK) {
2040 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2041 goto error;
2042 }
2043
2044 /* check target node type */
2045 if (!(dev->target->nodetype &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML))) {
2046 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2047 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2048 goto error;
2049 }
2050
2051 GETVAL(value, child, "value");
2052 if (!strcmp(value, "false")) {
2053 d->flags |= LY_NODE_MAND_FALSE;
2054 } else if (!strcmp(value, "true")) {
2055 d->flags |= LY_NODE_MAND_TRUE;
2056 } else {
2057 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2058 goto error;
2059 }
2060
2061 if (d->mod == LY_DEVIATE_ADD) {
2062 /* check that there is no current value */
2063 if (dev->target->flags & LY_NODE_MAND_MASK) {
2064 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2065 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2066 goto error;
2067 }
2068 }
2069
2070 if (d->mod == LY_DEVIATE_DEL) {
2071 /* check values */
2072 if ((d->flags & LY_NODE_MAND_MASK) != (dev->target->flags & LY_NODE_MAND_MASK)) {
2073 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2074 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2075 goto error;
2076 }
2077 /* remove current mandatory value of the target */
2078 dev->target->flags &= ~LY_NODE_MAND_MASK;
2079 } else { /* add (already checked) and replace */
2080 /* remove current mandatory value of the target ... */
2081 dev->target->flags &= ~LY_NODE_MAND_MASK;
2082
2083 /* ... and replace it with the value specified in deviation */
2084 dev->target->flags |= d->flags & LY_NODE_MAND_MASK;
2085 }
2086 } else if (!strcmp(child->name, "min-elements")) {
2087 if (f_min) {
2088 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2089 goto error;
2090 }
2091 f_min = 1;
2092
2093 if (deviate_minmax(dev->target, child, d, 0)) {
2094 goto error;
2095 }
2096 } else if (!strcmp(child->name, "max-elements")) {
2097 if (d->max) {
2098 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2099 goto error;
2100 }
2101
2102 if (deviate_minmax(dev->target, child, d, 1)) {
2103 goto error;
2104 }
2105 } else if (!strcmp(child->name, "must")) {
2106 c_must++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002107 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
2108 continue;
2109 } else if (!strcmp(child->name, "type")) {
2110 if (d->type) {
2111 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2112 goto error;
2113 }
2114
2115 /* check target node type */
2116 if (dev->target->nodetype == LY_NODE_LEAF) {
2117 t = &((struct ly_mnode_leaf *)dev->target)->type;
2118 } else if (dev->target->nodetype == LY_NODE_LEAFLIST) {
2119 t = &((struct ly_mnode_leaflist *)dev->target)->type;
2120 } else {
2121 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2122 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2123 goto error;
2124 }
2125
2126 if (d->mod == LY_DEVIATE_ADD) {
2127 /* not allowed, type is always present at the target */
2128 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2129 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2130 goto error;
2131 } else if (d->mod == LY_DEVIATE_DEL) {
2132 /* not allowed, type cannot be deleted from the target */
2133 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2134 LOGVAL(VE_SPEC, 0, "Deleteing type from the target is not allowed.");
2135 goto error;
2136 }
2137
2138 /* replace */
2139 /* remove current units value of the target ... */
2140 ly_type_free(dev->target->module->ctx, t);
2141
2142 /* ... and replace it with the value specified in deviation */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02002143 if (fill_yin_type(module, dev->target, child, t, NULL)) {
Radek Krejcieb00f512015-07-01 16:44:58 +02002144 goto error;
2145 }
2146 d->type = t;
2147 } else if (!strcmp(child->name, "unique")) {
2148 c_uniq++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002149 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
2150 continue;
2151 } else if (!strcmp(child->name, "units")) {
2152 if (d->units) {
2153 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2154 goto error;
2155 }
2156
2157 /* check target node type */
2158 if (dev->target->nodetype == LY_NODE_LEAFLIST) {
2159 stritem = &((struct ly_mnode_leaflist *)dev->target)->units;
2160 } else if (dev->target->nodetype == LY_NODE_LEAF) {
2161 stritem = &((struct ly_mnode_leaf *)dev->target)->units;
2162 } else {
2163 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2164 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2165 goto error;
2166 }
2167
2168 /* get units value */
2169 GETVAL(value, child, "name");
2170 d->units = lydict_insert(module->ctx, value, 0);
2171
2172 /* apply to target */
2173 if (d->mod == LY_DEVIATE_ADD) {
2174 /* check that there is no current value */
2175 if (*stritem) {
2176 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2177 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2178 goto error;
2179 }
2180 }
2181
2182 if (d->mod == LY_DEVIATE_DEL) {
2183 /* check values */
2184 if (*stritem != d->units) {
2185 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2186 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2187 goto error;
2188 }
2189 /* remove current units value of the target */
2190 lydict_remove(dev->target->module->ctx, *stritem);
2191 } else { /* add (already checked) and replace */
2192 /* remove current units value of the target ... */
2193 lydict_remove(dev->target->module->ctx, *stritem);
2194
2195 /* ... and replace it with the value specified in deviation */
2196 *stritem = lydict_insert(module->ctx, value, 0);
2197 }
2198 } else {
2199 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2200 goto error;
2201 }
2202
2203 lyxml_free_elem(module->ctx, child);
2204 }
2205
2206 if (c_must) {
2207 /* check target node type */
2208 switch (dev->target->nodetype) {
2209 case LY_NODE_LEAF:
2210 trg_must = &((struct ly_mnode_leaf *)dev->target)->must;
2211 trg_must_size = &((struct ly_mnode_leaf *)dev->target)->must_size;
2212 break;
2213 case LY_NODE_CONTAINER:
2214 trg_must = &((struct ly_mnode_container *)dev->target)->must;
2215 trg_must_size = &((struct ly_mnode_container *)dev->target)->must_size;
2216 break;
2217 case LY_NODE_LEAFLIST:
2218 trg_must = &((struct ly_mnode_leaflist *)dev->target)->must;
2219 trg_must_size = &((struct ly_mnode_leaflist *)dev->target)->must_size;
2220 break;
2221 case LY_NODE_LIST:
2222 trg_must = &((struct ly_mnode_list *)dev->target)->must;
2223 trg_must_size = &((struct ly_mnode_list *)dev->target)->must_size;
2224 break;
2225 case LY_NODE_ANYXML:
2226 trg_must = &((struct ly_mnode_anyxml *)dev->target)->must;
2227 trg_must_size = &((struct ly_mnode_anyxml *)dev->target)->must_size;
2228 break;
2229 default:
2230 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2231 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2232 goto error;
2233 }
2234
2235 if (d->mod == LY_DEVIATE_RPL) {
2236 /* remove target's musts and allocate new array for it */
2237 if (!*trg_must) {
2238 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2239 LOGVAL(VE_SPEC, 0, "Property \"must\" to replace does not exists in target.");
2240 goto error;
2241 }
2242
2243 for (i = 0; i < list->must_size; i++) {
2244 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2245 }
2246 free(*trg_must);
2247 *trg_must = d->must = calloc(c_must, sizeof *d->must);
2248 d->must_size = c_must;
2249 *trg_must_size = 0;
2250 } else if (d->mod == LY_DEVIATE_ADD) {
2251 /* reallocate the must array of the target */
2252 d->must = realloc(*trg_must, (c_must + *trg_must_size) * sizeof *d->must);
2253 *trg_must = d->must;
2254 d->must = &(*trg_must[*trg_must_size]);
2255 d->must_size = c_must;
2256 } else { /* LY_DEVIATE_DEL */
2257 d->must = calloc(c_must, sizeof *d->must);
2258 }
2259 }
2260 if (c_uniq) {
2261 /* check target node type */
2262 if (dev->target->nodetype != LY_NODE_LIST) {
2263 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2264 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2265 goto error;
2266 }
2267
2268 list = (struct ly_mnode_list *)dev->target;
2269 if (d->mod == LY_DEVIATE_RPL) {
2270 /* remove target's unique and allocate new array for it */
2271 if (!list->unique) {
2272 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2273 LOGVAL(VE_SPEC, 0, "Property \"unique\" to replace does not exists in target.");
2274 goto error;
2275 }
2276
2277 for (i = 0; i < list->unique_size; i++) {
2278 free(list->unique[i].leafs);
2279 }
2280 free(list->unique);
2281 list->unique = d->unique = calloc(c_uniq, sizeof *d->unique);
2282 d->unique_size = c_uniq;
2283 list->unique_size = 0;
2284 } else if (d->mod == LY_DEVIATE_ADD) {
2285 /* reallocate the unique array of the target */
2286 d->unique = realloc(list->unique, (c_uniq + list->unique_size) * sizeof *d->unique);
2287 list->unique = d->unique;
2288 d->unique = &list->unique[list->unique_size];
2289 d->unique_size = c_uniq;
2290 } else { /* LY_DEVIATE_DEL */
2291 d->unique = calloc(c_uniq, sizeof *d->unique);
2292 }
2293 }
2294
2295 /* process deviation properties with 0..n cardinality */
Radek Krejci73adb602015-07-02 18:07:40 +02002296 LY_TREE_FOR(develem->child, child) {
Radek Krejcieb00f512015-07-01 16:44:58 +02002297 if (!strcmp(child->name, "must")) {
2298 if (d->mod == LY_DEVIATE_DEL) {
2299 if (fill_yin_must(module, child, &d->must[d->must_size])) {
2300 goto error;
2301 }
2302
2303 /* find must to delete, we are ok with just matching conditions */
2304 for (i = 0; i < *trg_must_size; i++) {
2305 if (d->must[d->must_size].expr == (*trg_must)[i].expr) {
2306 /* we have a match, free the must structure ... */
2307 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2308 /* ... and maintain the array */
2309 (*trg_must_size)--;
2310 if (i != *trg_must_size) {
2311 (*trg_must)[i].expr = (*trg_must)[*trg_must_size].expr;
2312 (*trg_must)[i].dsc = (*trg_must)[*trg_must_size].dsc;
2313 (*trg_must)[i].ref = (*trg_must)[*trg_must_size].ref;
2314 (*trg_must)[i].eapptag = (*trg_must)[*trg_must_size].eapptag;
2315 (*trg_must)[i].emsg = (*trg_must)[*trg_must_size].emsg;
2316 }
2317 if (!(*trg_must_size)) {
2318 free(*trg_must);
2319 *trg_must = NULL;
2320 } else {
2321 (*trg_must)[*trg_must_size].expr = NULL;
2322 (*trg_must)[*trg_must_size].dsc = NULL;
2323 (*trg_must)[*trg_must_size].ref = NULL;
2324 (*trg_must)[*trg_must_size].eapptag = NULL;
2325 (*trg_must)[*trg_must_size].emsg = NULL;
2326 }
2327
2328 i = -1; /* set match flag */
2329 break;
2330 }
2331 }
2332 d->must_size++;
2333 if (i != -1) {
2334 /* no match found */
2335 LOGVAL(VE_INARG, LOGLINE(child), d->must[d->must_size - 1].expr, child->name);
2336 LOGVAL(VE_SPEC, 0, "Value does not match any must from the target.");
2337 goto error;
2338 }
2339 } else { /* replace or add */
2340 if (fill_yin_must(dev->target->module, child, &((*trg_must)[*trg_must_size]))) {
2341 goto error;
2342 }
2343 (*trg_must_size)++;
2344 }
2345 } else if (!strcmp(child->name, "unique")) {
2346 if (d->mod == LY_DEVIATE_DEL) {
2347 if (parse_unique(dev->target, child, &d->unique[d->unique_size])) {
2348 goto error;
2349 }
2350
2351 /* find unique structures to delete */
2352 for (i = 0; i < list->unique_size; i++) {
2353 if (list->unique[i].leafs_size != d->unique[d->unique_size].leafs_size) {
2354 continue;
2355 }
2356
2357 for (j = 0; j < d->unique[d->unique_size].leafs_size; j++) {
2358 if (list->unique[i].leafs[j] != d->unique[d->unique_size].leafs[j]) {
2359 break;
2360 }
2361 }
2362
2363 if (j == d->unique[d->unique_size].leafs_size) {
2364 /* we have a match, free the unique structure ... */
2365 free(list->unique[i].leafs);
2366 /* ... and maintain the array */
2367 list->unique_size--;
2368 if (i != list->unique_size) {
2369 list->unique[i].leafs_size = list->unique[list->unique_size].leafs_size;
2370 list->unique[i].leafs = list->unique[list->unique_size].leafs;
2371 }
2372
2373 if (!list->unique_size) {
2374 free(list->unique);
2375 list->unique = NULL;
2376 } else {
2377 list->unique[list->unique_size].leafs_size = 0;
2378 list->unique[list->unique_size].leafs = NULL;
2379 }
2380
2381 i = -1; /* set match flag */
2382 break;
2383 }
2384 }
2385
2386 d->unique_size++;
2387 if (i != -1) {
2388 /* no match found */
2389 LOGVAL(VE_INARG, LOGLINE(child), lyxml_get_attr(child, "tag", NULL), child->name);
2390 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2391 goto error;
2392 }
2393 } else { /* replace or add */
2394 if (parse_unique(dev->target, child, &list->unique[list->unique_size])) {
2395 goto error;
2396 }
2397 list->unique_size++;
2398 }
2399 }
Radek Krejcieb00f512015-07-01 16:44:58 +02002400 }
Radek Krejci5b917642015-07-02 09:03:13 +02002401
2402 dev->deviate_size++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002403 }
2404
Radek Krejcieb00f512015-07-01 16:44:58 +02002405 return EXIT_SUCCESS;
2406
2407error:
2408
2409 if (dev->deviate) {
2410 for (i = 0; i < dev->deviate_size; i++) {
2411 lydict_remove(module->ctx, dev->deviate[i].dflt);
2412 lydict_remove(module->ctx, dev->deviate[i].units);
2413
2414 if (dev->deviate[i].mod == LY_DEVIATE_DEL) {
2415 for (j = 0; j < dev->deviate[i].must_size; j++) {
2416 ly_restr_free(module->ctx, &dev->deviate[i].must[j]);
2417 }
2418 free(dev->deviate[i].must);
2419
2420 for (j = 0; j < dev->deviate[i].unique_size; j++) {
2421 free(dev->deviate[i].unique[j].leafs);
2422 }
2423 free(dev->deviate[i].unique);
2424 }
2425 }
2426 free(dev->deviate);
2427 }
2428
2429 return EXIT_FAILURE;
2430}
2431
2432static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002433fill_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 +02002434{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002435 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002436 struct lyxml_elem *next, *child;
2437 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02002438
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002439 GETVAL(value, yin, "target-node");
2440 aug->target_name = lydict_insert(module->ctx, value, 0);
2441 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02002442
Radek Krejci6a113852015-07-03 16:04:20 +02002443 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, OPT_NACMEXT)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002444 goto error;
2445 }
2446
2447 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002448 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2449 /* garbage */
2450 lyxml_free_elem(module->ctx, child);
2451 continue;
2452 }
2453
Radek Krejci3cf9e222015-06-18 11:37:50 +02002454 if (!strcmp(child->name, "if-feature")) {
2455 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002456 } else if (!strcmp(child->name, "when")) {
2457 if (aug->when) {
2458 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2459 goto error;
2460 }
2461
2462 aug->when = read_yin_when(module, child);
2463 lyxml_free_elem(module->ctx, child);
2464
2465 if (!aug->when) {
2466 goto error;
2467 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002468
2469 /* check allowed sub-statements */
2470 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
2471 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
2472 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
2473 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2474 goto error;
2475 }
2476 }
2477
2478 if (c) {
2479 aug->features = calloc(c, sizeof *aug->features);
2480 }
2481
2482 LY_TREE_FOR_SAFE(yin->child, next, child) {
2483 if (!strcmp(child->name, "if-feature")) {
2484 GETVAL(value, child, "name");
2485 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
2486 if (!aug->features[aug->features_size]) {
2487 goto error;
2488 }
2489 aug->features_size++;
Radek Krejci73adb602015-07-02 18:07:40 +02002490 lyxml_free_elem(module->ctx, child);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002491 }
2492
Radek Krejci73adb602015-07-02 18:07:40 +02002493 /* data nodes are still kept under yin */
Radek Krejci3cf9e222015-06-18 11:37:50 +02002494 }
2495
2496 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002497 * when we will have the target node
2498 */
2499 lyxml_unlink_elem(yin);
2500 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02002501
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002502 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02002503
2504error:
2505
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002506 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02002507}
2508
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002509static int
2510fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02002511{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002512 struct lyxml_elem *sub, *next;
2513 const char *value;
2514 char *endptr;
2515 int f_mand = 0, f_min = 0, f_max = 0;
2516 int c_must = 0;
2517 int r;
2518 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002519
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002520 GETVAL(value, yin, "target-node");
2521 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02002522
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002523 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
2524 goto error;
2525 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002526
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002527 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002528 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
2529 /* garbage */
2530 lyxml_free_elem(module->ctx, sub);
2531 continue;
2532 }
2533
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002534 /* limited applicability */
2535 if (!strcmp(sub->name, "default")) {
2536 /* leaf or choice */
2537 if (rfn->mod.dflt) {
2538 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2539 goto error;
2540 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002542 /* check possibility of statements combination */
2543 if (rfn->target_type) {
2544 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
2545 if (!rfn->target_type) {
2546 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2547 goto error;
2548 }
2549 } else {
2550 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
2551 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002552
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002553 GETVAL(value, sub, "value");
2554 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
2555 } else if (!strcmp(sub->name, "mandatory")) {
2556 /* leaf, choice or anyxml */
2557 if (f_mand) {
2558 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2559 goto error;
2560 }
2561 /* just checking the flags in leaf is not sufficient, we would allow
2562 * multiple mandatory statements with the "false" value
2563 */
2564 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002565
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002566 /* check possibility of statements combination */
2567 if (rfn->target_type) {
2568 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
2569 if (!rfn->target_type) {
2570 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2571 goto error;
2572 }
2573 } else {
2574 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
2575 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002577 GETVAL(value, sub, "value");
2578 if (!strcmp(value, "true")) {
2579 rfn->flags |= LY_NODE_MAND_TRUE;
2580 } else if (!strcmp(value, "false")) {
2581 rfn->flags |= LY_NODE_MAND_FALSE;
2582 } else {
2583 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2584 goto error;
2585 }
2586 } else if (!strcmp(sub->name, "min-elements")) {
2587 /* list or leaf-list */
2588 if (f_min) {
2589 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2590 goto error;
2591 }
2592 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002593
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002594 /* check possibility of statements combination */
2595 if (rfn->target_type) {
2596 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2597 if (!rfn->target_type) {
2598 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2599 goto error;
2600 }
2601 } else {
2602 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2603 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002604
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002605 GETVAL(value, sub, "value");
2606 while (isspace(value[0])) {
2607 value++;
2608 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002609
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002610 /* convert it to uint32_t */
2611 errno = 0;
2612 endptr = NULL;
2613 val = strtoul(value, &endptr, 10);
2614 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2615 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2616 goto error;
2617 }
2618 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002619
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002620 /* magic - bit 3 in flags means min set */
2621 rfn->flags |= 0x04;
2622 } else if (!strcmp(sub->name, "max-elements")) {
2623 /* list or leaf-list */
2624 if (f_max) {
2625 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2626 goto error;
2627 }
2628 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002629
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002630 /* check possibility of statements combination */
2631 if (rfn->target_type) {
2632 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2633 if (!rfn->target_type) {
2634 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2635 goto error;
2636 }
2637 } else {
2638 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2639 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002640
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002641 GETVAL(value, sub, "value");
2642 while (isspace(value[0])) {
2643 value++;
2644 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002645
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002646 /* convert it to uint32_t */
2647 errno = 0;
2648 endptr = NULL;
2649 val = strtoul(value, &endptr, 10);
2650 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2651 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2652 goto error;
2653 }
2654 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002655
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002656 /* magic - bit 4 in flags means min set */
2657 rfn->flags |= 0x08;
2658 } else if (!strcmp(sub->name, "presence")) {
2659 /* container */
2660 if (rfn->mod.presence) {
2661 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2662 goto error;
2663 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002664
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002665 /* check possibility of statements combination */
2666 if (rfn->target_type) {
2667 rfn->target_type &= LY_NODE_CONTAINER;
2668 if (!rfn->target_type) {
2669 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2670 goto error;
2671 }
2672 } else {
2673 rfn->target_type = LY_NODE_CONTAINER;
2674 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002675
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002676 GETVAL(value, sub, "value");
2677 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
2678 } else if (!strcmp(sub->name, "must")) {
2679 /* leaf-list, list, container or anyxml */
2680 /* check possibility of statements combination */
2681 if (rfn->target_type) {
2682 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
2683 if (!rfn->target_type) {
2684 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2685 goto error;
2686 }
2687 } else {
2688 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
2689 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002690
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002691 c_must++;
Radek Krejci41882de2015-07-02 16:34:58 +02002692 continue;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002693
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002694 } else {
2695 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2696 goto error;
2697 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002698
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002699 lyxml_free_elem(module->ctx, sub);
2700 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002701
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002702 /* process nodes with cardinality of 0..n */
2703 if (c_must) {
2704 rfn->must = calloc(c_must, sizeof *rfn->must);
2705 }
Radek Krejci73adb602015-07-02 18:07:40 +02002706 LY_TREE_FOR(yin->child, sub) {
2707 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
2708 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002709
Radek Krejci73adb602015-07-02 18:07:40 +02002710 if (r) {
2711 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002712 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002713 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002715 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002716
2717error:
2718
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002719 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002720}
2721
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002722static int
2723fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02002724{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002725 struct lyxml_elem *child;
2726 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002728 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002729 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2730 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02002731 continue;
2732 }
2733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002734 if (!strcmp(child->name, "prefix")) {
2735 GETVAL(value, child, "value");
2736 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
2737 goto error;
2738 }
2739 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
2740 } else if (!strcmp(child->name, "revision-date")) {
2741 if (imp->rev[0]) {
2742 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2743 goto error;
2744 }
2745 GETVAL(value, child, "date");
2746 if (check_date(value, LOGLINE(child))) {
2747 goto error;
2748 }
2749 memcpy(imp->rev, value, LY_REV_SIZE - 1);
2750 } else {
2751 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2752 goto error;
2753 }
2754 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002756 /* check mandatory information */
2757 if (!imp->prefix) {
2758 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
2759 goto error;
2760 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002761
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002762 GETVAL(value, yin, "module");
2763 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
2764 if (!imp->module) {
2765 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
2766 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2767 goto error;
2768 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002769
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002770 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002771
2772error:
2773
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002774 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002775}
2776
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002777static int
2778fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02002779{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002780 struct lyxml_elem *child;
2781 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002782
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002783 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002784 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2785 /* garbage */
2786 continue;
2787 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002788 if (!strcmp(child->name, "revision-date")) {
2789 if (inc->rev[0]) {
2790 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2791 goto error;
2792 }
2793 GETVAL(value, child, "date");
2794 if (check_date(value, LOGLINE(child))) {
2795 goto error;
2796 }
2797 memcpy(inc->rev, value, LY_REV_SIZE - 1);
2798 } else {
2799 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2800 goto error;
2801 }
2802 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002803
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002804 GETVAL(value, yin, "module");
Michal Vasko7bf06882015-07-03 15:33:56 +02002805 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL, 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002806 if (!inc->submodule) {
2807 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
2808 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2809 goto error;
2810 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002811
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002812 /* check that belongs-to corresponds */
2813 if (module->type) {
2814 module = ((struct ly_submodule *)module)->belongsto;
2815 }
2816 if (inc->submodule->belongsto != module) {
2817 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2818 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
2819 goto error;
2820 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002821
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002822 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002823
2824error:
2825
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002826 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002827}
2828
Radek Krejcida04f4a2015-05-21 12:54:09 +02002829/*
2830 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02002831 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02002832 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02002833 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002834static int
2835read_yin_common(struct ly_module *module, struct ly_mnode *parent,
2836 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002837{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002838 const char *value;
2839 struct lyxml_elem *sub, *next;
2840 struct ly_ctx *const ctx = module->ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002841
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002842 if (opt & OPT_MODULE) {
2843 mnode->module = module;
2844 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002845
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002846 if (opt & OPT_IDENT) {
2847 GETVAL(value, xmlnode, "name");
2848 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
2849 goto error;
2850 }
2851 mnode->name = lydict_insert(ctx, value, strlen(value));
2852 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002853
Radek Krejci6764bb32015-07-03 15:16:04 +02002854 /* inherit NACM flags */
Radek Krejci6a113852015-07-03 16:04:20 +02002855 if ((opt & OPT_NACMEXT) && parent) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002856 mnode->nacm = parent->nacm;
2857 }
2858
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002859 /* process local parameters */
2860 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002861 if (!sub->ns) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002862 /* garbage */
Radek Krejci6764bb32015-07-03 15:16:04 +02002863 lyxml_free_elem(ctx, sub);
2864 continue;
2865 }
2866 if (strcmp(sub->ns->value, LY_NSYIN)) {
2867 /* NACM extensions */
Radek Krejci6a113852015-07-03 16:04:20 +02002868 if ((opt & OPT_NACMEXT) && !strcmp(sub->ns->value, LY_NSNACM)) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002869 if (!strcmp(sub->name, "default-deny-write")) {
2870 mnode->nacm |= LY_NACM_DENYW;
2871 } else if (!strcmp(sub->name, "default-deny-all")) {
2872 mnode->nacm |= LY_NACM_DENYA;
2873 } else {
2874 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2875 goto error;
2876 }
2877 }
2878
2879 /* else garbage */
2880 lyxml_free_elem(ctx, sub);
Radek Krejci0d70c372015-07-02 16:23:10 +02002881 continue;
2882 }
2883
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002884 if (!strcmp(sub->name, "description")) {
2885 if (mnode->dsc) {
2886 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2887 goto error;
2888 }
2889 mnode->dsc = read_yin_subnode(ctx, sub, "text");
2890 if (!mnode->dsc) {
Radek Krejci73adb602015-07-02 18:07:40 +02002891 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002892 }
2893 } else if (!strcmp(sub->name, "reference")) {
2894 if (mnode->ref) {
2895 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2896 goto error;
2897 }
2898 mnode->ref = read_yin_subnode(ctx, sub, "text");
2899 if (!mnode->ref) {
Radek Krejci73adb602015-07-02 18:07:40 +02002900 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002901 }
2902 } else if (!strcmp(sub->name, "status")) {
2903 if (mnode->flags & LY_NODE_STATUS_MASK) {
2904 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2905 goto error;
2906 }
2907 GETVAL(value, sub, "value");
2908 if (!strcmp(value, "current")) {
2909 mnode->flags |= LY_NODE_STATUS_CURR;
2910 } else if (!strcmp(value, "deprecated")) {
2911 mnode->flags |= LY_NODE_STATUS_DEPRC;
2912 } else if (!strcmp(value, "obsolete")) {
2913 mnode->flags |= LY_NODE_STATUS_OBSLT;
2914 } else {
2915 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
Radek Krejci73adb602015-07-02 18:07:40 +02002916 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002917 }
2918 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
2919 if (mnode->flags & LY_NODE_CONFIG_MASK) {
2920 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2921 goto error;
2922 }
2923 GETVAL(value, sub, "value");
2924 if (!strcmp(value, "false")) {
2925 mnode->flags |= LY_NODE_CONFIG_R;
2926 } else if (!strcmp(value, "true")) {
2927 mnode->flags |= LY_NODE_CONFIG_W;
2928 } else {
2929 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
Radek Krejci73adb602015-07-02 18:07:40 +02002930 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002931 }
2932 } else {
2933 /* skip the lyxml_free_elem */
2934 continue;
2935 }
2936 lyxml_free_elem(ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002937 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002938
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002939 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
2940 /* get config flag from parent */
2941 if (parent) {
2942 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2943 } else {
2944 /* default config is true */
2945 mnode->flags |= LY_NODE_CONFIG_W;
2946 }
2947 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002948
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002949 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02002950
2951error:
2952
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002953 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002954}
2955
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002956static struct ly_when *
2957read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
2958{
Radek Krejci53ebfb12015-06-19 09:35:59 +02002959 struct ly_when *retval = NULL;
Radek Krejci73adb602015-07-02 18:07:40 +02002960 struct lyxml_elem *child;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002961 const char *value;
2962
2963 retval = calloc(1, sizeof *retval);
2964
2965 GETVAL(value, yin, "condition");
2966 retval->cond = lydict_insert(module->ctx, value, 0);
2967
Radek Krejci73adb602015-07-02 18:07:40 +02002968 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002969 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2970 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02002971 continue;
2972 }
2973
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002974 if (!strcmp(child->name, "description")) {
2975 if (retval->dsc) {
2976 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2977 goto error;
2978 }
2979 retval->dsc = read_yin_subnode(module->ctx, child, "text");
2980 if (!retval->dsc) {
2981 goto error;
2982 }
2983 } else if (!strcmp(child->name, "reference")) {
2984 if (retval->ref) {
2985 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2986 goto error;
2987 }
2988 retval->ref = read_yin_subnode(module->ctx, child, "text");
2989 if (!retval->ref) {
2990 goto error;
2991 }
2992 } else {
2993 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2994 goto error;
2995 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002996 }
2997
2998 return retval;
2999
3000error:
3001
Radek Krejci53ebfb12015-06-19 09:35:59 +02003002 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003003 return NULL;
3004}
3005
Radek Krejcib4cf2022015-06-03 14:40:05 +02003006/* additional check in case statement - the child must be unique across
3007 * all other case names and its data children
3008 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003009static int
3010check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02003011{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003012 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003013
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003014 if (new->nodetype == LY_NODE_CHOICE) {
3015 /* we have nested choice in case, so we need recursion */
3016 LY_TREE_FOR(new->child, mnode) {
3017 if (mnode->nodetype == LY_NODE_CASE) {
3018 LY_TREE_FOR(mnode->child, submnode) {
3019 if (check_branch_id(parent, submnode, new, line)) {
3020 return EXIT_FAILURE;
3021 }
3022 }
3023 } else if (check_branch_id(parent, mnode, new, line)) {
3024 return EXIT_FAILURE;
3025 }
3026 }
3027 } else {
3028 LY_TREE_FOR(parent->child, mnode) {
3029 if (mnode == excl) {
3030 continue;
3031 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003032
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003033 if (!strcmp(new->name, mnode->name)) {
3034 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
3035 return EXIT_FAILURE;
3036 }
3037 if (mnode->nodetype == LY_NODE_CASE) {
3038 LY_TREE_FOR(mnode->child, submnode) {
3039 if (!strcmp(new->name, submnode->name)) {
3040 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
3041 return EXIT_FAILURE;
3042 }
3043 }
3044 }
3045 }
3046 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003047
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003048 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003049}
3050
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003051static struct ly_mnode *
3052read_yin_case(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003053 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02003054{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003055 struct lyxml_elem *sub, *next;
3056 struct ly_mnode_case *mcase;
3057 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003058 int c_ftrs = 0;
3059 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003061 mcase = calloc(1, sizeof *mcase);
3062 mcase->nodetype = LY_NODE_CASE;
3063 mcase->prev = (struct ly_mnode *)mcase;
3064 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003065
Radek Krejci6a113852015-07-03 16:04:20 +02003066 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT | OPT_NACMEXT)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003067 goto error;
3068 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003069
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003070 /* process choice's specific children */
3071 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003072 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3073 /* garbage */
3074 lyxml_free_elem(module->ctx, sub);
3075 continue;
3076 }
3077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003078 if (!strcmp(sub->name, "container")) {
3079 mnode = read_yin_container(module, retval, sub, resolve, unres);
3080 } else if (!strcmp(sub->name, "leaf-list")) {
3081 mnode = read_yin_leaflist(module, retval, sub, resolve);
3082 } else if (!strcmp(sub->name, "leaf")) {
3083 mnode = read_yin_leaf(module, retval, sub, resolve);
3084 } else if (!strcmp(sub->name, "list")) {
3085 mnode = read_yin_list(module, retval, sub, resolve, unres);
3086 } else if (!strcmp(sub->name, "uses")) {
3087 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3088 } else if (!strcmp(sub->name, "choice")) {
3089 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3090 } else if (!strcmp(sub->name, "anyxml")) {
3091 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02003092 } else if (!strcmp(sub->name, "if-feature")) {
3093 c_ftrs++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003094 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
3095 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003096 } else if (!strcmp(sub->name, "when")) {
3097 if (mcase->when) {
3098 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3099 goto error;
3100 }
3101
3102 mcase->when = read_yin_when(module, sub);
3103 if (!mcase->when) {
3104 goto error;
3105 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003106 } else {
3107 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3108 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003109 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003110
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003111 if (!mnode) {
3112 goto error;
3113 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
3114 goto error;
3115 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003116
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003117 mnode = NULL;
3118 lyxml_free_elem(module->ctx, sub);
3119 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003120
Radek Krejci3cf9e222015-06-18 11:37:50 +02003121 if (c_ftrs) {
3122 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
3123 }
Radek Krejci73adb602015-07-02 18:07:40 +02003124 LY_TREE_FOR(yin->child, sub) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003125 GETVAL(value, sub, "name");
3126 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
3127 if (!mcase->features[mcase->features_size]) {
3128 goto error;
3129 }
3130 mcase->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003131 }
Radek Krejcib388c152015-06-04 17:03:03 +02003132
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003133 /* insert the node into the schema tree */
3134 if (ly_mnode_addchild(parent, retval)) {
3135 goto error;
3136 }
Radek Krejcib7155b52015-06-10 17:03:01 +02003137
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003138 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003139
3140error:
3141
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003142 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02003143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003144 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003145}
3146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003147static struct ly_mnode *
3148read_yin_choice(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003149 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003150{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003151 struct lyxml_elem *sub, *next;
3152 struct ly_ctx *const ctx = module->ctx;
3153 struct ly_mnode *retval, *mnode = NULL;
3154 struct ly_mnode_choice *choice;
3155 const char *value;
3156 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003157 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003159 choice = calloc(1, sizeof *choice);
3160 choice->nodetype = LY_NODE_CHOICE;
3161 choice->prev = (struct ly_mnode *)choice;
3162 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003163
Radek Krejci6a113852015-07-03 16:04:20 +02003164 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003165 goto error;
3166 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003167
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003168 /* process choice's specific children */
3169 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003170 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3171 /* garbage */
3172 lyxml_free_elem(module->ctx, sub);
3173 continue;
3174 }
3175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003176 if (!strcmp(sub->name, "container")) {
3177 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
3178 goto error;
3179 }
3180 } else if (!strcmp(sub->name, "leaf-list")) {
3181 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
3182 goto error;
3183 }
3184 } else if (!strcmp(sub->name, "leaf")) {
3185 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
3186 goto error;
3187 }
3188 } else if (!strcmp(sub->name, "list")) {
3189 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
3190 goto error;
3191 }
3192 } else if (!strcmp(sub->name, "case")) {
3193 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
3194 goto error;
3195 }
3196 } else if (!strcmp(sub->name, "anyxml")) {
3197 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
3198 goto error;
3199 }
3200 } else if (!strcmp(sub->name, "default")) {
3201 if (dflt_str) {
3202 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3203 goto error;
3204 }
3205 GETVAL(value, sub, "value");
3206 dflt_str = strdup(value);
3207 } else if (!strcmp(sub->name, "mandatory")) {
3208 if (f_mand) {
3209 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3210 goto error;
3211 }
3212 /* just checking the flags in leaf is not sufficient, we would allow
3213 * multiple mandatory statements with the "false" value
3214 */
3215 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003217 GETVAL(value, sub, "value");
3218 if (!strcmp(value, "true")) {
3219 choice->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003220 } else if (!strcmp(value, "false")) {
3221 choice->flags |= LY_NODE_MAND_FALSE;
3222 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003223 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3224 goto error;
3225 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003226 } else if (!strcmp(sub->name, "when")) {
3227 if (choice->when) {
3228 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3229 goto error;
3230 }
3231
3232 choice->when = read_yin_when(module, sub);
3233 if (!choice->when) {
3234 goto error;
3235 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003236 } else if (!strcmp(sub->name, "if-feature")) {
3237 c_ftrs++;
3238
3239 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
3240 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003241 } else {
3242 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3243 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003244 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003245
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003246 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
3247 goto error;
3248 }
3249 mnode = NULL;
3250 lyxml_free_elem(ctx, sub);
3251 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003252
Radek Krejci3cf9e222015-06-18 11:37:50 +02003253 if (c_ftrs) {
3254 choice->features = calloc(c_ftrs, sizeof *choice->features);
3255 }
3256
Radek Krejci73adb602015-07-02 18:07:40 +02003257 LY_TREE_FOR(yin->child, sub) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003258 GETVAL(value, sub, "name");
3259 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
3260 if (!choice->features[choice->features_size]) {
3261 goto error;
3262 }
3263 choice->features_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003264 }
3265
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003266 /* check - default is prohibited in combination with mandatory */
3267 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
3268 LOGVAL(VE_SPEC, LOGLINE(yin),
3269 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
3270 goto error;
3271 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003272
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003273 /* link default with the case */
3274 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02003275 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003276 if (!choice->dflt) {
3277 /* default branch not found */
3278 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
3279 goto error;
3280 }
3281 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003283 /* insert the node into the schema tree */
3284 if (parent && ly_mnode_addchild(parent, retval)) {
3285 goto error;
3286 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003287
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003288 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02003289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003290 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003291
3292error:
3293
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003294 ly_mnode_free(retval);
3295 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003296
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003297 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003298}
3299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003300static struct ly_mnode *
3301read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02003302{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003303 struct ly_mnode *retval;
3304 struct ly_mnode_leaf *anyxml;
3305 struct lyxml_elem *sub, *next;
3306 const char *value;
3307 int r;
3308 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003309 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02003310
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003311 anyxml = calloc(1, sizeof *anyxml);
3312 anyxml->nodetype = LY_NODE_ANYXML;
3313 anyxml->prev = (struct ly_mnode *)anyxml;
3314 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02003315
Radek Krejci6a113852015-07-03 16:04:20 +02003316 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003317 goto error;
3318 }
Radek Krejci863c2852015-06-03 15:47:11 +02003319
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003320 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003321 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3322 /* garbage */
3323 lyxml_free_elem(module->ctx, sub);
3324 continue;
3325 }
3326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003327 if (!strcmp(sub->name, "mandatory")) {
3328 if (f_mand) {
3329 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3330 goto error;
3331 }
3332 /* just checking the flags in leaf is not sufficient, we would allow
3333 * multiple mandatory statements with the "false" value
3334 */
3335 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02003336
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003337 GETVAL(value, sub, "value");
3338 if (!strcmp(value, "true")) {
3339 anyxml->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003340 } else if (!strcmp(value, "false")) {
3341 anyxml->flags |= LY_NODE_MAND_FALSE;
3342 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003343 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3344 goto error;
3345 }
3346 /* else false is the default value, so we can ignore it */
3347 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003348 } else if (!strcmp(sub->name, "when")) {
3349 if (anyxml->when) {
3350 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3351 goto error;
3352 }
3353
3354 anyxml->when = read_yin_when(module, sub);
3355 lyxml_free_elem(module->ctx, sub);
3356
3357 if (!anyxml->when) {
3358 goto error;
3359 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003360 } else if (!strcmp(sub->name, "must")) {
3361 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003362 } else if (!strcmp(sub->name, "if-feature")) {
3363 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02003364
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003365 } else {
3366 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3367 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003368 }
3369 }
Radek Krejci863c2852015-06-03 15:47:11 +02003370
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003371 /* middle part - process nodes with cardinality of 0..n */
3372 if (c_must) {
3373 anyxml->must = calloc(c_must, sizeof *anyxml->must);
3374 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003375 if (c_ftrs) {
3376 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
3377 }
Radek Krejci863c2852015-06-03 15:47:11 +02003378
Radek Krejci73adb602015-07-02 18:07:40 +02003379 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003380 if (!strcmp(sub->name, "must")) {
3381 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
3382 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02003383
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003384 if (r) {
3385 goto error;
3386 }
Radek Krejci0b24d752015-07-02 15:02:27 +02003387 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003388 GETVAL(value, sub, "name");
3389 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
3390 if (!anyxml->features[anyxml->features_size]) {
3391 goto error;
3392 }
3393 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003394 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003395 }
Radek Krejci863c2852015-06-03 15:47:11 +02003396
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003397 if (parent && ly_mnode_addchild(parent, retval)) {
3398 goto error;
3399 }
Radek Krejci863c2852015-06-03 15:47:11 +02003400
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003401 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02003402
3403error:
3404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003405 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02003406
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003407 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02003408}
3409
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003410static struct ly_mnode *
3411read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003412{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003413 struct ly_mnode *retval;
3414 struct ly_mnode_leaf *leaf;
3415 struct lyxml_elem *sub, *next;
3416 const char *value;
3417 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003418 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003420 leaf = calloc(1, sizeof *leaf);
3421 leaf->nodetype = LY_NODE_LEAF;
3422 leaf->prev = (struct ly_mnode *)leaf;
3423 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003424
Radek Krejci6a113852015-07-03 16:04:20 +02003425 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003426 goto error;
3427 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003428
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003429 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003430 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3431 /* garbage */
3432 lyxml_free_elem(module->ctx, sub);
3433 continue;
3434 }
3435
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003436 if (!strcmp(sub->name, "type")) {
3437 if (leaf->type.der) {
3438 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3439 goto error;
3440 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003441 if (fill_yin_type(module, parent, sub, &leaf->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003442 goto error;
3443 }
3444 } else if (!strcmp(sub->name, "default")) {
3445 if (leaf->dflt) {
3446 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3447 goto error;
3448 }
3449 GETVAL(value, sub, "value");
3450 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
3451 } else if (!strcmp(sub->name, "units")) {
3452 if (leaf->units) {
3453 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3454 goto error;
3455 }
3456 GETVAL(value, sub, "name");
3457 leaf->units = lydict_insert(module->ctx, value, strlen(value));
3458 } else if (!strcmp(sub->name, "mandatory")) {
3459 if (f_mand) {
3460 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3461 goto error;
3462 }
3463 /* just checking the flags in leaf is not sufficient, we would allow
3464 * multiple mandatory statements with the "false" value
3465 */
3466 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02003467
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003468 GETVAL(value, sub, "value");
3469 if (!strcmp(value, "true")) {
3470 leaf->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003471 } else if (!strcmp(value, "false")) {
3472 leaf->flags |= LY_NODE_MAND_FALSE;
3473 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003474 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3475 goto error;
3476 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003477 } else if (!strcmp(sub->name, "when")) {
3478 if (leaf->when) {
3479 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3480 goto error;
3481 }
3482
3483 leaf->when = read_yin_when(module, sub);
3484 if (!leaf->when) {
3485 goto error;
3486 }
3487
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003488 } else if (!strcmp(sub->name, "must")) {
Radek Krejci41882de2015-07-02 16:34:58 +02003489 c_must++;
3490 continue;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003491 } else if (!strcmp(sub->name, "if-feature")) {
3492 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003493 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02003494
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003495 } else {
3496 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3497 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003498 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003499
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003500 lyxml_free_elem(module->ctx, sub);
3501 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003502
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003503 /* check mandatory parameters */
3504 if (!leaf->type.der) {
3505 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3506 goto error;
3507 }
3508 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
3509 goto error;
3510 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003511
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003512 /* middle part - process nodes with cardinality of 0..n */
3513 if (c_must) {
3514 leaf->must = calloc(c_must, sizeof *leaf->must);
3515 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003516 if (c_ftrs) {
3517 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
3518 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003519
Radek Krejci73adb602015-07-02 18:07:40 +02003520 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003521 if (!strcmp(sub->name, "must")) {
3522 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
3523 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003525 if (r) {
3526 goto error;
3527 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003528 } else if (!strcmp(sub->name, "if-feature")) {
3529 GETVAL(value, sub, "name");
3530 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
3531 if (!leaf->features[leaf->features_size]) {
3532 goto error;
3533 }
3534 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003535 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003536 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003537
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003538 if (parent && ly_mnode_addchild(parent, retval)) {
3539 goto error;
3540 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003541
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003542 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003543
3544error:
3545
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003546 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003547
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003548 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003549}
3550
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003551static struct ly_mnode *
3552read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003553{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003554 struct ly_mnode *retval;
3555 struct ly_mnode_leaflist *llist;
3556 struct lyxml_elem *sub, *next;
3557 const char *value;
3558 char *endptr;
3559 unsigned long val;
3560 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003561 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003562 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003563
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003564 llist = calloc(1, sizeof *llist);
3565 llist->nodetype = LY_NODE_LEAFLIST;
3566 llist->prev = (struct ly_mnode *)llist;
3567 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003568
Radek Krejci6a113852015-07-03 16:04:20 +02003569 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003570 goto error;
3571 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003572
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003573 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003574 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3575 /* garbage */
3576 lyxml_free_elem(module->ctx, sub);
3577 continue;
3578 }
3579
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003580 if (!strcmp(sub->name, "type")) {
3581 if (llist->type.der) {
3582 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3583 goto error;
3584 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003585 if (fill_yin_type(module, parent, sub, &llist->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003586 goto error;
3587 }
3588 } else if (!strcmp(sub->name, "units")) {
3589 if (llist->units) {
3590 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3591 goto error;
3592 }
3593 GETVAL(value, sub, "name");
3594 llist->units = lydict_insert(module->ctx, value, strlen(value));
3595 } else if (!strcmp(sub->name, "ordered-by")) {
3596 if (f_ordr) {
3597 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3598 goto error;
3599 }
3600 /* just checking the flags in llist is not sufficient, we would
3601 * allow multiple ordered-by statements with the "system" value
3602 */
3603 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003604
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003605 if (llist->flags & LY_NODE_CONFIG_R) {
3606 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3607 * state data
3608 */
3609 lyxml_free_elem(module->ctx, sub);
3610 continue;
3611 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003612
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003613 GETVAL(value, sub, "value");
3614 if (!strcmp(value, "user")) {
3615 llist->flags |= LY_NODE_USERORDERED;
3616 } else if (strcmp(value, "system")) {
3617 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3618 goto error;
Radek Krejci41882de2015-07-02 16:34:58 +02003619 } /* else system is the default value, so we can ignore it */
3620
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003621 } else if (!strcmp(sub->name, "must")) {
3622 c_must++;
Radek Krejci41882de2015-07-02 16:34:58 +02003623 continue;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003624 } else if (!strcmp(sub->name, "if-feature")) {
3625 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003626 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02003627
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003628 } else if (!strcmp(sub->name, "min-elements")) {
3629 if (f_min) {
3630 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3631 goto error;
3632 }
3633 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003634
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003635 GETVAL(value, sub, "value");
3636 while (isspace(value[0])) {
3637 value++;
3638 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003639
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003640 /* convert it to uint32_t */
3641 errno = 0;
3642 endptr = NULL;
3643 val = strtoul(value, &endptr, 10);
3644 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
3645 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3646 goto error;
3647 }
3648 llist->min = (uint32_t) val;
3649 } else if (!strcmp(sub->name, "max-elements")) {
3650 if (f_max) {
3651 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3652 goto error;
3653 }
3654 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003655
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003656 GETVAL(value, sub, "value");
3657 while (isspace(value[0])) {
3658 value++;
3659 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003660
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003661 /* convert it to uint32_t */
3662 errno = 0;
3663 endptr = NULL;
3664 val = strtoul(value, &endptr, 10);
3665 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3666 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3667 goto error;
3668 }
3669 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003670 } else if (!strcmp(sub->name, "when")) {
3671 if (llist->when) {
3672 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3673 goto error;
3674 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003675
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003676 llist->when = read_yin_when(module, sub);
3677 if (!llist->when) {
3678 goto error;
3679 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003680 } else {
3681 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3682 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003683 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003684
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003685 lyxml_free_elem(module->ctx, sub);
3686 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003687
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003688 /* check constraints */
3689 if (!llist->type.der) {
3690 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3691 goto error;
3692 }
3693 if (llist->max && llist->min > llist->max) {
3694 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3695 goto error;
3696 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003698 /* middle part - process nodes with cardinality of 0..n */
3699 if (c_must) {
3700 llist->must = calloc(c_must, sizeof *llist->must);
3701 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003702 if (c_ftrs) {
3703 llist->features = calloc(c_ftrs, sizeof *llist->features);
3704 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003705
Radek Krejci73adb602015-07-02 18:07:40 +02003706 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003707 if (!strcmp(sub->name, "must")) {
3708 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
3709 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003711 if (r) {
3712 goto error;
3713 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003714 } else if (!strcmp(sub->name, "if-feature")) {
3715 GETVAL(value, sub, "name");
3716 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
3717 if (!llist->features[llist->features_size]) {
3718 goto error;
3719 }
3720 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003721 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003722 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003723
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003724 if (parent && ly_mnode_addchild(parent, retval)) {
3725 goto error;
3726 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003728 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003729
3730error:
3731
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003732 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003734 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003735}
3736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003737static struct ly_mnode *
3738read_yin_list(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003739 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003740{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003741 struct ly_mnode *retval, *mnode;
3742 struct ly_mnode_list *list;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003743 struct lyxml_elem *sub, *next, root, uniq;
3744 int i, r;
3745 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003746 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003747 int f_ordr = 0, f_max = 0, f_min = 0;
Radek Krejcieb00f512015-07-01 16:44:58 +02003748 const char *key_str = NULL, *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003749 char *auxs;
3750 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003752 /* init */
3753 memset(&root, 0, sizeof root);
3754 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02003755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003756 list = calloc(1, sizeof *list);
3757 list->nodetype = LY_NODE_LIST;
3758 list->prev = (struct ly_mnode *)list;
3759 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003760
Radek Krejci6a113852015-07-03 16:04:20 +02003761 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003762 goto error;
3763 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003764
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003765 /* process list's specific children */
3766 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003767 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3768 /* garbage */
3769 lyxml_free_elem(module->ctx, sub);
3770 continue;
3771 }
3772
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003773 /* data statements */
3774 if (!strcmp(sub->name, "container") ||
3775 !strcmp(sub->name, "leaf-list") ||
3776 !strcmp(sub->name, "leaf") ||
3777 !strcmp(sub->name, "list") ||
3778 !strcmp(sub->name, "choice") ||
3779 !strcmp(sub->name, "uses") ||
3780 !strcmp(sub->name, "grouping") ||
3781 !strcmp(sub->name, "anyxml")) {
3782 lyxml_unlink_elem(sub);
3783 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003784
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003785 /* array counters */
3786 } else if (!strcmp(sub->name, "key")) {
3787 /* check cardinality 0..1 */
3788 if (list->keys_size) {
3789 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
3790 goto error;
3791 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003792
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003793 /* count the number of keys */
3794 GETVAL(value, sub, "value");
3795 key_str = value;
3796 while ((value = strpbrk(value, " \t\n"))) {
3797 list->keys_size++;
3798 while (isspace(*value)) {
3799 value++;
3800 }
3801 }
3802 list->keys_size++;
3803 list->keys = calloc(list->keys_size, sizeof *list->keys);
3804 } else if (!strcmp(sub->name, "unique")) {
3805 c_uniq++;
3806 lyxml_unlink_elem(sub);
3807 lyxml_add_child(&uniq, sub);
3808 } else if (!strcmp(sub->name, "typedef")) {
3809 c_tpdf++;
3810 } else if (!strcmp(sub->name, "must")) {
3811 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003812 } else if (!strcmp(sub->name, "if-feature")) {
3813 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02003814
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003815 /* optional stetments */
3816 } else if (!strcmp(sub->name, "ordered-by")) {
3817 if (f_ordr) {
3818 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3819 goto error;
3820 }
3821 /* just checking the flags in llist is not sufficient, we would
3822 * allow multiple ordered-by statements with the "system" value
3823 */
3824 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003825
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003826 if (list->flags & LY_NODE_CONFIG_R) {
3827 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3828 * state data
3829 */
3830 lyxml_free_elem(module->ctx, sub);
3831 continue;
3832 }
Radek Krejci345ad742015-06-03 11:04:18 +02003833
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003834 GETVAL(value, sub, "value");
3835 if (!strcmp(value, "user")) {
3836 list->flags |= LY_NODE_USERORDERED;
3837 } else if (strcmp(value, "system")) {
3838 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3839 goto error;
3840 }
3841 /* else system is the default value, so we can ignore it */
3842 lyxml_free_elem(module->ctx, sub);
3843 } else if (!strcmp(sub->name, "min-elements")) {
3844 if (f_min) {
3845 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3846 goto error;
3847 }
3848 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003849
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003850 GETVAL(value, sub, "value");
3851 while (isspace(value[0])) {
3852 value++;
3853 }
Radek Krejci345ad742015-06-03 11:04:18 +02003854
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003855 /* convert it to uint32_t */
3856 errno = 0;
3857 auxs = NULL;
3858 val = strtoul(value, &auxs, 10);
3859 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
3860 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3861 goto error;
3862 }
3863 list->min = (uint32_t) val;
3864 lyxml_free_elem(module->ctx, sub);
3865 } else if (!strcmp(sub->name, "max-elements")) {
3866 if (f_max) {
3867 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3868 goto error;
3869 }
3870 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003871
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003872 GETVAL(value, sub, "value");
3873 while (isspace(value[0])) {
3874 value++;
3875 }
Radek Krejci345ad742015-06-03 11:04:18 +02003876
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003877 /* convert it to uint32_t */
3878 errno = 0;
3879 auxs = NULL;
3880 val = strtoul(value, &auxs, 10);
3881 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3882 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3883 goto error;
3884 }
3885 list->max = (uint32_t) val;
3886 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003887 } else if (!strcmp(sub->name, "when")) {
3888 if (list->when) {
3889 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3890 goto error;
3891 }
3892
3893 list->when = read_yin_when(module, sub);
3894 lyxml_free_elem(module->ctx, sub);
3895
3896 if (!list->when) {
3897 goto error;
3898 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003899 } else {
3900 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3901 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003902 }
3903 }
Radek Krejci345ad742015-06-03 11:04:18 +02003904
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003905 /* check - if list is configuration, key statement is mandatory */
3906 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
3907 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
3908 goto error;
3909 }
3910 if (list->max && list->min > list->max) {
3911 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3912 goto error;
3913 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003914
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003915 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3916 if (c_tpdf) {
3917 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
3918 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003919 if (c_must) {
3920 list->must = calloc(c_must, sizeof *list->must);
3921 }
3922 if (c_ftrs) {
3923 list->features = calloc(c_ftrs, sizeof *list->features);
3924 }
Radek Krejci73adb602015-07-02 18:07:40 +02003925 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003926 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003927 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003928 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02003929
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003930 if (r) {
3931 goto error;
3932 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003933 } else if (!strcmp(sub->name, "if-feature")) {
3934 GETVAL(value, sub, "name");
3935 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
3936 if (!list->features[list->features_size]) {
3937 goto error;
3938 }
3939 list->features_size++;
3940 } else if (!strcmp(sub->name, "must")) {
3941 r = fill_yin_must(module, sub, &list->must[list->must_size]);
3942 list->must_size++;
3943
3944 if (r) {
3945 goto error;
3946 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003947 }
3948 }
Radek Krejci25d782a2015-05-22 15:03:23 +02003949
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003950 /* last part - process data nodes */
3951 LY_TREE_FOR_SAFE(root.child, next, sub) {
3952 if (!strcmp(sub->name, "container")) {
3953 mnode = read_yin_container(module, retval, sub, resolve, unres);
3954 } else if (!strcmp(sub->name, "leaf-list")) {
3955 mnode = read_yin_leaflist(module, retval, sub, resolve);
3956 } else if (!strcmp(sub->name, "leaf")) {
3957 mnode = read_yin_leaf(module, retval, sub, resolve);
3958 } else if (!strcmp(sub->name, "list")) {
3959 mnode = read_yin_list(module, retval, sub, resolve, unres);
3960 } else if (!strcmp(sub->name, "choice")) {
3961 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3962 } else if (!strcmp(sub->name, "uses")) {
3963 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3964 } else if (!strcmp(sub->name, "grouping")) {
3965 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3966 } else if (!strcmp(sub->name, "anyxml")) {
3967 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003968 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003969 if (!mnode) {
3970 goto error;
3971 }
Radek Krejci73adb602015-07-02 18:07:40 +02003972
3973 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003974 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003976 if (parent && ly_mnode_addchild(parent, retval)) {
3977 goto error;
3978 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003979
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003980 if (!key_str) {
3981 /* config false list without a key */
3982 return retval;
3983 }
Radek Krejci812b10a2015-05-28 16:48:25 +02003984
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003985 /* link key leafs into the list structure and check all constraints */
3986 for (i = 0; i < list->keys_size; i++) {
3987 /* get the key name */
3988 if ((value = strpbrk(key_str, " \t\n"))) {
3989 len = value - key_str;
3990 while (isspace(*value)) {
3991 value++;
3992 }
3993 } else {
3994 len = strlen(key_str);
3995 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02003996
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003997 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02003998
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003999 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
4000 goto error;
4001 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02004002
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004003 /* prepare for next iteration */
4004 while (value && isspace(*value)) {
4005 value++;
4006 }
4007 key_str = value;
4008 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02004009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004010 /* process unique statements */
4011 if (c_uniq) {
4012 list->unique = calloc(c_uniq, sizeof *list->unique);
4013 }
4014 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
Radek Krejcieb00f512015-07-01 16:44:58 +02004015 if (parse_unique(retval, sub, &list->unique[list->unique_size++])) {
4016 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004017 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004018
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004019 lyxml_free_elem(module->ctx, sub);
4020 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004021
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004022 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004023
4024error:
4025
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004026 ly_mnode_free(retval);
4027 while (root.child) {
4028 lyxml_free_elem(module->ctx, root.child);
4029 }
4030 while (uniq.child) {
4031 lyxml_free_elem(module->ctx, uniq.child);
4032 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004033
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004034 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004035}
4036
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004037static struct ly_mnode *
4038read_yin_container(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004039 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004040{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004041 struct lyxml_elem *sub, *next, root;
4042 struct ly_mnode *mnode = NULL;
4043 struct ly_mnode *retval;
4044 struct ly_mnode_container *cont;
4045 const char *value;
4046 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004047 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004048
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004049 /* init */
4050 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02004051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004052 cont = calloc(1, sizeof *cont);
4053 cont->nodetype = LY_NODE_CONTAINER;
4054 cont->prev = (struct ly_mnode *)cont;
4055 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004056
Radek Krejci6a113852015-07-03 16:04:20 +02004057 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_CONFIG | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004058 goto error;
4059 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004061 /* process container's specific children */
4062 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci6764bb32015-07-03 15:16:04 +02004063 if (!sub->ns) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004064 /* garbage */
4065 lyxml_free_elem(module->ctx, sub);
4066 continue;
4067 }
4068
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004069 if (!strcmp(sub->name, "presence")) {
4070 if (cont->presence) {
4071 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4072 goto error;
4073 }
4074 GETVAL(value, sub, "value");
4075 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02004076
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004077 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02004078 } else if (!strcmp(sub->name, "when")) {
4079 if (cont->when) {
4080 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4081 goto error;
4082 }
4083
4084 cont->when = read_yin_when(module, sub);
4085 lyxml_free_elem(module->ctx, sub);
4086
4087 if (!cont->when) {
4088 goto error;
4089 }
Radek Krejci4c31f122015-06-02 14:51:22 +02004090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004091 /* data statements */
4092 } else if (!strcmp(sub->name, "container") ||
4093 !strcmp(sub->name, "leaf-list") ||
4094 !strcmp(sub->name, "leaf") ||
4095 !strcmp(sub->name, "list") ||
4096 !strcmp(sub->name, "choice") ||
4097 !strcmp(sub->name, "uses") ||
4098 !strcmp(sub->name, "grouping") ||
4099 !strcmp(sub->name, "anyxml")) {
4100 lyxml_unlink_elem(sub);
4101 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004103 /* array counters */
4104 } else if (!strcmp(sub->name, "typedef")) {
4105 c_tpdf++;
4106 } else if (!strcmp(sub->name, "must")) {
4107 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004108 } else if (!strcmp(sub->name, "if-feature")) {
4109 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004110 } else {
4111 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4112 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004113 }
4114 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004115
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004116 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4117 if (c_tpdf) {
4118 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
4119 }
4120 if (c_must) {
4121 cont->must = calloc(c_must, sizeof *cont->must);
4122 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004123 if (c_ftrs) {
4124 cont->features = calloc(c_ftrs, sizeof *cont->features);
4125 }
Radek Krejci800af702015-06-02 13:46:01 +02004126
Radek Krejci73adb602015-07-02 18:07:40 +02004127 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004128 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004129 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004130 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004131
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004132 if (r) {
4133 goto error;
4134 }
4135 } else if (!strcmp(sub->name, "must")) {
4136 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
4137 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02004138
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004139 if (r) {
4140 goto error;
4141 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004142 } else if (!strcmp(sub->name, "if-feature")) {
4143 GETVAL(value, sub, "name");
4144 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004145 if (!cont->features[cont->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004146 goto error;
4147 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004148 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004149 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004151 /* last part - process data nodes */
4152 LY_TREE_FOR_SAFE(root.child, next, sub) {
4153 if (!strcmp(sub->name, "container")) {
4154 mnode = read_yin_container(module, retval, sub, resolve, unres);
4155 } else if (!strcmp(sub->name, "leaf-list")) {
4156 mnode = read_yin_leaflist(module, retval, sub, resolve);
4157 } else if (!strcmp(sub->name, "leaf")) {
4158 mnode = read_yin_leaf(module, retval, sub, resolve);
4159 } else if (!strcmp(sub->name, "list")) {
4160 mnode = read_yin_list(module, retval, sub, resolve, unres);
4161 } else if (!strcmp(sub->name, "choice")) {
4162 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4163 } else if (!strcmp(sub->name, "uses")) {
4164 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4165 } else if (!strcmp(sub->name, "grouping")) {
4166 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4167 } else if (!strcmp(sub->name, "anyxml")) {
4168 mnode = read_yin_anyxml(module, retval, sub, resolve);
4169 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004170 if (!mnode) {
4171 goto error;
4172 }
Radek Krejci73adb602015-07-02 18:07:40 +02004173
4174 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004175 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004176
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004177 if (parent && ly_mnode_addchild(parent, retval)) {
4178 goto error;
4179 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004180
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004181 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004182
4183error:
4184
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004185 ly_mnode_free(retval);
4186 while (root.child) {
4187 lyxml_free_elem(module->ctx, root.child);
4188 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004189
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004190 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004191}
4192
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004193static struct ly_mnode *
4194read_yin_grouping(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004195 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004196{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004197 struct lyxml_elem *sub, *next, root;
4198 struct ly_mnode *mnode = NULL;
4199 struct ly_mnode *retval;
4200 struct ly_mnode_grp *grp;
4201 int r;
4202 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004203
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004204 /* init */
4205 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02004206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004207 grp = calloc(1, sizeof *grp);
4208 grp->nodetype = LY_NODE_GROUPING;
4209 grp->prev = (struct ly_mnode *)grp;
4210 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004211
Radek Krejci6a113852015-07-03 16:04:20 +02004212 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004213 goto error;
4214 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004215
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004216 LY_TREE_FOR_SAFE(node->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004217 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4218 /* garbage */
4219 lyxml_free_elem(module->ctx, sub);
4220 continue;
4221 }
4222
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004223 /* data statements */
4224 if (!strcmp(sub->name, "container") ||
4225 !strcmp(sub->name, "leaf-list") ||
4226 !strcmp(sub->name, "leaf") ||
4227 !strcmp(sub->name, "list") ||
4228 !strcmp(sub->name, "choice") ||
4229 !strcmp(sub->name, "uses") ||
4230 !strcmp(sub->name, "grouping") ||
4231 !strcmp(sub->name, "anyxml")) {
4232 lyxml_unlink_elem(sub);
4233 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004234
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004235 /* array counters */
4236 } else if (!strcmp(sub->name, "typedef")) {
4237 c_tpdf++;
4238 } else {
4239 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4240 goto error;
4241 }
4242 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004243
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004244 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4245 if (c_tpdf) {
4246 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
4247 }
Radek Krejci73adb602015-07-02 18:07:40 +02004248 LY_TREE_FOR(node->child, sub) {
4249 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size], NULL);
4250 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004251
Radek Krejci73adb602015-07-02 18:07:40 +02004252 if (r) {
4253 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004254 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004255 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004256
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004257 /* last part - process data nodes */
4258 LY_TREE_FOR_SAFE(root.child, next, sub) {
4259 if (!strcmp(sub->name, "container")) {
4260 mnode = read_yin_container(module, retval, sub, resolve, unres);
4261 } else if (!strcmp(sub->name, "leaf-list")) {
4262 mnode = read_yin_leaflist(module, retval, sub, resolve);
4263 } else if (!strcmp(sub->name, "leaf")) {
4264 mnode = read_yin_leaf(module, retval, sub, resolve);
4265 } else if (!strcmp(sub->name, "list")) {
4266 mnode = read_yin_list(module, retval, sub, resolve, unres);
4267 } else if (!strcmp(sub->name, "choice")) {
4268 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4269 } else if (!strcmp(sub->name, "uses")) {
4270 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4271 } else if (!strcmp(sub->name, "grouping")) {
4272 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4273 } else if (!strcmp(sub->name, "anyxml")) {
4274 mnode = read_yin_anyxml(module, retval, sub, resolve);
4275 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004276 if (!mnode) {
4277 goto error;
4278 }
Radek Krejci73adb602015-07-02 18:07:40 +02004279
4280 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004281 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004282
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004283 if (parent && ly_mnode_addchild(parent, retval)) {
4284 goto error;
4285 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004286
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004287 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004288
4289error:
4290
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004291 ly_mnode_free(retval);
4292 while (root.child) {
4293 lyxml_free_elem(module->ctx, root.child);
4294 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004296 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004297}
4298
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004299static struct ly_mnode *
4300read_yin_input_output(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004301 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004302{
Radek Krejcie0674f82015-06-15 13:58:51 +02004303 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004304 struct ly_mnode *mnode = NULL;
4305 struct ly_mnode *retval;
4306 struct ly_mnode_input_output *inout;
4307 int r;
4308 int c_tpdf = 0;
4309
Radek Krejcie0674f82015-06-15 13:58:51 +02004310 /* init */
4311 memset(&root, 0, sizeof root);
4312
Michal Vasko38d01f72015-06-15 09:41:06 +02004313 inout = calloc(1, sizeof *inout);
4314
4315 if (!strcmp(yin->name, "input")) {
4316 inout->nodetype = LY_NODE_INPUT;
4317 } else if (!strcmp(yin->name, "output")) {
4318 inout->nodetype = LY_NODE_OUTPUT;
4319 } else {
4320 assert(0);
4321 }
4322
4323 inout->prev = (struct ly_mnode *)inout;
4324 retval = (struct ly_mnode *)inout;
4325
Radek Krejci6a113852015-07-03 16:04:20 +02004326 if (read_yin_common(module, parent, retval, yin, OPT_MODULE | OPT_NACMEXT)) {
Michal Vaskoebeac942015-06-15 12:11:50 +02004327 goto error;
4328 }
4329
Michal Vasko38d01f72015-06-15 09:41:06 +02004330 /* data statements */
4331 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004332 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4333 /* garbage */
4334 lyxml_free_elem(module->ctx, sub);
4335 continue;
4336 }
4337
Michal Vasko38d01f72015-06-15 09:41:06 +02004338 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004339 !strcmp(sub->name, "leaf-list") ||
4340 !strcmp(sub->name, "leaf") ||
4341 !strcmp(sub->name, "list") ||
4342 !strcmp(sub->name, "choice") ||
4343 !strcmp(sub->name, "uses") ||
4344 !strcmp(sub->name, "grouping") ||
4345 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004346 lyxml_unlink_elem(sub);
4347 lyxml_add_child(&root, sub);
4348
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004349 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004350 } else if (!strcmp(sub->name, "typedef")) {
4351 c_tpdf++;
Radek Krejcid2bfa792015-07-02 16:45:29 +02004352
Michal Vasko38d01f72015-06-15 09:41:06 +02004353 } else {
4354 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4355 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004356 }
4357 }
4358
4359 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4360 if (c_tpdf) {
4361 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
4362 }
4363
Radek Krejci73adb602015-07-02 18:07:40 +02004364 LY_TREE_FOR(yin->child, sub) {
4365 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size], NULL);
4366 inout->tpdf_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004367
Radek Krejci73adb602015-07-02 18:07:40 +02004368 if (r) {
4369 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004370 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004371 }
4372
4373 /* last part - process data nodes */
4374 LY_TREE_FOR_SAFE(root.child, next, sub) {
4375 if (!strcmp(sub->name, "container")) {
4376 mnode = read_yin_container(module, retval, sub, resolve, unres);
4377 } else if (!strcmp(sub->name, "leaf-list")) {
4378 mnode = read_yin_leaflist(module, retval, sub, resolve);
4379 } else if (!strcmp(sub->name, "leaf")) {
4380 mnode = read_yin_leaf(module, retval, sub, resolve);
4381 } else if (!strcmp(sub->name, "list")) {
4382 mnode = read_yin_list(module, retval, sub, resolve, unres);
4383 } else if (!strcmp(sub->name, "choice")) {
4384 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4385 } else if (!strcmp(sub->name, "uses")) {
4386 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4387 } else if (!strcmp(sub->name, "grouping")) {
4388 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4389 } else if (!strcmp(sub->name, "anyxml")) {
4390 mnode = read_yin_anyxml(module, retval, sub, resolve);
4391 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004392 if (!mnode) {
4393 goto error;
4394 }
Radek Krejci73adb602015-07-02 18:07:40 +02004395
4396 lyxml_free_elem(module->ctx, sub);
Michal Vasko38d01f72015-06-15 09:41:06 +02004397 }
4398
4399 if (parent && ly_mnode_addchild(parent, retval)) {
4400 goto error;
4401 }
4402
4403 return retval;
4404
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004405error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004406
4407 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004408 while (root.child) {
4409 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004410 }
4411
4412 return NULL;
4413}
4414
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004415static struct ly_mnode *
4416read_yin_notif(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004417 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02004418{
Michal Vaskoc6551b32015-06-16 10:51:43 +02004419 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02004420 struct ly_mnode *mnode = NULL;
4421 struct ly_mnode *retval;
4422 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004423 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02004424 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004425 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02004426
Michal Vaskoc6551b32015-06-16 10:51:43 +02004427 memset(&root, 0, sizeof root);
4428
Michal Vasko0ea41032015-06-16 08:53:55 +02004429 notif = calloc(1, sizeof *notif);
4430 notif->nodetype = LY_NODE_NOTIF;
4431 notif->prev = (struct ly_mnode *)notif;
4432 retval = (struct ly_mnode *)notif;
4433
Radek Krejci6a113852015-07-03 16:04:20 +02004434 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004435 goto error;
4436 }
4437
4438 /* process rpc's specific children */
4439 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004440 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4441 /* garbage */
4442 lyxml_free_elem(module->ctx, sub);
4443 continue;
4444 }
4445
Michal Vasko0ea41032015-06-16 08:53:55 +02004446 /* data statements */
4447 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004448 !strcmp(sub->name, "leaf-list") ||
4449 !strcmp(sub->name, "leaf") ||
4450 !strcmp(sub->name, "list") ||
4451 !strcmp(sub->name, "choice") ||
4452 !strcmp(sub->name, "uses") ||
4453 !strcmp(sub->name, "grouping") ||
4454 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004455 lyxml_unlink_elem(sub);
4456 lyxml_add_child(&root, sub);
4457
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004458 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02004459 } else if (!strcmp(sub->name, "typedef")) {
4460 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004461 } else if (!strcmp(sub->name, "if-feature")) {
4462 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004463 } else {
4464 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4465 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02004466 }
4467 }
4468
4469 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4470 if (c_tpdf) {
4471 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
4472 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004473 if (c_ftrs) {
4474 notif->features = calloc(c_ftrs, sizeof *notif->features);
4475 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004476
Radek Krejci73adb602015-07-02 18:07:40 +02004477 LY_TREE_FOR(yin->child, sub) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004478 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004479 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size], NULL);
Michal Vasko0ea41032015-06-16 08:53:55 +02004480 notif->tpdf_size++;
4481
4482 if (r) {
4483 goto error;
4484 }
Radek Krejci0b24d752015-07-02 15:02:27 +02004485 } else if (!strcmp(sub->name, "if-features")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004486 GETVAL(value, sub, "name");
4487 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004488 if (!notif->features[notif->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004489 goto error;
4490 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004491 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004492 }
4493
4494 /* last part - process data nodes */
4495 LY_TREE_FOR_SAFE(root.child, next, sub) {
4496 if (!strcmp(sub->name, "container")) {
4497 mnode = read_yin_container(module, retval, sub, resolve, unres);
4498 } else if (!strcmp(sub->name, "leaf-list")) {
4499 mnode = read_yin_leaflist(module, retval, sub, resolve);
4500 } else if (!strcmp(sub->name, "leaf")) {
4501 mnode = read_yin_leaf(module, retval, sub, resolve);
4502 } else if (!strcmp(sub->name, "list")) {
4503 mnode = read_yin_list(module, retval, sub, resolve, unres);
4504 } else if (!strcmp(sub->name, "choice")) {
4505 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4506 } else if (!strcmp(sub->name, "uses")) {
4507 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4508 } else if (!strcmp(sub->name, "grouping")) {
4509 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4510 } else if (!strcmp(sub->name, "anyxml")) {
4511 mnode = read_yin_anyxml(module, retval, sub, resolve);
4512 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004513 if (!mnode) {
4514 goto error;
4515 }
Radek Krejci73adb602015-07-02 18:07:40 +02004516
4517 lyxml_free_elem(module->ctx, sub);
Michal Vasko0ea41032015-06-16 08:53:55 +02004518 }
4519
4520 if (parent && ly_mnode_addchild(parent, retval)) {
4521 goto error;
4522 }
4523
4524 return retval;
4525
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004526error:
Michal Vasko0ea41032015-06-16 08:53:55 +02004527
4528 ly_mnode_free(retval);
4529 while (root.child) {
4530 lyxml_free_elem(module->ctx, root.child);
4531 }
4532
4533 return NULL;
4534}
4535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004536static struct ly_mnode *
4537read_yin_rpc(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004538 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004539{
Radek Krejcie0674f82015-06-15 13:58:51 +02004540 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004541 struct ly_mnode *mnode = NULL;
4542 struct ly_mnode *retval;
4543 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004544 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02004545 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004546 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02004547
Radek Krejcie0674f82015-06-15 13:58:51 +02004548 /* init */
4549 memset(&root, 0, sizeof root);
4550
Michal Vasko38d01f72015-06-15 09:41:06 +02004551 rpc = calloc(1, sizeof *rpc);
4552 rpc->nodetype = LY_NODE_RPC;
4553 rpc->prev = (struct ly_mnode *)rpc;
4554 retval = (struct ly_mnode *)rpc;
4555
Radek Krejci6a113852015-07-03 16:04:20 +02004556 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004557 goto error;
4558 }
4559
4560 /* process rpc's specific children */
4561 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004562 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4563 /* garbage */
4564 lyxml_free_elem(module->ctx, sub);
4565 continue;
4566 }
4567
Michal Vasko38d01f72015-06-15 09:41:06 +02004568 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004569 if (rpc->child
4570 && (rpc->child->nodetype == LY_NODE_INPUT
4571 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004572 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4573 goto error;
4574 }
4575 lyxml_unlink_elem(sub);
4576 lyxml_add_child(&root, sub);
4577 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004578 if (rpc->child
4579 && (rpc->child->nodetype == LY_NODE_INPUT
4580 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004581 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4582 goto error;
4583 }
4584 lyxml_unlink_elem(sub);
4585 lyxml_add_child(&root, sub);
4586
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004587 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02004588 } else if (!strcmp(sub->name, "grouping")) {
4589 lyxml_unlink_elem(sub);
4590 lyxml_add_child(&root, sub);
4591
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004592 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004593 } else if (!strcmp(sub->name, "typedef")) {
4594 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004595 } else if (!strcmp(sub->name, "if-feature")) {
4596 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004597 } else {
4598 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4599 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004600 }
4601 }
4602
4603 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4604 if (c_tpdf) {
4605 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
4606 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004607 if (c_ftrs) {
4608 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
4609 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004610
Radek Krejci73adb602015-07-02 18:07:40 +02004611 LY_TREE_FOR(yin->child, sub) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004612 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004613 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size], NULL);
Michal Vasko38d01f72015-06-15 09:41:06 +02004614 rpc->tpdf_size++;
4615
4616 if (r) {
4617 goto error;
4618 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004619 } else if (!strcmp(sub->name, "if-feature")) {
4620 GETVAL(value, sub, "name");
4621 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004622 if (!rpc->features[rpc->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004623 goto error;
4624 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004625 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004626 }
4627
4628 /* last part - process data nodes */
4629 LY_TREE_FOR_SAFE(root.child, next, sub) {
4630 if (!strcmp(sub->name, "grouping")) {
4631 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4632 } else if (!strcmp(sub->name, "input")) {
4633 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4634 } else if (!strcmp(sub->name, "output")) {
4635 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4636 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004637 if (!mnode) {
4638 goto error;
4639 }
Radek Krejci73adb602015-07-02 18:07:40 +02004640
4641 lyxml_free_elem(module->ctx, sub);
Michal Vasko38d01f72015-06-15 09:41:06 +02004642 }
4643
4644 if (parent && ly_mnode_addchild(parent, retval)) {
4645 goto error;
4646 }
4647
4648 return retval;
4649
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004650error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004651
4652 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004653 while (root.child) {
4654 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004655 }
4656
4657 return NULL;
4658}
4659
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004660static int
4661find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004662{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004663 struct ly_module *searchmod = NULL, *module = uses->module;
4664 struct ly_mnode *mnode, *mnode_aux;
4665 const char *name;
4666 int prefix_len = 0;
4667 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004669 /* get referenced grouping */
4670 name = strchr(uses->name, ':');
4671 if (!name) {
4672 /* no prefix, search in local tree */
4673 name = uses->name;
4674 } else {
4675 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004677 /* set name to correct position after colon */
4678 prefix_len = name - uses->name;
4679 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004680
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004681 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
4682 /* prefix refers to the current module, ignore it */
4683 prefix_len = 0;
4684 }
4685 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004686
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004687 /* search */
4688 if (prefix_len) {
4689 /* in top-level groupings of some other module */
4690 for (i = 0; i < module->imp_size; i++) {
4691 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
4692 && !module->imp[i].prefix[prefix_len]) {
4693 searchmod = module->imp[i].module;
4694 break;
4695 }
4696 }
4697 if (!searchmod) {
4698 /* uses refers unknown data model */
4699 LOGVAL(VE_INPREFIX, line, name);
4700 return EXIT_FAILURE;
4701 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004703 LY_TREE_FOR(searchmod->data, mnode) {
4704 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4705 uses->grp = (struct ly_mnode_grp *)mnode;
4706 return EXIT_SUCCESS;
4707 }
4708 }
4709 } else {
4710 /* in local tree hierarchy */
4711 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
4712 LY_TREE_FOR(mnode_aux->child, mnode) {
4713 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4714 uses->grp = (struct ly_mnode_grp *)mnode;
4715 return EXIT_SUCCESS;
4716 }
4717 }
4718 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004719
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004720 /* search in top level of the current module */
4721 LY_TREE_FOR(module->data, mnode) {
4722 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4723 uses->grp = (struct ly_mnode_grp *)mnode;
4724 return EXIT_SUCCESS;
4725 }
4726 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004728 /* search in top-level of included modules */
4729 for (i = 0; i < module->inc_size; i++) {
4730 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
4731 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4732 uses->grp = (struct ly_mnode_grp *)mnode;
4733 return EXIT_SUCCESS;
4734 }
4735 }
4736 }
4737 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004738
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004739 /* not found, but no explicit error occured */
4740 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02004741}
4742
Radek Krejcif5be10f2015-06-16 13:29:36 +02004743static int
4744resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
4745{
Radek Krejci73adb602015-07-02 18:07:40 +02004746 struct lyxml_elem *yin, *sub;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004747 struct ly_mnode *mnode;
4748
4749 assert(module);
4750
4751 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004752 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004753 if (!aug->target) {
Radek Krejcia7c6ab92015-07-02 19:12:48 +02004754 LOGVAL(VE_INARG, line, aug->target_name, "uses");
Radek Krejcif5be10f2015-06-16 13:29:36 +02004755 return EXIT_FAILURE;
4756 }
4757
4758 if (!aug->child) {
4759 /* nothing to do */
4760 return EXIT_SUCCESS;
4761 }
4762
4763 yin = (struct lyxml_elem *)aug->child;
4764
Radek Krejcia90cf5c2015-07-02 15:32:49 +02004765 /* inherit config information from parent, augment does not have
4766 * config property, but we need to keep the information for subelements
4767 */
4768 aug->flags |= aug->target->flags & LY_NODE_CONFIG_MASK;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004769
Radek Krejci73adb602015-07-02 18:07:40 +02004770 LY_TREE_FOR(yin->child, sub) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004771 if (!strcmp(sub->name, "container")) {
4772 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
4773 } else if (!strcmp(sub->name, "leaf-list")) {
4774 mnode = read_yin_leaflist(module, aug->target, sub, 1);
4775 } else if (!strcmp(sub->name, "leaf")) {
4776 mnode = read_yin_leaf(module, aug->target, sub, 1);
4777 } else if (!strcmp(sub->name, "list")) {
4778 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
4779 } else if (!strcmp(sub->name, "uses")) {
4780 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
4781 } else if (!strcmp(sub->name, "choice")) {
4782 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4783 } else if (!strcmp(sub->name, "case")) {
4784 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4785 } else if (!strcmp(sub->name, "anyxml")) {
4786 mnode = read_yin_anyxml(module, aug->target, sub, 1);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004787 } else {
Radek Krejcid2bfa792015-07-02 16:45:29 +02004788 /* never should be here, since it was already pre-parsed by fill_yin_augment() */
Radek Krejcif5be10f2015-06-16 13:29:36 +02004789 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02004790 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004791 }
4792
4793 if (!mnode) {
4794 return EXIT_FAILURE;
4795 }
Radek Krejci3de29a72015-06-16 15:23:03 +02004796 /* check for mandatory nodes - if the target node is in another module
4797 * the added nodes cannot be mandatory
4798 */
4799 if (check_mandatory(mnode)) {
4800 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
4801 return EXIT_FAILURE;
4802 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004803
Radek Krejcif5be10f2015-06-16 13:29:36 +02004804 /* the parent pointer will point to the augment node, but all
4805 * siblings pointers and possibly the child node in target does
4806 * not know about the augment and follow the standard schema tree
4807 * structure
4808 */
4809 mnode->parent = (struct ly_mnode *)aug;
4810 mnode = NULL;
4811 }
4812
4813 lyxml_free_elem(module->ctx, yin);
4814 aug->child = NULL;
4815
4816 return EXIT_SUCCESS;
4817}
4818
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004819int
4820resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02004821{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004822 struct ly_ctx *ctx;
4823 struct ly_mnode *mnode = NULL, *mnode_aux;
4824 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02004825 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004826 int i, j;
4827 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02004828
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004829 /* copy the data nodes from grouping into the uses context */
4830 LY_TREE_FOR(uses->grp->child, mnode) {
4831 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
4832 if (!mnode_aux) {
4833 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
4834 return EXIT_FAILURE;
4835 }
4836 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
4837 ly_mnode_free(mnode_aux);
4838 return EXIT_FAILURE;
4839 }
4840 }
4841 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02004842
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004843 /* apply refines */
4844 for (i = 0; i < uses->refine_size; i++) {
4845 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02004846 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004847 if (!mnode) {
4848 LOGVAL(VE_INARG, line, rfn->target, "uses");
4849 return EXIT_FAILURE;
4850 }
Radek Krejci106efc02015-06-10 14:36:27 +02004851
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004852 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
4853 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
4854 return EXIT_FAILURE;
4855 }
Radek Krejci106efc02015-06-10 14:36:27 +02004856
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004857 /* description on any nodetype */
4858 if (rfn->dsc) {
4859 lydict_remove(ctx, mnode->dsc);
4860 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
4861 }
Radek Krejci106efc02015-06-10 14:36:27 +02004862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004863 /* reference on any nodetype */
4864 if (rfn->ref) {
4865 lydict_remove(ctx, mnode->ref);
4866 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
4867 }
Radek Krejci106efc02015-06-10 14:36:27 +02004868
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004869 /* config on any nodetype */
4870 if (rfn->flags & LY_NODE_CONFIG_MASK) {
4871 mnode->flags &= ~LY_NODE_CONFIG_MASK;
4872 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
4873 }
Radek Krejci106efc02015-06-10 14:36:27 +02004874
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004875 /* default value ... */
4876 if (rfn->mod.dflt) {
4877 if (mnode->nodetype == LY_NODE_LEAF) {
4878 /* leaf */
4879 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
4880 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
4881 } else if (mnode->nodetype == LY_NODE_CHOICE) {
4882 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004883 ((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 +02004884 if (!((struct ly_mnode_choice *)mnode)->dflt) {
4885 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
4886 return EXIT_FAILURE;
4887 }
4888 }
4889 }
Radek Krejci106efc02015-06-10 14:36:27 +02004890
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004891 /* mandatory on leaf, anyxml or choice */
Radek Krejcieb00f512015-07-01 16:44:58 +02004892 if (rfn->flags & LY_NODE_MAND_MASK) {
4893 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
4894 /* remove current value */
4895 mnode->flags &= ~LY_NODE_MAND_MASK;
4896
4897 /* set new value */
4898 mnode->flags |= (rfn->flags & LY_NODE_MAND_MASK);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004899 }
4900 }
Radek Krejci106efc02015-06-10 14:36:27 +02004901
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004902 /* presence on container */
4903 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
4904 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
4905 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
4906 }
Radek Krejci106efc02015-06-10 14:36:27 +02004907
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004908 /* min/max-elements on list or leaf-list */
4909 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
4910 /* magic - bit 3 in flags means min set, bit 4 says max set */
4911 if (rfn->flags & 0x04) {
4912 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
4913 }
4914 if (rfn->flags & 0x08) {
4915 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
4916 }
4917 }
Radek Krejci106efc02015-06-10 14:36:27 +02004918
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004919 /* must in leaf, leaf-list, list, container or anyxml */
4920 if (rfn->must_size) {
4921 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
4922 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
4923 if (!newmust) {
4924 LOGMEM;
4925 return EXIT_FAILURE;
4926 }
4927 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02004928 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004929 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
4930 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
4931 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
4932 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
4933 }
Radek Krejci106efc02015-06-10 14:36:27 +02004934
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004935 ((struct ly_mnode_leaf *)mnode)->must = newmust;
4936 ((struct ly_mnode_leaf *)mnode)->must_size = size;
4937 }
4938 }
Radek Krejci106efc02015-06-10 14:36:27 +02004939
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004940 /* apply augments */
4941 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004942 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004943 goto error;
4944 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004945 }
Radek Krejci106efc02015-06-10 14:36:27 +02004946
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004947 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02004948
4949error:
4950
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004951 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02004952}
Radek Krejci74705112015-06-05 10:25:44 +02004953
4954/*
4955 * resolve - referenced grouping should be bounded to the namespace (resolved)
4956 * only when uses does not appear in grouping. In a case of grouping's uses,
4957 * we just get information but we do not apply augment or refine to it.
4958 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004959static struct ly_mnode *
4960read_yin_uses(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004961 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02004962{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004963 struct lyxml_elem *sub, *next;
4964 struct ly_mnode *retval;
4965 struct ly_mnode_uses *uses;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004966 struct obj_list *unres_new;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004967 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004968 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004969 int r;
Radek Krejci74705112015-06-05 10:25:44 +02004970
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004971 uses = calloc(1, sizeof *uses);
4972 uses->nodetype = LY_NODE_USES;
4973 uses->prev = (struct ly_mnode *)uses;
4974 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02004975
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004976 GETVAL(value, node, "name");
4977 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02004978
Radek Krejci6a113852015-07-03 16:04:20 +02004979 if (read_yin_common(module, parent, retval, node, OPT_MODULE | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004980 goto error;
4981 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004982
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004983 /* get other properties of uses */
4984 LY_TREE_FOR_SAFE(node->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004985 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4986 /* garbage */
4987 lyxml_free_elem(module->ctx, sub);
4988 continue;
4989 }
4990
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004991 if (!strcmp(sub->name, "refine")) {
4992 c_ref++;
4993 } else if (!strcmp(sub->name, "augment")) {
4994 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004995 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02004996 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02004997 } else if (!strcmp(sub->name, "when")) {
4998 if (uses->when) {
4999 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
5000 goto error;
5001 }
5002
5003 uses->when = read_yin_when(module, sub);
5004 lyxml_free_elem(module->ctx, sub);
5005
5006 if (!uses->when) {
5007 goto error;
5008 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005009 } else {
5010 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
5011 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005012 }
5013 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005014
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005015 /* process properties with cardinality 0..n */
5016 if (c_ref) {
5017 uses->refine = calloc(c_ref, sizeof *uses->refine);
5018 }
5019 if (c_aug) {
5020 uses->augment = calloc(c_aug, sizeof *uses->augment);
5021 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005022 if (c_ftrs) {
5023 uses->features = calloc(c_ftrs, sizeof *uses->features);
5024 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005025
Radek Krejci73adb602015-07-02 18:07:40 +02005026 LY_TREE_FOR(node->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005027 if (!strcmp(sub->name, "refine")) {
5028 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
5029 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005030 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005031 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
5032 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005033 } else if (!strcmp(sub->name, "if-feature")) {
5034 GETVAL(value, sub, "name");
5035 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02005036 if (!uses->features[uses->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02005037 goto error;
5038 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02005039 r = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005040 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005041
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005042 if (r) {
5043 goto error;
5044 }
5045 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005046
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005047 if (find_grouping(parent, uses, LOGLINE(node))) {
5048 goto error;
5049 }
5050 if (!uses->grp) {
5051 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
5052 unres_new = calloc(1, sizeof *unres_new);
5053 if (*unres) {
5054 unres_new->next = *unres;
5055 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005056 unres_new->obj = retval;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005057 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02005058
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005059 /* put it at the beginning of the unresolved list */
5060 *unres = unres_new;
5061 }
Radek Krejci74705112015-06-05 10:25:44 +02005062
Radek Krejci368c38f2015-06-15 15:09:55 +02005063 if (parent && ly_mnode_addchild(parent, retval)) {
5064 goto error;
5065 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005066
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005067 if (resolve) {
5068 /* inherit config flag */
5069 if (parent) {
5070 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
5071 } else {
5072 /* default config is true */
5073 retval->flags |= LY_NODE_CONFIG_W;
5074 }
5075 }
Radek Krejcib388c152015-06-04 17:03:03 +02005076
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005077 if (resolve && uses->grp) {
5078 /* copy the data nodes from grouping into the uses context */
5079 if (resolve_uses(uses, LOGLINE(node))) {
5080 goto error;
5081 }
5082 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005083
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005084 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005085
5086error:
5087
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005088 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005089
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005090 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005091}
5092
Radek Krejciefaeba32015-05-27 14:30:57 +02005093/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005094static int
5095read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02005096{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005097 struct ly_ctx *ctx = module->ctx;
5098 struct ly_submodule *submodule = (struct ly_submodule *)module;
5099 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
5100 struct ly_mnode *mnode = NULL;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005101 struct obj_list *unres = NULL, *unres_next; /* unresolved objects */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005102 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005103 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02005104 int i;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005105 int unres_flag = 0; /* 0 for uses, 1 for types */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005106 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005107 /* counters */
Radek Krejcieb00f512015-07-01 16:44:58 +02005108 int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0, c_dev = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005109
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005110 /* init */
5111 memset(&root, 0, sizeof root);
5112 memset(&grps, 0, sizeof grps);
5113 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02005114 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02005115
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005116 /*
5117 * in the first run, we process elements with cardinality of 1 or 0..1 and
5118 * count elements with cardinality 0..n. Data elements (choices, containers,
5119 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
5120 * need have all top-level and groupings already prepared at that time. In
5121 * the middle loop, we process other elements with carinality of 0..n since
5122 * we need to allocate arrays to store them.
5123 */
5124 LY_TREE_FOR_SAFE(yin->child, next, node) {
5125 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
Radek Krejci0d70c372015-07-02 16:23:10 +02005126 /* garbage */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005127 lyxml_free_elem(ctx, node);
5128 continue;
5129 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005130
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005131 if (!module->type && !strcmp(node->name, "namespace")) {
5132 if (module->ns) {
5133 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5134 goto error;
5135 }
5136 GETVAL(value, node, "uri");
5137 module->ns = lydict_insert(ctx, value, strlen(value));
5138 lyxml_free_elem(ctx, node);
5139 } else if (!module->type && !strcmp(node->name, "prefix")) {
5140 if (module->prefix) {
5141 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5142 goto error;
5143 }
5144 GETVAL(value, node, "value");
5145 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
5146 goto error;
5147 }
5148 module->prefix = lydict_insert(ctx, value, strlen(value));
5149 lyxml_free_elem(ctx, node);
5150 } else if (module->type && !strcmp(node->name, "belongs-to")) {
5151 if (belongsto_flag) {
5152 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5153 goto error;
5154 }
5155 belongsto_flag = 1;
5156 GETVAL(value, node, "module");
5157 while (submodule->belongsto->type) {
5158 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
5159 }
5160 if (value != submodule->belongsto->name) {
5161 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5162 goto error;
5163 }
Radek Krejcif3886932015-06-04 17:36:06 +02005164
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005165 /* get the prefix substatement, start with checks */
5166 if (!node->child) {
5167 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
5168 goto error;
5169 } else if (strcmp(node->child->name, "prefix")) {
5170 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
5171 goto error;
5172 } else if (node->child->next) {
5173 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
5174 goto error;
5175 }
5176 /* and now finally get the value */
5177 GETVAL(value, node->child, "value");
5178 /* check here differs from a generic prefix check, since this prefix
5179 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02005180 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005181 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
5182 goto error;
5183 }
5184 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02005185
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005186 /* we are done with belongs-to */
5187 lyxml_free_elem(ctx, node);
Radek Krejcieb00f512015-07-01 16:44:58 +02005188
5189 /* counters (statements with n..1 cardinality) */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005190 } else if (!strcmp(node->name, "import")) {
5191 c_imp++;
5192 } else if (!strcmp(node->name, "revision")) {
5193 c_rev++;
5194 } else if (!strcmp(node->name, "typedef")) {
5195 c_tpdf++;
5196 } else if (!strcmp(node->name, "identity")) {
5197 c_ident++;
5198 } else if (!strcmp(node->name, "include")) {
5199 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02005200 } else if (!strcmp(node->name, "augment")) {
5201 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005202 } else if (!strcmp(node->name, "feature")) {
5203 c_ftrs++;
Radek Krejcieb00f512015-07-01 16:44:58 +02005204 } else if (!strcmp(node->name, "deviation")) {
5205 c_dev++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005207 /* data statements */
5208 } else if (!strcmp(node->name, "container") ||
5209 !strcmp(node->name, "leaf-list") ||
5210 !strcmp(node->name, "leaf") ||
5211 !strcmp(node->name, "list") ||
5212 !strcmp(node->name, "choice") ||
5213 !strcmp(node->name, "uses") ||
5214 !strcmp(node->name, "anyxml")) {
5215 lyxml_unlink_elem(node);
5216 lyxml_add_child(&root, node);
5217 } else if (!strcmp(node->name, "grouping")) {
5218 /* keep groupings separated and process them before other data statements */
5219 lyxml_unlink_elem(node);
5220 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005221
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005222 /* optional statements */
5223 } else if (!strcmp(node->name, "description")) {
5224 if (module->dsc) {
5225 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5226 goto error;
5227 }
5228 module->dsc = read_yin_subnode(ctx, node, "text");
5229 lyxml_free_elem(ctx, node);
5230 if (!module->dsc) {
5231 goto error;
5232 }
5233 } else if (!strcmp(node->name, "reference")) {
5234 if (module->ref) {
5235 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5236 goto error;
5237 }
5238 module->ref = read_yin_subnode(ctx, node, "text");
5239 lyxml_free_elem(ctx, node);
5240 if (!module->ref) {
5241 goto error;
5242 }
5243 } else if (!strcmp(node->name, "organization")) {
5244 if (module->org) {
5245 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5246 goto error;
5247 }
5248 module->org = read_yin_subnode(ctx, node, "text");
5249 lyxml_free_elem(ctx, node);
5250 if (!module->org) {
5251 goto error;
5252 }
5253 } else if (!strcmp(node->name, "contact")) {
5254 if (module->contact) {
5255 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5256 goto error;
5257 }
5258 module->contact = read_yin_subnode(ctx, node, "text");
5259 lyxml_free_elem(ctx, node);
5260 if (!module->contact) {
5261 goto error;
5262 }
5263 } else if (!strcmp(node->name, "yang-version")) {
5264 /* TODO: support YANG 1.1 ? */
5265 if (module->version) {
5266 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5267 goto error;
5268 }
5269 GETVAL(value, node, "value");
5270 if (strcmp(value, "1")) {
5271 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
5272 goto error;
5273 }
5274 module->version = 1;
5275 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02005276
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005277 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02005278 } else if (!strcmp(node->name, "rpc")) {
5279 lyxml_unlink_elem(node);
5280 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02005281 } else if (!strcmp(node->name, "notification")) {
5282 lyxml_unlink_elem(node);
5283 lyxml_add_child(&notifs, node);
Radek Krejci5166a892015-07-02 16:44:24 +02005284
5285 } else if (!strcmp(node->name, "extension")) {
5286 GETVAL(value, node, "name");
Radek Krejci5166a892015-07-02 16:44:24 +02005287
Radek Krejci6764bb32015-07-03 15:16:04 +02005288 /* we have 2 supported (hardcoded) extensions:
5289 * NACM's default-deny-write and default-deny-all
5290 */
5291 if (strcmp(module->ns, LY_NSNACM) ||
5292 (strcmp(value, "default-deny-write") && strcmp(value, "default-deny-all"))) {
5293 LOGWRN("Not supported \"%s\" extension statement found, ignoring.", value);
5294 lyxml_free_elem(ctx, node);
5295 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005296 } else {
5297 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
5298 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005299 }
5300 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005301
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005302 if (!submodule) {
5303 /* check for mandatory statements */
5304 if (!module->ns) {
5305 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
5306 goto error;
5307 }
5308 if (!module->prefix) {
5309 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
5310 goto error;
5311 }
5312 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02005313
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005314 /* allocate arrays for elements with cardinality of 0..n */
5315 if (c_imp) {
5316 module->imp = calloc(c_imp, sizeof *module->imp);
5317 }
5318 if (c_rev) {
5319 module->rev = calloc(c_rev, sizeof *module->rev);
5320 }
5321 if (c_tpdf) {
5322 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
5323 }
5324 if (c_ident) {
5325 module->ident = calloc(c_ident, sizeof *module->ident);
5326 }
5327 if (c_inc) {
5328 module->inc = calloc(c_inc, sizeof *module->inc);
5329 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005330 if (c_aug) {
5331 module->augment = calloc(c_aug, sizeof *module->augment);
5332 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005333 if (c_ftrs) {
5334 module->features = calloc(c_ftrs, sizeof *module->features);
5335 }
Radek Krejcieb00f512015-07-01 16:44:58 +02005336 if (c_dev) {
5337 module->deviation = calloc(c_dev, sizeof *module->deviation);
5338 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005339
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005340 /* now we are going to remember unresolved types, the flag is
5341 * used in case of error to get know how to free the structures
5342 * in unres list
5343 */
5344 unres_flag = 1;
5345
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005346 /* middle part - process nodes with cardinality of 0..n except the data nodes */
Radek Krejci73adb602015-07-02 18:07:40 +02005347 LY_TREE_FOR(yin->child, node) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005348 if (!strcmp(node->name, "import")) {
5349 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
5350 module->imp_size++;
5351 if (r) {
5352 goto error;
5353 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005354
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005355 /* check duplicities in imported modules */
5356 for (i = 0; i < module->imp_size - 1; i++) {
5357 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
5358 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
5359 goto error;
5360 }
5361 }
5362 } else if (!strcmp(node->name, "include")) {
5363 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
5364 module->inc_size++;
5365 if (r) {
5366 goto error;
5367 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005368
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005369 /* check duplications in include submodules */
5370 for (i = 0; i < module->inc_size - 1; i++) {
5371 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
5372 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
5373 module->inc[i].submodule->name);
5374 goto error;
5375 }
5376 }
5377 } else if (!strcmp(node->name, "revision")) {
5378 GETVAL(value, node, "date");
5379 if (check_date(value, LOGLINE(node))) {
5380 goto error;
5381 }
5382 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5383 /* check uniqueness of the revision date - not required by RFC */
5384 for (i = 0; i < module->rev_size; i++) {
5385 if (!strcmp(value, module->rev[i].date)) {
5386 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5387 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
5388 }
5389 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005390
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005391 LY_TREE_FOR(node->child, child) {
5392 if (!strcmp(child->name, "description")) {
5393 if (module->rev[module->rev_size].dsc) {
5394 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5395 goto error;
5396 }
5397 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
5398 if (!module->rev[module->rev_size].dsc) {
5399 goto error;
5400 }
5401 } else if (!strcmp(child->name, "reference")) {
5402 if (module->rev[module->rev_size].ref) {
5403 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5404 goto error;
5405 }
5406 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
5407 if (!module->rev[module->rev_size].ref) {
5408 goto error;
5409 }
5410 } else {
5411 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
5412 goto error;
5413 }
5414 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005415
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005416 /* keep the latest revision at position 0 */
5417 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
5418 /* switch their position */
5419 value = strdup(module->rev[0].date);
5420 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
5421 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5422 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02005423
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005424 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
5425 value = module->rev[0].dsc;
5426 module->rev[0].dsc = module->rev[module->rev_size].dsc;
5427 module->rev[module->rev_size].dsc = value;
5428 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005429
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005430 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
5431 value = module->rev[0].ref;
5432 module->rev[0].ref = module->rev[module->rev_size].ref;
5433 module->rev[module->rev_size].ref = value;
5434 }
5435 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005436
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005437 module->rev_size++;
5438 } else if (!strcmp(node->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005439 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size], &unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005440 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02005441
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005442 if (r) {
5443 goto error;
5444 }
5445 } else if (!strcmp(node->name, "identity")) {
5446 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
5447 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02005448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005449 if (r) {
5450 goto error;
5451 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005452 } else if (!strcmp(node->name, "feature")) {
5453 r = fill_yin_feature(module, node, &module->features[module->features_size]);
5454 module->features_size++;
5455
5456 if (r) {
5457 goto error;
5458 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005459 } else if (!strcmp(node->name, "augment")) {
5460 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
5461 module->augment_size++;
5462
5463 if (r) {
5464 goto error;
5465 }
5466
5467 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
5468 continue;
Radek Krejcieb00f512015-07-01 16:44:58 +02005469 } else if (!strcmp(node->name, "deviation")) {
5470 r = fill_yin_deviation(module, node, &module->deviation[module->deviation_size]);
5471 module->deviation_size++;
5472
5473 if (r) {
5474 goto error;
5475 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005476 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005477 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005478 /* resolve unresolved types (possible in typedef's with unions */
5479 while (unres) {
5480 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
Radek Krejci73adb602015-07-02 18:07:40 +02005481 if (fill_yin_type(module, NULL, node, (struct ly_type *)unres->obj, NULL)) {
5482 goto error;
5483 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005484
Radek Krejci73adb602015-07-02 18:07:40 +02005485 /* cleanup */
5486 lyxml_free_elem(ctx, node);
5487 ((struct ly_type *)unres->obj)->der = NULL;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005488 unres_next = unres->next;
5489 free(unres);
5490 unres = unres_next;
5491
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005492 }
5493 unres_flag = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005494
Radek Krejcif5be10f2015-06-16 13:29:36 +02005495 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005496 * refer to them
5497 */
5498 LY_TREE_FOR_SAFE(grps.child, next, node) {
5499 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005500 if (!mnode) {
5501 goto error;
5502 }
Radek Krejci74705112015-06-05 10:25:44 +02005503
Radek Krejci73adb602015-07-02 18:07:40 +02005504 lyxml_free_elem(ctx, node);
5505
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005506 /* include data element */
5507 if (module->data) {
5508 module->data->prev->next = mnode;
5509 mnode->prev = module->data->prev;
5510 module->data->prev = mnode;
5511 } else {
5512 module->data = mnode;
5513 }
5514 }
5515 while (unres) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005516 if (find_grouping(((struct ly_mnode_uses *)unres->obj)->parent, (struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005517 goto error;
5518 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005519 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5520 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005521 goto error;
5522 }
5523 unres_next = unres->next;
5524 free(unres);
5525 unres = unres_next;
5526 }
Radek Krejci74705112015-06-05 10:25:44 +02005527
Radek Krejcif5be10f2015-06-16 13:29:36 +02005528 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005529 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02005530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005531 if (!strcmp(node->name, "container")) {
5532 mnode = read_yin_container(module, NULL, node, 1, &unres);
5533 } else if (!strcmp(node->name, "leaf-list")) {
5534 mnode = read_yin_leaflist(module, NULL, node, 1);
5535 } else if (!strcmp(node->name, "leaf")) {
5536 mnode = read_yin_leaf(module, NULL, node, 1);
5537 } else if (!strcmp(node->name, "list")) {
5538 mnode = read_yin_list(module, NULL, node, 1, &unres);
5539 } else if (!strcmp(node->name, "choice")) {
5540 mnode = read_yin_choice(module, NULL, node, 1, &unres);
5541 } else if (!strcmp(node->name, "uses")) {
5542 mnode = read_yin_uses(module, NULL, node, 1, &unres);
5543 } else if (!strcmp(node->name, "anyxml")) {
5544 mnode = read_yin_anyxml(module, NULL, node, 1);
5545 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005546 if (!mnode) {
5547 goto error;
5548 }
Radek Krejci25d782a2015-05-22 15:03:23 +02005549
Radek Krejci73adb602015-07-02 18:07:40 +02005550 lyxml_free_elem(ctx, node);
5551
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005552 /* include data element */
5553 if (module->data) {
5554 module->data->prev->next = mnode;
5555 mnode->prev = module->data->prev;
5556 module->data->prev = mnode;
5557 } else {
5558 module->data = mnode;
5559 }
5560 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005561
5562 /* ... rpcs ... */
5563 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
5564 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
Radek Krejcif5be10f2015-06-16 13:29:36 +02005565 if (!mnode) {
5566 goto error;
5567 }
5568
Radek Krejci73adb602015-07-02 18:07:40 +02005569 lyxml_free_elem(ctx, node);
5570
Radek Krejcif5be10f2015-06-16 13:29:36 +02005571 /* include rpc element */
5572 if (module->rpc) {
5573 module->rpc->prev->next = mnode;
5574 mnode->prev = module->rpc->prev;
5575 module->rpc->prev = mnode;
5576 } else {
5577 module->rpc = mnode;
5578 }
5579 }
5580
5581 /* ... and notifications */
5582 LY_TREE_FOR_SAFE(notifs.child, next, node) {
5583 mnode = read_yin_notif(module, NULL, node, 0, &unres);
Radek Krejcif5be10f2015-06-16 13:29:36 +02005584 if (!mnode) {
5585 goto error;
5586 }
5587
Radek Krejci73adb602015-07-02 18:07:40 +02005588 lyxml_free_elem(ctx, node);
5589
Radek Krejcif5be10f2015-06-16 13:29:36 +02005590 /* include notification element */
5591 if (module->notif) {
5592 module->notif->prev->next = mnode;
5593 mnode->prev = module->notif->prev;
5594 module->notif->prev = mnode;
5595 } else {
5596 module->notif = mnode;
5597 }
5598 }
5599
5600 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005601 while (unres) {
5602 /* find referenced grouping */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005603 if (find_grouping(((struct ly_mnode_uses *)unres->obj)->parent, (struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005604 goto error;
5605 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005606 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5607 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005608 goto error;
5609 }
Radek Krejci74705112015-06-05 10:25:44 +02005610
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005611 /* resolve uses by copying grouping content under the uses */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005612 if (resolve_uses((struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005613 goto error;
5614 }
Radek Krejci74705112015-06-05 10:25:44 +02005615
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005616 unres_next = unres->next;
5617 free(unres);
5618 unres = unres_next;
5619 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005620
Radek Krejcif5be10f2015-06-16 13:29:36 +02005621 /* and finally apply augments */
5622 for (i = 0; i < module->augment_size; i++) {
5623 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005624 goto error;
5625 }
Michal Vasko0ea41032015-06-16 08:53:55 +02005626 }
5627
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005628 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02005629
5630error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005631 /* cleanup */
5632 while (root.child) {
5633 lyxml_free_elem(module->ctx, root.child);
5634 }
5635 while (grps.child) {
5636 lyxml_free_elem(module->ctx, grps.child);
5637 }
5638 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005639 lyxml_free_elem(module->ctx, rpcs.child);
5640 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005641
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005642 while (unres) {
5643 unres_next = unres->next;
5644 if (unres_flag) {
5645 /* free the XML subtrees kept in unresolved type structures */
5646 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
5647 lyxml_free_elem(ctx, node);
5648 }
5649
5650 free(unres);
5651 unres = unres_next;
5652 }
5653
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005654 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02005655}
5656
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005657struct ly_submodule *
5658yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005659{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005660 struct lyxml_elem *yin;
5661 struct ly_submodule *submodule = NULL;
5662 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02005663
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005664 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02005665
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005666 yin = lyxml_read(module->ctx, data, 0);
5667 if (!yin) {
5668 return NULL;
5669 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005670
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005671 /* check root element */
5672 if (!yin->name || strcmp(yin->name, "submodule")) {
5673 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5674 goto error;
5675 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005677 GETVAL(value, yin, "name");
5678 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5679 goto error;
5680 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005682 submodule = calloc(1, sizeof *submodule);
5683 if (!submodule) {
5684 LOGMEM;
5685 goto error;
5686 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005687
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005688 submodule->ctx = module->ctx;
5689 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
5690 submodule->type = 1;
5691 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02005692
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005693 LOGVRB("reading submodule %s", submodule->name);
5694 if (read_sub_module((struct ly_module *)submodule, yin)) {
5695 goto error;
5696 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005698 /* cleanup */
5699 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02005700
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005701 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02005702
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005703 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02005704
5705error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005706 /* cleanup */
5707 lyxml_free_elem(module->ctx, yin);
5708 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02005709
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005710 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02005711}
5712
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005713struct ly_module *
5714yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005715{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005716 struct lyxml_elem *yin;
5717 struct ly_module *module = NULL, **newlist = NULL;
5718 const char *value;
5719 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02005720
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005721 yin = lyxml_read(ctx, data, 0);
5722 if (!yin) {
5723 return NULL;
5724 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005725
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005726 /* check root element */
5727 if (!yin->name || strcmp(yin->name, "module")) {
5728 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5729 goto error;
5730 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005731
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005732 GETVAL(value, yin, "name");
5733 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5734 goto error;
5735 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005737 module = calloc(1, sizeof *module);
5738 if (!module) {
5739 LOGMEM;
5740 goto error;
5741 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005742
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005743 module->ctx = ctx;
5744 module->name = lydict_insert(ctx, value, strlen(value));
5745 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02005746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005747 LOGVRB("reading module %s", module->name);
5748 if (read_sub_module(module, yin)) {
5749 goto error;
5750 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005752 /* add to the context's list of modules */
5753 if (ctx->models.used == ctx->models.size) {
5754 newlist = realloc(ctx->models.list, ctx->models.size * 2);
5755 if (!newlist) {
5756 LOGMEM;
5757 goto error;
5758 }
5759 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
5760 newlist[i] = NULL;
5761 }
5762 ctx->models.size *= 2;
5763 ctx->models.list = newlist;
5764 }
5765 for (i = 0; ctx->models.list[i]; i++) {
5766 /* check name (name/revision) and namespace uniqueness */
5767 if (!strcmp(ctx->models.list[i]->name, module->name)) {
5768 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
5769 /* both data models are same, with no revision specified */
5770 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
5771 module->name);
5772 goto error;
5773 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
5774 /* one of the models does not have a revision, so they differs */
5775 continue;
5776 } else {
5777 /* both models have a revision statement which we have to
5778 * compare, revision at position 0 is the last revision
5779 */
5780 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
5781 /* we have the same modules */
5782 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
5783 module->rev[0].date);
5784 goto error;
5785 }
5786 }
5787 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
5788 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
5789 ctx->models.list[i]->name, module->name, module->ns);
5790 goto error;
5791 }
5792 }
5793 ctx->models.list[i] = module;
5794 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005796 /* cleanup */
5797 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005798
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005799 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005800
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005801 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005802
5803error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005804 /* cleanup */
5805 lyxml_free_elem(ctx, yin);
5806 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005807
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005808 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005809}