blob: c9729937b3677f037528c9ab440e0acb5d611158 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
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
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022#define _GNU_SOURCE
23
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020028#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020029
30#include "libyang.h"
31#include "resolve.h"
32#include "common.h"
33#include "parse.h"
34#include "dict.h"
35#include "tree_internal.h"
36
Michal Vasko730dfdf2015-08-11 14:48:05 +020037/**
38 * @brief Resolves length or range intervals. Does not log.
39 * Syntax is assumed to be correct, *local_intv MUST be NULL.
40 *
41 * @param[in] str_restr The restriction as a string.
42 * @param[in] type The type of the restriction.
43 * @param[in] superior_restr Flag whether to check superior
44 * types.
45 * @param[out] local_intv The final interval structure.
46 *
47 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
48 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +020049int
50resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr, struct len_ran_intv** local_intv)
51{
52 /* 0 - unsigned, 1 - signed, 2 - floating point */
53 int kind, ret = 0;
54 int64_t local_smin, local_smax;
55 uint64_t local_umin, local_umax;
56 long double local_fmin, local_fmax;
57 const char *seg_ptr, *ptr;
58 struct len_ran_intv *tmp_local_intv, *tmp_intv, *intv = NULL;
59
60 switch (type->base) {
61 case LY_TYPE_BINARY:
62 kind = 0;
63 local_umin = 0;
64 local_umax = 18446744073709551615UL;
65
66 if (!str_restr && type->info.binary.length) {
67 str_restr = type->info.binary.length->expr;
68 }
69 break;
70 case LY_TYPE_DEC64:
71 kind = 2;
72 local_fmin = -9223372036854775808.0;
73 local_fmin /= 1 << type->info.dec64.dig;
74 local_fmax = 9223372036854775807.0;
75 local_fmax /= 1 << type->info.dec64.dig;
76
77 if (!str_restr && type->info.dec64.range) {
78 str_restr = type->info.dec64.range->expr;
79 }
80 break;
81 case LY_TYPE_INT8:
82 kind = 1;
83 local_smin = -128;
84 local_smax = 127;
85
86 if (!str_restr && type->info.num.range) {
87 str_restr = type->info.num.range->expr;
88 }
89 break;
90 case LY_TYPE_INT16:
91 kind = 1;
92 local_smin = -32768;
93 local_smax = 32767;
94
95 if (!str_restr && type->info.num.range) {
96 str_restr = type->info.num.range->expr;
97 }
98 break;
99 case LY_TYPE_INT32:
100 kind = 1;
101 local_smin = -2147483648;
102 local_smax = 2147483647;
103
104 if (!str_restr && type->info.num.range) {
105 str_restr = type->info.num.range->expr;
106 }
107 break;
108 case LY_TYPE_INT64:
109 kind = 1;
110 local_smin = -9223372036854775807L - 1L;
111 local_smax = 9223372036854775807L;
112
113 if (!str_restr && type->info.num.range) {
114 str_restr = type->info.num.range->expr;
115 }
116 break;
117 case LY_TYPE_UINT8:
118 kind = 0;
119 local_umin = 0;
120 local_umax = 255;
121
122 if (!str_restr && type->info.num.range) {
123 str_restr = type->info.num.range->expr;
124 }
125 break;
126 case LY_TYPE_UINT16:
127 kind = 0;
128 local_umin = 0;
129 local_umax = 65535;
130
131 if (!str_restr && type->info.num.range) {
132 str_restr = type->info.num.range->expr;
133 }
134 break;
135 case LY_TYPE_UINT32:
136 kind = 0;
137 local_umin = 0;
138 local_umax = 4294967295;
139
140 if (!str_restr && type->info.num.range) {
141 str_restr = type->info.num.range->expr;
142 }
143 break;
144 case LY_TYPE_UINT64:
145 kind = 0;
146 local_umin = 0;
147 local_umax = 18446744073709551615UL;
148
149 if (!str_restr && type->info.num.range) {
150 str_restr = type->info.num.range->expr;
151 }
152 break;
153 case LY_TYPE_STRING:
154 kind = 0;
155 local_umin = 0;
156 local_umax = 18446744073709551615UL;
157
158 if (!str_restr && type->info.str.length) {
159 str_restr = type->info.str.length->expr;
160 }
161 break;
162 default:
163 LOGINT;
164 return EXIT_FAILURE;
165 }
166
167 /* process superior types */
168 if (type->der && superior_restr) {
169 assert(!resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv));
170 assert(!intv || (intv->kind == kind));
171 }
172
173 if (!str_restr) {
174 /* we are validating data and not have any restriction, but a superior type might have */
175 if (type->der && !superior_restr && !intv) {
176 assert(!resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv));
177 assert(!intv || (intv->kind == kind));
178 }
179 *local_intv = intv;
180 return EXIT_SUCCESS;
181 }
182
183 /* adjust local min and max */
184 if (intv) {
185 tmp_intv = intv;
186
187 if (kind == 0) {
188 local_umin = tmp_intv->value.uval.min;
189 } else if (kind == 1) {
190 local_smin = tmp_intv->value.sval.min;
191 } else if (kind == 2) {
192 local_fmin = tmp_intv->value.fval.min;
193 }
194
195 while (tmp_intv->next) {
196 tmp_intv = tmp_intv->next;
197 }
198
199 if (kind == 0) {
200 local_umax = tmp_intv->value.uval.max;
201 } else if (kind == 1) {
202 local_smax = tmp_intv->value.sval.max;
203 } else if (kind == 2) {
204 local_fmax = tmp_intv->value.fval.max;
205 }
206 }
207
208 /* finally parse our restriction */
209 seg_ptr = str_restr;
210 while (1) {
211 if (!*local_intv) {
212 *local_intv = malloc(sizeof **local_intv);
213 tmp_local_intv = *local_intv;
214 } else {
215 tmp_local_intv->next = malloc(sizeof **local_intv);
216 tmp_local_intv = tmp_local_intv->next;
217 }
218
219 tmp_local_intv->kind = kind;
220 tmp_local_intv->next = NULL;
221
222 /* min */
223 ptr = seg_ptr;
224 while (isspace(ptr[0])) {
225 ++ptr;
226 }
227 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
228 if (kind == 0) {
229 tmp_local_intv->value.uval.min = atoll(ptr);
230 } else if (kind == 1) {
231 tmp_local_intv->value.sval.min = atoll(ptr);
232 } else if (kind == 2) {
233 tmp_local_intv->value.fval.min = atoll(ptr);
234 }
235
236 if ((ptr[0] == '+') || (ptr[0] == '-')) {
237 ++ptr;
238 }
239 while (isdigit(ptr[0])) {
240 ++ptr;
241 }
242 } else if (!strncmp(ptr, "min", 3)) {
243 if (kind == 0) {
244 tmp_local_intv->value.uval.min = local_umin;
245 } else if (kind == 1) {
246 tmp_local_intv->value.sval.min = local_smin;
247 } else if (kind == 2) {
248 tmp_local_intv->value.fval.min = local_fmin;
249 }
250
251 ptr += 3;
252 } else if (!strncmp(ptr, "max", 3)) {
253 if (kind == 0) {
254 tmp_local_intv->value.uval.min = local_umax;
255 } else if (kind == 1) {
256 tmp_local_intv->value.sval.min = local_smax;
257 } else if (kind == 2) {
258 tmp_local_intv->value.fval.min = local_fmax;
259 }
260
261 ptr += 3;
262 } else {
263 assert(0);
264 }
265
266 while (isspace(ptr[0])) {
267 ptr++;
268 }
269
270 /* no interval or interval */
271 if ((ptr[0] == '|') || !ptr[0]) {
272 if (kind == 0) {
273 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
274 } else if (kind == 1) {
275 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
276 } else if (kind == 2) {
277 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
278 }
279 } else if (!strncmp(ptr, "..", 2)) {
280 /* skip ".." */
281 ptr += 2;
282 while (isspace(ptr[0])) {
283 ++ptr;
284 }
285
286 /* max */
287 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
288 if (kind == 0) {
289 tmp_local_intv->value.uval.max = atoll(ptr);
290 } else if (kind == 1) {
291 tmp_local_intv->value.sval.max = atoll(ptr);
292 } else if (kind == 2) {
293 tmp_local_intv->value.fval.max = atoll(ptr);
294 }
295 } else if (!strncmp(ptr, "max", 3)) {
296 if (kind == 0) {
297 tmp_local_intv->value.uval.max = local_umax;
298 } else if (kind == 1) {
299 tmp_local_intv->value.sval.max = local_smax;
300 } else if (kind == 2) {
301 tmp_local_intv->value.fval.max = local_fmax;
302 }
303 } else {
304 assert(0);
305 }
306 } else {
307 assert(0);
308 }
309
310 /* next segment (next OR) */
311 seg_ptr = strchr(seg_ptr, '|');
312 if (!seg_ptr) {
313 break;
314 }
315 seg_ptr++;
316 }
317
318 /* check local restrictions against superior ones */
319 if (intv) {
320 tmp_intv = intv;
321 tmp_local_intv = *local_intv;
322
323 while (tmp_local_intv && tmp_intv) {
324 /* reuse local variables */
325 if (kind == 0) {
326 local_umin = tmp_local_intv->value.uval.min;
327 local_umax = tmp_local_intv->value.uval.max;
328
329 /* it must be in this interval */
330 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
331 /* this interval is covered, next one */
332 if (local_umax <= tmp_intv->value.uval.max) {
333 tmp_local_intv = tmp_local_intv->next;
334 continue;
335 /* ascending order of restrictions -> fail */
336 } else {
337 ret = EXIT_FAILURE;
338 goto cleanup;
339 }
340 }
341 } else if (kind == 1) {
342 local_smin = tmp_local_intv->value.sval.min;
343 local_smax = tmp_local_intv->value.sval.max;
344
345 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
346 if (local_smax <= tmp_intv->value.sval.max) {
347 tmp_local_intv = tmp_local_intv->next;
348 continue;
349 } else {
350 ret = EXIT_FAILURE;
351 goto cleanup;
352 }
353 }
354 } else if (kind == 2) {
355 local_fmin = tmp_local_intv->value.fval.min;
356 local_fmax = tmp_local_intv->value.fval.max;
357
358 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
359 if (local_fmax <= tmp_intv->value.fval.max) {
360 tmp_local_intv = tmp_local_intv->next;
361 continue;
362 } else {
363 ret = EXIT_FAILURE;
364 goto cleanup;
365 }
366 }
367 }
368
369 tmp_intv = tmp_intv->next;
370 }
371
372 /* some interval left uncovered -> fail */
373 if (tmp_local_intv) {
374 ret = EXIT_FAILURE;
375 }
376
377 }
378
379cleanup:
380 while (intv) {
381 tmp_intv = intv->next;
382 free(intv);
383 intv = tmp_intv;
384 }
385
386 /* fail */
387 if (ret) {
388 while (*local_intv) {
389 tmp_local_intv = (*local_intv)->next;
390 free(*local_intv);
391 *local_intv = tmp_local_intv;
392 }
393 }
394
395 return ret;
396}
397
Michal Vasko730dfdf2015-08-11 14:48:05 +0200398/**
399 * @brief Resolve a typedef. Does not log.
400 *
401 * @param[in] name Typedef name.
402 * @param[in] prefix Typedef name prefix.
403 * @param[in] module The main module.
404 * @param[in] parent The parent of the resolved type definition.
405 *
406 * @return Typedef pointer on succes, NULL otherwise.
407 */
Radek Krejci1574a8d2015-08-03 14:16:52 +0200408struct lys_tpdf *
Radek Krejcib8048692015-08-05 13:36:34 +0200409resolve_superior_type(const char *name, const char *prefix, struct lys_module *module, struct lys_node *parent)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200410{
411 int i, j, found = 0;
Radek Krejci1574a8d2015-08-03 14:16:52 +0200412 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200413 int tpdf_size;
414
415 if (!prefix) {
416 /* no prefix, try built-in types */
417 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
418 if (!strcmp(ly_types[i].def->name, name)) {
419 return ly_types[i].def;
420 }
421 }
422 } else {
423 if (!strcmp(prefix, module->prefix)) {
424 /* prefix refers to the current module, ignore it */
425 prefix = NULL;
426 }
427 }
428
429 if (!prefix && parent) {
430 /* search in local typedefs */
431 while (parent) {
432 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200433 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +0200434 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
435 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200436 break;
437
Radek Krejci76512572015-08-04 09:47:08 +0200438 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +0200439 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
440 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200441 break;
442
Radek Krejci76512572015-08-04 09:47:08 +0200443 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +0200444 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
445 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200446 break;
447
Radek Krejci76512572015-08-04 09:47:08 +0200448 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +0200449 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
450 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200451 break;
452
Radek Krejci76512572015-08-04 09:47:08 +0200453 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +0200454 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
455 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200456 break;
457
Radek Krejci76512572015-08-04 09:47:08 +0200458 case LYS_INPUT:
459 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +0200460 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
461 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200462 break;
463
464 default:
465 parent = parent->parent;
466 continue;
467 }
468
469 for (i = 0; i < tpdf_size; i++) {
470 if (!strcmp(tpdf[i].name, name)) {
471 return &tpdf[i];
472 }
473 }
474
475 parent = parent->parent;
476 }
477 } else if (prefix) {
478 /* get module where to search */
479 for (i = 0; i < module->imp_size; i++) {
480 if (!strcmp(module->imp[i].prefix, prefix)) {
481 module = module->imp[i].module;
482 found = 1;
483 break;
484 }
485 }
486 if (!found) {
487 return NULL;
488 }
489 }
490
491 /* search in top level typedefs */
492 for (i = 0; i < module->tpdf_size; i++) {
493 if (!strcmp(module->tpdf[i].name, name)) {
494 return &module->tpdf[i];
495 }
496 }
497
498 /* search in submodules */
499 for (i = 0; i < module->inc_size; i++) {
500 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
501 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
502 return &module->inc[i].submodule->tpdf[j];
503 }
504 }
505 }
506
507 return NULL;
508}
509
510static int
Radek Krejci1574a8d2015-08-03 14:16:52 +0200511check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200512{
513 /* TODO - RFC 6020, sec. 7.3.4 */
514 (void)type;
515 (void)value;
516 return EXIT_SUCCESS;
517}
518
Michal Vasko730dfdf2015-08-11 14:48:05 +0200519/**
520 * @brief Check a key for mandatory attributes. Logs directly.
521 *
522 * @param[in] key The key to check.
523 * @param[in] flags What flags to check.
524 * @param[in] list The list of all the keys.
525 * @param[in] index Index of the key in the key list.
526 * @param[in] name The name of the keys.
527 * @param[in] len The name length.
528 * @param[in] line The line in the input file.
529 *
530 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
531 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200532static int
Michal Vaskof02e3742015-08-05 16:27:02 +0200533check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
534 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200535{
536 char *dup = NULL;
537 int j;
538
539 /* existence */
540 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +0200541 if (name[len] != '\0') {
542 dup = strdup(name);
543 dup[len] = '\0';
544 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200545 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200546 LOGVAL(LYE_KEY_MISS, line, name);
547 free(dup);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200548 return EXIT_FAILURE;
549 }
550
551 /* uniqueness */
552 for (j = index - 1; j >= 0; j--) {
553 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200554 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200555 return EXIT_FAILURE;
556 }
557 }
558
559 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +0200560 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200561 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200562 return EXIT_FAILURE;
563 }
564
565 /* type of the leaf is not built-in empty */
566 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200567 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200568 return EXIT_FAILURE;
569 }
570
571 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +0200572 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200573 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200574 return EXIT_FAILURE;
575 }
576
577 return EXIT_SUCCESS;
578}
579
Michal Vasko730dfdf2015-08-11 14:48:05 +0200580/**
581 * @brief Resolve (find) a prefix in a module include import. Does not log.
582 *
583 * @param[in] mod The module with the import.
584 * @param[in] prefix The prefix to find.
585 * @param[in] pref_len The prefix length.
586 *
587 * @return The matching module on success, NULL on error.
588 */
Michal Vaskof02e3742015-08-05 16:27:02 +0200589static struct lys_module *
590resolve_import_in_includes_recursive(struct lys_module *mod, const char *prefix, uint32_t pref_len)
591{
592 int i, j;
593 struct lys_submodule *sub_mod;
594 struct lys_module *ret;
595
596 for (i = 0; i < mod->inc_size; i++) {
597 sub_mod = mod->inc[i].submodule;
598 for (j = 0; j < sub_mod->imp_size; j++) {
599 if ((pref_len == strlen(sub_mod->imp[j].prefix))
600 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
601 return sub_mod->imp[j].module;
602 }
603 }
604 }
605
606 for (i = 0; i < mod->inc_size; i++) {
607 ret = resolve_import_in_includes_recursive((struct lys_module *)mod->inc[i].submodule, prefix, pref_len);
608 if (ret) {
609 return ret;
610 }
611 }
612
613 return NULL;
614}
615
Michal Vasko730dfdf2015-08-11 14:48:05 +0200616/**
617 * @brief Resolve (find) a prefix in a module import. Does not log.
618 *
619 * @param[in] mod The module with the import.
620 * @param[in] prefix The prefix to find.
621 * @param[in] pref_len The prefix length.
622 *
623 * @return The matching module on success, NULL on error.
624 */
Michal Vaskof02e3742015-08-05 16:27:02 +0200625static struct lys_module *
626resolve_prefixed_module(struct lys_module *mod, const char *prefix, uint32_t pref_len)
627{
628 int i;
629
630 /* module itself */
631 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
632 return mod;
633 }
634
635 /* imported modules */
636 for (i = 0; i < mod->imp_size; i++) {
637 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
638 return mod->imp[i].module;
639 }
640 }
641
642 /* imports in includes */
643 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
644}
645
Michal Vasko730dfdf2015-08-11 14:48:05 +0200646/**
647 * @brief Resolve (fill) a unique. Logs directly.
648 *
649 * @param[in] parent The parent node of the unique structure.
650 * @param[in] uniq_str The value of the unique node.
651 * @param[in] uniq_s The unique structure in question.
652 * @param[in] line The line in the input file.
653 *
654 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
655 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200656int
Michal Vaskof02e3742015-08-05 16:27:02 +0200657resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200658{
659 char *uniq_val, *uniq_begin, *start;
660 int i, j;
661
662 /* count the number of unique values */
663 uniq_val = uniq_begin = strdup(uniq_str);
664 uniq_s->leafs_size = 0;
665 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
666 uniq_s->leafs_size++;
667 while (isspace(*uniq_val)) {
668 uniq_val++;
669 }
670 }
671 uniq_s->leafs_size++;
672 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
673
674 /* interconnect unique values with the leafs */
675 uniq_val = uniq_begin;
676 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
677 start = uniq_val;
678 if ((uniq_val = strpbrk(start, " \t\n"))) {
679 *uniq_val = '\0'; /* add terminating NULL byte */
680 uniq_val++;
681 while (isspace(*uniq_val)) {
682 uniq_val++;
683 }
684 } /* else only one nodeid present/left already NULL byte terminated */
685
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200686 uniq_s->leafs[i] = (struct lys_node_leaf *)resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF);
687 if (!uniq_s->leafs[i] || (uniq_s->leafs[i]->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200688 LOGVAL(LYE_INARG, line, start, "unique");
689 if (!uniq_s->leafs[i]) {
690 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
691 } else {
692 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200693 }
694 goto error;
695 }
696
697 for (j = 0; j < i; j++) {
698 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200699 LOGVAL(LYE_INARG, line, start, "unique");
700 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200701 goto error;
702 }
703 }
704 }
705
706 free(uniq_begin);
707 return EXIT_SUCCESS;
708
709error:
710
711 free(uniq_s->leafs);
712 free(uniq_begin);
713
714 return EXIT_FAILURE;
715}
716
Michal Vasko730dfdf2015-08-11 14:48:05 +0200717/**
718 * @brief Resolve (fill) a grouping in an uses. Logs directly.
719 *
720 * @param[in] parent The parent node of the uses.
721 * @param[in] uses The uses in question.
722 * @param[in] line The line in the input file.
723 *
724 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
725 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200726static int
Michal Vaskof02e3742015-08-05 16:27:02 +0200727resolve_grouping(struct lys_node *parent, struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200728{
Radek Krejcib8048692015-08-05 13:36:34 +0200729 struct lys_module *searchmod = NULL, *module = uses->module;
Radek Krejci1d82ef62015-08-07 14:44:40 +0200730 struct lys_node *node, *node_aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200731 const char *name;
732 int prefix_len = 0;
733 int i;
734
735 /* get referenced grouping */
736 name = strchr(uses->name, ':');
737 if (!name) {
738 /* no prefix, search in local tree */
739 name = uses->name;
740 } else {
741 /* there is some prefix, check if it refer the same data model */
742
743 /* set name to correct position after colon */
744 prefix_len = name - uses->name;
745 name++;
746
747 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
748 /* prefix refers to the current module, ignore it */
749 prefix_len = 0;
750 }
751 }
752
753 /* search */
754 if (prefix_len) {
755 /* in top-level groupings of some other module */
756 for (i = 0; i < module->imp_size; i++) {
757 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
758 && !module->imp[i].prefix[prefix_len]) {
759 searchmod = module->imp[i].module;
760 break;
761 }
762 }
763 if (!searchmod) {
764 /* uses refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200765 LOGVAL(LYE_INPREF, line, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200766 return EXIT_FAILURE;
767 }
768
Radek Krejci1d82ef62015-08-07 14:44:40 +0200769 LY_TREE_FOR(searchmod->data, node) {
770 if (node->nodetype == LYS_GROUPING && !strcmp(node->name, name)) {
771 uses->grp = (struct lys_node_grp *)node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200772 return EXIT_SUCCESS;
773 }
774 }
775 } else {
776 /* in local tree hierarchy */
Radek Krejci1d82ef62015-08-07 14:44:40 +0200777 for (node_aux = parent; node_aux; node_aux = node_aux->parent) {
778 LY_TREE_FOR(node_aux->child, node) {
779 if (node->nodetype == LYS_GROUPING && !strcmp(node->name, name)) {
780 uses->grp = (struct lys_node_grp *)node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200781 return EXIT_SUCCESS;
782 }
783 }
784 }
785
786 /* search in top level of the current module */
Radek Krejci1d82ef62015-08-07 14:44:40 +0200787 LY_TREE_FOR(module->data, node) {
788 if (node->nodetype == LYS_GROUPING && !strcmp(node->name, name)) {
789 uses->grp = (struct lys_node_grp *)node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200790 return EXIT_SUCCESS;
791 }
792 }
793
794 /* search in top-level of included modules */
795 for (i = 0; i < module->inc_size; i++) {
Radek Krejci1d82ef62015-08-07 14:44:40 +0200796 LY_TREE_FOR(module->inc[i].submodule->data, node) {
797 if (node->nodetype == LYS_GROUPING && !strcmp(node->name, name)) {
798 uses->grp = (struct lys_node_grp *)node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200799 return EXIT_SUCCESS;
800 }
801 }
802 }
803 }
804
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200805 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200806 return EXIT_FAILURE;
807}
808
Michal Vasko730dfdf2015-08-11 14:48:05 +0200809/**
810 * @brief Resolve (find) a feature definition. Logs directly.
811 *
812 * @param[in] name Feature name.
813 * @param[in] module Module to search in.
814 * @param[in] line The line in the input file.
815 *
816 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
817 */
Radek Krejcib8048692015-08-05 13:36:34 +0200818static struct lys_feature *
Michal Vaskof02e3742015-08-05 16:27:02 +0200819resolve_feature(const char *name, struct lys_module *module, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200820{
821 const char *prefix;
Michal Vaskof02e3742015-08-05 16:27:02 +0200822 uint32_t prefix_len = 0;
823 int i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200824
825 assert(name);
826 assert(module);
827
828 /* check prefix */
829 prefix = name;
830 name = strchr(prefix, ':');
831 if (name) {
832 /* there is prefix */
833 prefix_len = name - prefix;
834 name++;
835
836 /* check whether the prefix points to the current module */
837 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
838 /* then ignore prefix and works as there is no prefix */
839 prefix_len = 0;
840 }
841 } else {
842 /* no prefix, set pointers correctly */
843 name = prefix;
844 }
845
846 if (prefix_len) {
847 /* search in imported modules */
Michal Vaskof02e3742015-08-05 16:27:02 +0200848 module = resolve_prefixed_module(module, prefix, prefix_len);
849 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200850 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200851 LOGVAL(LYE_INPREF, line, prefix);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200852 return NULL;
853 }
854 } else {
855 /* search in submodules */
856 for (i = 0; i < module->inc_size; i++) {
857 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
858 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
859 return &(module->inc[i].submodule->features[j]);
860 }
861 }
862 }
863 }
864
865 /* search in the identified module */
866 for (j = 0; j < module->features_size; j++) {
867 if (!strcmp(name, module->features[j].name)) {
868 return &module->features[j];
869 }
870 }
871
872 /* not found */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200873 LOGVAL(LYE_INRESOLV, line, "feature", prefix);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200874 return NULL;
875}
876
Michal Vasko730dfdf2015-08-11 14:48:05 +0200877/**
878 * @brief Resolve (find) a valid child of a parent. Does not log.
879 *
880 * Valid child means a chema pointer to a node that is part of
881 * the data meaning uses are skipped.
882 *
883 * @param[in] parent Parent to search in.
884 * @param[in] name Child name.
885 * @param[in] len Child name length.
886 * @param[in] type ORed desired type of the node.
887 *
888 * @return Node of the desired type, NULL if no matching node was found.
889 */
Radek Krejci76512572015-08-04 09:47:08 +0200890struct lys_node *
891resolve_child(struct lys_node *parent, const char *name, int len, LYS_NODE type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200892{
Radek Krejci76512572015-08-04 09:47:08 +0200893 struct lys_node *child, *result;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200894
895 if (!len) {
896 len = strlen(name);
897 }
898
899 LY_TREE_FOR(parent->child, child) {
Radek Krejci76512572015-08-04 09:47:08 +0200900 if (child->nodetype == LYS_USES) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200901 /* search recursively */
902 result = resolve_child(child, name, len, type);
903 if (result) {
904 return result;
905 }
906 }
907
908 if (child->nodetype & type) {
909 /* direct check */
910 if (child->name == name || (!strncmp(child->name, name, len) && !child->name[len])) {
911 return child;
912 }
913 }
914 }
915
916 return NULL;
917}
918
Michal Vasko730dfdf2015-08-11 14:48:05 +0200919/**
920 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200921 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200922 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200923 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200924 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200925 * - LYS_LEAF (like LYS_USES, but always returns a data node)
926 *
927 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
928 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200929 *
930 * @param[in] id Schema-nodeid string.
931 * @param[in] start Start of the relative search.
932 * @param[in] mod Module in question.
933 * @param[in] node_type Decides how to modify the search.
934 *
935 * @return Matching node, NULL on fail.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200936 */
Radek Krejci76512572015-08-04 09:47:08 +0200937struct lys_node *
Radek Krejcib8048692015-08-05 13:36:34 +0200938resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200939{
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200940 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +0200941 struct lys_node *sibling;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200942 int ret, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +0200943 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200944 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
945 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200946 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200947 uint8_t in_mod_part = 0;
948
949 assert(mod);
950 assert(id);
951
952 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
953 return NULL;
954 }
955 id += ret;
956
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200957 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200958 return NULL;
959 }
960
961 /* absolute-schema-nodeid */
962 if (!is_relative) {
963 if (prefix) {
964 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
965 if (!start_mod) {
966 return NULL;
967 }
968 start = start_mod->data;
969 } else {
970 start = mod->data;
971 start_mod = mod;
972 }
973 /* descendant-schema-nodeid */
974 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200975 if (start) {
976 start_mod = start->module;
977 } else {
978 start_mod = mod;
979 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200980 }
981
982 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +0200983 sibling = NULL;
984 LY_TREE_FOR(start, sibling) {
985 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200986 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
987 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +0200988 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +0200989 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200990
Michal Vasko1e989c02015-08-04 12:33:00 +0200991 /* prefix match check */
992 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +0200993 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
994 if (!prefix_mod) {
995 return NULL;
996 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +0200997 } else {
998 prefix_mod = mod;
999 if (prefix_mod->type) {
1000 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1001 }
1002 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001003
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001004 /* modules need to always be checked, we want to skip augments */
1005 if (!sibling->module->type) {
1006 if (prefix_mod != sibling->module) {
1007 continue;
1008 }
1009 } else {
1010 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1011 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001012 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001013 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001014
Michal Vasko1e989c02015-08-04 12:33:00 +02001015 /* the result node? */
1016 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001017 /* we're looking only for groupings, this is a data node */
1018 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1019 continue;
1020 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001021 return sibling;
1022 }
1023
Michal Vaskodcc7a802015-08-06 11:59:47 +02001024 /* we're looking for a grouping (node_type == LYS_USES),
1025 * but this isn't it, we cannot search inside
1026 */
1027 if (sibling->nodetype == LYS_GROUPING) {
1028 continue;
1029 }
1030
Michal Vasko1e989c02015-08-04 12:33:00 +02001031 /* check for shorthand cases - then 'start' does not change */
1032 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1033 || (sibling->nodetype == LYS_CASE)) {
1034 start = sibling->child;
1035 }
1036 break;
1037 }
1038 }
1039
1040 /* we did not find the case in direct siblings */
1041 if (node_type == LYS_CHOICE) {
1042 return NULL;
1043 }
1044
1045 /* no match */
1046 if (!sibling) {
1047 /* on augment search also RPCs and notifications, if we are in top-level */
1048 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1049 /* we have searched all the data nodes */
1050 if (in_mod_part == 0) {
1051 if (!in_submod) {
1052 start = start_mod->rpc;
1053 } else {
1054 start = start_mod->inc[in_submod-1].submodule->rpc;
1055 }
1056 in_mod_part = 1;
1057 continue;
1058 }
1059 /* we have searched all the RPCs */
1060 if (in_mod_part == 1) {
1061 if (!in_submod) {
1062 start = start_mod->notif;
1063 } else {
1064 start = start_mod->inc[in_submod-1].submodule->notif;
1065 }
1066 in_mod_part = 2;
1067 continue;
1068 }
1069 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001070 }
1071
Michal Vasko1e989c02015-08-04 12:33:00 +02001072 /* are we done with the included submodules as well? */
1073 if (in_submod == start_mod->inc_size) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001074 return NULL;
1075 }
1076
Michal Vasko1e989c02015-08-04 12:33:00 +02001077 /* we aren't, check the next one */
1078 ++in_submod;
1079 in_mod_part = 0;
1080 start = start_mod->inc[in_submod-1].submodule->data;
1081 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001082 }
1083
1084 /* we found our submodule */
1085 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001086 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001087 in_submod = 0;
1088 }
1089
1090 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1091 return NULL;
1092 }
1093 id += ret;
1094 }
1095
1096 /* cannot get here */
1097 return NULL;
1098}
1099
Michal Vasko730dfdf2015-08-11 14:48:05 +02001100/**
1101 * @brief Resolve (find) a data node. Does not log.
1102 *
1103 * @param[in] prefix Prefix of the data node.
1104 * @param[in] pref_len Length of the prefix.
1105 * @param[in] name Name of the data node.
1106 * @param[in] nam_len Length of the name.
1107 * @param[in] data_source Data node that defines the prefix and the name,
1108 * to find the correct module.
1109 * @param[in,out] parents Resolved nodes. If there are some parents,
1110 * they are replaced (!!) with the resolvents.
1111 *
1112 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1113 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001114static int
1115resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int nam_len, struct lyd_node *data_source,
Michal Vaskof02e3742015-08-05 16:27:02 +02001116 struct unres_data **parents)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001117{
1118 int flag;
Radek Krejcib8048692015-08-05 13:36:34 +02001119 struct lys_module *mod;
Michal Vaskof02e3742015-08-05 16:27:02 +02001120 struct unres_data *item, *par_iter;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001121 struct lyd_node *node;
1122
1123 if (prefix) {
1124 /* we have prefix, find appropriate module */
1125 mod = resolve_prefixed_module(data_source->schema->module, prefix, pref_len);
1126 if (!mod) {
1127 /* invalid prefix */
Michal Vaskof02e3742015-08-05 16:27:02 +02001128 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001129 }
1130 } else {
1131 /* no prefix, module is the same as of current node */
1132 mod = data_source->schema->module;
1133 }
1134
1135 if (!*parents) {
1136 *parents = malloc(sizeof **parents);
1137 (*parents)->dnode = NULL;
1138 (*parents)->next = NULL;
1139 }
1140 for (par_iter = *parents; par_iter; par_iter = par_iter->next) {
Radek Krejci76512572015-08-04 09:47:08 +02001141 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001142 /* skip */
1143 continue;
1144 }
1145 flag = 0;
1146 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : data_source, node) {
1147 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1148 && node->schema->name[nam_len] == '\0') {
1149 /* matching target */
1150 if (!flag) {
1151 /* replace leafref instead of the current parent */
1152 par_iter->dnode = node;
1153 flag = 1;
1154 } else {
1155 /* multiple matching, so create new leafref structure */
1156 item = malloc(sizeof *item);
1157 item->dnode = node;
1158 item->next = par_iter->next;
1159 par_iter->next = item;
1160 par_iter = par_iter->next;
1161 }
1162 }
1163 }
1164 }
1165
1166 return !flag;
1167}
1168
Michal Vasko730dfdf2015-08-11 14:48:05 +02001169/**
1170 * @brief Resolve a path predicate (leafref) in data context. Logs directly.
1171 *
1172 * @param[in] pred Predicate in question.
1173 * @param[in,out] node_match Nodes satisfying the restriction
1174 * without the predicate. Nodes not
1175 * satisfying the predicate are removed.
1176 * @param[in] line Line in the input file.
1177 *
1178 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1179 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001180static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001181resolve_path_predicate_data(const char *pred, struct unres_data **node_match, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001182{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001183 /* ... /node[source = destination] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02001184 struct unres_data *source_match, *dest_match, *node, *node_prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001185 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
1186 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
1187 int has_predicate, dest_parent_times, i;
1188
1189 do {
1190 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
1191 &pke_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001192 LOGVAL(LYE_INCHAR, line, pred[-i], pred-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001193 return -parsed+i;
1194 }
1195 parsed += i;
1196 pred += i;
1197
1198 for (node = *node_match; node;) {
1199 /* source */
1200 source_match = NULL;
1201 /* must be leaf (key of a list) */
1202 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
1203 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +02001204 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001205 LOGVAL(LYE_LINE, line);
1206 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001207 return -parsed;
1208 }
1209
1210 /* destination */
1211 dest_match = calloc(1, sizeof *dest_match);
1212 dest_match->dnode = node->dnode;
1213 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
1214 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001215 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001216 return -parsed+i;
1217 }
1218 pke_parsed += i;
1219 for (i = 0; i < dest_parent_times; ++i) {
1220 dest_match->dnode = dest_match->dnode->parent;
1221 if (!dest_match->dnode) {
1222 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001223 LOGVAL(LYE_LINE, line);
1224 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001225 return -parsed;
1226 }
1227 }
1228 while (1) {
1229 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
Michal Vasko1f76a282015-08-04 16:16:53 +02001230 || !dest_match->dnode || dest_match->next) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001231 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001232 LOGVAL(LYE_LINE, line);
1233 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001234 return -parsed;
1235 }
1236
1237 if (pke_len == pke_parsed) {
1238 break;
1239 }
Michal Vasko1f76a282015-08-04 16:16:53 +02001240 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001241 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001242 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001243 return -parsed+i;
1244 }
1245 pke_parsed += i;
1246 }
1247
1248 /* check match between source and destination nodes */
Radek Krejcib8048692015-08-05 13:36:34 +02001249 if (((struct lys_node_leaf *)source_match->dnode->schema)->type.base
1250 != ((struct lys_node_leaf *)dest_match->dnode->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001251 goto remove_leafref;
1252 }
1253
1254 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
1255 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
1256 goto remove_leafref;
1257 }
1258
1259 /* leafref is ok, continue check with next leafref */
1260 node_prev = node;
1261 node = node->next;
1262 continue;
1263
1264remove_leafref:
1265 /* does not fulfill conditions, remove leafref record */
1266 if (node_prev) {
1267 node_prev->next = node->next;
1268 free(node);
1269 node = node_prev->next;
1270 } else {
1271 node = (*node_match)->next;
1272 free(*node_match);
1273 *node_match = node;
1274 }
1275 }
1276 } while (has_predicate);
1277
1278 return parsed;
1279}
1280
Michal Vasko730dfdf2015-08-11 14:48:05 +02001281/**
1282 * @brief Resolve a path (leafref) in data context. Logs directly.
1283 *
1284 * @param[in] unres Nodes matching the schema path.
1285 * @param[in] path Path in question.
1286 * @param[in,out] ret Matching nodes.
1287 *
1288 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1289 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001290int
Michal Vaskof02e3742015-08-05 16:27:02 +02001291resolve_path_arg_data(struct unres_data *unres, const char *path, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001292{
Radek Krejci71b795b2015-08-10 16:20:39 +02001293 struct lyd_node *data = NULL;
Michal Vaskof02e3742015-08-05 16:27:02 +02001294 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001295 const char *prefix, *name;
Michal Vasko1f76a282015-08-04 16:16:53 +02001296 int pref_len, nam_len, has_predicate, parent_times, i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001297
1298 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001299 parent_times = 0;
1300
1301 /* searching for nodeset */
1302 do {
1303 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001304 LOGVAL(LYE_INCHAR, unres->line, path[-i], path-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001305 goto error;
1306 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001307 path += i;
1308
1309 if (!*ret) {
1310 *ret = calloc(1, sizeof **ret);
1311 for (i = 0; i < parent_times; ++i) {
1312 /* relative path */
1313 if (!*ret) {
1314 /* error, too many .. */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001315 LOGVAL(LYE_INVAL, unres->line, path, unres->dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001316 goto error;
1317 } else if (!(*ret)->dnode) {
1318 /* first .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02001319 data = (*ret)->dnode = unres->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001320 } else if (!(*ret)->dnode->parent) {
1321 /* we are in root */
1322 free(*ret);
1323 *ret = NULL;
1324 } else {
1325 /* multiple .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02001326 data = (*ret)->dnode = (*ret)->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001327 }
1328 }
1329
1330 /* absolute path */
1331 if (parent_times == -1) {
1332 for (data = unres->dnode; data->parent; data = data->parent);
1333 for (; data->prev->next; data = data->prev);
1334 }
1335 }
1336
1337 /* node identifier */
1338 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001339 LOGVAL(LYE_INELEM_LEN, unres->line, nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001340 goto error;
1341 }
1342
1343 if (has_predicate) {
1344 /* we have predicate, so the current results must be lists */
1345 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001346 if (riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02001347 ((struct lys_node_list *)riter->dnode->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001348 /* leafref is ok, continue check with next leafref */
1349 raux = riter;
1350 riter = riter->next;
1351 continue;
1352 }
1353
1354 /* does not fulfill conditions, remove leafref record */
1355 if (raux) {
1356 raux->next = riter->next;
1357 free(riter);
1358 riter = raux->next;
1359 } else {
1360 *ret = riter->next;
1361 free(riter);
1362 riter = *ret;
1363 }
1364 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001365 if ((i = resolve_path_predicate_data(path, ret, unres->line)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001366 goto error;
1367 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001368 path += i;
1369
1370 if (!*ret) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001371 LOGVAL(LYE_LINE, unres->line);
1372 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001373 goto error;
1374 }
1375 }
1376 } while (path[0] != '\0');
1377
Michal Vaskof02e3742015-08-05 16:27:02 +02001378 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001379
1380error:
1381
1382 while (*ret) {
1383 raux = (*ret)->next;
1384 free(*ret);
1385 *ret = raux;
1386 }
1387
Michal Vaskof02e3742015-08-05 16:27:02 +02001388 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001389}
1390
Michal Vasko730dfdf2015-08-11 14:48:05 +02001391/**
1392 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
1393 *
1394 * @param[in] path Path in question.
1395 * @param[in] mod Schema module.
1396 * @param[in] source_node Left operand node.
1397 * @param[in] dest_node Right ooperand node.
1398 * @param[in] line Line in the input file.
1399 *
1400 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1401 */
Michal Vasko1f76a282015-08-04 16:16:53 +02001402static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02001403resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02001404 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02001405{
1406 struct lys_node *src_node, *dst_node;
1407 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
1408 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
1409 int has_predicate, dest_parent_times = 0, i;
1410
1411 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02001412 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02001413 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02001414 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02001415 return -parsed+i;
1416 }
1417 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02001418 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02001419
1420 /* source (must be leaf, from the same module) */
1421 if (sour_pref && (resolve_prefixed_module(mod, sour_pref, sour_pref_len) != mod)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001422 LOGVAL(LYE_INPREF_LEN, line, sour_pref_len, sour_pref);
Michal Vasko1f76a282015-08-04 16:16:53 +02001423 return -parsed;
1424 }
1425
1426 src_node = resolve_child(source_node, source, sour_len, LYS_LEAF);
1427 if (!src_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001428 LOGVAL(LYE_LINE, line);
1429 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02001430 return -parsed;
1431 }
1432
1433 /* destination */
1434 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
1435 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001436 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02001437 return -parsed;
1438 }
1439 pke_parsed += i;
1440
1441 /* dest_node is actually the parent of this leaf, so skip the first ".." */
1442 dst_node = dest_node;
1443 for (i = 1; i < dest_parent_times; ++i) {
1444 dst_node = dst_node->parent;
1445 if (!dst_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001446 LOGVAL(LYE_LINE, line);
1447 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02001448 return -parsed;
1449 }
1450 }
1451 while (1) {
1452 if (dest_pref && (resolve_prefixed_module(mod, dest_pref, dest_pref_len) != mod)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001453 LOGVAL(LYE_INPREF_LEN, line, dest_pref_len, dest_pref);
Michal Vasko1f76a282015-08-04 16:16:53 +02001454 return -parsed;
1455 }
1456 dst_node = resolve_child(dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF);
1457 if (!dst_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001458 LOGVAL(LYE_LINE, line);
1459 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02001460 return -parsed;
1461 }
1462
1463 if (pke_len == pke_parsed) {
1464 break;
1465 }
1466
1467 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
1468 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001469 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02001470 return -parsed;
1471 }
1472 pke_parsed += i;
1473 }
1474
1475 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02001476 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
1477 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001478 LOGVAL(LYE_LINE, line);
1479 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02001480 return -parsed;
1481 }
1482 } while (has_predicate);
1483
1484 return parsed;
1485}
1486
Michal Vasko730dfdf2015-08-11 14:48:05 +02001487/**
1488 * @brief Resolve a path (leafref) in schema context. Logs indirectly.
1489 *
1490 * @param[in] mod Module in question.
1491 * @param[in] path Path in question.
1492 * @param[in] parent_node Parent of the leafref.
1493 * @param[in] line Line in the input file.
1494 *
1495 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1496 */
Michal Vaskoa5c4ad62015-08-11 14:59:43 +02001497static struct lys_node*
Michal Vaskof02e3742015-08-05 16:27:02 +02001498resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02001499{
1500 struct lys_node *child, *node;
1501 const char *id, *prefix, *name;
1502 int pref_len, nam_len, parent_times, has_predicate;
1503 int i, first;
1504
1505 first = 1;
1506 parent_times = 0;
1507 id = path;
1508
1509 do {
1510 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001511 LOGVAL(LYE_INCHAR, line, id[-i], id-i);
Radek Krejcib1c12512015-08-11 11:22:04 +02001512 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02001513 }
1514 id += i;
1515
1516 if (first) {
1517 if (parent_times == -1) {
1518 node = mod->data;
1519 } else if (parent_times > 0) {
1520 node = parent_node;
Michal Vasko73ae2562015-08-06 11:58:13 +02001521 /* node is the parent already, skip one ".." */
1522 for (i = 1; i < parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02001523 node = node->parent;
1524 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001525 LOGVAL(LYE_LINE, line);
1526 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02001527 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02001528 }
1529 }
1530 node = node->child;
1531 }
1532 first = 0;
1533 } else {
1534 node = node->child;
1535 }
1536
1537 /* node identifier */
1538 LY_TREE_FOR(node, child) {
1539 if (child->nodetype == LYS_GROUPING) {
1540 continue;
1541 }
1542
1543 if (!strncmp(child->name, name, nam_len) && !child->name[nam_len]) {
1544 break;
1545 }
1546 }
1547 if (!child) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001548 LOGVAL(LYE_LINE, line);
1549 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02001550 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02001551 }
1552 node = child;
1553
1554 if (has_predicate) {
1555 /* we have predicate, so the current result must be list */
1556 if (node->nodetype != LYS_LIST) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001557 LOGVAL(LYE_LINE, line);
1558 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02001559 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02001560 }
1561
1562 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Radek Krejcib1c12512015-08-11 11:22:04 +02001563 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02001564 }
1565 id += i;
1566 }
1567 } while (id[0]);
1568
Radek Krejcib1c12512015-08-11 11:22:04 +02001569 /* the target must be leaf or leaf-list */
1570 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
1571 LOGVAL(LYE_LINE, line);
1572 /* general error, the one written later will suffice */
1573 return NULL;
1574 }
1575
1576 return node;
Michal Vasko1f76a282015-08-04 16:16:53 +02001577}
1578
Michal Vasko730dfdf2015-08-11 14:48:05 +02001579/**
1580 * @brief Resolve instance-identifier predicate. Does not log.
1581 *
1582 * @param[in] pred Predicate in question.
1583 * @param[in,out] node_match Nodes matching the restriction without
1584 * the predicate. Nodes not satisfying
1585 * the predicate are removed.
1586 *
1587 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1588 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001589static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001590resolve_predicate(const char *pred, struct unres_data **node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001591{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001592 /* ... /node[target = value] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02001593 struct unres_data *target_match, *node, *node_prev = NULL, *tmp;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001594 const char *prefix, *name, *value;
1595 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
1596
1597 idx = -1;
1598 parsed = 0;
1599
1600 do {
1601 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
1602 return -parsed+i;
1603 }
1604 parsed += i;
1605 pred += i;
1606
1607 if (isdigit(name[0])) {
1608 idx = atoi(name);
1609 }
1610
1611 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
1612 /* target */
1613 target_match = NULL;
1614 if ((name[0] == '.') || !value) {
1615 target_match = calloc(1, sizeof *target_match);
1616 target_match->dnode = node->dnode;
1617 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
1618 return -parsed;
1619 }
1620
1621 /* check that we have the correct type */
1622 if (name[0] == '.') {
Radek Krejci76512572015-08-04 09:47:08 +02001623 if (node->dnode->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001624 goto remove_instid;
1625 }
1626 } else if (value) {
Radek Krejci76512572015-08-04 09:47:08 +02001627 if (node->dnode->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001628 goto remove_instid;
1629 }
1630 }
1631
1632 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
1633 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
1634 || (!value && (idx != cur_idx))) {
1635 goto remove_instid;
1636 }
1637
1638 while (target_match) {
1639 tmp = target_match->next;
1640 free(target_match);
1641 target_match = tmp;
1642 }
1643
1644 /* leafref is ok, continue check with next leafref */
1645 node_prev = node;
1646 node = node->next;
1647 continue;
1648
1649remove_instid:
1650 while (target_match) {
1651 tmp = target_match->next;
1652 free(target_match);
1653 target_match = tmp;
1654 }
1655
1656 /* does not fulfill conditions, remove leafref record */
1657 if (node_prev) {
1658 node_prev->next = node->next;
1659 free(node);
1660 node = node_prev->next;
1661 } else {
1662 node = (*node_match)->next;
1663 free(*node_match);
1664 *node_match = node;
1665 }
1666 }
1667 } while (has_predicate);
1668
1669 return parsed;
1670}
1671
Michal Vasko730dfdf2015-08-11 14:48:05 +02001672/**
1673 * @brief Resolve instance-identifier. Logs directly.
1674 *
1675 * @param[in] unres Node of the instance-id type.
1676 * @param[in] path Instance-identifier node value.
1677 * @param[in] path_len Path length.
1678 * @param[in,out] ret Matching nodes.
1679 *
1680 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1681 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001682int
Michal Vaskof02e3742015-08-05 16:27:02 +02001683resolve_instid(struct unres_data *unres, const char *path, int path_len, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001684{
1685 struct lyd_node *data;
Michal Vaskof02e3742015-08-05 16:27:02 +02001686 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001687 const char *apath = strndupa(path, path_len);
1688 const char *prefix, *name;
1689 int i, parsed, pref_len, nam_len, has_predicate;
1690
1691 parsed = 0;
1692
1693 /* we need root, absolute path */
1694 for (data = unres->dnode; data->parent; data = data->parent);
1695 for (; data->prev->next; data = data->prev);
1696
1697 /* searching for nodeset */
1698 do {
1699 if ((i = parse_instance_identifier(apath, &prefix, &pref_len, &name, &nam_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001700 LOGVAL(LYE_INCHAR, unres->line, apath[-i], apath-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001701 goto error;
1702 }
1703 parsed += i;
1704 apath += i;
1705
1706 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001707 LOGVAL(LYE_LINE, unres->line);
1708 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001709 goto error;
1710 }
1711
1712 if (has_predicate) {
1713 /* we have predicate, so the current results must be list or leaf-list */
1714 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001715 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02001716 ((struct lys_node_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +02001717 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001718 /* instid is ok, continue check with next instid */
1719 raux = riter;
1720 riter = riter->next;
1721 continue;
1722 }
1723
1724 /* does not fulfill conditions, remove inst record */
1725 if (raux) {
1726 raux->next = riter->next;
1727 free(riter);
1728 riter = raux->next;
1729 } else {
1730 *ret = riter->next;
1731 free(riter);
1732 riter = *ret;
1733 }
1734 }
1735 if ((i = resolve_predicate(apath, ret)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001736 LOGVAL(LYE_INPRED, unres->line, apath-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001737 goto error;
1738 }
1739 parsed += i;
1740 apath += i;
1741
1742 if (!*ret) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001743 LOGVAL(LYE_LINE, unres->line);
1744 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001745 goto error;
1746 }
1747 }
1748 } while (apath[0] != '\0');
1749
Michal Vaskof02e3742015-08-05 16:27:02 +02001750 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001751
1752error:
1753 while (*ret) {
1754 raux = (*ret)->next;
1755 free(*ret);
1756 *ret = raux;
1757 }
1758
Michal Vaskof02e3742015-08-05 16:27:02 +02001759 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001760}
1761
Michal Vasko730dfdf2015-08-11 14:48:05 +02001762/**
1763 * @brief Passes config flag down to children. Does not log.
1764 *
1765 * @param[in] node Parent node.
1766 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001767static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02001768inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001769{
Radek Krejci1d82ef62015-08-07 14:44:40 +02001770 LY_TREE_FOR(node, node) {
1771 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
1772 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001773 }
1774}
1775
Michal Vasko730dfdf2015-08-11 14:48:05 +02001776/**
1777 * @brief Resolve augment target, Does not log.
1778 *
1779 * @param[in] aug Augment in question.
1780 * @param[in] siblings Nodes where to start the search in.
1781 * @param[in] module Main module.
1782 *
1783 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1784 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02001785int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001786resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001787{
Radek Krejci76512572015-08-04 09:47:08 +02001788 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001789
1790 assert(module);
1791
1792 /* resolve target node */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001793 aug->target = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001794 if (!aug->target) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001795 return EXIT_FAILURE;
1796 }
1797
1798 if (!aug->child) {
1799 /* nothing to do */
1800 return EXIT_SUCCESS;
1801 }
1802
1803 /* inherit config information from parent, augment does not have
1804 * config property, but we need to keep the information for subelements
1805 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001806 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001807 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001808 inherit_config_flag(sub);
1809 }
1810
Radek Krejci0acbe1b2015-08-04 09:33:49 +02001811 /* reconnect augmenting data into the target - add them to the target child list */
1812 if (aug->target->child) {
1813 aux = aug->target->child->prev; /* remember current target's last node */
1814 aux->next = aug->child; /* connect augmenting data after target's last node */
1815 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
1816 aug->child->prev = aux; /* finish connecting of both child lists */
1817 } else {
1818 aug->target->child = aug->child;
1819 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001820
1821 return EXIT_SUCCESS;
1822}
1823
Michal Vasko730dfdf2015-08-11 14:48:05 +02001824/**
1825 * @brief Resolve uses, apply augments, refines. Logs directly.
1826 *
1827 * @param[in] uses Uses in question.
1828 * @param[in,out] unres List of unresolved items.
1829 * @param[in] line Line in the input file.
1830 *
1831 * @return EXIT_SUCCESS on success, EXIT_FAILURER otherwise.
1832 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001833int
Michal Vaskof02e3742015-08-05 16:27:02 +02001834resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001835{
1836 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02001837 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02001838 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001839 struct lys_restr *newmust;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001840 int i, j;
1841 uint8_t size;
1842
1843 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001844 LY_TREE_FOR(uses->grp->child, node) {
1845 node_aux = lys_node_dup(uses->module, node, uses->flags, 1, unres);
1846 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001847 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001848 return EXIT_FAILURE;
1849 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02001850 if (lys_node_addchild((struct lys_node *)uses, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001851 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001852 lys_node_free(node_aux);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001853 return EXIT_FAILURE;
1854 }
1855 }
1856 ctx = uses->module->ctx;
1857
1858 /* apply refines */
1859 for (i = 0; i < uses->refine_size; i++) {
1860 rfn = &uses->refine[i];
Radek Krejci1d82ef62015-08-07 14:44:40 +02001861 node = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF);
1862 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001863 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001864 return EXIT_FAILURE;
1865 }
1866
Radek Krejci1d82ef62015-08-07 14:44:40 +02001867 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001868 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001869 return EXIT_FAILURE;
1870 }
1871
1872 /* description on any nodetype */
1873 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001874 lydict_remove(ctx, node->dsc);
1875 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001876 }
1877
1878 /* reference on any nodetype */
1879 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001880 lydict_remove(ctx, node->ref);
1881 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001882 }
1883
1884 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001885 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001886 node->flags &= ~LYS_CONFIG_MASK;
1887 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001888 }
1889
1890 /* default value ... */
1891 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001892 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001893 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001894 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
1895 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
1896 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001897 /* choice */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001898 ((struct lys_node_choice *)node)->dflt = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE);
1899 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001900 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001901 return EXIT_FAILURE;
1902 }
1903 }
1904 }
1905
1906 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001907 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001908 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001909 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001910 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001911
1912 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001913 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001914 }
1915 }
1916
1917 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001918 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
1919 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
1920 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001921 }
1922
1923 /* min/max-elements on list or leaf-list */
1924 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02001925 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001926 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001927 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001928 }
1929 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001930 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001931 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02001932 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001933 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001934 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001935 }
1936 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001937 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001938 }
1939 }
1940
1941 /* must in leaf, leaf-list, list, container or anyxml */
1942 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02001943 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
1944 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001945 if (!newmust) {
1946 LOGMEM;
1947 return EXIT_FAILURE;
1948 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02001949 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001950 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
1951 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
1952 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
1953 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
1954 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
1955 }
1956
Radek Krejci1d82ef62015-08-07 14:44:40 +02001957 ((struct lys_node_leaf *)node)->must = newmust;
1958 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001959 }
1960 }
1961
1962 /* apply augments */
1963 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001964 if (resolve_augment(&uses->augment[i], uses->child, uses->module)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001965 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
1966 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001967 }
1968 }
1969
1970 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001971}
1972
Michal Vasko730dfdf2015-08-11 14:48:05 +02001973/**
1974 * @brief Resolve base identity recursively. Does not log.
1975 *
1976 * @param[in] module Main module.
1977 * @param[in] ident Identity in question.
1978 * @param[in] basename Base name of the identity.
1979 *
1980 * @return Pointer to the identity, NULL on error.
1981 */
Radek Krejcia52656e2015-08-05 13:41:50 +02001982static struct lys_ident *
1983resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001984{
Michal Vaskof02e3742015-08-05 16:27:02 +02001985 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02001986 struct lys_ident *base_iter = NULL;
1987 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001988
1989 /* search module */
1990 for (i = 0; i < module->ident_size; i++) {
1991 if (!strcmp(basename, module->ident[i].name)) {
1992
1993 if (!ident) {
1994 /* just search for type, so do not modify anything, just return
1995 * the base identity pointer
1996 */
1997 return &module->ident[i];
1998 }
1999
2000 /* we are resolving identity definition, so now update structures */
2001 ident->base = base_iter = &module->ident[i];
2002
2003 break;
2004 }
2005 }
2006
2007 /* search submodules */
2008 if (!base_iter) {
2009 for (j = 0; j < module->inc_size; j++) {
2010 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2011 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2012
2013 if (!ident) {
2014 return &module->inc[j].submodule->ident[i];
2015 }
2016
2017 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2018 break;
2019 }
2020 }
2021 }
2022 }
2023
2024 /* we found it somewhere */
2025 if (base_iter) {
2026 while (base_iter) {
2027 for (der = base_iter->der; der && der->next; der = der->next);
2028 if (der) {
2029 der->next = malloc(sizeof *der);
2030 der = der->next;
2031 } else {
2032 ident->base->der = der = malloc(sizeof *der);
2033 }
2034 der->next = NULL;
2035 der->ident = ident;
2036
2037 base_iter = base_iter->base;
2038 }
2039 return ident->base;
2040 }
2041
2042 return NULL;
2043}
2044
Michal Vasko730dfdf2015-08-11 14:48:05 +02002045/**
2046 * @brief Resolve base identity. Logs directly.
2047 *
2048 * @param[in] module Main module.
2049 * @param[in] ident Identity in question.
2050 * @param[in] basename Base name of the identity.
2051 * @param[in] parent Either "type" or "ident".
2052 * @param[in] line Line in the input file.
2053 *
2054 * @return Pointer to the base identity, NULL on error.
2055 */
Radek Krejcia52656e2015-08-05 13:41:50 +02002056static struct lys_ident *
Michal Vaskof02e3742015-08-05 16:27:02 +02002057resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
2058 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002059{
2060 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02002061 int i, prefix_len = 0;
Radek Krejcia52656e2015-08-05 13:41:50 +02002062 struct lys_ident *result;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002063
2064 /* search for the base identity */
2065 name = strchr(basename, ':');
2066 if (name) {
2067 /* set name to correct position after colon */
2068 prefix_len = name - basename;
2069 name++;
2070
2071 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
2072 /* prefix refers to the current module, ignore it */
2073 prefix_len = 0;
2074 }
2075 } else {
2076 name = basename;
2077 }
2078
2079 if (prefix_len) {
2080 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002081 module = resolve_prefixed_module(module, basename, prefix_len);
2082 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002083 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002084 LOGVAL(LYE_INPREF, line, basename);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002085 return NULL;
2086 }
2087 } else {
2088 /* search in submodules */
2089 for (i = 0; i < module->inc_size; i++) {
Radek Krejcib8048692015-08-05 13:36:34 +02002090 result = resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002091 if (result) {
2092 return result;
2093 }
2094 }
2095 }
2096
2097 /* search in the identified module */
2098 result = resolve_base_ident_sub(module, ident, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002099 if (!result) {
2100 LOGVAL(LYE_INARG, line, basename, parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101 }
2102
2103 return result;
2104}
2105
Michal Vasko730dfdf2015-08-11 14:48:05 +02002106/**
2107 * @brief Resolve identityref. Does not log.
2108 *
2109 * @param[in] base Base identity.
2110 * @param[in] name Identityref name.
2111 * @param[in] ns Namespace of the identityref.
2112 *
2113 * @return Pointer to the identity resolvent, NULL on error.
2114 */
Radek Krejcia52656e2015-08-05 13:41:50 +02002115struct lys_ident *
2116resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002117{
Radek Krejcia52656e2015-08-05 13:41:50 +02002118 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002119
2120 if (!base || !name || !ns) {
2121 return NULL;
2122 }
2123
2124 for(der = base->der; der; der = der->next) {
2125 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
2126 /* we have match */
2127 return der->ident;
2128 }
2129 }
2130
2131 /* not found */
2132 return NULL;
2133}
2134
Michal Vasko730dfdf2015-08-11 14:48:05 +02002135/**
2136 * @brief Resolve unres identity. Logs directly.
2137 *
2138 * @param[in] mod Main module.
2139 * @param[in] ident Identity in question.
2140 * @param[in] base_name Base name of the identity.
2141 * @param[in] line Line in the input file.
2142 *
2143 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2144 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002145static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002146resolve_unres_ident(struct lys_module *mod, struct lys_ident *ident, const char *base_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002147{
Michal Vaskof02e3742015-08-05 16:27:02 +02002148 if (resolve_base_ident(mod, ident, base_name, "ident", line)) {
2149 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002150 }
2151
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002152 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identity", base_name);
2153 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002154}
2155
Michal Vasko730dfdf2015-08-11 14:48:05 +02002156/**
2157 * @brief Resolve unres identityref. Logs directly.
2158 *
2159 * @param[in] mod Main module.
2160 * @param[in] type Type in question.
2161 * @param[in] base_name Base name of the identity.
2162 * @param[in] line Line in the input file.
2163 *
2164 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2165 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002167resolve_unres_type_identref(struct lys_module *mod, struct lys_type *type, const char *base_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002168{
Michal Vaskof02e3742015-08-05 16:27:02 +02002169 type->info.ident.ref = resolve_base_ident(mod, NULL, base_name, "type", line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002170 if (type->info.ident.ref) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002171 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002172 }
2173
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002174 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identityref", base_name);
2175 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002176}
2177
Michal Vasko730dfdf2015-08-11 14:48:05 +02002178/**
2179 * @brief Resolve unres leafref. Logs directly.
2180 *
2181 * @param[in] mod Main module.
2182 * @param[in] type Type in question.
2183 * @param[in] node Leafref schema node.
2184 * @param[in] line Line in the input file.
2185 *
2186 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2187 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002188static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002189resolve_unres_type_leafref(struct lys_module *mod, struct lys_type *type, struct lys_node *node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002190{
Radek Krejcib1c12512015-08-11 11:22:04 +02002191 type->info.lref.target = (struct lys_node_leaf *)resolve_path_arg_schema(mod, type->info.lref.path, node, line);
2192 if (type->info.lref.target) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002193 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002194 }
2195
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002196 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "leafref", type->info.lref.path);
2197 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002198}
2199
Michal Vasko730dfdf2015-08-11 14:48:05 +02002200/**
2201 * @brief Resolve unres derived type. Logs directly.
2202 *
2203 * @param[in] mod Main module.
2204 * @param[in] type Type in question.
2205 * @param[in] type_name Derived type name,
2206 * @param[in] line Line in the input file.
2207 *
2208 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2209 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002210static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002211resolve_unres_type_der(struct lys_module *mod, struct lys_type *type, const char *type_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002212{
Radek Krejci76512572015-08-04 09:47:08 +02002213 type->der = resolve_superior_type(type_name, type->prefix, mod, (struct lys_node *)type->der);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002214 if (type->der) {
Michal Vaskoa91333d2015-08-03 16:03:06 +02002215 type->base = type->der->type.base;
Michal Vaskof02e3742015-08-05 16:27:02 +02002216 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002217 }
2218
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002219 LOGVAL(LYE_INRESOLV, line, "type", type_name);
2220 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002221}
2222
Michal Vasko730dfdf2015-08-11 14:48:05 +02002223/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002224 * @brief Resolve unres if-feature. Logs directly.
2225 *
2226 * @param[in] mod Main module.
2227 * @param[in,out] feat_ptr Pointer to the resolved feature.
2228 * @param[in] feat_name Name of the feature.
2229 * @param[in] line Line in the input file.
2230 *
2231 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2232 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002233static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002234resolve_unres_iffeature(struct lys_module *mod, struct lys_feature **feat_ptr, const char *feat_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002235{
Michal Vaskof02e3742015-08-05 16:27:02 +02002236 *feat_ptr = resolve_feature(feat_name, mod, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002237 if (*feat_ptr) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002238 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002239 }
2240
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002241 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "if-feature", feat_name);
2242 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002243}
2244
Michal Vasko730dfdf2015-08-11 14:48:05 +02002245/**
2246 * @brief Resolve unres uses. Logs directly.
2247 *
2248 * @param[in] uses Uses in question.
2249 * @param[in] unres Specific unres item.
2250 * @param[in] line Line in the input file.
2251 *
2252 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2253 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002254static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002255resolve_unres_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002256{
Michal Vaskof02e3742015-08-05 16:27:02 +02002257 if (uses->grp || !resolve_grouping(uses->parent, uses, line)) {
2258 if (!resolve_uses(uses, unres, line)) {
2259 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02002260 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002261 }
2262
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002263 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "uses", uses->name);
2264 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002265}
2266
Michal Vasko730dfdf2015-08-11 14:48:05 +02002267/**
2268 * @brief Resolve unres identity. Logs directly.
2269 *
2270 * @param[in] type Type in question.
2271 * @param[in] dflt Default value.
2272 * @param[in] line Line in the input file.
2273 *
2274 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2275 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002276static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002277resolve_unres_type_dflt(struct lys_type *type, const char *dflt, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002278{
Michal Vasko12e30842015-08-04 11:54:00 +02002279 if (!check_default(type, dflt)) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002280 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02002281 }
2282
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002283 LOGVAL(LYE_INRESOLV, line, "type default", dflt);
2284 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002285}
2286
Michal Vasko730dfdf2015-08-11 14:48:05 +02002287/**
2288 * @brief Resolve choice default. Logs directly.
2289 *
2290 * @param[in] choice Main module.
2291 * @param[in] dflt Default case name.
2292 * @param[in] line Line in the input file.
2293 *
2294 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2295 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002296static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002297resolve_unres_choice_dflt(struct lys_node_choice *choice, const char *dflt, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002298{
Michal Vasko1f76a282015-08-04 16:16:53 +02002299 choice->dflt = resolve_child((struct lys_node *)choice, dflt, strlen(dflt), LYS_ANYXML | LYS_CASE
Radek Krejci76512572015-08-04 09:47:08 +02002300 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002301 if (choice->dflt) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002302 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002303 }
2304
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002305 LOGVAL(LYE_INRESOLV, line, "choice default", dflt);
2306 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002307}
2308
Michal Vasko730dfdf2015-08-11 14:48:05 +02002309/**
2310 * @brief Resolve unres identity. Logs directly.
2311 *
2312 * @param[in] list List in question.
2313 * @param[in] keys_str Keys node value.
2314 * @param[in] line Line in the input file.
2315 *
2316 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2317 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002318static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002319resolve_unres_list_keys(struct lys_node_list *list, const char *keys_str, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002320{
2321 int i, len;
2322 const char *value;
2323
2324 for (i = 0; i < list->keys_size; ++i) {
2325 /* get the key name */
2326 if ((value = strpbrk(keys_str, " \t\n"))) {
2327 len = value - keys_str;
2328 while (isspace(value[0])) {
2329 value++;
2330 }
2331 } else {
2332 len = strlen(keys_str);
2333 }
2334
Radek Krejcib8048692015-08-05 13:36:34 +02002335 list->keys[i] = (struct lys_node_leaf *)resolve_child((struct lys_node *)list, keys_str, len, LYS_LEAF);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002336
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002337 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
2338 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
2339 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002340 }
2341
2342 /* prepare for next iteration */
2343 while (value && isspace(value[0])) {
2344 value++;
2345 }
2346 keys_str = value;
2347 }
2348
Michal Vaskof02e3742015-08-05 16:27:02 +02002349 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002350}
2351
Michal Vasko730dfdf2015-08-11 14:48:05 +02002352/**
2353 * @brief Resolve unres unique. Logs directly.
2354 *
2355 * @param[in] uniq Unique in question.
2356 * @param[in] uniq_str Unique node value.
2357 * @param[in] line Line in the input file.
2358 *
2359 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
2360 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002361static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002362resolve_unres_list_uniq(struct lys_unique *uniq, const char *uniq_str, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002363{
Michal Vaskof02e3742015-08-05 16:27:02 +02002364 if (!resolve_unique((struct lys_node *)uniq->leafs, uniq_str, uniq, line)) {
2365 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02002366 }
2367
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002368 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list unique", uniq_str);
2369 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002370}
2371
2372static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002373resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002374{
2375 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02002376 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002377}
2378
2379static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002380resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002381{
2382 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02002383 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002384}
2385
Michal Vaskof02e3742015-08-05 16:27:02 +02002386/* logs indirectly
2387 * line == -1 means do not log, 0 means unknown */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002388static int
Radek Krejci1d82ef62015-08-07 14:44:40 +02002389resolve_unres_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_node, struct unres_schema *unres,
Michal Vaskof02e3742015-08-05 16:27:02 +02002390 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002391{
2392 int ret = EXIT_FAILURE, has_str = 0;
2393
2394 switch (type) {
2395 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002396 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02002397 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002398 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002399 ret = resolve_unres_ident(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002400 has_str = 1;
2401 break;
2402 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002403 ret = resolve_unres_type_identref(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002404 has_str = 1;
2405 break;
2406 case UNRES_TYPE_LEAFREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002407 ret = resolve_unres_type_leafref(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002408 has_str = 0;
2409 break;
2410 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002411 ret = resolve_unres_type_der(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002412 has_str = 1;
2413 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002414 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002415 ret = resolve_unres_iffeature(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002416 has_str = 1;
2417 break;
2418 case UNRES_USES:
Michal Vaskof02e3742015-08-05 16:27:02 +02002419 ret = resolve_unres_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002420 has_str = 0;
2421 break;
2422 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002423 ret = resolve_unres_type_dflt(item, str_node, line);
2424 /* do not remove str_node (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002425 has_str = 0;
2426 break;
2427 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002428 ret = resolve_unres_choice_dflt(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002429 has_str = 1;
2430 break;
2431 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002432 ret = resolve_unres_list_keys(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002433 has_str = 1;
2434 break;
2435 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002436 ret = resolve_unres_list_uniq(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002437 has_str = 1;
2438 break;
2439 case UNRES_WHEN:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002440 ret = resolve_unres_when(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002441 has_str = 0;
2442 break;
2443 case UNRES_MUST:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002444 ret = resolve_unres_must(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002445 has_str = 0;
2446 break;
2447 }
2448
2449 if (has_str && !ret) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002450 lydict_remove(mod->ctx, str_node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002451 }
2452
2453 return ret;
2454}
2455
Michal Vaskof02e3742015-08-05 16:27:02 +02002456/* logs directly */
2457static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002458print_unres_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002459{
Michal Vaskof02e3742015-08-05 16:27:02 +02002460 char line_str[18];
2461
2462 if (line) {
2463 sprintf(line_str, " (line %u)", line);
2464 } else {
2465 line_str[0] = '\0';
2466 }
2467
2468 switch (type) {
2469 case UNRES_RESOLVED:
2470 LOGINT;
2471 break;
2472 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002473 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002474 break;
2475 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002476 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002477 break;
2478 case UNRES_TYPE_LEAFREF:
2479 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
2480 break;
2481 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002482 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002483 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02002484 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002485 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "if-feature", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002486 break;
2487 case UNRES_USES:
2488 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
2489 break;
2490 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002491 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "type default", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002492 break;
2493 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002494 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "choice default", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002495 break;
2496 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002497 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list keys", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002498 break;
2499 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02002500 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list unique", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02002501 break;
2502 case UNRES_WHEN:
2503 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
2504 break;
2505 case UNRES_MUST:
2506 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
2507 break;
2508 }
2509}
2510
2511/* logs indirectly */
2512int
2513resolve_unres(struct lys_module *mod, struct unres_schema *unres)
2514{
2515 uint32_t i, resolved = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002516
2517 assert(unres);
2518
2519 /* uses */
2520 for (i = 0; i < unres->count; ++i) {
2521 if (unres->type[i] != UNRES_USES) {
2522 continue;
2523 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002524 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, unres->line[i])) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002525 unres->type[i] = UNRES_RESOLVED;
2526 ++resolved;
2527 }
2528 }
2529
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002530 /* the rest */
2531 for (i = 0; i < unres->count; ++i) {
2532 if (unres->type[i] == UNRES_RESOLVED) {
2533 continue;
2534 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002535 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, unres->line[i])) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002536 unres->type[i] = UNRES_RESOLVED;
2537 ++resolved;
2538 }
2539 }
2540
2541 if (resolved < unres->count) {
2542 return EXIT_FAILURE;
2543 }
2544
2545 return EXIT_SUCCESS;
2546}
2547
Michal Vaskof02e3742015-08-05 16:27:02 +02002548/* logs indirectly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002549void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002550unres_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, const char *str,
Michal Vaskof02e3742015-08-05 16:27:02 +02002551 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002552{
2553 str = lydict_insert(mod->ctx, str, 0);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002554 unres_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002555}
2556
Michal Vaskof02e3742015-08-05 16:27:02 +02002557/* logs indirectly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002558void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002559unres_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
2560 struct lys_node *node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561{
2562 assert(unres && item);
2563
Radek Krejci1d82ef62015-08-07 14:44:40 +02002564 if (!resolve_unres_item(mod, item, type, node, unres, UINT_MAX)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002565 return;
2566 }
2567
Radek Krejci1d82ef62015-08-07 14:44:40 +02002568 print_unres_item_fail(item, type, node, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02002569
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002570 unres->count++;
2571 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
2572 unres->item[unres->count-1] = item;
2573 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
2574 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002575 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
2576 unres->str_snode[unres->count-1] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002577 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
2578 unres->line[unres->count-1] = line;
2579}
2580
Michal Vaskof02e3742015-08-05 16:27:02 +02002581/* logs indirectly */
Michal Vaskodad19402015-08-06 09:51:53 +02002582int
Radek Krejci1d82ef62015-08-07 14:44:40 +02002583unres_dup(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, void *new_item)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002584{
2585 int i;
2586
2587 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02002588 LOGINT;
2589 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002590 }
2591
Radek Krejci1d82ef62015-08-07 14:44:40 +02002592 i = unres_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593
2594 if (i == -1) {
Michal Vaskodad19402015-08-06 09:51:53 +02002595 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002596 }
2597
Michal Vasko4adc10f2015-08-11 15:26:17 +02002598 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002599 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002600 unres_add_node(mod, unres, new_item, type, unres->str_snode[i], 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002601 } else {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002602 unres_add_str(mod, unres, new_item, type, unres->str_snode[i], 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002603 }
Michal Vaskodad19402015-08-06 09:51:53 +02002604
2605 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002606}
2607
Michal Vaskof02e3742015-08-05 16:27:02 +02002608/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002609int
Radek Krejci1d82ef62015-08-07 14:44:40 +02002610unres_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002611{
2612 uint32_t ret = -1, i;
2613
2614 for (i = 0; i < unres->count; ++i) {
2615 if ((unres->item[i] == item) && (unres->type[i] == type)) {
2616 ret = i;
2617 break;
2618 }
2619 }
2620
2621 return ret;
2622}