blob: 9dde7692c8923e885da81c145f337208e39549e4 [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 }
Michal Vasko54e426f2015-07-07 15:38:02 +0200838 GETVAL(value, child, "value");
Radek Krejci461d1622015-06-30 14:06:28 +0200839 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 Krejci9a1b95a2015-07-09 15:32:21 +0200868 struct ly_type_bit bit;
Radek Krejci994b6f62015-06-18 16:47:27 +0200869 int i, j;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200870 int64_t v, v_;
Radek Krejci994b6f62015-06-18 16:47:27 +0200871 int64_t p, p_;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200872
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200873 GETVAL(value, yin, "name");
874
875 if (!type->prefix) {
876 /* if we are trying to resolve unresolved type,
877 * prefix is already stored
878 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200879 delim = strchr(value, ':');
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200880 if (delim) {
881 type->prefix = lydict_insert(module->ctx, value, delim - value);
882 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200883 }
Radek Krejci667b97f2015-05-25 15:03:30 +0200884
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200885 type->der = find_superior_type(value, module, parent);
886 if (!type->der) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +0200887 if (unres) {
888 /* store it for later resolving */
889 LOGVRB("Unresolved type of \"%s\" (line %d), trying to resolve it later", value, LOGLINE(yin));
890 unres_new = calloc(1, sizeof *unres_new);
891 if (*unres) {
892 unres_new->next = *unres;
893 }
894 /* keep XML data for later processing */
895 type->der = (struct ly_tpdf *)lyxml_dup_elem(module->ctx, yin, NULL, 1);
896
897 unres_new->obj = type;
898 unres_new->line = LOGLINE(yin);
899
900 /* put it at the beginning of the unresolved list */
901 *unres = unres_new;
902 return EXIT_SUCCESS;
903 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200904 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
905 goto error;
906 }
907 type->base = type->der->type.base;
Radek Krejci25d782a2015-05-22 15:03:23 +0200908
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200909 switch (type->base) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200910 case LY_TYPE_BITS:
Radek Krejci994b6f62015-06-18 16:47:27 +0200911 /* RFC 6020 9.7.4 - bit */
912
913 /* get bit specifications, at least one must be present */
914 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200915 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
916 /* garbage */
917 lyxml_free_elem(module->ctx, node);
918 continue;
919 }
920
Radek Krejci994b6f62015-06-18 16:47:27 +0200921 if (!strcmp(node->name, "bit")) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200922 type->info.bits.count++;
Radek Krejci41726f92015-06-19 13:11:05 +0200923 } else {
924 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
925 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +0200926 }
927 }
Radek Krejciac781922015-07-09 15:35:14 +0200928 if (!type->der->type.der && !type->info.bits.count) {
929 /* type is derived directly from buit-in bits type and bit statement is required */
Radek Krejci994b6f62015-06-18 16:47:27 +0200930 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "bit", "type");
931 goto error;
932 }
Radek Krejciac781922015-07-09 15:35:14 +0200933 if (type->der->type.der && type->info.bits.count) {
934 /* type is not directly derived from buit-in bits type and bit statement is prohibited */
935 LOGVAL(VE_INSTMT, LOGLINE(yin), "bit");
936 goto error;
937 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200938
939 type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
Radek Krejci73adb602015-07-02 18:07:40 +0200940 p = 0;
941 i = -1;
942 LY_TREE_FOR(yin->child, next) {
943 i++;
944
945 GETVAL(value, next, "name");
946 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(next), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200947 goto error;
948 }
949 type->info.bits.bit[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci73adb602015-07-02 18:07:40 +0200950 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.bits.bit[i], next, 0)) {
Radek Krejci994b6f62015-06-18 16:47:27 +0200951 type->info.bits.count = i + 1;
952 goto error;
953 }
954
955 /* check the name uniqueness */
956 for (j = 0; j < i; j++) {
957 if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
Radek Krejci73adb602015-07-02 18:07:40 +0200958 LOGVAL(VE_BITS_DUPNAME, LOGLINE(next), type->info.bits.bit[i].name);
Radek Krejci994b6f62015-06-18 16:47:27 +0200959 type->info.bits.count = i + 1;
960 goto error;
961 }
962 }
963
Radek Krejci0d70c372015-07-02 16:23:10 +0200964 p_ = -1;
Radek Krejci73adb602015-07-02 18:07:40 +0200965 LY_TREE_FOR(next->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200966 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
967 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +0200968 continue;
Radek Krejci994b6f62015-06-18 16:47:27 +0200969 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200970
Radek Krejci0d70c372015-07-02 16:23:10 +0200971 if (!strcmp(node->name, "position")) {
972 GETVAL(value, node, "value");
973 p_ = strtol(value, NULL, 10);
974
975 /* range check */
976 if (p_ < 0 || p_ > UINT32_MAX) {
977 LOGVAL(VE_INARG, LOGLINE(node), value, "bit/position");
978 type->info.bits.count = i + 1;
979 goto error;
980 }
981 type->info.bits.bit[i].pos = (uint32_t)p_;
982
983 /* keep the highest enum value for automatic increment */
Michal Vasko9ab05942015-07-07 15:38:26 +0200984 if (type->info.bits.bit[i].pos >= p) {
Radek Krejci0d70c372015-07-02 16:23:10 +0200985 p = type->info.bits.bit[i].pos;
986 p++;
987 } else {
988 /* check that the value is unique */
989 for (j = 0; j < i; j++) {
990 if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
991 LOGVAL(VE_BITS_DUPVAL, LOGLINE(node), type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
992 type->info.bits.count = i + 1;
993 goto error;
994 }
Radek Krejci994b6f62015-06-18 16:47:27 +0200995 }
996 }
Radek Krejci0d70c372015-07-02 16:23:10 +0200997 } else {
Radek Krejci73adb602015-07-02 18:07:40 +0200998 LOGVAL(VE_INSTMT, LOGLINE(next), next->name);
Radek Krejci0d70c372015-07-02 16:23:10 +0200999 goto error;
Radek Krejci994b6f62015-06-18 16:47:27 +02001000 }
Radek Krejci0d70c372015-07-02 16:23:10 +02001001 }
1002 if (p_ == -1) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001003 /* assign value automatically */
1004 if (p > UINT32_MAX) {
Radek Krejci73adb602015-07-02 18:07:40 +02001005 LOGVAL(VE_INARG, LOGLINE(next), "4294967295", "bit/position");
Radek Krejci994b6f62015-06-18 16:47:27 +02001006 type->info.bits.count = i + 1;
1007 goto error;
1008 }
1009 type->info.bits.bit[i].pos = (uint32_t)p;
1010 p++;
1011 }
Radek Krejci9a1b95a2015-07-09 15:32:21 +02001012
1013 /* keep them ordered by position */
1014 j = i;
1015 while (j && type->info.bits.bit[j - 1].pos > type->info.bits.bit[j].pos) {
1016 /* switch them */
1017 memcpy(&bit, &type->info.bits.bit[j], sizeof bit);
1018 memcpy(&type->info.bits.bit[j], &type->info.bits.bit[j - 1], sizeof bit);
1019 memcpy(&type->info.bits.bit[j - 1], &bit, sizeof bit);
1020 j--;
1021 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001022 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001023 break;
Radek Krejci25d782a2015-05-22 15:03:23 +02001024
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001025 case LY_TYPE_DEC64:
Radek Krejcif9401c32015-06-26 16:47:36 +02001026 /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
Radek Krejci73adb602015-07-02 18:07:40 +02001027 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001028 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1029 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001030 continue;
1031 }
1032
Radek Krejcif9401c32015-06-26 16:47:36 +02001033 if (!strcmp(node->name, "range")) {
1034 if (type->info.dec64.range) {
1035 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1036 goto error;
1037 }
1038
1039 GETVAL(value, node, "value");
1040 if (check_length(value, type, LOGLINE(node))) {
1041 goto error;
1042 }
1043 type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
1044 type->info.dec64.range->expr = lydict_insert(module->ctx, value, 0);
1045
1046 /* get possible substatements */
1047 if (read_restr_substmt(module->ctx, type->info.dec64.range, node)) {
1048 goto error;
1049 }
1050 } else if (!strcmp(node->name, "fraction-digits")) {
1051 if (type->info.dec64.dig) {
1052 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1053 goto error;
1054 }
1055 GETVAL(value, node, "value");
1056 v = strtol(value, NULL, 10);
1057
1058 /* range check */
1059 if (v < 1 || v > 18) {
1060 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1061 goto error;
1062 }
1063 type->info.dec64.dig = (uint8_t)v;
1064 } else {
1065 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1066 goto error;
1067 }
Radek Krejcif9401c32015-06-26 16:47:36 +02001068 }
1069
1070 /* mandatory sub-statement(s) check */
1071 if (!type->info.dec64.dig && !type->der->type.der) {
1072 /* decimal64 type directly derived from built-in type requires fraction-digits */
1073 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "fraction-digits", "type");
1074 goto error;
1075 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001076 break;
Radek Krejci25d782a2015-05-22 15:03:23 +02001077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001078 case LY_TYPE_ENUM:
Radek Krejci994b6f62015-06-18 16:47:27 +02001079 /* RFC 6020 9.6 - enum */
Radek Krejci25d782a2015-05-22 15:03:23 +02001080
Radek Krejci994b6f62015-06-18 16:47:27 +02001081 /* get enum specifications, at least one must be present */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001082 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001083 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1084 /* garbage */
1085 lyxml_free_elem(module->ctx, node);
1086 continue;
1087 }
1088
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001089 if (!strcmp(node->name, "enum")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001090 type->info.enums.count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +02001091 } else {
1092 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1093 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001094 }
1095 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001096 if (!type->info.enums.count) {
1097 if (type->der->type.der) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001098 /* this is just a derived type with no enum specified/required */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001099 break;
1100 }
1101 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "enum", "type");
1102 goto error;
1103 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001104
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001105 type->info.enums.list = calloc(type->info.enums.count, sizeof *type->info.enums.list);
Radek Krejci73adb602015-07-02 18:07:40 +02001106 v = 0;
1107 i = -1;
1108 LY_TREE_FOR(yin->child, next) {
1109 i++;
1110
1111 GETVAL(value, next, "name");
1112 if (check_identifier(value, LY_IDENT_SIMPLE, LOGLINE(next), NULL, NULL)) {
Radek Krejci994b6f62015-06-18 16:47:27 +02001113 goto error;
1114 }
1115 type->info.enums.list[i].name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci73adb602015-07-02 18:07:40 +02001116 if (read_yin_common(module, NULL, (struct ly_mnode *)&type->info.enums.list[i], next, 0)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001117 type->info.enums.count = i + 1;
1118 goto error;
1119 }
Radek Krejci994b6f62015-06-18 16:47:27 +02001120
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001121 /* the assigned name MUST NOT have any leading or trailing whitespace characters */
1122 value = type->info.enums.list[i].name;
1123 if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
Radek Krejci73adb602015-07-02 18:07:40 +02001124 LOGVAL(VE_ENUM_WS, LOGLINE(next), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001125 type->info.enums.count = i + 1;
1126 goto error;
1127 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001128
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001129 /* check the name uniqueness */
1130 for (j = 0; j < i; j++) {
1131 if (!strcmp(type->info.enums.list[j].name, type->info.enums.list[i].name)) {
Radek Krejci73adb602015-07-02 18:07:40 +02001132 LOGVAL(VE_ENUM_DUPNAME, LOGLINE(next), type->info.enums.list[i].name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001133 type->info.enums.count = i + 1;
1134 goto error;
1135 }
1136 }
Radek Krejci04581c62015-05-22 21:24:00 +02001137
Radek Krejci0d70c372015-07-02 16:23:10 +02001138 v_ = -1;
Radek Krejci73adb602015-07-02 18:07:40 +02001139 LY_TREE_FOR(next->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001140 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1141 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001142 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001143 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001144
Radek Krejci0d70c372015-07-02 16:23:10 +02001145 if (!strcmp(node->name, "value")) {
1146 GETVAL(value, node, "value");
1147 v_ = strtol(value, NULL, 10);
1148
1149 /* range check */
1150 if (v_ < INT32_MIN || v_ > INT32_MAX) {
1151 LOGVAL(VE_INARG, LOGLINE(node), value, "enum/value");
1152 type->info.enums.count = i + 1;
1153 goto error;
1154 }
1155 type->info.enums.list[i].value = v_;
1156
1157 /* keep the highest enum value for automatic increment */
1158 if (type->info.enums.list[i].value > v) {
1159 v = type->info.enums.list[i].value;
1160 v++;
1161 } else {
1162 /* check that the value is unique */
1163 for (j = 0; j < i; j++) {
1164 if (type->info.enums.list[j].value == type->info.enums.list[i].value) {
1165 LOGVAL(VE_ENUM_DUPVAL, LOGLINE(node), type->info.enums.list[i].value,
1166 type->info.enums.list[i].name);
1167 type->info.enums.count = i + 1;
1168 goto error;
1169 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001170 }
1171 }
Radek Krejci0d70c372015-07-02 16:23:10 +02001172 } else {
Radek Krejci73adb602015-07-02 18:07:40 +02001173 LOGVAL(VE_INSTMT, LOGLINE(next), next->name);
Radek Krejci0d70c372015-07-02 16:23:10 +02001174 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001175 }
Radek Krejci0d70c372015-07-02 16:23:10 +02001176 }
1177 if (v_ == -1) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001178 /* assign value automatically */
1179 if (v > INT32_MAX) {
Radek Krejci73adb602015-07-02 18:07:40 +02001180 LOGVAL(VE_INARG, LOGLINE(next), "2147483648", "enum/value");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001181 type->info.enums.count = i + 1;
1182 goto error;
1183 }
1184 type->info.enums.list[i].value = v;
1185 v++;
1186 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001187 }
1188 break;
1189
1190 case LY_TYPE_IDENT:
Radek Krejci994b6f62015-06-18 16:47:27 +02001191 /* RFC 6020 9.10 - base */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001192
1193 /* get base specification, exactly one must be present */
Radek Krejci0d70c372015-07-02 16:23:10 +02001194 LY_TREE_FOR_SAFE(yin->child, next, node) {
1195 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1196 /* garbage */
1197 lyxml_free_elem(module->ctx, node);
1198 continue;
1199 }
1200
1201 if (strcmp(yin->child->name, "base")) {
1202 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1203 goto error;
1204 }
1205 }
1206
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001207 if (!yin->child) {
Radek Krejci65c889c2015-06-22 10:17:22 +02001208 if (type->der->type.der) {
1209 /* this is just a derived type with no base specified/required */
1210 break;
1211 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001212 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "base", "type");
1213 goto error;
1214 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001215 if (yin->child->next) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001216 LOGVAL(VE_TOOMANY, LOGLINE(yin->child->next), yin->child->next->name, yin->name);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001217 goto error;
1218 }
1219 type->info.ident.ref = find_base_ident(module, NULL, yin->child);
1220 if (!type->info.ident.ref) {
1221 return EXIT_FAILURE;
1222 }
1223 break;
1224
1225 case LY_TYPE_INST:
Radek Krejciaf351422015-06-19 14:49:38 +02001226 /* RFC 6020 9.13.2 - require-instance */
Radek Krejci73adb602015-07-02 18:07:40 +02001227 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001228 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1229 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001230 continue;
1231 }
1232
Radek Krejciaf351422015-06-19 14:49:38 +02001233 if (!strcmp(node->name, "require-instance")) {
1234 if (type->info.inst.req) {
1235 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1236 goto error;
1237 }
1238 GETVAL(value, node, "value");
1239 if (strcmp(value, "true")) {
1240 type->info.inst.req = 1;
1241 } else if (strcmp(value, "false")) {
1242 type->info.inst.req = -1;
1243 } else {
1244 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1245 goto error;
1246 }
1247 } else {
1248 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1249 goto error;
1250 }
Radek Krejciaf351422015-06-19 14:49:38 +02001251 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001252 break;
1253
Radek Krejcif2860132015-06-20 12:37:20 +02001254 case LY_TYPE_BINARY:
1255 /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001256 case LY_TYPE_INT8:
1257 case LY_TYPE_INT16:
1258 case LY_TYPE_INT32:
1259 case LY_TYPE_INT64:
1260 case LY_TYPE_UINT8:
1261 case LY_TYPE_UINT16:
1262 case LY_TYPE_UINT32:
1263 case LY_TYPE_UINT64:
Radek Krejcif2860132015-06-20 12:37:20 +02001264 /* RFC 6020 9.2.4 - range */
1265
1266 /* length and range are actually the same restriction, so process
1267 * them by this common code, we just need to differ the name and
1268 * structure where the information will be stored
1269 */
1270 if (type->base == LY_TYPE_BINARY) {
1271 restr = &type->info.binary.length;
1272 name = "length";
1273 } else {
1274 restr = &type->info.num.range;
1275 name = "range";
1276 }
1277
Radek Krejci73adb602015-07-02 18:07:40 +02001278 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001279 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1280 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001281 continue;
1282 }
1283
Radek Krejcif2860132015-06-20 12:37:20 +02001284 if (!strcmp(node->name, name)) {
1285 if (*restr) {
1286 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1287 goto error;
1288 }
1289
1290 GETVAL(value, node, "value");
1291 if (check_length(value, type, LOGLINE(node))) {
1292 goto error;
1293 }
1294 *restr = calloc(1, sizeof **restr);
1295 (*restr)->expr = lydict_insert(module->ctx, value, 0);
1296
1297 /* get possible substatements */
1298 if (read_restr_substmt(module->ctx, *restr, node)) {
1299 goto error;
1300 }
1301 } else {
1302 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1303 goto error;
1304 }
Radek Krejcif2860132015-06-20 12:37:20 +02001305 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001306 break;
1307
1308 case LY_TYPE_LEAFREF:
Radek Krejcidc4c1412015-06-19 15:39:54 +02001309 /* RFC 6020 9.9.2 - path */
Radek Krejci73adb602015-07-02 18:07:40 +02001310 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001311 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1312 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001313 continue;
1314 }
1315
Radek Krejcidc4c1412015-06-19 15:39:54 +02001316 if (!strcmp(node->name, "path")) {
1317 if (type->info.lref.path) {
1318 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1319 goto error;
1320 }
1321
1322 GETVAL(value, node, "value");
1323 /* TODO
1324 * it would be nice to perform here a check that target is leaf or leaf-list,
Radek Krejcic63c9b02015-06-26 16:51:31 +02001325 * but schema is not finished yet and path can point almost to anywhere, so
Radek Krejcidc4c1412015-06-19 15:39:54 +02001326 * we will have to check the path at the end of parsing the schema.
1327 */
1328 type->info.lref.path = lydict_insert(module->ctx, value, 0);
1329 } else {
1330 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1331 goto error;
1332 }
Radek Krejci73adb602015-07-02 18:07:40 +02001333 }
1334
1335 if (!type->info.lref.path) {
1336 if (type->der->type.der) {
1337 /* this is just a derived type with no path specified/required */
1338 break;
1339 }
1340 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "path", "type");
1341 goto error;
Radek Krejcidc4c1412015-06-19 15:39:54 +02001342 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001343 break;
1344
1345 case LY_TYPE_STRING:
Radek Krejci3733a802015-06-19 13:43:21 +02001346 /* RFC 6020 9.4.4 - length */
1347 /* RFC 6020 9.4.6 - pattern */
Radek Krejci73adb602015-07-02 18:07:40 +02001348 i = 0;
Radek Krejci3733a802015-06-19 13:43:21 +02001349 LY_TREE_FOR_SAFE(yin->child, next, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001350 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1351 /* garbage */
1352 lyxml_free_elem(module->ctx, node);
1353 continue;
1354 }
1355
Radek Krejci3733a802015-06-19 13:43:21 +02001356 if (!strcmp(node->name, "length")) {
1357 if (type->info.str.length) {
1358 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1359 goto error;
1360 }
1361
1362 GETVAL(value, node, "value");
1363 if (check_length(value, type, LOGLINE(node))) {
1364 goto error;
1365 }
1366 type->info.str.length = calloc(1, sizeof *type->info.str.length);
1367 type->info.str.length->expr = lydict_insert(module->ctx, value, 0);
1368
Radek Krejci5fbc9162015-06-19 14:11:11 +02001369 /* get possible sub-statements */
1370 if (read_restr_substmt(module->ctx, type->info.str.length, node)) {
Radek Krejci3733a802015-06-19 13:43:21 +02001371 goto error;
1372 }
Radek Krejci82d971d2015-06-19 14:20:50 +02001373 lyxml_free_elem(module->ctx, node);
Radek Krejci3733a802015-06-19 13:43:21 +02001374 } else if (!strcmp(node->name, "pattern")) {
Radek Krejci73adb602015-07-02 18:07:40 +02001375 i++;
Radek Krejci3733a802015-06-19 13:43:21 +02001376 } else {
Radek Krejci82d971d2015-06-19 14:20:50 +02001377 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
Radek Krejci3733a802015-06-19 13:43:21 +02001378 goto error;
1379 }
1380 }
Radek Krejci5fbc9162015-06-19 14:11:11 +02001381 /* store patterns in array */
Radek Krejci73adb602015-07-02 18:07:40 +02001382 if (i) {
1383 type->info.str.patterns = calloc(i, sizeof *type->info.str.patterns);
1384 LY_TREE_FOR(yin->child, node) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001385 GETVAL(value, yin->child, "value");
Radek Krejci73adb602015-07-02 18:07:40 +02001386 type->info.str.patterns[type->info.str.pat_count].expr = lydict_insert(module->ctx, value, 0);
Radek Krejci5fbc9162015-06-19 14:11:11 +02001387
1388 /* get possible sub-statements */
Radek Krejci73adb602015-07-02 18:07:40 +02001389 if (read_restr_substmt(module->ctx, &type->info.str.patterns[type->info.str.pat_count], yin->child)) {
Radek Krejci5fbc9162015-06-19 14:11:11 +02001390 goto error;
1391 }
Radek Krejci73adb602015-07-02 18:07:40 +02001392 type->info.str.pat_count++;
Radek Krejci5fbc9162015-06-19 14:11:11 +02001393 }
1394 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001395 break;
1396
1397 case LY_TYPE_UNION:
Radek Krejcie4c366b2015-07-02 10:11:31 +02001398 /* RFC 6020 7.4 - type */
1399 /* count number of types in union */
1400 i = 0;
Radek Krejci0d70c372015-07-02 16:23:10 +02001401 LY_TREE_FOR_SAFE(yin->child, next, node) {
1402 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1403 /* garbage */
1404 lyxml_free_elem(module->ctx, node);
1405 continue;
1406 }
1407
Radek Krejcie4c366b2015-07-02 10:11:31 +02001408 if (!strcmp(node->name, "type")) {
1409 i++;
1410 } else {
1411 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1412 goto error;
1413 }
1414 }
1415
1416 if (!i) {
1417 if (type->der->type.der) {
1418 /* this is just a derived type with no base specified/required */
1419 break;
1420 }
1421 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", "(union) type");
1422 goto error;
1423 }
1424
1425 /* allocate array for union's types ... */
1426 type->info.uni.type = calloc(i, sizeof *type->info.uni.type);
1427 /* ... and fill the structures */
Radek Krejci73adb602015-07-02 18:07:40 +02001428 LY_TREE_FOR(yin->child, node) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001429 if (fill_yin_type(module, parent, node, &type->info.uni.type[type->info.uni.count], unres)) {
Radek Krejcie4c366b2015-07-02 10:11:31 +02001430 goto error;
1431 }
1432 type->info.uni.count++;
1433
1434 /* union's type cannot be empty or leafref */
1435 if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_EMPTY) {
1436 LOGVAL(VE_INARG, LOGLINE(node), "empty", node->name);
1437 goto error;
1438 } else if (type->info.uni.type[type->info.uni.count - 1].base == LY_TYPE_LEAFREF) {
1439 LOGVAL(VE_INARG, LOGLINE(node), "leafref", node->name);
1440 goto error;
1441 }
Radek Krejcie4c366b2015-07-02 10:11:31 +02001442 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001443 break;
1444
1445 default:
Radek Krejci6e328cd2015-06-26 16:24:11 +02001446 /* no sub-statement allowed in:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001447 * LY_TYPE_BOOL, LY_TYPE_EMPTY
1448 */
Radek Krejci0d70c372015-07-02 16:23:10 +02001449 LY_TREE_FOR(yin->child, node) {
1450 if (node->ns && !strcmp(node->ns->value, LY_NSYIN)) {
1451 LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
1452 goto error;
1453 }
Radek Krejci6e328cd2015-06-26 16:24:11 +02001454 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001455 break;
1456 }
1457
1458 return EXIT_SUCCESS;
Radek Krejci25d782a2015-05-22 15:03:23 +02001459
1460error:
1461
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001462 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001463}
1464
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001465static int
Radek Krejci8de7b0f2015-07-02 11:43:42 +02001466fill_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 +02001467{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001468 const char *value;
Radek Krejci73adb602015-07-02 18:07:40 +02001469 struct lyxml_elem *node;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001471 GETVAL(value, yin, "name");
1472 if (check_identifier(value, LY_IDENT_TYPE, LOGLINE(yin), module, parent)) {
1473 goto error;
1474 }
1475 tpdf->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejcida04f4a2015-05-21 12:54:09 +02001476
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001477 /* generic part - status, description, reference */
1478 if (read_yin_common(module, NULL, (struct ly_mnode *)tpdf, yin, OPT_IDENT)) {
1479 goto error;
1480 }
Radek Krejcieac35532015-05-31 19:09:15 +02001481
Radek Krejci73adb602015-07-02 18:07:40 +02001482 LY_TREE_FOR(yin->child, node) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001483 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
1484 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02001485 continue;
1486 }
1487
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001488 if (!strcmp(node->name, "type")) {
1489 if (tpdf->type.der) {
1490 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1491 goto error;
1492 }
Radek Krejci73adb602015-07-02 18:07:40 +02001493 if (fill_yin_type(module, parent, node, &tpdf->type, unres)) {
1494 goto error;
1495 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001496 } else if (!strcmp(node->name, "default")) {
1497 if (tpdf->dflt) {
1498 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1499 goto error;
1500 }
1501 GETVAL(value, node, "value");
1502 tpdf->dflt = lydict_insert(module->ctx, value, strlen(value));
1503 } else if (!strcmp(node->name, "units")) {
1504 if (tpdf->units) {
1505 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
1506 goto error;
1507 }
1508 GETVAL(value, node, "name");
1509 tpdf->units = lydict_insert(module->ctx, value, strlen(value));
1510 } else {
1511 LOGVAL(VE_INSTMT, LOGLINE(node), value);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001512 goto error;
1513 }
1514 }
Radek Krejci25d782a2015-05-22 15:03:23 +02001515
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001516 /* check mandatory value */
1517 if (!tpdf->type.der) {
1518 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
1519 goto error;
1520 }
Radek Krejcieac35532015-05-31 19:09:15 +02001521
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001522 /* check default value */
1523 if (check_default(&tpdf->type, tpdf->dflt)) {
1524 goto error;
1525 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02001526
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001527 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02001528
1529error:
1530
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001531 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02001532}
1533
Radek Krejci3cf9e222015-06-18 11:37:50 +02001534static struct ly_feature *
1535resolve_feature(const char *name, struct ly_module *module, unsigned int line)
1536{
1537 const char *prefix;
1538 unsigned int prefix_len = 0;
1539 int i, j, found = 0;
1540
1541 assert(name);
1542 assert(module);
1543
1544 /* check prefix */
1545 prefix = name;
1546 name = strchr(prefix, ':');
1547 if (name) {
1548 /* there is prefix */
1549 prefix_len = name - prefix;
1550 name++;
1551
1552 /* check whether the prefix points to the current module */
1553 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1554 /* then ignore prefix and works as there is no prefix */
1555 prefix_len = 0;
1556 }
1557 } else {
1558 /* no prefix, set pointers correctly */
1559 name = prefix;
1560 }
1561
1562 if (prefix_len) {
1563 /* search in imported modules */
1564 for (i = 0; i < module->imp_size; i++) {
1565 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
1566 module = module->imp[i].module;
1567 found = 1;
1568 break;
1569 }
1570 }
1571 if (!found) {
1572 /* identity refers unknown data model */
1573 LOGVAL(VE_INPREFIX, line, prefix);
1574 return NULL;
1575 }
1576 } else {
1577 /* search in submodules */
1578 for (i = 0; i < module->inc_size; i++) {
1579 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1580 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1581 return &(module->inc[i].submodule->features[j]);
1582 }
1583 }
1584 }
1585 }
1586
1587 /* search in the identified module */
1588 for (j = 0; j < module->features_size; j++) {
1589 if (!strcmp(name, module->features[j].name)) {
1590 return &module->features[j];
1591 }
1592 }
1593
1594 /* not found */
1595 return NULL;
1596}
1597
1598static int
1599fill_yin_feature(struct ly_module *module, struct lyxml_elem *yin, struct ly_feature *f)
1600{
1601 const char *value;
1602 struct lyxml_elem *child, *next;
1603 int c = 0;
1604
Radek Krejcib05774c2015-06-18 13:52:59 +02001605 GETVAL(value, yin, "name");
1606 if (check_identifier(value, LY_IDENT_FEATURE, LOGLINE(yin), module, NULL)) {
1607 goto error;
1608 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02001609 f->name = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci6a113852015-07-03 16:04:20 +02001610 f->module = module;
Radek Krejcib05774c2015-06-18 13:52:59 +02001611
Radek Krejci6a113852015-07-03 16:04:20 +02001612 if (read_yin_common(module, NULL, (struct ly_mnode *)f, yin, 0)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001613 goto error;
1614 }
1615
1616 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001617 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1618 /* garbage */
1619 lyxml_free_elem(module->ctx, child);
1620 continue;
1621 }
1622
Radek Krejci3cf9e222015-06-18 11:37:50 +02001623 if (!strcmp(child->name, "if-feature")) {
1624 c++;
1625 } else {
1626 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1627 goto error;
1628 }
1629 }
1630
1631 if (c) {
1632 f->features = calloc(c, sizeof *f->features);
1633 }
Radek Krejci73adb602015-07-02 18:07:40 +02001634 LY_TREE_FOR(yin->child, child) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02001635 GETVAL(value, child, "name");
1636 f->features[f->features_size] = resolve_feature(value, module, LOGLINE(child));
1637 if (!f->features[f->features_size]) {
1638 goto error;
1639 }
1640 f->features_size++;
1641 }
1642
Radek Krejci3cf9e222015-06-18 11:37:50 +02001643 return EXIT_SUCCESS;
1644
1645error:
1646
1647 return EXIT_FAILURE;
1648}
1649
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001650static int
Radek Krejci0bd5db42015-06-19 13:30:07 +02001651fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_restr *must)
Radek Krejci800af702015-06-02 13:46:01 +02001652{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001653 const char *value;
Radek Krejci800af702015-06-02 13:46:01 +02001654
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001655 GETVAL(value, yin, "condition");
Radek Krejci0bd5db42015-06-19 13:30:07 +02001656 must->expr = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02001657
Radek Krejci41726f92015-06-19 13:11:05 +02001658 return read_restr_substmt(module->ctx, must, yin);
Radek Krejci800af702015-06-02 13:46:01 +02001659
Radek Krejci41726f92015-06-19 13:11:05 +02001660error: /* GETVAL requires this label */
Radek Krejci800af702015-06-02 13:46:01 +02001661
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001662 return EXIT_FAILURE;
Radek Krejci800af702015-06-02 13:46:01 +02001663}
1664
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02001665static int
Radek Krejcieb00f512015-07-01 16:44:58 +02001666parse_unique(struct ly_mnode *parent, struct lyxml_elem *node, struct ly_unique *uniq_s)
1667{
1668 const char *value;
Radek Krejcie82ce862015-07-01 16:49:39 +02001669 char *uniq_str = NULL, *uniq_val, *start;
Radek Krejcieb00f512015-07-01 16:44:58 +02001670 int i, j;
1671
1672 /* count the number of unique values */
1673 GETVAL(value, node, "tag");
1674 uniq_val = uniq_str = strdup(value);
1675 uniq_s->leafs_size = 0;
1676 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1677 uniq_s->leafs_size++;
1678 while (isspace(*uniq_val)) {
1679 uniq_val++;
1680 }
1681 }
1682 uniq_s->leafs_size++;
1683 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1684
1685 /* interconnect unique values with the leafs */
1686 uniq_val = uniq_str;
1687 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1688 start = uniq_val;
1689 if ((uniq_val = strpbrk(start, " \t\n"))) {
1690 *uniq_val = '\0'; /* add terminating NULL byte */
1691 uniq_val++;
1692 while (isspace(*uniq_val)) {
1693 uniq_val++;
1694 }
1695 } /* else only one nodeid present/left already NULL byte terminated */
1696
1697 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LY_NODE_USES);
1698 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LY_NODE_LEAF) {
1699 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1700 if (!uniq_s->leafs[i]) {
1701 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
1702 } else {
1703 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
1704 }
1705 goto error;
1706 }
1707
1708 for (j = 0; j < i; j++) {
1709 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
1710 LOGVAL(VE_INARG, LOGLINE(node), start, node->name);
1711 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
1712 goto error;
1713 }
1714 }
1715 }
1716
1717 free(uniq_str);
1718 return EXIT_SUCCESS;
1719
1720error:
1721
1722 free(uniq_s->leafs);
1723 free(uniq_str);
1724
1725 return EXIT_FAILURE;
1726}
1727
1728/*
1729 * type: 0 - min, 1 - max
1730 */
1731static int
1732deviate_minmax(struct ly_mnode *target, struct lyxml_elem *node, struct ly_deviate *d, int type)
1733{
1734 const char *value;
1735 char *endptr;
1736 unsigned long val;
1737 uint32_t *ui32val;
1738
1739 /* check target node type */
1740 if (target->nodetype == LY_NODE_LEAFLIST) {
1741 if (type) {
1742 ui32val = &((struct ly_mnode_leaflist *)target)->max;
1743 } else {
1744 ui32val = &((struct ly_mnode_leaflist *)target)->min;
1745 }
1746 } else if (target->nodetype == LY_NODE_LIST) {
1747 if (type) {
1748 ui32val = &((struct ly_mnode_list *)target)->max;
1749 } else {
1750 ui32val = &((struct ly_mnode_list *)target)->min;
1751 }
1752 } else {
1753 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1754 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", node->name);
1755 goto error;
1756 }
1757
1758 GETVAL(value, node, "value");
1759 while (isspace(value[0])) {
1760 value++;
1761 }
1762
1763 /* convert it to uint32_t */
1764 errno = 0;
1765 endptr = NULL;
1766 val = strtoul(value, &endptr, 10);
1767 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
1768 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1769 goto error;
1770 }
1771 if (type) {
1772 d->max = (uint32_t)val;
1773 } else {
1774 d->min = (uint32_t)val;
1775 }
1776
1777 if (d->mod == LY_DEVIATE_ADD) {
1778 /* check that there is no current value */
1779 if (*ui32val) {
1780 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
1781 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1782 goto error;
1783 }
1784 }
1785
1786 if (d->mod == LY_DEVIATE_DEL) {
1787 /* check values */
1788 if ((uint32_t)val != *ui32val) {
1789 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
1790 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1791 goto error;
1792 }
1793 /* remove current min-elements value of the target */
1794 *ui32val = 0;
1795 } else { /* add (already checked) and replace */
1796 /* set new value specified in deviation */
1797 *ui32val = (uint32_t)val;
1798 }
1799
1800 return EXIT_SUCCESS;
1801
1802error:
1803
1804 return EXIT_FAILURE;
1805}
1806
1807static int
1808fill_yin_deviation(struct ly_module *module, struct lyxml_elem *yin, struct ly_deviation *dev)
1809{
1810 const char *value, **stritem;
1811 struct lyxml_elem *next, *child, *develem;
1812 int c_dev = 0, c_must, c_uniq;
1813 int f_min = 0; /* flags */
1814 int i, j;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001815 struct ly_deviate *d = NULL;
1816 struct ly_mnode *mnode = NULL;
1817 struct ly_mnode_choice *choice = NULL;
1818 struct ly_mnode_leaf *leaf = NULL;
1819 struct ly_mnode_list *list = NULL;
1820 struct ly_type *t = NULL;
Radek Krejcie4c366b2015-07-02 10:11:31 +02001821 uint8_t *trg_must_size = NULL;
Radek Krejcif1a830b2015-07-02 09:11:39 +02001822 struct ly_restr **trg_must = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001823
1824 GETVAL(value, yin, "target-node");
1825 dev->target_name = lydict_insert(module->ctx, value, 0);
1826
1827 /* resolve target node */
1828 dev->target = resolve_schema_nodeid(dev->target_name, NULL, module, LY_NODE_AUGMENT);
1829 if (!dev->target) {
1830 LOGVAL(VE_INARG, LOGLINE(yin), dev->target_name, yin->name);
1831 goto error;
1832 }
1833 if (dev->target->module == module) {
1834 LOGVAL(VE_SPEC, LOGLINE(yin), "Deviating own module is not allowed.");
1835 goto error;
1836 }
1837 /* mark the target module as deviated */
1838 dev->target->module->deviated = 1;
1839
1840 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001841 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1842 /* garbage */
1843 lyxml_free_elem(module->ctx, child);
1844 continue;
1845 }
1846
Radek Krejcieb00f512015-07-01 16:44:58 +02001847 if (!strcmp(child->name, "description")) {
1848 if (dev->dsc) {
1849 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1850 goto error;
1851 }
1852 dev->dsc = read_yin_subnode(module->ctx, child, "text");
1853 if (!dev->dsc) {
1854 goto error;
1855 }
1856 } else if (!strcmp(child->name, "reference")) {
1857 if (dev->ref) {
1858 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1859 goto error;
1860 }
1861 dev->ref = read_yin_subnode(module->ctx, child, "text");
1862 if (!dev->ref) {
1863 goto error;
1864 }
1865 } else if (!strcmp(child->name, "deviate")) {
1866 c_dev++;
1867
1868 /* skip lyxml_free_elem() at the end of the loop, node will be
1869 * further processed later
1870 */
1871 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02001872
Radek Krejcieb00f512015-07-01 16:44:58 +02001873 } else {
1874 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1875 goto error;
1876 }
1877
1878 lyxml_free_elem(module->ctx, child);
1879 }
1880
1881 if (c_dev) {
1882 dev->deviate = calloc(c_dev, sizeof *dev->deviate);
1883 }
1884
1885 LY_TREE_FOR(yin->child, develem) {
1886 /* init */
1887 f_min = 0;
1888 c_must = 0;
1889 c_uniq = 0;
1890
1891 /* get deviation type */
1892 GETVAL(value, develem, "value");
1893 if (!strcmp(value, "not-supported")) {
1894 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_NO;
1895 /* no property expected in this case */
1896 if (develem->child) {
1897 LOGVAL(VE_INSTMT, LOGLINE(develem->child), develem->child->name);
1898 goto error;
1899 }
1900
Radek Krejci5b917642015-07-02 09:03:13 +02001901 /* and neither any other deviate statement is expected,
1902 * not-supported deviation must be the only deviation of the target
1903 */
1904 if (dev->deviate_size || develem->next) {
1905 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1906 LOGVAL(VE_SPEC, 0, "\"not-supported\" deviation cannot be combined with any other deviation.");
1907 goto error;
1908 }
1909
1910
Radek Krejcieb00f512015-07-01 16:44:58 +02001911 /* remove target node */
1912 ly_mnode_free(dev->target);
Radek Krejci5b917642015-07-02 09:03:13 +02001913 dev->target = NULL;
Radek Krejcieb00f512015-07-01 16:44:58 +02001914
Radek Krejci5b917642015-07-02 09:03:13 +02001915 dev->deviate_size = 1;
1916 return EXIT_SUCCESS;
Radek Krejcieb00f512015-07-01 16:44:58 +02001917 } else if (!strcmp(value, "add")) {
1918 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_ADD;
1919 } else if (!strcmp(value, "replace")) {
1920 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_RPL;
1921 } else if (!strcmp(value, "delete")) {
1922 dev->deviate[dev->deviate_size].mod = LY_DEVIATE_DEL;
1923 } else {
1924 LOGVAL(VE_INARG, LOGLINE(develem), value, develem->name);
1925 goto error;
1926 }
1927 d = &dev->deviate[dev->deviate_size];
1928
1929 /* process deviation properties */
1930 LY_TREE_FOR_SAFE(develem->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02001931 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
1932 /* garbage */
1933 lyxml_free_elem(module->ctx, child);
1934 continue;
1935 }
1936
Radek Krejcieb00f512015-07-01 16:44:58 +02001937 if (!strcmp(child->name, "config")) {
1938 if (d->flags & LY_NODE_CONFIG_MASK) {
1939 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1940 goto error;
1941 }
1942
1943 /* for we deviate from RFC 6020 and allow config property even it is/is not
1944 * specified in the target explicitly since config property inherits. So we expect
1945 * that config is specified in every node. But for delete, we check that the value
1946 * is the same as here in deviation
1947 */
1948 GETVAL(value, child, "value");
1949 if (!strcmp(value, "false")) {
1950 d->flags |= LY_NODE_CONFIG_R;
1951 } else if (!strcmp(value, "true")) {
1952 d->flags |= LY_NODE_CONFIG_W;
1953 } else {
1954 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1955 goto error;
1956 }
1957
1958 if (d->mod == LY_DEVIATE_DEL) {
1959 /* check values */
1960 if ((d->flags & LY_NODE_CONFIG_MASK) != (dev->target->flags & LY_NODE_CONFIG_MASK)) {
1961 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
1962 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
1963 goto error;
1964 }
1965 /* remove current config value of the target ... */
1966 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1967
1968 /* ... and inherit config value from the target's parent */
1969 if (dev->target->parent) {
1970 dev->target->flags |= dev->target->parent->flags & LY_NODE_CONFIG_MASK;
1971 } else {
1972 /* default config is true */
1973 dev->target->flags |= LY_NODE_CONFIG_W;
1974 }
1975 } else { /* add and replace are the same in this case */
1976 /* remove current config value of the target ... */
1977 dev->target->flags &= ~LY_NODE_CONFIG_MASK;
1978
1979 /* ... and replace it with the value specified in deviation */
1980 dev->target->flags |= d->flags & LY_NODE_CONFIG_MASK;
1981 }
1982 } else if (!strcmp(child->name, "default")) {
1983 if (d->dflt) {
1984 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
1985 goto error;
1986 }
1987 GETVAL(value, child, "value");
1988 d->dflt = lydict_insert(module->ctx, value, 0);
1989
1990 if (dev->target->nodetype == LY_NODE_CHOICE) {
1991 choice = (struct ly_mnode_choice *)dev->target;
1992
1993 if (d->mod == LY_DEVIATE_ADD) {
1994 /* check that there is no current value */
1995 if (choice->dflt) {
1996 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
1997 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
1998 goto error;
1999 }
2000 }
2001
2002 mnode = resolve_schema_nodeid(d->dflt, (struct ly_mnode *)choice, choice->module, LY_NODE_CHOICE);
2003 if (d->mod == LY_DEVIATE_DEL) {
2004 if (!choice->dflt || choice->dflt != mnode) {
2005 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2006 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2007 goto error;
2008 }
2009 } else { /* add (already checked) and replace */
2010 choice->dflt = mnode;
2011 if (!choice->dflt) {
2012 /* default branch not found */
2013 LOGVAL(VE_INARG, LOGLINE(yin), value, "default");
2014 goto error;
2015 }
2016 }
2017 } else if (dev->target->nodetype == LY_NODE_LEAF) {
2018 leaf = (struct ly_mnode_leaf *)dev->target;
2019
2020 if (d->mod == LY_DEVIATE_ADD) {
2021 /* check that there is no current value */
2022 if (leaf->dflt) {
2023 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2024 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2025 goto error;
2026 }
2027 }
2028
2029 if (d->mod == LY_DEVIATE_DEL) {
2030 if (!leaf->dflt || leaf->dflt != d->dflt) {
2031 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2032 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2033 goto error;
2034 }
2035 /* remove value */
2036 lydict_remove(leaf->module->ctx, leaf->dflt);
2037 leaf->dflt = NULL;
2038 } else { /* add (already checked) and replace */
2039 /* remove value */
2040 lydict_remove(leaf->module->ctx, leaf->dflt);
2041
2042 /* set new value */
2043 leaf->dflt = lydict_insert(leaf->module->ctx, d->dflt, 0);
2044 }
2045 } else {
2046 /* invalid target for default value */
2047 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2048 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2049 goto error;
2050 }
2051 } else if (!strcmp(child->name, "mandatory")) {
2052 if (d->flags & LY_NODE_MAND_MASK) {
2053 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2054 goto error;
2055 }
2056
2057 /* check target node type */
2058 if (!(dev->target->nodetype &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML))) {
2059 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2060 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2061 goto error;
2062 }
2063
2064 GETVAL(value, child, "value");
2065 if (!strcmp(value, "false")) {
2066 d->flags |= LY_NODE_MAND_FALSE;
2067 } else if (!strcmp(value, "true")) {
2068 d->flags |= LY_NODE_MAND_TRUE;
2069 } else {
2070 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2071 goto error;
2072 }
2073
2074 if (d->mod == LY_DEVIATE_ADD) {
2075 /* check that there is no current value */
2076 if (dev->target->flags & LY_NODE_MAND_MASK) {
2077 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2078 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2079 goto error;
2080 }
2081 }
2082
2083 if (d->mod == LY_DEVIATE_DEL) {
2084 /* check values */
2085 if ((d->flags & LY_NODE_MAND_MASK) != (dev->target->flags & LY_NODE_MAND_MASK)) {
2086 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2087 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2088 goto error;
2089 }
2090 /* remove current mandatory value of the target */
2091 dev->target->flags &= ~LY_NODE_MAND_MASK;
2092 } else { /* add (already checked) and replace */
2093 /* remove current mandatory value of the target ... */
2094 dev->target->flags &= ~LY_NODE_MAND_MASK;
2095
2096 /* ... and replace it with the value specified in deviation */
2097 dev->target->flags |= d->flags & LY_NODE_MAND_MASK;
2098 }
2099 } else if (!strcmp(child->name, "min-elements")) {
2100 if (f_min) {
2101 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2102 goto error;
2103 }
2104 f_min = 1;
2105
2106 if (deviate_minmax(dev->target, child, d, 0)) {
2107 goto error;
2108 }
2109 } else if (!strcmp(child->name, "max-elements")) {
2110 if (d->max) {
2111 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2112 goto error;
2113 }
2114
2115 if (deviate_minmax(dev->target, child, d, 1)) {
2116 goto error;
2117 }
2118 } else if (!strcmp(child->name, "must")) {
2119 c_must++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002120 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
2121 continue;
2122 } else if (!strcmp(child->name, "type")) {
2123 if (d->type) {
2124 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2125 goto error;
2126 }
2127
2128 /* check target node type */
2129 if (dev->target->nodetype == LY_NODE_LEAF) {
2130 t = &((struct ly_mnode_leaf *)dev->target)->type;
2131 } else if (dev->target->nodetype == LY_NODE_LEAFLIST) {
2132 t = &((struct ly_mnode_leaflist *)dev->target)->type;
2133 } else {
2134 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2135 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2136 goto error;
2137 }
2138
2139 if (d->mod == LY_DEVIATE_ADD) {
2140 /* not allowed, type is always present at the target */
2141 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2142 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2143 goto error;
2144 } else if (d->mod == LY_DEVIATE_DEL) {
2145 /* not allowed, type cannot be deleted from the target */
2146 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2147 LOGVAL(VE_SPEC, 0, "Deleteing type from the target is not allowed.");
2148 goto error;
2149 }
2150
2151 /* replace */
2152 /* remove current units value of the target ... */
2153 ly_type_free(dev->target->module->ctx, t);
2154
2155 /* ... and replace it with the value specified in deviation */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02002156 if (fill_yin_type(module, dev->target, child, t, NULL)) {
Radek Krejcieb00f512015-07-01 16:44:58 +02002157 goto error;
2158 }
2159 d->type = t;
2160 } else if (!strcmp(child->name, "unique")) {
2161 c_uniq++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002162 /* skip lyxml_free_elem() at the end of the loop, this node will be processed later */
2163 continue;
2164 } else if (!strcmp(child->name, "units")) {
2165 if (d->units) {
2166 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2167 goto error;
2168 }
2169
2170 /* check target node type */
2171 if (dev->target->nodetype == LY_NODE_LEAFLIST) {
2172 stritem = &((struct ly_mnode_leaflist *)dev->target)->units;
2173 } else if (dev->target->nodetype == LY_NODE_LEAF) {
2174 stritem = &((struct ly_mnode_leaf *)dev->target)->units;
2175 } else {
2176 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2177 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2178 goto error;
2179 }
2180
2181 /* get units value */
2182 GETVAL(value, child, "name");
2183 d->units = lydict_insert(module->ctx, value, 0);
2184
2185 /* apply to target */
2186 if (d->mod == LY_DEVIATE_ADD) {
2187 /* check that there is no current value */
2188 if (*stritem) {
2189 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2190 LOGVAL(VE_SPEC, 0, "Adding property that already exists.");
2191 goto error;
2192 }
2193 }
2194
2195 if (d->mod == LY_DEVIATE_DEL) {
2196 /* check values */
2197 if (*stritem != d->units) {
2198 LOGVAL(VE_INARG, LOGLINE(child), value, child->name);
2199 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2200 goto error;
2201 }
2202 /* remove current units value of the target */
2203 lydict_remove(dev->target->module->ctx, *stritem);
2204 } else { /* add (already checked) and replace */
2205 /* remove current units value of the target ... */
2206 lydict_remove(dev->target->module->ctx, *stritem);
2207
2208 /* ... and replace it with the value specified in deviation */
2209 *stritem = lydict_insert(module->ctx, value, 0);
2210 }
2211 } else {
2212 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2213 goto error;
2214 }
2215
2216 lyxml_free_elem(module->ctx, child);
2217 }
2218
2219 if (c_must) {
2220 /* check target node type */
2221 switch (dev->target->nodetype) {
2222 case LY_NODE_LEAF:
2223 trg_must = &((struct ly_mnode_leaf *)dev->target)->must;
2224 trg_must_size = &((struct ly_mnode_leaf *)dev->target)->must_size;
2225 break;
2226 case LY_NODE_CONTAINER:
2227 trg_must = &((struct ly_mnode_container *)dev->target)->must;
2228 trg_must_size = &((struct ly_mnode_container *)dev->target)->must_size;
2229 break;
2230 case LY_NODE_LEAFLIST:
2231 trg_must = &((struct ly_mnode_leaflist *)dev->target)->must;
2232 trg_must_size = &((struct ly_mnode_leaflist *)dev->target)->must_size;
2233 break;
2234 case LY_NODE_LIST:
2235 trg_must = &((struct ly_mnode_list *)dev->target)->must;
2236 trg_must_size = &((struct ly_mnode_list *)dev->target)->must_size;
2237 break;
2238 case LY_NODE_ANYXML:
2239 trg_must = &((struct ly_mnode_anyxml *)dev->target)->must;
2240 trg_must_size = &((struct ly_mnode_anyxml *)dev->target)->must_size;
2241 break;
2242 default:
2243 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2244 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2245 goto error;
2246 }
2247
2248 if (d->mod == LY_DEVIATE_RPL) {
2249 /* remove target's musts and allocate new array for it */
2250 if (!*trg_must) {
2251 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2252 LOGVAL(VE_SPEC, 0, "Property \"must\" to replace does not exists in target.");
2253 goto error;
2254 }
2255
2256 for (i = 0; i < list->must_size; i++) {
2257 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2258 }
2259 free(*trg_must);
2260 *trg_must = d->must = calloc(c_must, sizeof *d->must);
2261 d->must_size = c_must;
2262 *trg_must_size = 0;
2263 } else if (d->mod == LY_DEVIATE_ADD) {
2264 /* reallocate the must array of the target */
2265 d->must = realloc(*trg_must, (c_must + *trg_must_size) * sizeof *d->must);
2266 *trg_must = d->must;
2267 d->must = &(*trg_must[*trg_must_size]);
2268 d->must_size = c_must;
2269 } else { /* LY_DEVIATE_DEL */
2270 d->must = calloc(c_must, sizeof *d->must);
2271 }
2272 }
2273 if (c_uniq) {
2274 /* check target node type */
2275 if (dev->target->nodetype != LY_NODE_LIST) {
2276 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2277 LOGVAL(VE_SPEC, 0, "Target node does not allow \"%s\" property.", child->name);
2278 goto error;
2279 }
2280
2281 list = (struct ly_mnode_list *)dev->target;
2282 if (d->mod == LY_DEVIATE_RPL) {
2283 /* remove target's unique and allocate new array for it */
2284 if (!list->unique) {
2285 LOGVAL(VE_INARG, LOGLINE(develem), "replace", "deviate");
2286 LOGVAL(VE_SPEC, 0, "Property \"unique\" to replace does not exists in target.");
2287 goto error;
2288 }
2289
2290 for (i = 0; i < list->unique_size; i++) {
2291 free(list->unique[i].leafs);
2292 }
2293 free(list->unique);
2294 list->unique = d->unique = calloc(c_uniq, sizeof *d->unique);
2295 d->unique_size = c_uniq;
2296 list->unique_size = 0;
2297 } else if (d->mod == LY_DEVIATE_ADD) {
2298 /* reallocate the unique array of the target */
2299 d->unique = realloc(list->unique, (c_uniq + list->unique_size) * sizeof *d->unique);
2300 list->unique = d->unique;
2301 d->unique = &list->unique[list->unique_size];
2302 d->unique_size = c_uniq;
2303 } else { /* LY_DEVIATE_DEL */
2304 d->unique = calloc(c_uniq, sizeof *d->unique);
2305 }
2306 }
2307
2308 /* process deviation properties with 0..n cardinality */
Radek Krejci73adb602015-07-02 18:07:40 +02002309 LY_TREE_FOR(develem->child, child) {
Radek Krejcieb00f512015-07-01 16:44:58 +02002310 if (!strcmp(child->name, "must")) {
2311 if (d->mod == LY_DEVIATE_DEL) {
2312 if (fill_yin_must(module, child, &d->must[d->must_size])) {
2313 goto error;
2314 }
2315
2316 /* find must to delete, we are ok with just matching conditions */
2317 for (i = 0; i < *trg_must_size; i++) {
2318 if (d->must[d->must_size].expr == (*trg_must)[i].expr) {
2319 /* we have a match, free the must structure ... */
2320 ly_restr_free(dev->target->module->ctx, &(*trg_must[i]));
2321 /* ... and maintain the array */
2322 (*trg_must_size)--;
2323 if (i != *trg_must_size) {
2324 (*trg_must)[i].expr = (*trg_must)[*trg_must_size].expr;
2325 (*trg_must)[i].dsc = (*trg_must)[*trg_must_size].dsc;
2326 (*trg_must)[i].ref = (*trg_must)[*trg_must_size].ref;
2327 (*trg_must)[i].eapptag = (*trg_must)[*trg_must_size].eapptag;
2328 (*trg_must)[i].emsg = (*trg_must)[*trg_must_size].emsg;
2329 }
2330 if (!(*trg_must_size)) {
2331 free(*trg_must);
2332 *trg_must = NULL;
2333 } else {
2334 (*trg_must)[*trg_must_size].expr = NULL;
2335 (*trg_must)[*trg_must_size].dsc = NULL;
2336 (*trg_must)[*trg_must_size].ref = NULL;
2337 (*trg_must)[*trg_must_size].eapptag = NULL;
2338 (*trg_must)[*trg_must_size].emsg = NULL;
2339 }
2340
2341 i = -1; /* set match flag */
2342 break;
2343 }
2344 }
2345 d->must_size++;
2346 if (i != -1) {
2347 /* no match found */
2348 LOGVAL(VE_INARG, LOGLINE(child), d->must[d->must_size - 1].expr, child->name);
2349 LOGVAL(VE_SPEC, 0, "Value does not match any must from the target.");
2350 goto error;
2351 }
2352 } else { /* replace or add */
2353 if (fill_yin_must(dev->target->module, child, &((*trg_must)[*trg_must_size]))) {
2354 goto error;
2355 }
2356 (*trg_must_size)++;
2357 }
2358 } else if (!strcmp(child->name, "unique")) {
2359 if (d->mod == LY_DEVIATE_DEL) {
2360 if (parse_unique(dev->target, child, &d->unique[d->unique_size])) {
2361 goto error;
2362 }
2363
2364 /* find unique structures to delete */
2365 for (i = 0; i < list->unique_size; i++) {
2366 if (list->unique[i].leafs_size != d->unique[d->unique_size].leafs_size) {
2367 continue;
2368 }
2369
2370 for (j = 0; j < d->unique[d->unique_size].leafs_size; j++) {
2371 if (list->unique[i].leafs[j] != d->unique[d->unique_size].leafs[j]) {
2372 break;
2373 }
2374 }
2375
2376 if (j == d->unique[d->unique_size].leafs_size) {
2377 /* we have a match, free the unique structure ... */
2378 free(list->unique[i].leafs);
2379 /* ... and maintain the array */
2380 list->unique_size--;
2381 if (i != list->unique_size) {
2382 list->unique[i].leafs_size = list->unique[list->unique_size].leafs_size;
2383 list->unique[i].leafs = list->unique[list->unique_size].leafs;
2384 }
2385
2386 if (!list->unique_size) {
2387 free(list->unique);
2388 list->unique = NULL;
2389 } else {
2390 list->unique[list->unique_size].leafs_size = 0;
2391 list->unique[list->unique_size].leafs = NULL;
2392 }
2393
2394 i = -1; /* set match flag */
2395 break;
2396 }
2397 }
2398
2399 d->unique_size++;
2400 if (i != -1) {
2401 /* no match found */
2402 LOGVAL(VE_INARG, LOGLINE(child), lyxml_get_attr(child, "tag", NULL), child->name);
2403 LOGVAL(VE_SPEC, 0, "Value differs from the target being deleted.");
2404 goto error;
2405 }
2406 } else { /* replace or add */
2407 if (parse_unique(dev->target, child, &list->unique[list->unique_size])) {
2408 goto error;
2409 }
2410 list->unique_size++;
2411 }
2412 }
Radek Krejcieb00f512015-07-01 16:44:58 +02002413 }
Radek Krejci5b917642015-07-02 09:03:13 +02002414
2415 dev->deviate_size++;
Radek Krejcieb00f512015-07-01 16:44:58 +02002416 }
2417
Radek Krejcieb00f512015-07-01 16:44:58 +02002418 return EXIT_SUCCESS;
2419
2420error:
2421
2422 if (dev->deviate) {
2423 for (i = 0; i < dev->deviate_size; i++) {
2424 lydict_remove(module->ctx, dev->deviate[i].dflt);
2425 lydict_remove(module->ctx, dev->deviate[i].units);
2426
2427 if (dev->deviate[i].mod == LY_DEVIATE_DEL) {
2428 for (j = 0; j < dev->deviate[i].must_size; j++) {
2429 ly_restr_free(module->ctx, &dev->deviate[i].must[j]);
2430 }
2431 free(dev->deviate[i].must);
2432
2433 for (j = 0; j < dev->deviate[i].unique_size; j++) {
2434 free(dev->deviate[i].unique[j].leafs);
2435 }
2436 free(dev->deviate[i].unique);
2437 }
2438 }
2439 free(dev->deviate);
2440 }
2441
2442 return EXIT_FAILURE;
2443}
2444
2445static int
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002446fill_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 +02002447{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002448 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02002449 struct lyxml_elem *next, *child;
2450 int c = 0;
Radek Krejci106efc02015-06-10 14:36:27 +02002451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002452 GETVAL(value, yin, "target-node");
2453 aug->target_name = lydict_insert(module->ctx, value, 0);
2454 aug->parent = parent;
Radek Krejci106efc02015-06-10 14:36:27 +02002455
Radek Krejci6a113852015-07-03 16:04:20 +02002456 if (read_yin_common(module, NULL, (struct ly_mnode *)aug, yin, OPT_NACMEXT)) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02002457 goto error;
2458 }
2459
2460 LY_TREE_FOR_SAFE(yin->child, next, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002461 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2462 /* garbage */
2463 lyxml_free_elem(module->ctx, child);
2464 continue;
2465 }
2466
Radek Krejci3cf9e222015-06-18 11:37:50 +02002467 if (!strcmp(child->name, "if-feature")) {
2468 c++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002469 } else if (!strcmp(child->name, "when")) {
2470 if (aug->when) {
2471 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2472 goto error;
2473 }
2474
2475 aug->when = read_yin_when(module, child);
2476 lyxml_free_elem(module->ctx, child);
2477
2478 if (!aug->when) {
2479 goto error;
2480 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02002481
2482 /* check allowed sub-statements */
2483 } else if (strcmp(child->name, "anyxml") && strcmp(child->name, "case") && strcmp(child->name, "choice") &&
2484 strcmp(child->name, "container") && strcmp(child->name, "leaf-list") && strcmp(child->name, "leaf") &&
2485 strcmp(child->name, "list") && strcmp(child->name, "uses")) {
2486 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2487 goto error;
2488 }
2489 }
2490
2491 if (c) {
2492 aug->features = calloc(c, sizeof *aug->features);
2493 }
2494
2495 LY_TREE_FOR_SAFE(yin->child, next, child) {
2496 if (!strcmp(child->name, "if-feature")) {
2497 GETVAL(value, child, "name");
2498 aug->features[aug->features_size] = resolve_feature(value, module, LOGLINE(child));
2499 if (!aug->features[aug->features_size]) {
2500 goto error;
2501 }
2502 aug->features_size++;
Radek Krejci73adb602015-07-02 18:07:40 +02002503 lyxml_free_elem(module->ctx, child);
Radek Krejci3cf9e222015-06-18 11:37:50 +02002504 }
2505
Radek Krejci73adb602015-07-02 18:07:40 +02002506 /* data nodes are still kept under yin */
Radek Krejci3cf9e222015-06-18 11:37:50 +02002507 }
2508
2509 /* do not resolve data now, just keep the definition which will be parsed later
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002510 * when we will have the target node
2511 */
2512 lyxml_unlink_elem(yin);
2513 aug->child = (struct ly_mnode *)yin;
Radek Krejci106efc02015-06-10 14:36:27 +02002514
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002515 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02002516
2517error:
2518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002519 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02002520}
2521
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002522static int
2523fill_yin_refine(struct ly_module *module, struct lyxml_elem *yin, struct ly_refine *rfn)
Radek Krejci3bde87f2015-06-05 16:51:58 +02002524{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002525 struct lyxml_elem *sub, *next;
2526 const char *value;
2527 char *endptr;
2528 int f_mand = 0, f_min = 0, f_max = 0;
2529 int c_must = 0;
2530 int r;
2531 unsigned long int val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002532
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002533 GETVAL(value, yin, "target-node");
2534 rfn->target = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci3bde87f2015-06-05 16:51:58 +02002535
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002536 if (read_yin_common(module, NULL, (struct ly_mnode *)rfn, yin, OPT_CONFIG)) {
2537 goto error;
2538 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002539
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002540 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002541 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
2542 /* garbage */
2543 lyxml_free_elem(module->ctx, sub);
2544 continue;
2545 }
2546
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002547 /* limited applicability */
2548 if (!strcmp(sub->name, "default")) {
2549 /* leaf or choice */
2550 if (rfn->mod.dflt) {
2551 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2552 goto error;
2553 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002555 /* check possibility of statements combination */
2556 if (rfn->target_type) {
2557 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE);
2558 if (!rfn->target_type) {
2559 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2560 goto error;
2561 }
2562 } else {
2563 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE;
2564 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002565
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002566 GETVAL(value, sub, "value");
2567 rfn->mod.dflt = lydict_insert(module->ctx, value, strlen(value));
2568 } else if (!strcmp(sub->name, "mandatory")) {
2569 /* leaf, choice or anyxml */
2570 if (f_mand) {
2571 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2572 goto error;
2573 }
2574 /* just checking the flags in leaf is not sufficient, we would allow
2575 * multiple mandatory statements with the "false" value
2576 */
2577 f_mand = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002578
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002579 /* check possibility of statements combination */
2580 if (rfn->target_type) {
2581 rfn->target_type &= (LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML);
2582 if (!rfn->target_type) {
2583 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2584 goto error;
2585 }
2586 } else {
2587 rfn->target_type = LY_NODE_LEAF | LY_NODE_CHOICE | LY_NODE_ANYXML;
2588 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002589
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002590 GETVAL(value, sub, "value");
2591 if (!strcmp(value, "true")) {
2592 rfn->flags |= LY_NODE_MAND_TRUE;
2593 } else if (!strcmp(value, "false")) {
2594 rfn->flags |= LY_NODE_MAND_FALSE;
2595 } else {
2596 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2597 goto error;
2598 }
2599 } else if (!strcmp(sub->name, "min-elements")) {
2600 /* list or leaf-list */
2601 if (f_min) {
2602 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2603 goto error;
2604 }
2605 f_min = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002606
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002607 /* check possibility of statements combination */
2608 if (rfn->target_type) {
2609 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2610 if (!rfn->target_type) {
2611 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2612 goto error;
2613 }
2614 } else {
2615 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2616 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002618 GETVAL(value, sub, "value");
2619 while (isspace(value[0])) {
2620 value++;
2621 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002622
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002623 /* convert it to uint32_t */
2624 errno = 0;
2625 endptr = NULL;
2626 val = strtoul(value, &endptr, 10);
2627 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
2628 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2629 goto error;
2630 }
2631 rfn->mod.list.min = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002632
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002633 /* magic - bit 3 in flags means min set */
2634 rfn->flags |= 0x04;
2635 } else if (!strcmp(sub->name, "max-elements")) {
2636 /* list or leaf-list */
2637 if (f_max) {
2638 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2639 goto error;
2640 }
2641 f_max = 1;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002642
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002643 /* check possibility of statements combination */
2644 if (rfn->target_type) {
2645 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST);
2646 if (!rfn->target_type) {
2647 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2648 goto error;
2649 }
2650 } else {
2651 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST;
2652 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002653
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002654 GETVAL(value, sub, "value");
2655 while (isspace(value[0])) {
2656 value++;
2657 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002658
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002659 /* convert it to uint32_t */
2660 errno = 0;
2661 endptr = NULL;
2662 val = strtoul(value, &endptr, 10);
2663 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
2664 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
2665 goto error;
2666 }
2667 rfn->mod.list.max = (uint32_t) val;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002669 /* magic - bit 4 in flags means min set */
2670 rfn->flags |= 0x08;
2671 } else if (!strcmp(sub->name, "presence")) {
2672 /* container */
2673 if (rfn->mod.presence) {
2674 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
2675 goto error;
2676 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002677
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002678 /* check possibility of statements combination */
2679 if (rfn->target_type) {
2680 rfn->target_type &= LY_NODE_CONTAINER;
2681 if (!rfn->target_type) {
2682 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2683 goto error;
2684 }
2685 } else {
2686 rfn->target_type = LY_NODE_CONTAINER;
2687 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002688
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002689 GETVAL(value, sub, "value");
2690 rfn->mod.presence = lydict_insert(module->ctx, value, strlen(value));
2691 } else if (!strcmp(sub->name, "must")) {
2692 /* leaf-list, list, container or anyxml */
2693 /* check possibility of statements combination */
2694 if (rfn->target_type) {
2695 rfn->target_type &= (LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML);
2696 if (!rfn->target_type) {
2697 LOGVAL(VE_SPEC, LOGLINE(sub), "invalid combination of refine substatements");
2698 goto error;
2699 }
2700 } else {
2701 rfn->target_type = LY_NODE_LIST | LY_NODE_LEAFLIST | LY_NODE_CONTAINER | LY_NODE_ANYXML;
2702 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002703
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002704 c_must++;
Radek Krejci41882de2015-07-02 16:34:58 +02002705 continue;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002706
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002707 } else {
2708 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2709 goto error;
2710 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002711
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002712 lyxml_free_elem(module->ctx, sub);
2713 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002714
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002715 /* process nodes with cardinality of 0..n */
2716 if (c_must) {
2717 rfn->must = calloc(c_must, sizeof *rfn->must);
2718 }
Radek Krejci73adb602015-07-02 18:07:40 +02002719 LY_TREE_FOR(yin->child, sub) {
2720 r = fill_yin_must(module, sub, &rfn->must[rfn->must_size]);
2721 rfn->must_size++;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002722
Radek Krejci73adb602015-07-02 18:07:40 +02002723 if (r) {
2724 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002725 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002726 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02002727
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002728 return EXIT_SUCCESS;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002729
2730error:
2731
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002732 return EXIT_FAILURE;
Radek Krejci3bde87f2015-06-05 16:51:58 +02002733}
2734
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002735static int
2736fill_yin_import(struct ly_module *module, struct lyxml_elem *yin, struct ly_import *imp)
Radek Krejciefaeba32015-05-27 14:30:57 +02002737{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002738 struct lyxml_elem *child;
2739 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002741 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002742 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2743 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02002744 continue;
2745 }
2746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002747 if (!strcmp(child->name, "prefix")) {
2748 GETVAL(value, child, "value");
2749 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(child), module, NULL)) {
2750 goto error;
2751 }
2752 imp->prefix = lydict_insert(module->ctx, value, strlen(value));
2753 } else if (!strcmp(child->name, "revision-date")) {
2754 if (imp->rev[0]) {
2755 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2756 goto error;
2757 }
2758 GETVAL(value, child, "date");
2759 if (check_date(value, LOGLINE(child))) {
2760 goto error;
2761 }
2762 memcpy(imp->rev, value, LY_REV_SIZE - 1);
2763 } else {
2764 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2765 goto error;
2766 }
2767 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002768
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002769 /* check mandatory information */
2770 if (!imp->prefix) {
2771 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", yin->name);
2772 goto error;
2773 }
Radek Krejcice7fb782015-05-29 16:52:34 +02002774
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002775 GETVAL(value, yin, "module");
2776 imp->module = ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL, 1);
2777 if (!imp->module) {
2778 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
2779 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2780 goto error;
2781 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002782
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002783 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002784
2785error:
2786
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002787 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002788}
2789
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002790static int
2791fill_yin_include(struct ly_module *module, struct lyxml_elem *yin, struct ly_include *inc)
Radek Krejciefaeba32015-05-27 14:30:57 +02002792{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002793 struct lyxml_elem *child;
2794 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02002795
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002796 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002797 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2798 /* garbage */
2799 continue;
2800 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002801 if (!strcmp(child->name, "revision-date")) {
2802 if (inc->rev[0]) {
2803 LOGVAL(VE_TOOMANY, LOGLINE(child), "revision-date", yin->name);
2804 goto error;
2805 }
2806 GETVAL(value, child, "date");
2807 if (check_date(value, LOGLINE(child))) {
2808 goto error;
2809 }
2810 memcpy(inc->rev, value, LY_REV_SIZE - 1);
2811 } else {
2812 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
2813 goto error;
2814 }
2815 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002816
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002817 GETVAL(value, yin, "module");
Michal Vasko7bf06882015-07-03 15:33:56 +02002818 inc->submodule = ly_ctx_get_submodule(module, value, inc->rev[0] ? inc->rev : NULL, 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002819 if (!inc->submodule) {
2820 LOGERR(LY_EVALID, "Including \"%s\" module into \"%s\" failed.", value, module->name);
2821 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2822 goto error;
2823 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002824
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002825 /* check that belongs-to corresponds */
2826 if (module->type) {
2827 module = ((struct ly_submodule *)module)->belongsto;
2828 }
2829 if (inc->submodule->belongsto != module) {
2830 LOGVAL(VE_INARG, LOGLINE(yin), value, yin->name);
2831 LOGVAL(VE_SPEC, 0, "The included module does not belongs-to the \"%s\" module", module->name);
2832 goto error;
2833 }
Radek Krejciefaeba32015-05-27 14:30:57 +02002834
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002835 return EXIT_SUCCESS;
Radek Krejcice7fb782015-05-29 16:52:34 +02002836
2837error:
2838
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002839 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02002840}
2841
Radek Krejcida04f4a2015-05-21 12:54:09 +02002842/*
2843 * Covers:
Radek Krejci25d782a2015-05-22 15:03:23 +02002844 * description, reference, status, optionaly config
Radek Krejcib388c152015-06-04 17:03:03 +02002845 *
Radek Krejcida04f4a2015-05-21 12:54:09 +02002846 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002847static int
2848read_yin_common(struct ly_module *module, struct ly_mnode *parent,
2849 struct ly_mnode *mnode, struct lyxml_elem *xmlnode, int opt)
Radek Krejcida04f4a2015-05-21 12:54:09 +02002850{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002851 const char *value;
2852 struct lyxml_elem *sub, *next;
2853 struct ly_ctx *const ctx = module->ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002854
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002855 if (opt & OPT_MODULE) {
2856 mnode->module = module;
2857 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002858
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002859 if (opt & OPT_IDENT) {
2860 GETVAL(value, xmlnode, "name");
2861 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(xmlnode), NULL, NULL)) {
2862 goto error;
2863 }
2864 mnode->name = lydict_insert(ctx, value, strlen(value));
2865 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002866
Radek Krejci6764bb32015-07-03 15:16:04 +02002867 /* inherit NACM flags */
Radek Krejci6a113852015-07-03 16:04:20 +02002868 if ((opt & OPT_NACMEXT) && parent) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002869 mnode->nacm = parent->nacm;
2870 }
2871
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002872 /* process local parameters */
2873 LY_TREE_FOR_SAFE(xmlnode->child, next, sub) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002874 if (!sub->ns) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002875 /* garbage */
Radek Krejci6764bb32015-07-03 15:16:04 +02002876 lyxml_free_elem(ctx, sub);
2877 continue;
2878 }
2879 if (strcmp(sub->ns->value, LY_NSYIN)) {
2880 /* NACM extensions */
Radek Krejci6a113852015-07-03 16:04:20 +02002881 if ((opt & OPT_NACMEXT) && !strcmp(sub->ns->value, LY_NSNACM)) {
Radek Krejci6764bb32015-07-03 15:16:04 +02002882 if (!strcmp(sub->name, "default-deny-write")) {
2883 mnode->nacm |= LY_NACM_DENYW;
2884 } else if (!strcmp(sub->name, "default-deny-all")) {
2885 mnode->nacm |= LY_NACM_DENYA;
2886 } else {
2887 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
2888 goto error;
2889 }
2890 }
2891
2892 /* else garbage */
2893 lyxml_free_elem(ctx, sub);
Radek Krejci0d70c372015-07-02 16:23:10 +02002894 continue;
2895 }
2896
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002897 if (!strcmp(sub->name, "description")) {
2898 if (mnode->dsc) {
2899 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2900 goto error;
2901 }
2902 mnode->dsc = read_yin_subnode(ctx, sub, "text");
2903 if (!mnode->dsc) {
Radek Krejci73adb602015-07-02 18:07:40 +02002904 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002905 }
2906 } else if (!strcmp(sub->name, "reference")) {
2907 if (mnode->ref) {
2908 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2909 goto error;
2910 }
2911 mnode->ref = read_yin_subnode(ctx, sub, "text");
2912 if (!mnode->ref) {
Radek Krejci73adb602015-07-02 18:07:40 +02002913 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002914 }
2915 } else if (!strcmp(sub->name, "status")) {
2916 if (mnode->flags & LY_NODE_STATUS_MASK) {
2917 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2918 goto error;
2919 }
2920 GETVAL(value, sub, "value");
2921 if (!strcmp(value, "current")) {
2922 mnode->flags |= LY_NODE_STATUS_CURR;
2923 } else if (!strcmp(value, "deprecated")) {
2924 mnode->flags |= LY_NODE_STATUS_DEPRC;
2925 } else if (!strcmp(value, "obsolete")) {
2926 mnode->flags |= LY_NODE_STATUS_OBSLT;
2927 } else {
2928 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
Radek Krejci73adb602015-07-02 18:07:40 +02002929 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002930 }
2931 } else if ((opt & OPT_CONFIG) && !strcmp(sub->name, "config")) {
2932 if (mnode->flags & LY_NODE_CONFIG_MASK) {
2933 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, xmlnode->name);
2934 goto error;
2935 }
2936 GETVAL(value, sub, "value");
2937 if (!strcmp(value, "false")) {
2938 mnode->flags |= LY_NODE_CONFIG_R;
2939 } else if (!strcmp(value, "true")) {
2940 mnode->flags |= LY_NODE_CONFIG_W;
2941 } else {
2942 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
Radek Krejci73adb602015-07-02 18:07:40 +02002943 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002944 }
2945 } else {
2946 /* skip the lyxml_free_elem */
2947 continue;
2948 }
2949 lyxml_free_elem(ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002950 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002951
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002952 if ((opt & OPT_INHERIT) && !(mnode->flags & LY_NODE_CONFIG_MASK)) {
2953 /* get config flag from parent */
2954 if (parent) {
2955 mnode->flags |= parent->flags & LY_NODE_CONFIG_MASK;
2956 } else {
2957 /* default config is true */
2958 mnode->flags |= LY_NODE_CONFIG_W;
2959 }
2960 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02002961
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002962 return EXIT_SUCCESS;
Radek Krejcieac35532015-05-31 19:09:15 +02002963
2964error:
2965
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02002966 return EXIT_FAILURE;
Radek Krejcida04f4a2015-05-21 12:54:09 +02002967}
2968
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002969static struct ly_when *
2970read_yin_when(struct ly_module *module,struct lyxml_elem *yin)
2971{
Radek Krejci53ebfb12015-06-19 09:35:59 +02002972 struct ly_when *retval = NULL;
Radek Krejci73adb602015-07-02 18:07:40 +02002973 struct lyxml_elem *child;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002974 const char *value;
2975
2976 retval = calloc(1, sizeof *retval);
2977
2978 GETVAL(value, yin, "condition");
2979 retval->cond = lydict_insert(module->ctx, value, 0);
2980
Radek Krejci73adb602015-07-02 18:07:40 +02002981 LY_TREE_FOR(yin->child, child) {
Radek Krejci0d70c372015-07-02 16:23:10 +02002982 if (!child->ns || strcmp(child->ns->value, LY_NSYIN)) {
2983 /* garbage */
Radek Krejci0d70c372015-07-02 16:23:10 +02002984 continue;
2985 }
2986
Radek Krejcib0af6ba2015-06-18 15:01:03 +02002987 if (!strcmp(child->name, "description")) {
2988 if (retval->dsc) {
2989 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2990 goto error;
2991 }
2992 retval->dsc = read_yin_subnode(module->ctx, child, "text");
2993 if (!retval->dsc) {
2994 goto error;
2995 }
2996 } else if (!strcmp(child->name, "reference")) {
2997 if (retval->ref) {
2998 LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
2999 goto error;
3000 }
3001 retval->ref = read_yin_subnode(module->ctx, child, "text");
3002 if (!retval->ref) {
3003 goto error;
3004 }
3005 } else {
3006 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
3007 goto error;
3008 }
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003009 }
3010
3011 return retval;
3012
3013error:
3014
Radek Krejci53ebfb12015-06-19 09:35:59 +02003015 ly_mnode_free((struct ly_mnode *)retval);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003016 return NULL;
3017}
3018
Radek Krejcib4cf2022015-06-03 14:40:05 +02003019/* additional check in case statement - the child must be unique across
3020 * all other case names and its data children
3021 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003022static int
3023check_branch_id(struct ly_mnode *parent, struct ly_mnode *new, struct ly_mnode *excl, int line)
Radek Krejcib4cf2022015-06-03 14:40:05 +02003024{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003025 struct ly_mnode *mnode, *submnode;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003026
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003027 if (new->nodetype == LY_NODE_CHOICE) {
3028 /* we have nested choice in case, so we need recursion */
3029 LY_TREE_FOR(new->child, mnode) {
3030 if (mnode->nodetype == LY_NODE_CASE) {
3031 LY_TREE_FOR(mnode->child, submnode) {
3032 if (check_branch_id(parent, submnode, new, line)) {
3033 return EXIT_FAILURE;
3034 }
3035 }
3036 } else if (check_branch_id(parent, mnode, new, line)) {
3037 return EXIT_FAILURE;
3038 }
3039 }
3040 } else {
3041 LY_TREE_FOR(parent->child, mnode) {
3042 if (mnode == excl) {
3043 continue;
3044 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003045
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003046 if (!strcmp(new->name, mnode->name)) {
3047 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
3048 return EXIT_FAILURE;
3049 }
3050 if (mnode->nodetype == LY_NODE_CASE) {
3051 LY_TREE_FOR(mnode->child, submnode) {
3052 if (!strcmp(new->name, submnode->name)) {
3053 LOGVAL(VE_INID, line, new->name, "duplicated identifier within a choice's cases");
3054 return EXIT_FAILURE;
3055 }
3056 }
3057 }
3058 }
3059 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003061 return EXIT_SUCCESS;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003062}
3063
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003064static struct ly_mnode *
3065read_yin_case(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003066 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcib4cf2022015-06-03 14:40:05 +02003067{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003068 struct lyxml_elem *sub, *next;
3069 struct ly_mnode_case *mcase;
3070 struct ly_mnode *retval, *mnode = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003071 int c_ftrs = 0;
3072 const char *value;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003073
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003074 mcase = calloc(1, sizeof *mcase);
3075 mcase->nodetype = LY_NODE_CASE;
3076 mcase->prev = (struct ly_mnode *)mcase;
3077 retval = (struct ly_mnode *)mcase;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003078
Radek Krejci6a113852015-07-03 16:04:20 +02003079 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_INHERIT | OPT_NACMEXT)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003080 goto error;
3081 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003082
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003083 /* process choice's specific children */
3084 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003085 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3086 /* garbage */
3087 lyxml_free_elem(module->ctx, sub);
3088 continue;
3089 }
3090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003091 if (!strcmp(sub->name, "container")) {
3092 mnode = read_yin_container(module, retval, sub, resolve, unres);
3093 } else if (!strcmp(sub->name, "leaf-list")) {
3094 mnode = read_yin_leaflist(module, retval, sub, resolve);
3095 } else if (!strcmp(sub->name, "leaf")) {
3096 mnode = read_yin_leaf(module, retval, sub, resolve);
3097 } else if (!strcmp(sub->name, "list")) {
3098 mnode = read_yin_list(module, retval, sub, resolve, unres);
3099 } else if (!strcmp(sub->name, "uses")) {
3100 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3101 } else if (!strcmp(sub->name, "choice")) {
3102 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3103 } else if (!strcmp(sub->name, "anyxml")) {
3104 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci3cf9e222015-06-18 11:37:50 +02003105 } else if (!strcmp(sub->name, "if-feature")) {
3106 c_ftrs++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003107 /* skip lyxml_free_elem() at the end of the loop, sub is processed later */
3108 continue;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003109 } else if (!strcmp(sub->name, "when")) {
3110 if (mcase->when) {
3111 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3112 goto error;
3113 }
3114
3115 mcase->when = read_yin_when(module, sub);
3116 if (!mcase->when) {
3117 goto error;
3118 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003119 } else {
3120 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3121 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003122 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003124 if (!mnode) {
3125 goto error;
3126 } else if (check_branch_id(parent, mnode, mnode, LOGLINE(sub))) {
3127 goto error;
3128 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003129
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003130 mnode = NULL;
3131 lyxml_free_elem(module->ctx, sub);
3132 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003133
Radek Krejci3cf9e222015-06-18 11:37:50 +02003134 if (c_ftrs) {
3135 mcase->features = calloc(c_ftrs, sizeof *mcase->features);
3136 }
Radek Krejci73adb602015-07-02 18:07:40 +02003137 LY_TREE_FOR(yin->child, sub) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003138 GETVAL(value, sub, "name");
3139 mcase->features[mcase->features_size] = resolve_feature(value, module, LOGLINE(sub));
3140 if (!mcase->features[mcase->features_size]) {
3141 goto error;
3142 }
3143 mcase->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003144 }
Radek Krejcib388c152015-06-04 17:03:03 +02003145
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003146 /* insert the node into the schema tree */
3147 if (ly_mnode_addchild(parent, retval)) {
3148 goto error;
3149 }
Radek Krejcib7155b52015-06-10 17:03:01 +02003150
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003151 return retval;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003152
3153error:
3154
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003155 ly_mnode_free(retval);
Radek Krejcib4cf2022015-06-03 14:40:05 +02003156
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003157 return NULL;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003158}
3159
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003160static struct ly_mnode *
3161read_yin_choice(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003162 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003163{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003164 struct lyxml_elem *sub, *next;
3165 struct ly_ctx *const ctx = module->ctx;
3166 struct ly_mnode *retval, *mnode = NULL;
3167 struct ly_mnode_choice *choice;
3168 const char *value;
3169 char *dflt_str = NULL;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003170 int f_mand = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003171
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003172 choice = calloc(1, sizeof *choice);
3173 choice->nodetype = LY_NODE_CHOICE;
3174 choice->prev = (struct ly_mnode *)choice;
3175 retval = (struct ly_mnode *)choice;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003176
Radek Krejci6a113852015-07-03 16:04:20 +02003177 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 +02003178 goto error;
3179 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003180
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003181 /* process choice's specific children */
3182 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003183 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3184 /* garbage */
3185 lyxml_free_elem(module->ctx, sub);
3186 continue;
3187 }
3188
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003189 if (!strcmp(sub->name, "container")) {
3190 if (!(mnode = read_yin_container(module, retval, sub, resolve, unres))) {
3191 goto error;
3192 }
3193 } else if (!strcmp(sub->name, "leaf-list")) {
3194 if (!(mnode = read_yin_leaflist(module, retval, sub, resolve))) {
3195 goto error;
3196 }
3197 } else if (!strcmp(sub->name, "leaf")) {
3198 if (!(mnode = read_yin_leaf(module, retval, sub, resolve))) {
3199 goto error;
3200 }
3201 } else if (!strcmp(sub->name, "list")) {
3202 if (!(mnode = read_yin_list(module, retval, sub, resolve, unres))) {
3203 goto error;
3204 }
3205 } else if (!strcmp(sub->name, "case")) {
3206 if (!(mnode = read_yin_case(module, retval, sub, resolve, unres))) {
3207 goto error;
3208 }
3209 } else if (!strcmp(sub->name, "anyxml")) {
3210 if (!(mnode = read_yin_anyxml(module, retval, sub, resolve))) {
3211 goto error;
3212 }
3213 } else if (!strcmp(sub->name, "default")) {
3214 if (dflt_str) {
3215 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3216 goto error;
3217 }
3218 GETVAL(value, sub, "value");
3219 dflt_str = strdup(value);
3220 } else if (!strcmp(sub->name, "mandatory")) {
3221 if (f_mand) {
3222 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3223 goto error;
3224 }
3225 /* just checking the flags in leaf is not sufficient, we would allow
3226 * multiple mandatory statements with the "false" value
3227 */
3228 f_mand = 1;
Radek Krejcib4cf2022015-06-03 14:40:05 +02003229
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003230 GETVAL(value, sub, "value");
3231 if (!strcmp(value, "true")) {
3232 choice->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003233 } else if (!strcmp(value, "false")) {
3234 choice->flags |= LY_NODE_MAND_FALSE;
3235 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003236 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3237 goto error;
3238 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003239 } else if (!strcmp(sub->name, "when")) {
3240 if (choice->when) {
3241 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3242 goto error;
3243 }
3244
3245 choice->when = read_yin_when(module, sub);
3246 if (!choice->when) {
3247 goto error;
3248 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003249 } else if (!strcmp(sub->name, "if-feature")) {
3250 c_ftrs++;
3251
3252 /* skip lyxml_free_elem() at the end of the loop, the sub node is processed later */
3253 continue;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003254 } else {
3255 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3256 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003257 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003258
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003259 if (mnode && check_branch_id(retval, mnode, mnode, LOGLINE(sub))) {
3260 goto error;
3261 }
3262 mnode = NULL;
3263 lyxml_free_elem(ctx, sub);
3264 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003265
Radek Krejci3cf9e222015-06-18 11:37:50 +02003266 if (c_ftrs) {
3267 choice->features = calloc(c_ftrs, sizeof *choice->features);
3268 }
3269
Radek Krejci73adb602015-07-02 18:07:40 +02003270 LY_TREE_FOR(yin->child, sub) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003271 GETVAL(value, sub, "name");
3272 choice->features[choice->features_size] = resolve_feature(value, module, LOGLINE(sub));
3273 if (!choice->features[choice->features_size]) {
3274 goto error;
3275 }
3276 choice->features_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003277 }
3278
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003279 /* check - default is prohibited in combination with mandatory */
3280 if (dflt_str && (choice->flags & LY_NODE_MAND_TRUE)) {
3281 LOGVAL(VE_SPEC, LOGLINE(yin),
3282 "The \"default\" statement MUST NOT be present on choices where \"mandatory\" is true.");
3283 goto error;
3284 }
Radek Krejcib4cf2022015-06-03 14:40:05 +02003285
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003286 /* link default with the case */
3287 if (dflt_str) {
Michal Vasko6f6ac232015-06-18 11:11:46 +02003288 choice->dflt = resolve_schema_nodeid(dflt_str, retval, module, LY_NODE_CHOICE);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003289 if (!choice->dflt) {
3290 /* default branch not found */
3291 LOGVAL(VE_INARG, LOGLINE(yin), dflt_str, "default");
3292 goto error;
3293 }
3294 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003296 /* insert the node into the schema tree */
3297 if (parent && ly_mnode_addchild(parent, retval)) {
3298 goto error;
3299 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003300
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003301 free(dflt_str);
Radek Krejcib7155b52015-06-10 17:03:01 +02003302
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003303 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003304
3305error:
3306
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003307 ly_mnode_free(retval);
3308 free(dflt_str);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003309
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003310 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003311}
3312
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003313static struct ly_mnode *
3314read_yin_anyxml(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejci863c2852015-06-03 15:47:11 +02003315{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003316 struct ly_mnode *retval;
3317 struct ly_mnode_leaf *anyxml;
3318 struct lyxml_elem *sub, *next;
3319 const char *value;
3320 int r;
3321 int f_mand = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003322 int c_must = 0, c_ftrs = 0;
Radek Krejci863c2852015-06-03 15:47:11 +02003323
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003324 anyxml = calloc(1, sizeof *anyxml);
3325 anyxml->nodetype = LY_NODE_ANYXML;
3326 anyxml->prev = (struct ly_mnode *)anyxml;
3327 retval = (struct ly_mnode *)anyxml;
Radek Krejci863c2852015-06-03 15:47:11 +02003328
Radek Krejci6a113852015-07-03 16:04:20 +02003329 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 +02003330 goto error;
3331 }
Radek Krejci863c2852015-06-03 15:47:11 +02003332
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003333 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003334 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3335 /* garbage */
3336 lyxml_free_elem(module->ctx, sub);
3337 continue;
3338 }
3339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003340 if (!strcmp(sub->name, "mandatory")) {
3341 if (f_mand) {
3342 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3343 goto error;
3344 }
3345 /* just checking the flags in leaf is not sufficient, we would allow
3346 * multiple mandatory statements with the "false" value
3347 */
3348 f_mand = 1;
Radek Krejci863c2852015-06-03 15:47:11 +02003349
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003350 GETVAL(value, sub, "value");
3351 if (!strcmp(value, "true")) {
3352 anyxml->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003353 } else if (!strcmp(value, "false")) {
3354 anyxml->flags |= LY_NODE_MAND_FALSE;
3355 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003356 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3357 goto error;
3358 }
3359 /* else false is the default value, so we can ignore it */
3360 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003361 } else if (!strcmp(sub->name, "when")) {
3362 if (anyxml->when) {
3363 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3364 goto error;
3365 }
3366
3367 anyxml->when = read_yin_when(module, sub);
3368 lyxml_free_elem(module->ctx, sub);
3369
3370 if (!anyxml->when) {
3371 goto error;
3372 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003373 } else if (!strcmp(sub->name, "must")) {
3374 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003375 } else if (!strcmp(sub->name, "if-feature")) {
3376 c_ftrs++;
Radek Krejci863c2852015-06-03 15:47:11 +02003377
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003378 } else {
3379 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3380 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003381 }
3382 }
Radek Krejci863c2852015-06-03 15:47:11 +02003383
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003384 /* middle part - process nodes with cardinality of 0..n */
3385 if (c_must) {
3386 anyxml->must = calloc(c_must, sizeof *anyxml->must);
3387 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003388 if (c_ftrs) {
3389 anyxml->features = calloc(c_ftrs, sizeof *anyxml->features);
3390 }
Radek Krejci863c2852015-06-03 15:47:11 +02003391
Radek Krejci73adb602015-07-02 18:07:40 +02003392 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003393 if (!strcmp(sub->name, "must")) {
3394 r = fill_yin_must(module, sub, &anyxml->must[anyxml->must_size]);
3395 anyxml->must_size++;
Radek Krejci863c2852015-06-03 15:47:11 +02003396
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003397 if (r) {
3398 goto error;
3399 }
Radek Krejci0b24d752015-07-02 15:02:27 +02003400 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02003401 GETVAL(value, sub, "name");
3402 anyxml->features[anyxml->features_size] = resolve_feature(value, module, LOGLINE(sub));
3403 if (!anyxml->features[anyxml->features_size]) {
3404 goto error;
3405 }
3406 anyxml->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003407 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003408 }
Radek Krejci863c2852015-06-03 15:47:11 +02003409
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003410 if (parent && ly_mnode_addchild(parent, retval)) {
3411 goto error;
3412 }
Radek Krejci863c2852015-06-03 15:47:11 +02003413
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003414 return retval;
Radek Krejci863c2852015-06-03 15:47:11 +02003415
3416error:
3417
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003418 ly_mnode_free(retval);
Radek Krejci863c2852015-06-03 15:47:11 +02003419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003420 return NULL;
Radek Krejci863c2852015-06-03 15:47:11 +02003421}
3422
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003423static struct ly_mnode *
3424read_yin_leaf(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003425{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003426 struct ly_mnode *retval;
3427 struct ly_mnode_leaf *leaf;
3428 struct lyxml_elem *sub, *next;
3429 const char *value;
3430 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003431 int c_must = 0, c_ftrs = 0, f_mand = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003432
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003433 leaf = calloc(1, sizeof *leaf);
3434 leaf->nodetype = LY_NODE_LEAF;
3435 leaf->prev = (struct ly_mnode *)leaf;
3436 retval = (struct ly_mnode *)leaf;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003437
Radek Krejci6a113852015-07-03 16:04:20 +02003438 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 +02003439 goto error;
3440 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003441
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003442 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003443 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3444 /* garbage */
3445 lyxml_free_elem(module->ctx, sub);
3446 continue;
3447 }
3448
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003449 if (!strcmp(sub->name, "type")) {
3450 if (leaf->type.der) {
3451 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3452 goto error;
3453 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003454 if (fill_yin_type(module, parent, sub, &leaf->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003455 goto error;
3456 }
3457 } else if (!strcmp(sub->name, "default")) {
3458 if (leaf->dflt) {
3459 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3460 goto error;
3461 }
3462 GETVAL(value, sub, "value");
3463 leaf->dflt = lydict_insert(module->ctx, value, strlen(value));
3464 } else if (!strcmp(sub->name, "units")) {
3465 if (leaf->units) {
3466 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3467 goto error;
3468 }
3469 GETVAL(value, sub, "name");
3470 leaf->units = lydict_insert(module->ctx, value, strlen(value));
3471 } else if (!strcmp(sub->name, "mandatory")) {
3472 if (f_mand) {
3473 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3474 goto error;
3475 }
3476 /* just checking the flags in leaf is not sufficient, we would allow
3477 * multiple mandatory statements with the "false" value
3478 */
3479 f_mand = 1;
Radek Krejci4c31f122015-06-02 14:51:22 +02003480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003481 GETVAL(value, sub, "value");
3482 if (!strcmp(value, "true")) {
3483 leaf->flags |= LY_NODE_MAND_TRUE;
Radek Krejcieb00f512015-07-01 16:44:58 +02003484 } else if (!strcmp(value, "false")) {
3485 leaf->flags |= LY_NODE_MAND_FALSE;
3486 } else {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003487 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3488 goto error;
3489 } /* else false is the default value, so we can ignore it */
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003490 } else if (!strcmp(sub->name, "when")) {
3491 if (leaf->when) {
3492 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3493 goto error;
3494 }
3495
3496 leaf->when = read_yin_when(module, sub);
3497 if (!leaf->when) {
3498 goto error;
3499 }
3500
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003501 } else if (!strcmp(sub->name, "must")) {
Radek Krejci41882de2015-07-02 16:34:58 +02003502 c_must++;
3503 continue;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003504 } else if (!strcmp(sub->name, "if-feature")) {
3505 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003506 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02003507
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003508 } else {
3509 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3510 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003511 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003512
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003513 lyxml_free_elem(module->ctx, sub);
3514 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003515
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003516 /* check mandatory parameters */
3517 if (!leaf->type.der) {
3518 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3519 goto error;
3520 }
3521 if (leaf->dflt && check_default(&leaf->type, leaf->dflt)) {
3522 goto error;
3523 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003524
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003525 /* middle part - process nodes with cardinality of 0..n */
3526 if (c_must) {
3527 leaf->must = calloc(c_must, sizeof *leaf->must);
3528 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003529 if (c_ftrs) {
3530 leaf->features = calloc(c_ftrs, sizeof *leaf->features);
3531 }
Radek Krejci4c31f122015-06-02 14:51:22 +02003532
Radek Krejci73adb602015-07-02 18:07:40 +02003533 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003534 if (!strcmp(sub->name, "must")) {
3535 r = fill_yin_must(module, sub, &leaf->must[leaf->must_size]);
3536 leaf->must_size++;
Radek Krejci4c31f122015-06-02 14:51:22 +02003537
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003538 if (r) {
3539 goto error;
3540 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003541 } else if (!strcmp(sub->name, "if-feature")) {
3542 GETVAL(value, sub, "name");
3543 leaf->features[leaf->features_size] = resolve_feature(value, module, LOGLINE(sub));
3544 if (!leaf->features[leaf->features_size]) {
3545 goto error;
3546 }
3547 leaf->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003548 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003549 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003550
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003551 if (parent && ly_mnode_addchild(parent, retval)) {
3552 goto error;
3553 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003554
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003555 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003556
3557error:
3558
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003559 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003560
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003561 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003562}
3563
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003564static struct ly_mnode *
3565read_yin_leaflist(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, int resolve)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003566{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003567 struct ly_mnode *retval;
3568 struct ly_mnode_leaflist *llist;
3569 struct lyxml_elem *sub, *next;
3570 const char *value;
3571 char *endptr;
3572 unsigned long val;
3573 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003574 int c_must = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003575 int f_ordr = 0, f_min = 0, f_max = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003576
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003577 llist = calloc(1, sizeof *llist);
3578 llist->nodetype = LY_NODE_LEAFLIST;
3579 llist->prev = (struct ly_mnode *)llist;
3580 retval = (struct ly_mnode *)llist;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003581
Radek Krejci6a113852015-07-03 16:04:20 +02003582 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 +02003583 goto error;
3584 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003585
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003586 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003587 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3588 /* garbage */
3589 lyxml_free_elem(module->ctx, sub);
3590 continue;
3591 }
3592
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003593 if (!strcmp(sub->name, "type")) {
3594 if (llist->type.der) {
3595 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3596 goto error;
3597 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003598 if (fill_yin_type(module, parent, sub, &llist->type, NULL)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003599 goto error;
3600 }
3601 } else if (!strcmp(sub->name, "units")) {
3602 if (llist->units) {
3603 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3604 goto error;
3605 }
3606 GETVAL(value, sub, "name");
3607 llist->units = lydict_insert(module->ctx, value, strlen(value));
3608 } else if (!strcmp(sub->name, "ordered-by")) {
3609 if (f_ordr) {
3610 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3611 goto error;
3612 }
3613 /* just checking the flags in llist is not sufficient, we would
3614 * allow multiple ordered-by statements with the "system" value
3615 */
3616 f_ordr = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003617
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003618 if (llist->flags & LY_NODE_CONFIG_R) {
3619 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3620 * state data
3621 */
3622 lyxml_free_elem(module->ctx, sub);
3623 continue;
3624 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003625
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003626 GETVAL(value, sub, "value");
3627 if (!strcmp(value, "user")) {
3628 llist->flags |= LY_NODE_USERORDERED;
3629 } else if (strcmp(value, "system")) {
3630 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3631 goto error;
Radek Krejci41882de2015-07-02 16:34:58 +02003632 } /* else system is the default value, so we can ignore it */
3633
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003634 } else if (!strcmp(sub->name, "must")) {
3635 c_must++;
Radek Krejci41882de2015-07-02 16:34:58 +02003636 continue;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003637 } else if (!strcmp(sub->name, "if-feature")) {
3638 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003639 continue;
Radek Krejci41882de2015-07-02 16:34:58 +02003640
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003641 } else if (!strcmp(sub->name, "min-elements")) {
3642 if (f_min) {
3643 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3644 goto error;
3645 }
3646 f_min = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003647
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003648 GETVAL(value, sub, "value");
3649 while (isspace(value[0])) {
3650 value++;
3651 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003652
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003653 /* convert it to uint32_t */
3654 errno = 0;
3655 endptr = NULL;
3656 val = strtoul(value, &endptr, 10);
3657 if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
3658 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3659 goto error;
3660 }
3661 llist->min = (uint32_t) val;
3662 } else if (!strcmp(sub->name, "max-elements")) {
3663 if (f_max) {
3664 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3665 goto error;
3666 }
3667 f_max = 1;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003668
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003669 GETVAL(value, sub, "value");
3670 while (isspace(value[0])) {
3671 value++;
3672 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003673
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003674 /* convert it to uint32_t */
3675 errno = 0;
3676 endptr = NULL;
3677 val = strtoul(value, &endptr, 10);
3678 if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3679 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3680 goto error;
3681 }
3682 llist->max = (uint32_t) val;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003683 } else if (!strcmp(sub->name, "when")) {
3684 if (llist->when) {
3685 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3686 goto error;
3687 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003688
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003689 llist->when = read_yin_when(module, sub);
3690 if (!llist->when) {
3691 goto error;
3692 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003693 } else {
3694 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3695 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003696 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003697
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003698 lyxml_free_elem(module->ctx, sub);
3699 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003700
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003701 /* check constraints */
3702 if (!llist->type.der) {
3703 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "type", yin->name);
3704 goto error;
3705 }
3706 if (llist->max && llist->min > llist->max) {
3707 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3708 goto error;
3709 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003711 /* middle part - process nodes with cardinality of 0..n */
3712 if (c_must) {
3713 llist->must = calloc(c_must, sizeof *llist->must);
3714 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003715 if (c_ftrs) {
3716 llist->features = calloc(c_ftrs, sizeof *llist->features);
3717 }
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003718
Radek Krejci73adb602015-07-02 18:07:40 +02003719 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003720 if (!strcmp(sub->name, "must")) {
3721 r = fill_yin_must(module, sub, &llist->must[llist->must_size]);
3722 llist->must_size++;
Radek Krejci8b4f23c2015-06-02 16:09:25 +02003723
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003724 if (r) {
3725 goto error;
3726 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003727 } else if (!strcmp(sub->name, "if-feature")) {
3728 GETVAL(value, sub, "name");
3729 llist->features[llist->features_size] = resolve_feature(value, module, LOGLINE(sub));
3730 if (!llist->features[llist->features_size]) {
3731 goto error;
3732 }
3733 llist->features_size++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003734 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003735 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003736
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003737 if (parent && ly_mnode_addchild(parent, retval)) {
3738 goto error;
3739 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003741 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003742
3743error:
3744
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003745 ly_mnode_free(retval);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003746
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003747 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003748}
3749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003750static struct ly_mnode *
3751read_yin_list(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003752 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02003753{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003754 struct ly_mnode *retval, *mnode;
3755 struct ly_mnode_list *list;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003756 struct lyxml_elem *sub, *next, root, uniq;
3757 int i, r;
3758 size_t len;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003759 int c_tpdf = 0, c_must = 0, c_uniq = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003760 int f_ordr = 0, f_max = 0, f_min = 0;
Radek Krejcieb00f512015-07-01 16:44:58 +02003761 const char *key_str = NULL, *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003762 char *auxs;
3763 unsigned long val;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003764
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003765 /* init */
3766 memset(&root, 0, sizeof root);
3767 memset(&uniq, 0, sizeof uniq);
Radek Krejcie0674f82015-06-15 13:58:51 +02003768
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003769 list = calloc(1, sizeof *list);
3770 list->nodetype = LY_NODE_LIST;
3771 list->prev = (struct ly_mnode *)list;
3772 retval = (struct ly_mnode *)list;
Radek Krejcida04f4a2015-05-21 12:54:09 +02003773
Radek Krejci6a113852015-07-03 16:04:20 +02003774 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 +02003775 goto error;
3776 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003777
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003778 /* process list's specific children */
3779 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02003780 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
3781 /* garbage */
3782 lyxml_free_elem(module->ctx, sub);
3783 continue;
3784 }
3785
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003786 /* data statements */
3787 if (!strcmp(sub->name, "container") ||
3788 !strcmp(sub->name, "leaf-list") ||
3789 !strcmp(sub->name, "leaf") ||
3790 !strcmp(sub->name, "list") ||
3791 !strcmp(sub->name, "choice") ||
3792 !strcmp(sub->name, "uses") ||
3793 !strcmp(sub->name, "grouping") ||
3794 !strcmp(sub->name, "anyxml")) {
3795 lyxml_unlink_elem(sub);
3796 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02003797
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003798 /* array counters */
3799 } else if (!strcmp(sub->name, "key")) {
3800 /* check cardinality 0..1 */
3801 if (list->keys_size) {
3802 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
3803 goto error;
3804 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02003805
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003806 /* count the number of keys */
3807 GETVAL(value, sub, "value");
3808 key_str = value;
3809 while ((value = strpbrk(value, " \t\n"))) {
3810 list->keys_size++;
3811 while (isspace(*value)) {
3812 value++;
3813 }
3814 }
3815 list->keys_size++;
3816 list->keys = calloc(list->keys_size, sizeof *list->keys);
3817 } else if (!strcmp(sub->name, "unique")) {
3818 c_uniq++;
3819 lyxml_unlink_elem(sub);
3820 lyxml_add_child(&uniq, sub);
3821 } else if (!strcmp(sub->name, "typedef")) {
3822 c_tpdf++;
3823 } else if (!strcmp(sub->name, "must")) {
3824 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02003825 } else if (!strcmp(sub->name, "if-feature")) {
3826 c_ftrs++;
Radek Krejci345ad742015-06-03 11:04:18 +02003827
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003828 /* optional stetments */
3829 } else if (!strcmp(sub->name, "ordered-by")) {
3830 if (f_ordr) {
3831 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3832 goto error;
3833 }
3834 /* just checking the flags in llist is not sufficient, we would
3835 * allow multiple ordered-by statements with the "system" value
3836 */
3837 f_ordr = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003838
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003839 if (list->flags & LY_NODE_CONFIG_R) {
3840 /* RFC 6020, 7.7.5 - ignore ordering when the list represents
3841 * state data
3842 */
3843 lyxml_free_elem(module->ctx, sub);
3844 continue;
3845 }
Radek Krejci345ad742015-06-03 11:04:18 +02003846
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003847 GETVAL(value, sub, "value");
3848 if (!strcmp(value, "user")) {
3849 list->flags |= LY_NODE_USERORDERED;
3850 } else if (strcmp(value, "system")) {
3851 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3852 goto error;
3853 }
3854 /* else system is the default value, so we can ignore it */
3855 lyxml_free_elem(module->ctx, sub);
3856 } else if (!strcmp(sub->name, "min-elements")) {
3857 if (f_min) {
3858 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3859 goto error;
3860 }
3861 f_min = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003862
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003863 GETVAL(value, sub, "value");
3864 while (isspace(value[0])) {
3865 value++;
3866 }
Radek Krejci345ad742015-06-03 11:04:18 +02003867
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003868 /* convert it to uint32_t */
3869 errno = 0;
3870 auxs = NULL;
3871 val = strtoul(value, &auxs, 10);
3872 if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
3873 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3874 goto error;
3875 }
3876 list->min = (uint32_t) val;
3877 lyxml_free_elem(module->ctx, sub);
3878 } else if (!strcmp(sub->name, "max-elements")) {
3879 if (f_max) {
3880 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3881 goto error;
3882 }
3883 f_max = 1;
Radek Krejci345ad742015-06-03 11:04:18 +02003884
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003885 GETVAL(value, sub, "value");
3886 while (isspace(value[0])) {
3887 value++;
3888 }
Radek Krejci345ad742015-06-03 11:04:18 +02003889
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003890 /* convert it to uint32_t */
3891 errno = 0;
3892 auxs = NULL;
3893 val = strtoul(value, &auxs, 10);
3894 if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
3895 LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
3896 goto error;
3897 }
3898 list->max = (uint32_t) val;
3899 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02003900 } else if (!strcmp(sub->name, "when")) {
3901 if (list->when) {
3902 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
3903 goto error;
3904 }
3905
3906 list->when = read_yin_when(module, sub);
3907 lyxml_free_elem(module->ctx, sub);
3908
3909 if (!list->when) {
3910 goto error;
3911 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003912 } else {
3913 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
3914 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003915 }
3916 }
Radek Krejci345ad742015-06-03 11:04:18 +02003917
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003918 /* check - if list is configuration, key statement is mandatory */
3919 if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
3920 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
3921 goto error;
3922 }
3923 if (list->max && list->min > list->max) {
3924 LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
3925 goto error;
3926 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003927
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003928 /* middle part - process nodes with cardinality of 0..n except the data nodes */
3929 if (c_tpdf) {
3930 list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
3931 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003932 if (c_must) {
3933 list->must = calloc(c_must, sizeof *list->must);
3934 }
3935 if (c_ftrs) {
3936 list->features = calloc(c_ftrs, sizeof *list->features);
3937 }
Radek Krejci73adb602015-07-02 18:07:40 +02003938 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003939 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02003940 r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003941 list->tpdf_size++;
Radek Krejcid7f0d012015-05-25 15:04:52 +02003942
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003943 if (r) {
3944 goto error;
3945 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02003946 } else if (!strcmp(sub->name, "if-feature")) {
3947 GETVAL(value, sub, "name");
3948 list->features[list->features_size] = resolve_feature(value, module, LOGLINE(sub));
3949 if (!list->features[list->features_size]) {
3950 goto error;
3951 }
3952 list->features_size++;
3953 } else if (!strcmp(sub->name, "must")) {
3954 r = fill_yin_must(module, sub, &list->must[list->must_size]);
3955 list->must_size++;
3956
3957 if (r) {
3958 goto error;
3959 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003960 }
3961 }
Radek Krejci25d782a2015-05-22 15:03:23 +02003962
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003963 /* last part - process data nodes */
3964 LY_TREE_FOR_SAFE(root.child, next, sub) {
3965 if (!strcmp(sub->name, "container")) {
3966 mnode = read_yin_container(module, retval, sub, resolve, unres);
3967 } else if (!strcmp(sub->name, "leaf-list")) {
3968 mnode = read_yin_leaflist(module, retval, sub, resolve);
3969 } else if (!strcmp(sub->name, "leaf")) {
3970 mnode = read_yin_leaf(module, retval, sub, resolve);
3971 } else if (!strcmp(sub->name, "list")) {
3972 mnode = read_yin_list(module, retval, sub, resolve, unres);
3973 } else if (!strcmp(sub->name, "choice")) {
3974 mnode = read_yin_choice(module, retval, sub, resolve, unres);
3975 } else if (!strcmp(sub->name, "uses")) {
3976 mnode = read_yin_uses(module, retval, sub, resolve, unres);
3977 } else if (!strcmp(sub->name, "grouping")) {
3978 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
3979 } else if (!strcmp(sub->name, "anyxml")) {
3980 mnode = read_yin_anyxml(module, retval, sub, resolve);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003981 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003982 if (!mnode) {
3983 goto error;
3984 }
Radek Krejci73adb602015-07-02 18:07:40 +02003985
3986 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003987 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003989 if (parent && ly_mnode_addchild(parent, retval)) {
3990 goto error;
3991 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02003992
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003993 if (!key_str) {
3994 /* config false list without a key */
3995 return retval;
3996 }
Radek Krejci812b10a2015-05-28 16:48:25 +02003997
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02003998 /* link key leafs into the list structure and check all constraints */
3999 for (i = 0; i < list->keys_size; i++) {
4000 /* get the key name */
4001 if ((value = strpbrk(key_str, " \t\n"))) {
4002 len = value - key_str;
4003 while (isspace(*value)) {
4004 value++;
4005 }
4006 } else {
4007 len = strlen(key_str);
4008 }
Radek Krejci3a734ed2015-05-26 15:23:18 +02004009
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004010 list->keys[i] = find_leaf(retval, key_str, len);
Radek Krejci8bc9ca02015-06-04 15:52:46 +02004011
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004012 if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
4013 goto error;
4014 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02004015
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004016 /* prepare for next iteration */
4017 while (value && isspace(*value)) {
4018 value++;
4019 }
4020 key_str = value;
4021 }
Radek Krejcid7f0d012015-05-25 15:04:52 +02004022
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004023 /* process unique statements */
4024 if (c_uniq) {
4025 list->unique = calloc(c_uniq, sizeof *list->unique);
4026 }
4027 LY_TREE_FOR_SAFE(uniq.child, next, sub) {
Radek Krejcieb00f512015-07-01 16:44:58 +02004028 if (parse_unique(retval, sub, &list->unique[list->unique_size++])) {
4029 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004030 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004031
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004032 lyxml_free_elem(module->ctx, sub);
4033 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004034
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004035 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004036
4037error:
4038
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004039 ly_mnode_free(retval);
4040 while (root.child) {
4041 lyxml_free_elem(module->ctx, root.child);
4042 }
4043 while (uniq.child) {
4044 lyxml_free_elem(module->ctx, uniq.child);
4045 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004046
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004047 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004048}
4049
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004050static struct ly_mnode *
4051read_yin_container(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004052 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004053{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004054 struct lyxml_elem *sub, *next, root;
4055 struct ly_mnode *mnode = NULL;
4056 struct ly_mnode *retval;
4057 struct ly_mnode_container *cont;
4058 const char *value;
4059 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004060 int c_tpdf = 0, c_must = 0, c_ftrs = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004061
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004062 /* init */
4063 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02004064
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004065 cont = calloc(1, sizeof *cont);
4066 cont->nodetype = LY_NODE_CONTAINER;
4067 cont->prev = (struct ly_mnode *)cont;
4068 retval = (struct ly_mnode *)cont;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004069
Radek Krejci6a113852015-07-03 16:04:20 +02004070 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 +02004071 goto error;
4072 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004073
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004074 /* process container's specific children */
4075 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci6764bb32015-07-03 15:16:04 +02004076 if (!sub->ns) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004077 /* garbage */
4078 lyxml_free_elem(module->ctx, sub);
4079 continue;
4080 }
4081
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004082 if (!strcmp(sub->name, "presence")) {
4083 if (cont->presence) {
4084 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4085 goto error;
4086 }
4087 GETVAL(value, sub, "value");
4088 cont->presence = lydict_insert(module->ctx, value, strlen(value));
Radek Krejci800af702015-06-02 13:46:01 +02004089
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004090 lyxml_free_elem(module->ctx, sub);
Radek Krejcib0af6ba2015-06-18 15:01:03 +02004091 } else if (!strcmp(sub->name, "when")) {
4092 if (cont->when) {
4093 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4094 goto error;
4095 }
4096
4097 cont->when = read_yin_when(module, sub);
4098 lyxml_free_elem(module->ctx, sub);
4099
4100 if (!cont->when) {
4101 goto error;
4102 }
Radek Krejci4c31f122015-06-02 14:51:22 +02004103
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004104 /* data statements */
4105 } else if (!strcmp(sub->name, "container") ||
4106 !strcmp(sub->name, "leaf-list") ||
4107 !strcmp(sub->name, "leaf") ||
4108 !strcmp(sub->name, "list") ||
4109 !strcmp(sub->name, "choice") ||
4110 !strcmp(sub->name, "uses") ||
4111 !strcmp(sub->name, "grouping") ||
4112 !strcmp(sub->name, "anyxml")) {
4113 lyxml_unlink_elem(sub);
4114 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004115
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004116 /* array counters */
4117 } else if (!strcmp(sub->name, "typedef")) {
4118 c_tpdf++;
4119 } else if (!strcmp(sub->name, "must")) {
4120 c_must++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004121 } else if (!strcmp(sub->name, "if-feature")) {
4122 c_ftrs++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004123 } else {
4124 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4125 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004126 }
4127 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004128
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004129 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4130 if (c_tpdf) {
4131 cont->tpdf = calloc(c_tpdf, sizeof *cont->tpdf);
4132 }
4133 if (c_must) {
4134 cont->must = calloc(c_must, sizeof *cont->must);
4135 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004136 if (c_ftrs) {
4137 cont->features = calloc(c_ftrs, sizeof *cont->features);
4138 }
Radek Krejci800af702015-06-02 13:46:01 +02004139
Radek Krejci73adb602015-07-02 18:07:40 +02004140 LY_TREE_FOR(yin->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004141 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004142 r = fill_yin_typedef(module, retval, sub, &cont->tpdf[cont->tpdf_size], NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004143 cont->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004145 if (r) {
4146 goto error;
4147 }
4148 } else if (!strcmp(sub->name, "must")) {
4149 r = fill_yin_must(module, sub, &cont->must[cont->must_size]);
4150 cont->must_size++;
Radek Krejci800af702015-06-02 13:46:01 +02004151
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004152 if (r) {
4153 goto error;
4154 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004155 } else if (!strcmp(sub->name, "if-feature")) {
4156 GETVAL(value, sub, "name");
4157 cont->features[cont->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004158 if (!cont->features[cont->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004159 goto error;
4160 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004161 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004162 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004163
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004164 /* last part - process data nodes */
4165 LY_TREE_FOR_SAFE(root.child, next, sub) {
4166 if (!strcmp(sub->name, "container")) {
4167 mnode = read_yin_container(module, retval, sub, resolve, unres);
4168 } else if (!strcmp(sub->name, "leaf-list")) {
4169 mnode = read_yin_leaflist(module, retval, sub, resolve);
4170 } else if (!strcmp(sub->name, "leaf")) {
4171 mnode = read_yin_leaf(module, retval, sub, resolve);
4172 } else if (!strcmp(sub->name, "list")) {
4173 mnode = read_yin_list(module, retval, sub, resolve, unres);
4174 } else if (!strcmp(sub->name, "choice")) {
4175 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4176 } else if (!strcmp(sub->name, "uses")) {
4177 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4178 } else if (!strcmp(sub->name, "grouping")) {
4179 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4180 } else if (!strcmp(sub->name, "anyxml")) {
4181 mnode = read_yin_anyxml(module, retval, sub, resolve);
4182 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004183 if (!mnode) {
4184 goto error;
4185 }
Radek Krejci73adb602015-07-02 18:07:40 +02004186
4187 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004188 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004189
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004190 if (parent && ly_mnode_addchild(parent, retval)) {
4191 goto error;
4192 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004193
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004194 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004195
4196error:
4197
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004198 ly_mnode_free(retval);
4199 while (root.child) {
4200 lyxml_free_elem(module->ctx, root.child);
4201 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004202
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004203 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004204}
4205
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004206static struct ly_mnode *
4207read_yin_grouping(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004208 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejcida04f4a2015-05-21 12:54:09 +02004209{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004210 struct lyxml_elem *sub, *next, root;
4211 struct ly_mnode *mnode = NULL;
4212 struct ly_mnode *retval;
4213 struct ly_mnode_grp *grp;
4214 int r;
4215 int c_tpdf = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004216
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004217 /* init */
4218 memset(&root, 0, sizeof root);
Radek Krejcie0674f82015-06-15 13:58:51 +02004219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004220 grp = calloc(1, sizeof *grp);
4221 grp->nodetype = LY_NODE_GROUPING;
4222 grp->prev = (struct ly_mnode *)grp;
4223 retval = (struct ly_mnode *)grp;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004224
Radek Krejci6a113852015-07-03 16:04:20 +02004225 if (read_yin_common(module, parent, retval, node, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004226 goto error;
4227 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004228
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004229 LY_TREE_FOR_SAFE(node->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004230 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4231 /* garbage */
4232 lyxml_free_elem(module->ctx, sub);
4233 continue;
4234 }
4235
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004236 /* data statements */
4237 if (!strcmp(sub->name, "container") ||
4238 !strcmp(sub->name, "leaf-list") ||
4239 !strcmp(sub->name, "leaf") ||
4240 !strcmp(sub->name, "list") ||
4241 !strcmp(sub->name, "choice") ||
4242 !strcmp(sub->name, "uses") ||
4243 !strcmp(sub->name, "grouping") ||
4244 !strcmp(sub->name, "anyxml")) {
4245 lyxml_unlink_elem(sub);
4246 lyxml_add_child(&root, sub);
Radek Krejcida04f4a2015-05-21 12:54:09 +02004247
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004248 /* array counters */
4249 } else if (!strcmp(sub->name, "typedef")) {
4250 c_tpdf++;
4251 } else {
4252 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4253 goto error;
4254 }
4255 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004256
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004257 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4258 if (c_tpdf) {
4259 grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
4260 }
Radek Krejci73adb602015-07-02 18:07:40 +02004261 LY_TREE_FOR(node->child, sub) {
4262 r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size], NULL);
4263 grp->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02004264
Radek Krejci73adb602015-07-02 18:07:40 +02004265 if (r) {
4266 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004267 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004268 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004269
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004270 /* last part - process data nodes */
4271 LY_TREE_FOR_SAFE(root.child, next, sub) {
4272 if (!strcmp(sub->name, "container")) {
4273 mnode = read_yin_container(module, retval, sub, resolve, unres);
4274 } else if (!strcmp(sub->name, "leaf-list")) {
4275 mnode = read_yin_leaflist(module, retval, sub, resolve);
4276 } else if (!strcmp(sub->name, "leaf")) {
4277 mnode = read_yin_leaf(module, retval, sub, resolve);
4278 } else if (!strcmp(sub->name, "list")) {
4279 mnode = read_yin_list(module, retval, sub, resolve, unres);
4280 } else if (!strcmp(sub->name, "choice")) {
4281 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4282 } else if (!strcmp(sub->name, "uses")) {
4283 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4284 } else if (!strcmp(sub->name, "grouping")) {
4285 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4286 } else if (!strcmp(sub->name, "anyxml")) {
4287 mnode = read_yin_anyxml(module, retval, sub, resolve);
4288 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004289 if (!mnode) {
4290 goto error;
4291 }
Radek Krejci73adb602015-07-02 18:07:40 +02004292
4293 lyxml_free_elem(module->ctx, sub);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004294 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004295
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004296 if (parent && ly_mnode_addchild(parent, retval)) {
4297 goto error;
4298 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004299
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004300 return retval;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004301
4302error:
4303
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004304 ly_mnode_free(retval);
4305 while (root.child) {
4306 lyxml_free_elem(module->ctx, root.child);
4307 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02004308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004309 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02004310}
4311
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004312static struct ly_mnode *
4313read_yin_input_output(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004314 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004315{
Radek Krejcie0674f82015-06-15 13:58:51 +02004316 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004317 struct ly_mnode *mnode = NULL;
4318 struct ly_mnode *retval;
4319 struct ly_mnode_input_output *inout;
4320 int r;
4321 int c_tpdf = 0;
4322
Radek Krejcie0674f82015-06-15 13:58:51 +02004323 /* init */
4324 memset(&root, 0, sizeof root);
4325
Michal Vasko38d01f72015-06-15 09:41:06 +02004326 inout = calloc(1, sizeof *inout);
4327
4328 if (!strcmp(yin->name, "input")) {
4329 inout->nodetype = LY_NODE_INPUT;
4330 } else if (!strcmp(yin->name, "output")) {
4331 inout->nodetype = LY_NODE_OUTPUT;
4332 } else {
4333 assert(0);
4334 }
4335
4336 inout->prev = (struct ly_mnode *)inout;
4337 retval = (struct ly_mnode *)inout;
4338
Radek Krejci6a113852015-07-03 16:04:20 +02004339 if (read_yin_common(module, parent, retval, yin, OPT_MODULE | OPT_NACMEXT)) {
Michal Vaskoebeac942015-06-15 12:11:50 +02004340 goto error;
4341 }
4342
Michal Vasko38d01f72015-06-15 09:41:06 +02004343 /* data statements */
4344 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004345 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4346 /* garbage */
4347 lyxml_free_elem(module->ctx, sub);
4348 continue;
4349 }
4350
Michal Vasko38d01f72015-06-15 09:41:06 +02004351 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004352 !strcmp(sub->name, "leaf-list") ||
4353 !strcmp(sub->name, "leaf") ||
4354 !strcmp(sub->name, "list") ||
4355 !strcmp(sub->name, "choice") ||
4356 !strcmp(sub->name, "uses") ||
4357 !strcmp(sub->name, "grouping") ||
4358 !strcmp(sub->name, "anyxml")) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004359 lyxml_unlink_elem(sub);
4360 lyxml_add_child(&root, sub);
4361
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004362 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004363 } else if (!strcmp(sub->name, "typedef")) {
4364 c_tpdf++;
Radek Krejcid2bfa792015-07-02 16:45:29 +02004365
Michal Vasko38d01f72015-06-15 09:41:06 +02004366 } else {
4367 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4368 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004369 }
4370 }
4371
4372 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4373 if (c_tpdf) {
4374 inout->tpdf = calloc(c_tpdf, sizeof *inout->tpdf);
4375 }
4376
Radek Krejci73adb602015-07-02 18:07:40 +02004377 LY_TREE_FOR(yin->child, sub) {
4378 r = fill_yin_typedef(module, retval, sub, &inout->tpdf[inout->tpdf_size], NULL);
4379 inout->tpdf_size++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004380
Radek Krejci73adb602015-07-02 18:07:40 +02004381 if (r) {
4382 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004383 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004384 }
4385
4386 /* last part - process data nodes */
4387 LY_TREE_FOR_SAFE(root.child, next, sub) {
4388 if (!strcmp(sub->name, "container")) {
4389 mnode = read_yin_container(module, retval, sub, resolve, unres);
4390 } else if (!strcmp(sub->name, "leaf-list")) {
4391 mnode = read_yin_leaflist(module, retval, sub, resolve);
4392 } else if (!strcmp(sub->name, "leaf")) {
4393 mnode = read_yin_leaf(module, retval, sub, resolve);
4394 } else if (!strcmp(sub->name, "list")) {
4395 mnode = read_yin_list(module, retval, sub, resolve, unres);
4396 } else if (!strcmp(sub->name, "choice")) {
4397 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4398 } else if (!strcmp(sub->name, "uses")) {
4399 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4400 } else if (!strcmp(sub->name, "grouping")) {
4401 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4402 } else if (!strcmp(sub->name, "anyxml")) {
4403 mnode = read_yin_anyxml(module, retval, sub, resolve);
4404 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004405 if (!mnode) {
4406 goto error;
4407 }
Radek Krejci73adb602015-07-02 18:07:40 +02004408
4409 lyxml_free_elem(module->ctx, sub);
Michal Vasko38d01f72015-06-15 09:41:06 +02004410 }
4411
4412 if (parent && ly_mnode_addchild(parent, retval)) {
4413 goto error;
4414 }
4415
4416 return retval;
4417
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004418error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004419
4420 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004421 while (root.child) {
4422 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004423 }
4424
4425 return NULL;
4426}
4427
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004428static struct ly_mnode *
4429read_yin_notif(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004430 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko0ea41032015-06-16 08:53:55 +02004431{
Michal Vaskoc6551b32015-06-16 10:51:43 +02004432 struct lyxml_elem *sub, *next, root;
Michal Vasko0ea41032015-06-16 08:53:55 +02004433 struct ly_mnode *mnode = NULL;
4434 struct ly_mnode *retval;
4435 struct ly_mnode_notif *notif;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004436 const char *value;
Michal Vasko0ea41032015-06-16 08:53:55 +02004437 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004438 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko0ea41032015-06-16 08:53:55 +02004439
Michal Vaskoc6551b32015-06-16 10:51:43 +02004440 memset(&root, 0, sizeof root);
4441
Michal Vasko0ea41032015-06-16 08:53:55 +02004442 notif = calloc(1, sizeof *notif);
4443 notif->nodetype = LY_NODE_NOTIF;
4444 notif->prev = (struct ly_mnode *)notif;
4445 retval = (struct ly_mnode *)notif;
4446
Radek Krejci6a113852015-07-03 16:04:20 +02004447 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004448 goto error;
4449 }
4450
4451 /* process rpc's specific children */
4452 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004453 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4454 /* garbage */
4455 lyxml_free_elem(module->ctx, sub);
4456 continue;
4457 }
4458
Michal Vasko0ea41032015-06-16 08:53:55 +02004459 /* data statements */
4460 if (!strcmp(sub->name, "container") ||
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004461 !strcmp(sub->name, "leaf-list") ||
4462 !strcmp(sub->name, "leaf") ||
4463 !strcmp(sub->name, "list") ||
4464 !strcmp(sub->name, "choice") ||
4465 !strcmp(sub->name, "uses") ||
4466 !strcmp(sub->name, "grouping") ||
4467 !strcmp(sub->name, "anyxml")) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004468 lyxml_unlink_elem(sub);
4469 lyxml_add_child(&root, sub);
4470
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004471 /* array counters */
Michal Vasko0ea41032015-06-16 08:53:55 +02004472 } else if (!strcmp(sub->name, "typedef")) {
4473 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004474 } else if (!strcmp(sub->name, "if-feature")) {
4475 c_ftrs++;
Michal Vasko0ea41032015-06-16 08:53:55 +02004476 } else {
4477 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4478 goto error;
Michal Vasko0ea41032015-06-16 08:53:55 +02004479 }
4480 }
4481
4482 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4483 if (c_tpdf) {
4484 notif->tpdf = calloc(c_tpdf, sizeof *notif->tpdf);
4485 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004486 if (c_ftrs) {
4487 notif->features = calloc(c_ftrs, sizeof *notif->features);
4488 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004489
Radek Krejci73adb602015-07-02 18:07:40 +02004490 LY_TREE_FOR(yin->child, sub) {
Michal Vasko0ea41032015-06-16 08:53:55 +02004491 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004492 r = fill_yin_typedef(module, retval, sub, &notif->tpdf[notif->tpdf_size], NULL);
Michal Vasko0ea41032015-06-16 08:53:55 +02004493 notif->tpdf_size++;
4494
4495 if (r) {
4496 goto error;
4497 }
Radek Krejci0b24d752015-07-02 15:02:27 +02004498 } else if (!strcmp(sub->name, "if-features")) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004499 GETVAL(value, sub, "name");
4500 notif->features[notif->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004501 if (!notif->features[notif->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004502 goto error;
4503 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004504 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004505 }
4506
4507 /* last part - process data nodes */
4508 LY_TREE_FOR_SAFE(root.child, next, sub) {
4509 if (!strcmp(sub->name, "container")) {
4510 mnode = read_yin_container(module, retval, sub, resolve, unres);
4511 } else if (!strcmp(sub->name, "leaf-list")) {
4512 mnode = read_yin_leaflist(module, retval, sub, resolve);
4513 } else if (!strcmp(sub->name, "leaf")) {
4514 mnode = read_yin_leaf(module, retval, sub, resolve);
4515 } else if (!strcmp(sub->name, "list")) {
4516 mnode = read_yin_list(module, retval, sub, resolve, unres);
4517 } else if (!strcmp(sub->name, "choice")) {
4518 mnode = read_yin_choice(module, retval, sub, resolve, unres);
4519 } else if (!strcmp(sub->name, "uses")) {
4520 mnode = read_yin_uses(module, retval, sub, resolve, unres);
4521 } else if (!strcmp(sub->name, "grouping")) {
4522 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4523 } else if (!strcmp(sub->name, "anyxml")) {
4524 mnode = read_yin_anyxml(module, retval, sub, resolve);
4525 }
Michal Vasko0ea41032015-06-16 08:53:55 +02004526 if (!mnode) {
4527 goto error;
4528 }
Radek Krejci73adb602015-07-02 18:07:40 +02004529
4530 lyxml_free_elem(module->ctx, sub);
Michal Vasko0ea41032015-06-16 08:53:55 +02004531 }
4532
4533 if (parent && ly_mnode_addchild(parent, retval)) {
4534 goto error;
4535 }
4536
4537 return retval;
4538
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004539error:
Michal Vasko0ea41032015-06-16 08:53:55 +02004540
4541 ly_mnode_free(retval);
4542 while (root.child) {
4543 lyxml_free_elem(module->ctx, root.child);
4544 }
4545
4546 return NULL;
4547}
4548
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004549static struct ly_mnode *
4550read_yin_rpc(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004551 struct ly_mnode *parent, struct lyxml_elem *yin, int resolve, struct obj_list **unres)
Michal Vasko38d01f72015-06-15 09:41:06 +02004552{
Radek Krejcie0674f82015-06-15 13:58:51 +02004553 struct lyxml_elem *sub, *next, root;
Michal Vasko38d01f72015-06-15 09:41:06 +02004554 struct ly_mnode *mnode = NULL;
4555 struct ly_mnode *retval;
4556 struct ly_mnode_rpc *rpc;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004557 const char *value;
Michal Vasko38d01f72015-06-15 09:41:06 +02004558 int r;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004559 int c_tpdf = 0, c_ftrs = 0;
Michal Vasko38d01f72015-06-15 09:41:06 +02004560
Radek Krejcie0674f82015-06-15 13:58:51 +02004561 /* init */
4562 memset(&root, 0, sizeof root);
4563
Michal Vasko38d01f72015-06-15 09:41:06 +02004564 rpc = calloc(1, sizeof *rpc);
4565 rpc->nodetype = LY_NODE_RPC;
4566 rpc->prev = (struct ly_mnode *)rpc;
4567 retval = (struct ly_mnode *)rpc;
4568
Radek Krejci6a113852015-07-03 16:04:20 +02004569 if (read_yin_common(module, parent, retval, yin, OPT_IDENT | OPT_MODULE | OPT_NACMEXT)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004570 goto error;
4571 }
4572
4573 /* process rpc's specific children */
4574 LY_TREE_FOR_SAFE(yin->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004575 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4576 /* garbage */
4577 lyxml_free_elem(module->ctx, sub);
4578 continue;
4579 }
4580
Michal Vasko38d01f72015-06-15 09:41:06 +02004581 if (!strcmp(sub->name, "input")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004582 if (rpc->child
4583 && (rpc->child->nodetype == LY_NODE_INPUT
4584 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004585 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4586 goto error;
4587 }
4588 lyxml_unlink_elem(sub);
4589 lyxml_add_child(&root, sub);
4590 } else if (!strcmp(sub->name, "output")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004591 if (rpc->child
4592 && (rpc->child->nodetype == LY_NODE_INPUT
4593 || (rpc->child->next && rpc->child->next->nodetype == LY_NODE_INPUT))) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004594 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
4595 goto error;
4596 }
4597 lyxml_unlink_elem(sub);
4598 lyxml_add_child(&root, sub);
4599
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004600 /* data statements */
Michal Vasko38d01f72015-06-15 09:41:06 +02004601 } else if (!strcmp(sub->name, "grouping")) {
4602 lyxml_unlink_elem(sub);
4603 lyxml_add_child(&root, sub);
4604
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004605 /* array counters */
Michal Vasko38d01f72015-06-15 09:41:06 +02004606 } else if (!strcmp(sub->name, "typedef")) {
4607 c_tpdf++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004608 } else if (!strcmp(sub->name, "if-feature")) {
4609 c_ftrs++;
Michal Vasko38d01f72015-06-15 09:41:06 +02004610 } else {
4611 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
4612 goto error;
Michal Vasko38d01f72015-06-15 09:41:06 +02004613 }
4614 }
4615
4616 /* middle part - process nodes with cardinality of 0..n except the data nodes */
4617 if (c_tpdf) {
4618 rpc->tpdf = calloc(c_tpdf, sizeof *rpc->tpdf);
4619 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004620 if (c_ftrs) {
4621 rpc->features = calloc(c_ftrs, sizeof *rpc->features);
4622 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004623
Radek Krejci73adb602015-07-02 18:07:40 +02004624 LY_TREE_FOR(yin->child, sub) {
Michal Vasko38d01f72015-06-15 09:41:06 +02004625 if (!strcmp(sub->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004626 r = fill_yin_typedef(module, retval, sub, &rpc->tpdf[rpc->tpdf_size], NULL);
Michal Vasko38d01f72015-06-15 09:41:06 +02004627 rpc->tpdf_size++;
4628
4629 if (r) {
4630 goto error;
4631 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02004632 } else if (!strcmp(sub->name, "if-feature")) {
4633 GETVAL(value, sub, "name");
4634 rpc->features[rpc->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02004635 if (!rpc->features[rpc->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02004636 goto error;
4637 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004638 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004639 }
4640
4641 /* last part - process data nodes */
4642 LY_TREE_FOR_SAFE(root.child, next, sub) {
4643 if (!strcmp(sub->name, "grouping")) {
4644 mnode = read_yin_grouping(module, retval, sub, resolve, unres);
4645 } else if (!strcmp(sub->name, "input")) {
4646 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4647 } else if (!strcmp(sub->name, "output")) {
4648 mnode = read_yin_input_output(module, retval, sub, resolve, unres);
4649 }
Michal Vasko38d01f72015-06-15 09:41:06 +02004650 if (!mnode) {
4651 goto error;
4652 }
Radek Krejci73adb602015-07-02 18:07:40 +02004653
4654 lyxml_free_elem(module->ctx, sub);
Michal Vasko38d01f72015-06-15 09:41:06 +02004655 }
4656
4657 if (parent && ly_mnode_addchild(parent, retval)) {
4658 goto error;
4659 }
4660
4661 return retval;
4662
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004663error:
Michal Vasko38d01f72015-06-15 09:41:06 +02004664
4665 ly_mnode_free(retval);
Michal Vasko3a9abf82015-06-17 10:18:26 +02004666 while (root.child) {
4667 lyxml_free_elem(module->ctx, root.child);
Michal Vasko38d01f72015-06-15 09:41:06 +02004668 }
4669
4670 return NULL;
4671}
4672
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004673static int
4674find_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004675{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004676 struct ly_module *searchmod = NULL, *module = uses->module;
4677 struct ly_mnode *mnode, *mnode_aux;
4678 const char *name;
4679 int prefix_len = 0;
4680 int i;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004681
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004682 /* get referenced grouping */
4683 name = strchr(uses->name, ':');
4684 if (!name) {
4685 /* no prefix, search in local tree */
4686 name = uses->name;
4687 } else {
4688 /* there is some prefix, check if it refer the same data model */
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004689
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004690 /* set name to correct position after colon */
4691 prefix_len = name - uses->name;
4692 name++;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004693
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004694 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
4695 /* prefix refers to the current module, ignore it */
4696 prefix_len = 0;
4697 }
4698 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004699
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004700 /* search */
4701 if (prefix_len) {
4702 /* in top-level groupings of some other module */
4703 for (i = 0; i < module->imp_size; i++) {
4704 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
4705 && !module->imp[i].prefix[prefix_len]) {
4706 searchmod = module->imp[i].module;
4707 break;
4708 }
4709 }
4710 if (!searchmod) {
4711 /* uses refers unknown data model */
4712 LOGVAL(VE_INPREFIX, line, name);
4713 return EXIT_FAILURE;
4714 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004715
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004716 LY_TREE_FOR(searchmod->data, mnode) {
4717 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4718 uses->grp = (struct ly_mnode_grp *)mnode;
4719 return EXIT_SUCCESS;
4720 }
4721 }
4722 } else {
4723 /* in local tree hierarchy */
4724 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
4725 LY_TREE_FOR(mnode_aux->child, mnode) {
4726 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4727 uses->grp = (struct ly_mnode_grp *)mnode;
4728 return EXIT_SUCCESS;
4729 }
4730 }
4731 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004732
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004733 /* search in top level of the current module */
4734 LY_TREE_FOR(module->data, mnode) {
4735 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4736 uses->grp = (struct ly_mnode_grp *)mnode;
4737 return EXIT_SUCCESS;
4738 }
4739 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004740
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004741 /* search in top-level of included modules */
4742 for (i = 0; i < module->inc_size; i++) {
4743 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
4744 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
4745 uses->grp = (struct ly_mnode_grp *)mnode;
4746 return EXIT_SUCCESS;
4747 }
4748 }
4749 }
4750 }
Radek Krejci1e9b9992015-06-04 17:57:04 +02004751
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004752 /* not found, but no explicit error occured */
4753 return EXIT_SUCCESS;
Radek Krejci74705112015-06-05 10:25:44 +02004754}
4755
Radek Krejcif5be10f2015-06-16 13:29:36 +02004756static int
4757resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
4758{
Radek Krejci73adb602015-07-02 18:07:40 +02004759 struct lyxml_elem *yin, *sub;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004760 struct ly_mnode *mnode;
4761
4762 assert(module);
4763
4764 /* resolve target node */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004765 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004766 if (!aug->target) {
Radek Krejcia7c6ab92015-07-02 19:12:48 +02004767 LOGVAL(VE_INARG, line, aug->target_name, "uses");
Radek Krejcif5be10f2015-06-16 13:29:36 +02004768 return EXIT_FAILURE;
4769 }
4770
4771 if (!aug->child) {
4772 /* nothing to do */
4773 return EXIT_SUCCESS;
4774 }
4775
4776 yin = (struct lyxml_elem *)aug->child;
4777
Radek Krejcia90cf5c2015-07-02 15:32:49 +02004778 /* inherit config information from parent, augment does not have
4779 * config property, but we need to keep the information for subelements
4780 */
4781 aug->flags |= aug->target->flags & LY_NODE_CONFIG_MASK;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004782
Radek Krejci73adb602015-07-02 18:07:40 +02004783 LY_TREE_FOR(yin->child, sub) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004784 if (!strcmp(sub->name, "container")) {
4785 mnode = read_yin_container(module, aug->target, sub, 1, NULL);
4786 } else if (!strcmp(sub->name, "leaf-list")) {
4787 mnode = read_yin_leaflist(module, aug->target, sub, 1);
4788 } else if (!strcmp(sub->name, "leaf")) {
4789 mnode = read_yin_leaf(module, aug->target, sub, 1);
4790 } else if (!strcmp(sub->name, "list")) {
4791 mnode = read_yin_list(module, aug->target, sub, 1, NULL);
4792 } else if (!strcmp(sub->name, "uses")) {
4793 mnode = read_yin_uses(module, aug->target, sub, 1, NULL);
4794 } else if (!strcmp(sub->name, "choice")) {
4795 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4796 } else if (!strcmp(sub->name, "case")) {
4797 mnode = read_yin_case(module, aug->target, sub, 1, NULL);
4798 } else if (!strcmp(sub->name, "anyxml")) {
4799 mnode = read_yin_anyxml(module, aug->target, sub, 1);
Radek Krejcif5be10f2015-06-16 13:29:36 +02004800 } else {
Radek Krejcid2bfa792015-07-02 16:45:29 +02004801 /* never should be here, since it was already pre-parsed by fill_yin_augment() */
Radek Krejcif5be10f2015-06-16 13:29:36 +02004802 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
Radek Krejci3de29a72015-06-16 15:23:03 +02004803 return EXIT_FAILURE;
Radek Krejcif5be10f2015-06-16 13:29:36 +02004804 }
4805
4806 if (!mnode) {
4807 return EXIT_FAILURE;
4808 }
Radek Krejci3de29a72015-06-16 15:23:03 +02004809 /* check for mandatory nodes - if the target node is in another module
4810 * the added nodes cannot be mandatory
4811 */
4812 if (check_mandatory(mnode)) {
4813 LOGVAL(VE_SPEC, LOGLINE(sub), "When augmenting data in another module, mandatory statement is not allowed.");
4814 return EXIT_FAILURE;
4815 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02004816
Radek Krejcif5be10f2015-06-16 13:29:36 +02004817 /* the parent pointer will point to the augment node, but all
4818 * siblings pointers and possibly the child node in target does
4819 * not know about the augment and follow the standard schema tree
4820 * structure
4821 */
4822 mnode->parent = (struct ly_mnode *)aug;
4823 mnode = NULL;
4824 }
4825
4826 lyxml_free_elem(module->ctx, yin);
4827 aug->child = NULL;
4828
4829 return EXIT_SUCCESS;
4830}
4831
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004832int
4833resolve_uses(struct ly_mnode_uses *uses, unsigned int line)
Radek Krejci106efc02015-06-10 14:36:27 +02004834{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004835 struct ly_ctx *ctx;
4836 struct ly_mnode *mnode = NULL, *mnode_aux;
4837 struct ly_refine *rfn;
Radek Krejci0bd5db42015-06-19 13:30:07 +02004838 struct ly_restr *newmust;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004839 int i, j;
4840 uint8_t size;
Radek Krejci106efc02015-06-10 14:36:27 +02004841
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004842 /* copy the data nodes from grouping into the uses context */
4843 LY_TREE_FOR(uses->grp->child, mnode) {
4844 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line);
4845 if (!mnode_aux) {
4846 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
4847 return EXIT_FAILURE;
4848 }
4849 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
4850 ly_mnode_free(mnode_aux);
4851 return EXIT_FAILURE;
4852 }
4853 }
4854 ctx = uses->module->ctx;
Radek Krejci106efc02015-06-10 14:36:27 +02004855
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004856 /* apply refines */
4857 for (i = 0; i < uses->refine_size; i++) {
4858 rfn = &uses->refine[i];
Michal Vasko6f6ac232015-06-18 11:11:46 +02004859 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004860 if (!mnode) {
4861 LOGVAL(VE_INARG, line, rfn->target, "uses");
4862 return EXIT_FAILURE;
4863 }
Radek Krejci106efc02015-06-10 14:36:27 +02004864
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004865 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
4866 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
4867 return EXIT_FAILURE;
4868 }
Radek Krejci106efc02015-06-10 14:36:27 +02004869
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004870 /* description on any nodetype */
4871 if (rfn->dsc) {
4872 lydict_remove(ctx, mnode->dsc);
4873 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
4874 }
Radek Krejci106efc02015-06-10 14:36:27 +02004875
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004876 /* reference on any nodetype */
4877 if (rfn->ref) {
4878 lydict_remove(ctx, mnode->ref);
4879 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
4880 }
Radek Krejci106efc02015-06-10 14:36:27 +02004881
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004882 /* config on any nodetype */
4883 if (rfn->flags & LY_NODE_CONFIG_MASK) {
4884 mnode->flags &= ~LY_NODE_CONFIG_MASK;
4885 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
4886 }
Radek Krejci106efc02015-06-10 14:36:27 +02004887
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004888 /* default value ... */
4889 if (rfn->mod.dflt) {
4890 if (mnode->nodetype == LY_NODE_LEAF) {
4891 /* leaf */
4892 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
4893 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
4894 } else if (mnode->nodetype == LY_NODE_CHOICE) {
4895 /* choice */
Michal Vasko6f6ac232015-06-18 11:11:46 +02004896 ((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 +02004897 if (!((struct ly_mnode_choice *)mnode)->dflt) {
4898 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
4899 return EXIT_FAILURE;
4900 }
4901 }
4902 }
Radek Krejci106efc02015-06-10 14:36:27 +02004903
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004904 /* mandatory on leaf, anyxml or choice */
Radek Krejcieb00f512015-07-01 16:44:58 +02004905 if (rfn->flags & LY_NODE_MAND_MASK) {
4906 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
4907 /* remove current value */
4908 mnode->flags &= ~LY_NODE_MAND_MASK;
4909
4910 /* set new value */
4911 mnode->flags |= (rfn->flags & LY_NODE_MAND_MASK);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004912 }
4913 }
Radek Krejci106efc02015-06-10 14:36:27 +02004914
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004915 /* presence on container */
4916 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
4917 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
4918 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
4919 }
Radek Krejci106efc02015-06-10 14:36:27 +02004920
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004921 /* min/max-elements on list or leaf-list */
4922 if (mnode->nodetype & (LY_NODE_LEAFLIST | LY_NODE_LIST)) {
4923 /* magic - bit 3 in flags means min set, bit 4 says max set */
4924 if (rfn->flags & 0x04) {
4925 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
4926 }
4927 if (rfn->flags & 0x08) {
4928 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
4929 }
4930 }
Radek Krejci106efc02015-06-10 14:36:27 +02004931
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004932 /* must in leaf, leaf-list, list, container or anyxml */
4933 if (rfn->must_size) {
4934 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
4935 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
4936 if (!newmust) {
4937 LOGMEM;
4938 return EXIT_FAILURE;
4939 }
4940 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
Radek Krejci0bd5db42015-06-19 13:30:07 +02004941 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004942 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
4943 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
4944 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
4945 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
4946 }
Radek Krejci106efc02015-06-10 14:36:27 +02004947
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004948 ((struct ly_mnode_leaf *)mnode)->must = newmust;
4949 ((struct ly_mnode_leaf *)mnode)->must_size = size;
4950 }
4951 }
Radek Krejci106efc02015-06-10 14:36:27 +02004952
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004953 /* apply augments */
4954 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcif5be10f2015-06-16 13:29:36 +02004955 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004956 goto error;
4957 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004958 }
Radek Krejci106efc02015-06-10 14:36:27 +02004959
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004960 return EXIT_SUCCESS;
Radek Krejci106efc02015-06-10 14:36:27 +02004961
4962error:
4963
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004964 return EXIT_FAILURE;
Radek Krejci106efc02015-06-10 14:36:27 +02004965}
Radek Krejci74705112015-06-05 10:25:44 +02004966
4967/*
4968 * resolve - referenced grouping should be bounded to the namespace (resolved)
4969 * only when uses does not appear in grouping. In a case of grouping's uses,
4970 * we just get information but we do not apply augment or refine to it.
4971 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004972static struct ly_mnode *
4973read_yin_uses(struct ly_module *module,
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004974 struct ly_mnode *parent, struct lyxml_elem *node, int resolve, struct obj_list **unres)
Radek Krejci74705112015-06-05 10:25:44 +02004975{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004976 struct lyxml_elem *sub, *next;
4977 struct ly_mnode *retval;
4978 struct ly_mnode_uses *uses;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02004979 struct obj_list *unres_new;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004980 const char *value;
Radek Krejci3cf9e222015-06-18 11:37:50 +02004981 int c_ref = 0, c_aug = 0, c_ftrs = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004982 int r;
Radek Krejci74705112015-06-05 10:25:44 +02004983
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004984 uses = calloc(1, sizeof *uses);
4985 uses->nodetype = LY_NODE_USES;
4986 uses->prev = (struct ly_mnode *)uses;
4987 retval = (struct ly_mnode *)uses;
Radek Krejci74705112015-06-05 10:25:44 +02004988
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004989 GETVAL(value, node, "name");
4990 uses->name = lydict_insert(module->ctx, value, 0);
Radek Krejci106efc02015-06-10 14:36:27 +02004991
Radek Krejci6a113852015-07-03 16:04:20 +02004992 if (read_yin_common(module, parent, retval, node, OPT_MODULE | OPT_NACMEXT | (resolve ? OPT_INHERIT : 0))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004993 goto error;
4994 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02004995
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02004996 /* get other properties of uses */
4997 LY_TREE_FOR_SAFE(node->child, next, sub) {
Radek Krejci0d70c372015-07-02 16:23:10 +02004998 if (!sub->ns || strcmp(sub->ns->value, LY_NSYIN)) {
4999 /* garbage */
5000 lyxml_free_elem(module->ctx, sub);
5001 continue;
5002 }
5003
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005004 if (!strcmp(sub->name, "refine")) {
5005 c_ref++;
5006 } else if (!strcmp(sub->name, "augment")) {
5007 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005008 } else if (!strcmp(sub->name, "if-feature")) {
Radek Krejci56e89772015-06-19 10:00:54 +02005009 c_ftrs++;
Radek Krejcib0af6ba2015-06-18 15:01:03 +02005010 } else if (!strcmp(sub->name, "when")) {
5011 if (uses->when) {
5012 LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, node->name);
5013 goto error;
5014 }
5015
5016 uses->when = read_yin_when(module, sub);
5017 lyxml_free_elem(module->ctx, sub);
5018
5019 if (!uses->when) {
5020 goto error;
5021 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005022 } else {
5023 LOGVAL(VE_INSTMT, LOGLINE(sub), sub->name);
5024 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005025 }
5026 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005027
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005028 /* process properties with cardinality 0..n */
5029 if (c_ref) {
5030 uses->refine = calloc(c_ref, sizeof *uses->refine);
5031 }
5032 if (c_aug) {
5033 uses->augment = calloc(c_aug, sizeof *uses->augment);
5034 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005035 if (c_ftrs) {
5036 uses->features = calloc(c_ftrs, sizeof *uses->features);
5037 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005038
Radek Krejci73adb602015-07-02 18:07:40 +02005039 LY_TREE_FOR(node->child, sub) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005040 if (!strcmp(sub->name, "refine")) {
5041 r = fill_yin_refine(module, sub, &uses->refine[uses->refine_size]);
5042 uses->refine_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005043 } else if (!strcmp(sub->name, "augment")) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005044 r = fill_yin_augment(module, retval, sub, &uses->augment[uses->augment_size]);
5045 uses->augment_size++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005046 } else if (!strcmp(sub->name, "if-feature")) {
5047 GETVAL(value, sub, "name");
5048 uses->features[uses->features_size] = resolve_feature(value, module, LOGLINE(sub));
Radek Krejci73adb602015-07-02 18:07:40 +02005049 if (!uses->features[uses->features_size++]) {
Radek Krejci3cf9e222015-06-18 11:37:50 +02005050 goto error;
5051 }
Radek Krejcib1f1da62015-06-19 10:09:53 +02005052 r = 0;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005053 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005054
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005055 if (r) {
5056 goto error;
5057 }
5058 }
Radek Krejci3bde87f2015-06-05 16:51:58 +02005059
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005060 if (find_grouping(parent, uses, LOGLINE(node))) {
5061 goto error;
5062 }
5063 if (!uses->grp) {
5064 LOGVRB("Unresolved uses of \"%s\" (line %d), trying to resolve it later", uses->name, LOGLINE(node));
5065 unres_new = calloc(1, sizeof *unres_new);
5066 if (*unres) {
5067 unres_new->next = *unres;
5068 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005069 unres_new->obj = retval;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005070 unres_new->line = LOGLINE(node);
Radek Krejci74705112015-06-05 10:25:44 +02005071
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005072 /* put it at the beginning of the unresolved list */
5073 *unres = unres_new;
5074 }
Radek Krejci74705112015-06-05 10:25:44 +02005075
Radek Krejci368c38f2015-06-15 15:09:55 +02005076 if (parent && ly_mnode_addchild(parent, retval)) {
5077 goto error;
5078 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005079
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005080 if (resolve) {
5081 /* inherit config flag */
5082 if (parent) {
5083 retval->flags |= parent->flags & LY_NODE_CONFIG_MASK;
5084 } else {
5085 /* default config is true */
5086 retval->flags |= LY_NODE_CONFIG_W;
5087 }
5088 }
Radek Krejcib388c152015-06-04 17:03:03 +02005089
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005090 if (resolve && uses->grp) {
5091 /* copy the data nodes from grouping into the uses context */
5092 if (resolve_uses(uses, LOGLINE(node))) {
5093 goto error;
5094 }
5095 }
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005097 return retval;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005098
5099error:
5100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005101 ly_mnode_free(retval);
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005103 return NULL;
Radek Krejcic7c9a6c2015-05-25 16:35:06 +02005104}
5105
Radek Krejciefaeba32015-05-27 14:30:57 +02005106/* common code for yin_read_module() and yin_read_submodule() */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005107static int
5108read_sub_module(struct ly_module *module, struct lyxml_elem *yin)
Radek Krejcida04f4a2015-05-21 12:54:09 +02005109{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005110 struct ly_ctx *ctx = module->ctx;
5111 struct ly_submodule *submodule = (struct ly_submodule *)module;
5112 struct lyxml_elem *next, *node, *child, root, grps, rpcs, notifs;
5113 struct ly_mnode *mnode = NULL;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005114 struct obj_list *unres = NULL, *unres_next; /* unresolved objects */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005115 const char *value;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005116 int r;
Michal Vasko38d01f72015-06-15 09:41:06 +02005117 int i;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005118 int unres_flag = 0; /* 0 for uses, 1 for types */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005119 int belongsto_flag = 0;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005120 /* counters */
Radek Krejcieb00f512015-07-01 16:44:58 +02005121 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 +02005122
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005123 /* init */
5124 memset(&root, 0, sizeof root);
5125 memset(&grps, 0, sizeof grps);
5126 memset(&rpcs, 0, sizeof rpcs);
Michal Vasko0ea41032015-06-16 08:53:55 +02005127 memset(&notifs, 0, sizeof notifs);
Radek Krejcie0674f82015-06-15 13:58:51 +02005128
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005129 /*
5130 * in the first run, we process elements with cardinality of 1 or 0..1 and
5131 * count elements with cardinality 0..n. Data elements (choices, containers,
5132 * leafs, lists, leaf-lists) are moved aside to be processed last, since we
5133 * need have all top-level and groupings already prepared at that time. In
5134 * the middle loop, we process other elements with carinality of 0..n since
5135 * we need to allocate arrays to store them.
5136 */
5137 LY_TREE_FOR_SAFE(yin->child, next, node) {
5138 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
Radek Krejci0d70c372015-07-02 16:23:10 +02005139 /* garbage */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005140 lyxml_free_elem(ctx, node);
5141 continue;
5142 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005144 if (!module->type && !strcmp(node->name, "namespace")) {
5145 if (module->ns) {
5146 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5147 goto error;
5148 }
5149 GETVAL(value, node, "uri");
5150 module->ns = lydict_insert(ctx, value, strlen(value));
5151 lyxml_free_elem(ctx, node);
5152 } else if (!module->type && !strcmp(node->name, "prefix")) {
5153 if (module->prefix) {
5154 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5155 goto error;
5156 }
5157 GETVAL(value, node, "value");
5158 if (check_identifier(value, LY_IDENT_PREFIX, LOGLINE(node), module, NULL)) {
5159 goto error;
5160 }
5161 module->prefix = lydict_insert(ctx, value, strlen(value));
5162 lyxml_free_elem(ctx, node);
5163 } else if (module->type && !strcmp(node->name, "belongs-to")) {
5164 if (belongsto_flag) {
5165 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5166 goto error;
5167 }
5168 belongsto_flag = 1;
5169 GETVAL(value, node, "module");
5170 while (submodule->belongsto->type) {
5171 submodule->belongsto = ((struct ly_submodule *)submodule->belongsto)->belongsto;
5172 }
5173 if (value != submodule->belongsto->name) {
5174 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5175 goto error;
5176 }
Radek Krejcif3886932015-06-04 17:36:06 +02005177
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005178 /* get the prefix substatement, start with checks */
5179 if (!node->child) {
5180 LOGVAL(VE_MISSSTMT2, LOGLINE(node), "prefix", node->name);
5181 goto error;
5182 } else if (strcmp(node->child->name, "prefix")) {
5183 LOGVAL(VE_INSTMT, LOGLINE(node->child), node->child->name);
5184 goto error;
5185 } else if (node->child->next) {
5186 LOGVAL(VE_INSTMT, LOGLINE(node->child->next), node->child->next->name);
5187 goto error;
5188 }
5189 /* and now finally get the value */
5190 GETVAL(value, node->child, "value");
5191 /* check here differs from a generic prefix check, since this prefix
5192 * don't have to be unique
Michal Vasko38d01f72015-06-15 09:41:06 +02005193 */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005194 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(node->child), NULL, NULL)) {
5195 goto error;
5196 }
5197 module->prefix = lydict_insert(ctx, value, strlen(value));
Radek Krejci0af13872015-05-30 11:50:52 +02005198
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005199 /* we are done with belongs-to */
5200 lyxml_free_elem(ctx, node);
Radek Krejcieb00f512015-07-01 16:44:58 +02005201
5202 /* counters (statements with n..1 cardinality) */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005203 } else if (!strcmp(node->name, "import")) {
5204 c_imp++;
5205 } else if (!strcmp(node->name, "revision")) {
5206 c_rev++;
5207 } else if (!strcmp(node->name, "typedef")) {
5208 c_tpdf++;
5209 } else if (!strcmp(node->name, "identity")) {
5210 c_ident++;
5211 } else if (!strcmp(node->name, "include")) {
5212 c_inc++;
Radek Krejcif5be10f2015-06-16 13:29:36 +02005213 } else if (!strcmp(node->name, "augment")) {
5214 c_aug++;
Radek Krejci3cf9e222015-06-18 11:37:50 +02005215 } else if (!strcmp(node->name, "feature")) {
5216 c_ftrs++;
Radek Krejcieb00f512015-07-01 16:44:58 +02005217 } else if (!strcmp(node->name, "deviation")) {
5218 c_dev++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005220 /* data statements */
5221 } else if (!strcmp(node->name, "container") ||
5222 !strcmp(node->name, "leaf-list") ||
5223 !strcmp(node->name, "leaf") ||
5224 !strcmp(node->name, "list") ||
5225 !strcmp(node->name, "choice") ||
5226 !strcmp(node->name, "uses") ||
5227 !strcmp(node->name, "anyxml")) {
5228 lyxml_unlink_elem(node);
5229 lyxml_add_child(&root, node);
5230 } else if (!strcmp(node->name, "grouping")) {
5231 /* keep groupings separated and process them before other data statements */
5232 lyxml_unlink_elem(node);
5233 lyxml_add_child(&grps, node);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005234
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005235 /* optional statements */
5236 } else if (!strcmp(node->name, "description")) {
5237 if (module->dsc) {
5238 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5239 goto error;
5240 }
5241 module->dsc = read_yin_subnode(ctx, node, "text");
5242 lyxml_free_elem(ctx, node);
5243 if (!module->dsc) {
5244 goto error;
5245 }
5246 } else if (!strcmp(node->name, "reference")) {
5247 if (module->ref) {
5248 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5249 goto error;
5250 }
5251 module->ref = read_yin_subnode(ctx, node, "text");
5252 lyxml_free_elem(ctx, node);
5253 if (!module->ref) {
5254 goto error;
5255 }
5256 } else if (!strcmp(node->name, "organization")) {
5257 if (module->org) {
5258 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5259 goto error;
5260 }
5261 module->org = read_yin_subnode(ctx, node, "text");
5262 lyxml_free_elem(ctx, node);
5263 if (!module->org) {
5264 goto error;
5265 }
5266 } else if (!strcmp(node->name, "contact")) {
5267 if (module->contact) {
5268 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5269 goto error;
5270 }
5271 module->contact = read_yin_subnode(ctx, node, "text");
5272 lyxml_free_elem(ctx, node);
5273 if (!module->contact) {
5274 goto error;
5275 }
5276 } else if (!strcmp(node->name, "yang-version")) {
5277 /* TODO: support YANG 1.1 ? */
5278 if (module->version) {
5279 LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
5280 goto error;
5281 }
5282 GETVAL(value, node, "value");
5283 if (strcmp(value, "1")) {
5284 LOGVAL(VE_INARG, LOGLINE(node), value, "yang-version");
5285 goto error;
5286 }
5287 module->version = 1;
5288 lyxml_free_elem(ctx, node);
Michal Vasko38d01f72015-06-15 09:41:06 +02005289
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005290 /* rpcs & notifications */
Michal Vasko38d01f72015-06-15 09:41:06 +02005291 } else if (!strcmp(node->name, "rpc")) {
5292 lyxml_unlink_elem(node);
5293 lyxml_add_child(&rpcs, node);
Michal Vasko0ea41032015-06-16 08:53:55 +02005294 } else if (!strcmp(node->name, "notification")) {
5295 lyxml_unlink_elem(node);
5296 lyxml_add_child(&notifs, node);
Radek Krejci5166a892015-07-02 16:44:24 +02005297
5298 } else if (!strcmp(node->name, "extension")) {
5299 GETVAL(value, node, "name");
Radek Krejci5166a892015-07-02 16:44:24 +02005300
Radek Krejci6764bb32015-07-03 15:16:04 +02005301 /* we have 2 supported (hardcoded) extensions:
5302 * NACM's default-deny-write and default-deny-all
5303 */
5304 if (strcmp(module->ns, LY_NSNACM) ||
5305 (strcmp(value, "default-deny-write") && strcmp(value, "default-deny-all"))) {
5306 LOGWRN("Not supported \"%s\" extension statement found, ignoring.", value);
5307 lyxml_free_elem(ctx, node);
5308 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005309 } else {
5310 LOGVAL(VE_INSTMT, LOGLINE(node), node->name);
5311 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005312 }
5313 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005314
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005315 if (!submodule) {
5316 /* check for mandatory statements */
5317 if (!module->ns) {
5318 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
5319 goto error;
5320 }
5321 if (!module->prefix) {
5322 LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "prefix", "module");
5323 goto error;
5324 }
5325 }
Radek Krejcibb3257d2015-05-21 23:03:51 +02005326
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005327 /* allocate arrays for elements with cardinality of 0..n */
5328 if (c_imp) {
5329 module->imp = calloc(c_imp, sizeof *module->imp);
5330 }
5331 if (c_rev) {
5332 module->rev = calloc(c_rev, sizeof *module->rev);
5333 }
5334 if (c_tpdf) {
5335 module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
5336 }
5337 if (c_ident) {
5338 module->ident = calloc(c_ident, sizeof *module->ident);
5339 }
5340 if (c_inc) {
5341 module->inc = calloc(c_inc, sizeof *module->inc);
5342 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005343 if (c_aug) {
5344 module->augment = calloc(c_aug, sizeof *module->augment);
5345 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005346 if (c_ftrs) {
5347 module->features = calloc(c_ftrs, sizeof *module->features);
5348 }
Radek Krejcieb00f512015-07-01 16:44:58 +02005349 if (c_dev) {
5350 module->deviation = calloc(c_dev, sizeof *module->deviation);
5351 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005352
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005353 /* now we are going to remember unresolved types, the flag is
5354 * used in case of error to get know how to free the structures
5355 * in unres list
5356 */
5357 unres_flag = 1;
5358
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005359 /* middle part - process nodes with cardinality of 0..n except the data nodes */
Radek Krejci73adb602015-07-02 18:07:40 +02005360 LY_TREE_FOR(yin->child, node) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005361 if (!strcmp(node->name, "import")) {
5362 r = fill_yin_import(module, node, &module->imp[module->imp_size]);
5363 module->imp_size++;
5364 if (r) {
5365 goto error;
5366 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005367
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005368 /* check duplicities in imported modules */
5369 for (i = 0; i < module->imp_size - 1; i++) {
5370 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
5371 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
5372 goto error;
5373 }
5374 }
5375 } else if (!strcmp(node->name, "include")) {
5376 r = fill_yin_include(module, node, &module->inc[module->inc_size]);
5377 module->inc_size++;
5378 if (r) {
5379 goto error;
5380 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005381
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005382 /* check duplications in include submodules */
5383 for (i = 0; i < module->inc_size - 1; i++) {
5384 if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
5385 LOGVAL(VE_SPEC, LOGLINE(node), "Importing module \"%s\" repeatedly.",
5386 module->inc[i].submodule->name);
5387 goto error;
5388 }
5389 }
5390 } else if (!strcmp(node->name, "revision")) {
5391 GETVAL(value, node, "date");
5392 if (check_date(value, LOGLINE(node))) {
5393 goto error;
5394 }
5395 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5396 /* check uniqueness of the revision date - not required by RFC */
5397 for (i = 0; i < module->rev_size; i++) {
5398 if (!strcmp(value, module->rev[i].date)) {
5399 LOGVAL(VE_INARG, LOGLINE(node), value, node->name);
5400 LOGVAL(VE_SPEC, 0, "Revision is not unique.");
5401 }
5402 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005403
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005404 LY_TREE_FOR(node->child, child) {
5405 if (!strcmp(child->name, "description")) {
5406 if (module->rev[module->rev_size].dsc) {
5407 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5408 goto error;
5409 }
5410 module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child, "text");
5411 if (!module->rev[module->rev_size].dsc) {
5412 goto error;
5413 }
5414 } else if (!strcmp(child->name, "reference")) {
5415 if (module->rev[module->rev_size].ref) {
5416 LOGVAL(VE_TOOMANY, LOGLINE(node), child->name, node->name);
5417 goto error;
5418 }
5419 module->rev[module->rev_size].ref = read_yin_subnode(ctx, child, "text");
5420 if (!module->rev[module->rev_size].ref) {
5421 goto error;
5422 }
5423 } else {
5424 LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
5425 goto error;
5426 }
5427 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005428
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005429 /* keep the latest revision at position 0 */
5430 if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
5431 /* switch their position */
5432 value = strdup(module->rev[0].date);
5433 memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
5434 memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
5435 free((char *)value);
Radek Krejcice7fb782015-05-29 16:52:34 +02005436
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005437 if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
5438 value = module->rev[0].dsc;
5439 module->rev[0].dsc = module->rev[module->rev_size].dsc;
5440 module->rev[module->rev_size].dsc = value;
5441 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005442
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005443 if (module->rev[0].ref != module->rev[module->rev_size].ref) {
5444 value = module->rev[0].ref;
5445 module->rev[0].ref = module->rev[module->rev_size].ref;
5446 module->rev[module->rev_size].ref = value;
5447 }
5448 }
Radek Krejcice7fb782015-05-29 16:52:34 +02005449
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005450 module->rev_size++;
5451 } else if (!strcmp(node->name, "typedef")) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005452 r = fill_yin_typedef(module, NULL, node, &module->tpdf[module->tpdf_size], &unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005453 module->tpdf_size++;
Radek Krejci25d782a2015-05-22 15:03:23 +02005454
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005455 if (r) {
5456 goto error;
5457 }
5458 } else if (!strcmp(node->name, "identity")) {
5459 r = fill_yin_identity(module, node, &module->ident[module->ident_size]);
5460 module->ident_size++;
Radek Krejci6793db02015-05-22 17:49:54 +02005461
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005462 if (r) {
5463 goto error;
5464 }
Radek Krejci3cf9e222015-06-18 11:37:50 +02005465 } else if (!strcmp(node->name, "feature")) {
5466 r = fill_yin_feature(module, node, &module->features[module->features_size]);
5467 module->features_size++;
5468
5469 if (r) {
5470 goto error;
5471 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005472 } else if (!strcmp(node->name, "augment")) {
5473 r = fill_yin_augment(module, NULL, node, &module->augment[module->augment_size]);
5474 module->augment_size++;
5475
5476 if (r) {
5477 goto error;
5478 }
5479
5480 /* node is reconnected into the augment, so we have to skip its free at the end of the loop */
5481 continue;
Radek Krejcieb00f512015-07-01 16:44:58 +02005482 } else if (!strcmp(node->name, "deviation")) {
5483 r = fill_yin_deviation(module, node, &module->deviation[module->deviation_size]);
5484 module->deviation_size++;
5485
5486 if (r) {
5487 goto error;
5488 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005489 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005490 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005491 /* resolve unresolved types (possible in typedef's with unions */
5492 while (unres) {
5493 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
Radek Krejci73adb602015-07-02 18:07:40 +02005494 if (fill_yin_type(module, NULL, node, (struct ly_type *)unres->obj, NULL)) {
5495 goto error;
5496 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005497
Radek Krejci73adb602015-07-02 18:07:40 +02005498 /* cleanup */
5499 lyxml_free_elem(ctx, node);
5500 ((struct ly_type *)unres->obj)->der = NULL;
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005501 unres_next = unres->next;
5502 free(unres);
5503 unres = unres_next;
5504
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005505 }
5506 unres_flag = 0;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005507
Radek Krejcif5be10f2015-06-16 13:29:36 +02005508 /* process data nodes. Start with groupings to allow uses
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005509 * refer to them
5510 */
5511 LY_TREE_FOR_SAFE(grps.child, next, node) {
5512 mnode = read_yin_grouping(module, NULL, node, 0, &unres);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005513 if (!mnode) {
5514 goto error;
5515 }
Radek Krejci74705112015-06-05 10:25:44 +02005516
Radek Krejci73adb602015-07-02 18:07:40 +02005517 lyxml_free_elem(ctx, node);
5518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005519 /* include data element */
5520 if (module->data) {
5521 module->data->prev->next = mnode;
5522 mnode->prev = module->data->prev;
5523 module->data->prev = mnode;
5524 } else {
5525 module->data = mnode;
5526 }
5527 }
5528 while (unres) {
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005529 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 +02005530 goto error;
5531 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005532 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5533 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005534 goto error;
5535 }
5536 unres_next = unres->next;
5537 free(unres);
5538 unres = unres_next;
5539 }
Radek Krejci74705112015-06-05 10:25:44 +02005540
Radek Krejcif5be10f2015-06-16 13:29:36 +02005541 /* parse data nodes, ... */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005542 LY_TREE_FOR_SAFE(root.child, next, node) {
Radek Krejcida04f4a2015-05-21 12:54:09 +02005543
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005544 if (!strcmp(node->name, "container")) {
5545 mnode = read_yin_container(module, NULL, node, 1, &unres);
5546 } else if (!strcmp(node->name, "leaf-list")) {
5547 mnode = read_yin_leaflist(module, NULL, node, 1);
5548 } else if (!strcmp(node->name, "leaf")) {
5549 mnode = read_yin_leaf(module, NULL, node, 1);
5550 } else if (!strcmp(node->name, "list")) {
5551 mnode = read_yin_list(module, NULL, node, 1, &unres);
5552 } else if (!strcmp(node->name, "choice")) {
5553 mnode = read_yin_choice(module, NULL, node, 1, &unres);
5554 } else if (!strcmp(node->name, "uses")) {
5555 mnode = read_yin_uses(module, NULL, node, 1, &unres);
5556 } else if (!strcmp(node->name, "anyxml")) {
5557 mnode = read_yin_anyxml(module, NULL, node, 1);
5558 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005559 if (!mnode) {
5560 goto error;
5561 }
Radek Krejci25d782a2015-05-22 15:03:23 +02005562
Radek Krejci73adb602015-07-02 18:07:40 +02005563 lyxml_free_elem(ctx, node);
5564
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005565 /* include data element */
5566 if (module->data) {
5567 module->data->prev->next = mnode;
5568 mnode->prev = module->data->prev;
5569 module->data->prev = mnode;
5570 } else {
5571 module->data = mnode;
5572 }
5573 }
Radek Krejcif5be10f2015-06-16 13:29:36 +02005574
5575 /* ... rpcs ... */
5576 LY_TREE_FOR_SAFE(rpcs.child, next, node) {
5577 mnode = read_yin_rpc(module, NULL, node, 0, &unres);
Radek Krejcif5be10f2015-06-16 13:29:36 +02005578 if (!mnode) {
5579 goto error;
5580 }
5581
Radek Krejci73adb602015-07-02 18:07:40 +02005582 lyxml_free_elem(ctx, node);
5583
Radek Krejcif5be10f2015-06-16 13:29:36 +02005584 /* include rpc element */
5585 if (module->rpc) {
5586 module->rpc->prev->next = mnode;
5587 mnode->prev = module->rpc->prev;
5588 module->rpc->prev = mnode;
5589 } else {
5590 module->rpc = mnode;
5591 }
5592 }
5593
5594 /* ... and notifications */
5595 LY_TREE_FOR_SAFE(notifs.child, next, node) {
5596 mnode = read_yin_notif(module, NULL, node, 0, &unres);
Radek Krejcif5be10f2015-06-16 13:29:36 +02005597 if (!mnode) {
5598 goto error;
5599 }
5600
Radek Krejci73adb602015-07-02 18:07:40 +02005601 lyxml_free_elem(ctx, node);
5602
Radek Krejcif5be10f2015-06-16 13:29:36 +02005603 /* include notification element */
5604 if (module->notif) {
5605 module->notif->prev->next = mnode;
5606 mnode->prev = module->notif->prev;
5607 module->notif->prev = mnode;
5608 } else {
5609 module->notif = mnode;
5610 }
5611 }
5612
5613 /* and now try to resolve unresolved uses, if any */
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005614 while (unres) {
5615 /* find referenced grouping */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005616 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 +02005617 goto error;
5618 }
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005619 if (!((struct ly_mnode_uses *)unres->obj)->grp) {
5620 LOGVAL(VE_INARG, unres->line, ((struct ly_mnode_uses *)unres->obj)->name, "uses");
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005621 goto error;
5622 }
Radek Krejci74705112015-06-05 10:25:44 +02005623
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005624 /* resolve uses by copying grouping content under the uses */
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005625 if (resolve_uses((struct ly_mnode_uses *)unres->obj, unres->line)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005626 goto error;
5627 }
Radek Krejci74705112015-06-05 10:25:44 +02005628
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005629 unres_next = unres->next;
5630 free(unres);
5631 unres = unres_next;
5632 }
Radek Krejcida04f4a2015-05-21 12:54:09 +02005633
Radek Krejcif5be10f2015-06-16 13:29:36 +02005634 /* and finally apply augments */
5635 for (i = 0; i < module->augment_size; i++) {
5636 if (resolve_augment(&module->augment[i], NULL, module, 0)) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005637 goto error;
5638 }
Michal Vasko0ea41032015-06-16 08:53:55 +02005639 }
5640
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005641 return EXIT_SUCCESS;
Radek Krejciefaeba32015-05-27 14:30:57 +02005642
5643error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005644 /* cleanup */
5645 while (root.child) {
5646 lyxml_free_elem(module->ctx, root.child);
5647 }
5648 while (grps.child) {
5649 lyxml_free_elem(module->ctx, grps.child);
5650 }
5651 while (rpcs.child) {
Michal Vasko38d01f72015-06-15 09:41:06 +02005652 lyxml_free_elem(module->ctx, rpcs.child);
5653 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005654
Radek Krejci8de7b0f2015-07-02 11:43:42 +02005655 while (unres) {
5656 unres_next = unres->next;
5657 if (unres_flag) {
5658 /* free the XML subtrees kept in unresolved type structures */
5659 node = (struct lyxml_elem *)((struct ly_type *)unres->obj)->der;
5660 lyxml_free_elem(ctx, node);
5661 }
5662
5663 free(unres);
5664 unres = unres_next;
5665 }
5666
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005667 return EXIT_FAILURE;
Radek Krejciefaeba32015-05-27 14:30:57 +02005668}
5669
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005670struct ly_submodule *
5671yin_read_submodule(struct ly_module *module, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005672{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005673 struct lyxml_elem *yin;
5674 struct ly_submodule *submodule = NULL;
5675 const char *value;
Radek Krejciefaeba32015-05-27 14:30:57 +02005676
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005677 assert(module->ctx);
Radek Krejciefaeba32015-05-27 14:30:57 +02005678
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005679 yin = lyxml_read(module->ctx, data, 0);
5680 if (!yin) {
5681 return NULL;
5682 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005683
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005684 /* check root element */
5685 if (!yin->name || strcmp(yin->name, "submodule")) {
5686 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5687 goto error;
5688 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005689
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005690 GETVAL(value, yin, "name");
5691 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5692 goto error;
5693 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005694
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005695 submodule = calloc(1, sizeof *submodule);
5696 if (!submodule) {
5697 LOGMEM;
5698 goto error;
5699 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005700
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005701 submodule->ctx = module->ctx;
5702 submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
5703 submodule->type = 1;
5704 submodule->belongsto = module;
Radek Krejciefaeba32015-05-27 14:30:57 +02005705
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005706 LOGVRB("reading submodule %s", submodule->name);
5707 if (read_sub_module((struct ly_module *)submodule, yin)) {
5708 goto error;
5709 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005710
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005711 /* cleanup */
5712 lyxml_free_elem(module->ctx, yin);
Radek Krejciefaeba32015-05-27 14:30:57 +02005713
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005714 LOGVRB("submodule %s successfully parsed", submodule->name);
Radek Krejciefaeba32015-05-27 14:30:57 +02005715
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005716 return submodule;
Radek Krejciefaeba32015-05-27 14:30:57 +02005717
5718error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005719 /* cleanup */
5720 lyxml_free_elem(module->ctx, yin);
5721 ly_submodule_free(submodule);
Radek Krejciefaeba32015-05-27 14:30:57 +02005722
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005723 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +02005724}
5725
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005726struct ly_module *
5727yin_read_module(struct ly_ctx *ctx, const char *data)
Radek Krejciefaeba32015-05-27 14:30:57 +02005728{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005729 struct lyxml_elem *yin;
5730 struct ly_module *module = NULL, **newlist = NULL;
5731 const char *value;
5732 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +02005733
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005734 yin = lyxml_read(ctx, data, 0);
5735 if (!yin) {
5736 return NULL;
5737 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005738
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005739 /* check root element */
5740 if (!yin->name || strcmp(yin->name, "module")) {
5741 LOGVAL(VE_INSTMT, LOGLINE(yin), yin->name);
5742 goto error;
5743 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005744
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005745 GETVAL(value, yin, "name");
5746 if (check_identifier(value, LY_IDENT_NAME, LOGLINE(yin), NULL, NULL)) {
5747 goto error;
5748 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005749
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005750 module = calloc(1, sizeof *module);
5751 if (!module) {
5752 LOGMEM;
5753 goto error;
5754 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005755
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005756 module->ctx = ctx;
5757 module->name = lydict_insert(ctx, value, strlen(value));
5758 module->type = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +02005759
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005760 LOGVRB("reading module %s", module->name);
5761 if (read_sub_module(module, yin)) {
5762 goto error;
5763 }
Radek Krejciefaeba32015-05-27 14:30:57 +02005764
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005765 /* add to the context's list of modules */
5766 if (ctx->models.used == ctx->models.size) {
5767 newlist = realloc(ctx->models.list, ctx->models.size * 2);
5768 if (!newlist) {
5769 LOGMEM;
5770 goto error;
5771 }
5772 for (i = ctx->models.size; i < ctx->models.size * 2; i++) {
5773 newlist[i] = NULL;
5774 }
5775 ctx->models.size *= 2;
5776 ctx->models.list = newlist;
5777 }
5778 for (i = 0; ctx->models.list[i]; i++) {
5779 /* check name (name/revision) and namespace uniqueness */
5780 if (!strcmp(ctx->models.list[i]->name, module->name)) {
5781 if (!ctx->models.list[i]->rev_size && !module->rev_size) {
5782 /* both data models are same, with no revision specified */
5783 LOGERR(LY_EINVAL, "Module \"%s\" (no revision in either of them specified) already in context.",
5784 module->name);
5785 goto error;
5786 } else if (!ctx->models.list[i]->rev_size || !module->rev_size) {
5787 /* one of the models does not have a revision, so they differs */
5788 continue;
5789 } else {
5790 /* both models have a revision statement which we have to
5791 * compare, revision at position 0 is the last revision
5792 */
5793 if (!strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
5794 /* we have the same modules */
5795 LOGERR(LY_EINVAL, "Module \"%s\", revision %s already in context.", module->name,
5796 module->rev[0].date);
5797 goto error;
5798 }
5799 }
5800 } else if (!strcmp(ctx->models.list[i]->ns, module->ns)) {
5801 LOGERR(LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\"",
5802 ctx->models.list[i]->name, module->name, module->ns);
5803 goto error;
5804 }
5805 }
5806 ctx->models.list[i] = module;
5807 ctx->models.used++;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005808
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005809 /* cleanup */
5810 lyxml_free_elem(ctx, yin);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005811
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005812 LOGVRB("module %s successfully parsed", module->name);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005813
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005814 return module;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005815
5816error:
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005817 /* cleanup */
5818 lyxml_free_elem(ctx, yin);
5819 ly_module_free(module);
Radek Krejcida04f4a2015-05-21 12:54:09 +02005820
Radek Krejci6e4ffbb2015-06-16 10:34:41 +02005821 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +02005822}