blob: 47100b92d8eabfaf1cfd59de5c6820ba825b1433 [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"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020033#include "dict.h"
34#include "tree_internal.h"
35
Michal Vasko730dfdf2015-08-11 14:48:05 +020036/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020037 * @brief Parse an identifier.
38 *
39 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
40 * identifier = (ALPHA / "_")
41 * *(ALPHA / DIGIT / "_" / "-" / ".")
42 *
43 * @param[in] id Identifier in question.
44 *
45 * @return Number of characters successfully parsed.
46 */
47static int
48parse_identifier(const char *id)
49{
50 int parsed = 0;
51
52 if (((id[0] == 'x') || (id[0] == 'X'))
53 && ((id[1] == 'm') || (id[0] == 'M'))
54 && ((id[2] == 'l') || (id[2] == 'L'))) {
55 return -parsed;
56 }
57
58 if (!isalpha(id[0]) && (id[0] != '_')) {
59 return -parsed;
60 }
61
62 ++parsed;
63 ++id;
64
65 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
66 ++parsed;
67 ++id;
68 }
69
70 return parsed;
71}
72
73/**
74 * @brief Parse a node-identifier.
75 *
76 * node-identifier = [prefix ":"] identifier
77 *
78 * @param[in] id Identifier in question.
79 * @param[out] prefix Points to the prefix, NULL if there is not any.
80 * @param[out] pref_len Length of the prefix, 0 if there is not any.
81 * @param[out] name Points to the node name.
82 * @param[out] nam_len Length of the node name.
83 *
84 * @return Number of characters successfully parsed,
85 * positive on success, negative on failure.
86 */
87static int
88parse_node_identifier(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len)
89{
90 int parsed = 0, ret;
91
92 assert(id);
93 if (prefix) {
94 *prefix = NULL;
95 }
96 if (pref_len) {
97 *pref_len = 0;
98 }
99 if (name) {
100 *name = NULL;
101 }
102 if (nam_len) {
103 *nam_len = 0;
104 }
105
106 if ((ret = parse_identifier(id)) < 1) {
107 return ret;
108 }
109
110 if (prefix) {
111 *prefix = id;
112 }
113 if (pref_len) {
114 *pref_len = ret;
115 }
116
117 parsed += ret;
118 id += ret;
119
120 /* there is prefix */
121 if (id[0] == ':') {
122 ++parsed;
123 ++id;
124
125 /* there isn't */
126 } else {
127 if (name && prefix) {
128 *name = *prefix;
129 }
130 if (prefix) {
131 *prefix = NULL;
132 }
133
134 if (nam_len && pref_len) {
135 *nam_len = *pref_len;
136 }
137 if (pref_len) {
138 *pref_len = 0;
139 }
140
141 return parsed;
142 }
143
144 /* identifier (node name) */
145 if ((ret = parse_identifier(id)) < 1) {
146 return -parsed+ret;
147 }
148
149 if (name) {
150 *name = id;
151 }
152 if (nam_len) {
153 *nam_len = ret;
154 }
155
156 return parsed+ret;
157}
158
159/**
160 * @brief Parse a path-predicate (leafref).
161 *
162 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
163 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
164 *
165 * @param[in] id Identifier in question.
166 * @param[out] prefix Points to the prefix, NULL if there is not any.
167 * @param[out] pref_len Length of the prefix, 0 if there is not any.
168 * @param[out] name Points to the node name.
169 * @param[out] nam_len Length of the node name.
170 * @param[out] path_key_expr Points to the path-key-expr.
171 * @param[out] pke_len Length of the path-key-expr.
172 * @param[out] has_predicate Flag to mark whether there is another predicate following.
173 *
174 * @return Number of characters successfully parsed,
175 * positive on success, negative on failure.
176 */
177static int
178parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, const char **path_key_expr, int *pke_len, int *has_predicate)
179{
180 const char *ptr;
181 int parsed = 0, ret;
182
183 assert(id);
184 if (prefix) {
185 *prefix = NULL;
186 }
187 if (pref_len) {
188 *pref_len = 0;
189 }
190 if (name) {
191 *name = NULL;
192 }
193 if (nam_len) {
194 *nam_len = 0;
195 }
196 if (path_key_expr) {
197 *path_key_expr = NULL;
198 }
199 if (pke_len) {
200 *pke_len = 0;
201 }
202 if (has_predicate) {
203 *has_predicate = 0;
204 }
205
206 if (id[0] != '[') {
207 return -parsed;
208 }
209
210 ++parsed;
211 ++id;
212
213 while (isspace(id[0])) {
214 ++parsed;
215 ++id;
216 }
217
218 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
219 return -parsed+ret;
220 }
221
222 parsed += ret;
223 id += ret;
224
225 while (isspace(id[0])) {
226 ++parsed;
227 ++id;
228 }
229
230 if (id[0] != '=') {
231 return -parsed;
232 }
233
234 ++parsed;
235 ++id;
236
237 while (isspace(id[0])) {
238 ++parsed;
239 ++id;
240 }
241
242 if ((ptr = strchr(id, ']')) == NULL) {
243 return -parsed;
244 }
245
246 --ptr;
247 while (isspace(ptr[0])) {
248 --ptr;
249 }
250 ++ptr;
251
252 ret = ptr-id;
253 if (path_key_expr) {
254 *path_key_expr = id;
255 }
256 if (pke_len) {
257 *pke_len = ret;
258 }
259
260 parsed += ret;
261 id += ret;
262
263 while (isspace(id[0])) {
264 ++parsed;
265 ++id;
266 }
267
268 assert(id[0] == ']');
269
270 if (id[1] == '[') {
271 *has_predicate = 1;
272 }
273
274 return parsed+1;
275}
276
277/**
278 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
279 * the ".." and the first node-identifier, other calls parse a single
280 * node-identifier each.
281 *
282 * path-key-expr = current-function-invocation *WSP "/" *WSP
283 * rel-path-keyexpr
284 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
285 * *(node-identifier *WSP "/" *WSP)
286 * node-identifier
287 *
288 * @param[in] id Identifier in question.
289 * @param[out] prefix Points to the prefix, NULL if there is not any.
290 * @param[out] pref_len Length of the prefix, 0 if there is not any.
291 * @param[out] name Points to the node name.
292 * @param[out] nam_len Length of the node name.
293 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
294 * must not be changed between consecutive calls.
295 * @return Number of characters successfully parsed,
296 * positive on success, negative on failure.
297 */
298static int
299parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times)
300{
301 int parsed = 0, ret, par_times = 0;
302
303 assert(id);
304 assert(parent_times);
305 if (prefix) {
306 *prefix = NULL;
307 }
308 if (pref_len) {
309 *pref_len = 0;
310 }
311 if (name) {
312 *name = NULL;
313 }
314 if (nam_len) {
315 *nam_len = 0;
316 }
317
318 if (!*parent_times) {
319 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
320 if (strncmp(id, "current()", 9)) {
321 return -parsed;
322 }
323
324 parsed += 9;
325 id += 9;
326
327 while (isspace(id[0])) {
328 ++parsed;
329 ++id;
330 }
331
332 if (id[0] != '/') {
333 return -parsed;
334 }
335
336 ++parsed;
337 ++id;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 /* rel-path-keyexpr */
345 if (strncmp(id, "..", 2)) {
346 return -parsed;
347 }
348 ++par_times;
349
350 parsed += 2;
351 id += 2;
352
353 while (isspace(id[0])) {
354 ++parsed;
355 ++id;
356 }
357 }
358
359 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
360 *
361 * first parent reference with whitespaces already parsed
362 */
363 if (id[0] != '/') {
364 return -parsed;
365 }
366
367 ++parsed;
368 ++id;
369
370 while (isspace(id[0])) {
371 ++parsed;
372 ++id;
373 }
374
375 while (!strncmp(id, "..", 2) && !*parent_times) {
376 ++par_times;
377
378 parsed += 2;
379 id += 2;
380
381 while (isspace(id[0])) {
382 ++parsed;
383 ++id;
384 }
385
386 if (id[0] != '/') {
387 return -parsed;
388 }
389
390 ++parsed;
391 ++id;
392
393 while (isspace(id[0])) {
394 ++parsed;
395 ++id;
396 }
397 }
398
399 if (!*parent_times) {
400 *parent_times = par_times;
401 }
402
403 /* all parent references must be parsed at this point */
404 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
405 return -parsed+ret;
406 }
407
408 parsed += ret;
409 id += ret;
410
411 return parsed;
412}
413
414/**
415 * @brief Parse path-arg (leafref).
416 *
417 * path-arg = absolute-path / relative-path
418 * absolute-path = 1*("/" (node-identifier *path-predicate))
419 * relative-path = 1*(".." "/") descendant-path
420 *
421 * @param[in] id Identifier in question.
422 * @param[out] prefix Points to the prefix, NULL if there is not any.
423 * @param[out] pref_len Length of the prefix, 0 if there is not any.
424 * @param[out] name Points to the node name.
425 * @param[out] nam_len Length of the node name.
426 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
427 * must not be changed between consecutive calls. -1 if the
428 * path is relative.
429 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
430 *
431 * @return Number of characters successfully parsed,
432 * positive on success, negative on failure.
433 */
434static int
435parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times, int *has_predicate)
436{
437 int parsed = 0, ret, par_times = 0;
438
439 assert(id);
440 assert(parent_times);
441 if (prefix) {
442 *prefix = NULL;
443 }
444 if (pref_len) {
445 *pref_len = 0;
446 }
447 if (name) {
448 *name = NULL;
449 }
450 if (nam_len) {
451 *nam_len = 0;
452 }
453 if (has_predicate) {
454 *has_predicate = 0;
455 }
456
457 if (!*parent_times && !strncmp(id, "..", 2)) {
458 ++par_times;
459
460 parsed += 2;
461 id += 2;
462
463 while (!strncmp(id, "/..", 3)) {
464 ++par_times;
465
466 parsed += 3;
467 id += 3;
468 }
469 }
470
471 if (!*parent_times) {
472 if (par_times) {
473 *parent_times = par_times;
474 } else {
475 *parent_times = -1;
476 }
477 }
478
479 if (id[0] != '/') {
480 return -parsed;
481 }
482
483 /* skip '/' */
484 ++parsed;
485 ++id;
486
487 /* node-identifier ([prefix:]identifier) */
488 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
489 return -parsed-ret;
490 }
491
492 parsed += ret;
493 id += ret;
494
495 /* there is no predicate */
496 if ((id[0] == '/') || !id[0]) {
497 return parsed;
498 } else if (id[0] != '[') {
499 return -parsed;
500 }
501
502 if (has_predicate) {
503 *has_predicate = 1;
504 }
505
506 return parsed;
507}
508
509/**
510 * @brief Parse instance-identifier (instance-identifier).
511 *
512 * instance-identifier = 1*("/" (node-identifier *predicate))
513 *
514 * @param[in] id Identifier in question.
515 * @param[out] prefix Points to the prefix, NULL if there is not any.
516 * @param[out] pref_len Length of the prefix, 0 if there is not any.
517 * @param[out] name Points to the node name.
518 * @param[out] nam_len Length of the node name.
519 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
520 *
521 * @return Number of characters successfully parsed,
522 * positive on success, negative on failure.
523 */
524static int
525parse_instance_identifier(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *has_predicate)
526{
527 int parsed = 0, ret;
528
529 assert(id);
530 if (prefix) {
531 *prefix = NULL;
532 }
533 if (pref_len) {
534 *pref_len = 0;
535 }
536 if (name) {
537 *name = NULL;
538 }
539 if (nam_len) {
540 *nam_len = 0;
541 }
542 if (has_predicate) {
543 *has_predicate = 0;
544 }
545
546 if (id[0] != '/') {
547 return -parsed;
548 }
549
550 ++parsed;
551 ++id;
552
553 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
554 return -parsed+ret;
555 }
556
557 parsed += ret;
558 id += ret;
559
560 if ((id[0] == '[') && has_predicate) {
561 *has_predicate = 1;
562 }
563
564 return parsed;
565}
566
567/**
568 * @brief Parse predicate (instance-identifier).
569 *
570 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
571 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
572 * ((DQUOTE string DQUOTE) /
573 * (SQUOTE string SQUOTE))
574 * pos = non-negative-integer-value
575 *
576 * @param[in] id Identifier in question.
577 * @param[out] prefix Points to the prefix, NULL if there is not any.
578 * @param[out] pref_len Length of the prefix, 0 if there is not any.
579 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
580 * @param[out] nam_len Length of the node name.
581 * @param[out] value Value the node-identifier must have (string from the grammar),
582 * NULL if there is not any.
583 * @param[out] val_len Length of the value, 0 if there is not any.
584 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
585 *
586 * @return Number of characters successfully parsed,
587 * positive on success, negative on failure.
588 */
589static int
590parse_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, const char **value, int *val_len, int *has_predicate)
591{
592 const char *ptr;
593 int parsed = 0, ret;
594 char quote;
595
596 assert(id);
597 if (prefix) {
598 *prefix = NULL;
599 }
600 if (pref_len) {
601 *pref_len = 0;
602 }
603 if (name) {
604 *name = NULL;
605 }
606 if (nam_len) {
607 *nam_len = 0;
608 }
609 if (value) {
610 *value = NULL;
611 }
612 if (val_len) {
613 *val_len = 0;
614 }
615 if (has_predicate) {
616 *has_predicate = 0;
617 }
618
619 if (id[0] != '[') {
620 return -parsed;
621 }
622
623 ++parsed;
624 ++id;
625
626 while (isspace(id[0])) {
627 ++parsed;
628 ++id;
629 }
630
631 /* pos */
632 if (isdigit(id[0])) {
633 if (name) {
634 *name = id;
635 }
636
637 if (id[0] == '0') {
638 ++parsed;
639 ++id;
640
641 if (isdigit(id[0])) {
642 return -parsed;
643 }
644 }
645
646 while (isdigit(id[0])) {
647 ++parsed;
648 ++id;
649 }
650
651 if (nam_len) {
652 *nam_len = id-(*name);
653 }
654
655 /* "." */
656 } else if (id[0] == '.') {
657 if (name) {
658 *name = id;
659 }
660 if (nam_len) {
661 *nam_len = 1;
662 }
663
664 ++parsed;
665 ++id;
666
667 /* node-identifier */
668 } else {
669 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
670 return -parsed+ret;
671 }
672 }
673
674 while (isspace(id[0])) {
675 ++parsed;
676 ++id;
677 }
678
679 if (id[0] != '=') {
680 return -parsed;
681 }
682
683 ++parsed;
684 ++id;
685
686 while (isspace(id[0])) {
687 ++parsed;
688 ++id;
689 }
690
691 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
692 if ((id[0] == '\"') || (id[0] == '\'')) {
693 quote = id[0];
694
695 ++parsed;
696 ++id;
697
698 if ((ptr = strchr(id, quote)) == NULL) {
699 return -parsed;
700 }
701 ret = ptr-id;
702
703 if (value) {
704 *value = id;
705 }
706 if (val_len) {
707 *val_len = ret;
708 }
709
710 parsed += ret+1;
711 id += ret+1;
712 } else {
713 return -parsed;
714 }
715
716 while (isspace(id[0])) {
717 ++parsed;
718 ++id;
719 }
720
721 if (id[0] != ']') {
722 return -parsed;
723 }
724
725 ++parsed;
726 ++id;
727
728 if ((id[0] == '[') && has_predicate) {
729 *has_predicate = 1;
730 }
731
732 return parsed;
733}
734
735/**
736 * @brief Parse schema-nodeid.
737 *
738 * schema-nodeid = absolute-schema-nodeid /
739 * descendant-schema-nodeid
740 * absolute-schema-nodeid = 1*("/" node-identifier)
741 * descendant-schema-nodeid =
742 * node-identifier
743 * absolute-schema-nodeid
744 *
745 * @param[in] id Identifier in question.
746 * @param[out] prefix Points to the prefix, NULL if there is not any.
747 * @param[out] pref_len Length of the prefix, 0 if there is not any.
748 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
749 * @param[out] nam_len Length of the node name.
750 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
751 * on the first call, must not be changed between consecutive calls.
752 *
753 * @return Number of characters successfully parsed,
754 * positive on success, negative on failure.
755 */
756static int
757parse_schema_nodeid(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *is_relative)
758{
759 int parsed = 0, ret;
760
761 assert(id);
762 assert(is_relative);
763 if (prefix) {
764 *prefix = NULL;
765 }
766 if (pref_len) {
767 *pref_len = 0;
768 }
769 if (name) {
770 *name = NULL;
771 }
772 if (nam_len) {
773 *nam_len = 0;
774 }
775
776 if (id[0] != '/') {
777 if (*is_relative != -1) {
778 return -parsed;
779 } else {
780 *is_relative = 1;
781 }
782 } else {
783 if (*is_relative == -1) {
784 *is_relative = 0;
785 }
786 ++parsed;
787 ++id;
788 }
789
790 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
791 return -parsed+ret;
792 }
793
794 return parsed+ret;
795}
796
797/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200798 * @brief Resolves length or range intervals. Does not log.
799 * Syntax is assumed to be correct, *local_intv MUST be NULL.
800 *
801 * @param[in] str_restr The restriction as a string.
802 * @param[in] type The type of the restriction.
803 * @param[in] superior_restr Flag whether to check superior
804 * types.
805 * @param[out] local_intv The final interval structure.
806 *
807 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
808 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200809int
810resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr, struct len_ran_intv** local_intv)
811{
812 /* 0 - unsigned, 1 - signed, 2 - floating point */
813 int kind, ret = 0;
814 int64_t local_smin, local_smax;
815 uint64_t local_umin, local_umax;
816 long double local_fmin, local_fmax;
817 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200818 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200819
820 switch (type->base) {
821 case LY_TYPE_BINARY:
822 kind = 0;
823 local_umin = 0;
824 local_umax = 18446744073709551615UL;
825
826 if (!str_restr && type->info.binary.length) {
827 str_restr = type->info.binary.length->expr;
828 }
829 break;
830 case LY_TYPE_DEC64:
831 kind = 2;
832 local_fmin = -9223372036854775808.0;
833 local_fmin /= 1 << type->info.dec64.dig;
834 local_fmax = 9223372036854775807.0;
835 local_fmax /= 1 << type->info.dec64.dig;
836
837 if (!str_restr && type->info.dec64.range) {
838 str_restr = type->info.dec64.range->expr;
839 }
840 break;
841 case LY_TYPE_INT8:
842 kind = 1;
843 local_smin = -128;
844 local_smax = 127;
845
846 if (!str_restr && type->info.num.range) {
847 str_restr = type->info.num.range->expr;
848 }
849 break;
850 case LY_TYPE_INT16:
851 kind = 1;
852 local_smin = -32768;
853 local_smax = 32767;
854
855 if (!str_restr && type->info.num.range) {
856 str_restr = type->info.num.range->expr;
857 }
858 break;
859 case LY_TYPE_INT32:
860 kind = 1;
861 local_smin = -2147483648;
862 local_smax = 2147483647;
863
864 if (!str_restr && type->info.num.range) {
865 str_restr = type->info.num.range->expr;
866 }
867 break;
868 case LY_TYPE_INT64:
869 kind = 1;
870 local_smin = -9223372036854775807L - 1L;
871 local_smax = 9223372036854775807L;
872
873 if (!str_restr && type->info.num.range) {
874 str_restr = type->info.num.range->expr;
875 }
876 break;
877 case LY_TYPE_UINT8:
878 kind = 0;
879 local_umin = 0;
880 local_umax = 255;
881
882 if (!str_restr && type->info.num.range) {
883 str_restr = type->info.num.range->expr;
884 }
885 break;
886 case LY_TYPE_UINT16:
887 kind = 0;
888 local_umin = 0;
889 local_umax = 65535;
890
891 if (!str_restr && type->info.num.range) {
892 str_restr = type->info.num.range->expr;
893 }
894 break;
895 case LY_TYPE_UINT32:
896 kind = 0;
897 local_umin = 0;
898 local_umax = 4294967295;
899
900 if (!str_restr && type->info.num.range) {
901 str_restr = type->info.num.range->expr;
902 }
903 break;
904 case LY_TYPE_UINT64:
905 kind = 0;
906 local_umin = 0;
907 local_umax = 18446744073709551615UL;
908
909 if (!str_restr && type->info.num.range) {
910 str_restr = type->info.num.range->expr;
911 }
912 break;
913 case LY_TYPE_STRING:
914 kind = 0;
915 local_umin = 0;
916 local_umax = 18446744073709551615UL;
917
918 if (!str_restr && type->info.str.length) {
919 str_restr = type->info.str.length->expr;
920 }
921 break;
922 default:
923 LOGINT;
924 return EXIT_FAILURE;
925 }
926
927 /* process superior types */
928 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200929 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
930 LOGINT;
931 return EXIT_FAILURE;
932 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200933 assert(!intv || (intv->kind == kind));
934 }
935
936 if (!str_restr) {
937 /* we are validating data and not have any restriction, but a superior type might have */
938 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200939 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
940 LOGINT;
941 return EXIT_FAILURE;
942 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200943 assert(!intv || (intv->kind == kind));
944 }
945 *local_intv = intv;
946 return EXIT_SUCCESS;
947 }
948
949 /* adjust local min and max */
950 if (intv) {
951 tmp_intv = intv;
952
953 if (kind == 0) {
954 local_umin = tmp_intv->value.uval.min;
955 } else if (kind == 1) {
956 local_smin = tmp_intv->value.sval.min;
957 } else if (kind == 2) {
958 local_fmin = tmp_intv->value.fval.min;
959 }
960
961 while (tmp_intv->next) {
962 tmp_intv = tmp_intv->next;
963 }
964
965 if (kind == 0) {
966 local_umax = tmp_intv->value.uval.max;
967 } else if (kind == 1) {
968 local_smax = tmp_intv->value.sval.max;
969 } else if (kind == 2) {
970 local_fmax = tmp_intv->value.fval.max;
971 }
972 }
973
974 /* finally parse our restriction */
975 seg_ptr = str_restr;
976 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +0200977 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200978 *local_intv = malloc(sizeof **local_intv);
979 tmp_local_intv = *local_intv;
980 } else {
981 tmp_local_intv->next = malloc(sizeof **local_intv);
982 tmp_local_intv = tmp_local_intv->next;
983 }
984
985 tmp_local_intv->kind = kind;
986 tmp_local_intv->next = NULL;
987
988 /* min */
989 ptr = seg_ptr;
990 while (isspace(ptr[0])) {
991 ++ptr;
992 }
993 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
994 if (kind == 0) {
995 tmp_local_intv->value.uval.min = atoll(ptr);
996 } else if (kind == 1) {
997 tmp_local_intv->value.sval.min = atoll(ptr);
998 } else if (kind == 2) {
999 tmp_local_intv->value.fval.min = atoll(ptr);
1000 }
1001
1002 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1003 ++ptr;
1004 }
1005 while (isdigit(ptr[0])) {
1006 ++ptr;
1007 }
1008 } else if (!strncmp(ptr, "min", 3)) {
1009 if (kind == 0) {
1010 tmp_local_intv->value.uval.min = local_umin;
1011 } else if (kind == 1) {
1012 tmp_local_intv->value.sval.min = local_smin;
1013 } else if (kind == 2) {
1014 tmp_local_intv->value.fval.min = local_fmin;
1015 }
1016
1017 ptr += 3;
1018 } else if (!strncmp(ptr, "max", 3)) {
1019 if (kind == 0) {
1020 tmp_local_intv->value.uval.min = local_umax;
1021 } else if (kind == 1) {
1022 tmp_local_intv->value.sval.min = local_smax;
1023 } else if (kind == 2) {
1024 tmp_local_intv->value.fval.min = local_fmax;
1025 }
1026
1027 ptr += 3;
1028 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001029 LOGINT;
1030 ret = EXIT_FAILURE;
1031 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001032 }
1033
1034 while (isspace(ptr[0])) {
1035 ptr++;
1036 }
1037
1038 /* no interval or interval */
1039 if ((ptr[0] == '|') || !ptr[0]) {
1040 if (kind == 0) {
1041 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1042 } else if (kind == 1) {
1043 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1044 } else if (kind == 2) {
1045 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1046 }
1047 } else if (!strncmp(ptr, "..", 2)) {
1048 /* skip ".." */
1049 ptr += 2;
1050 while (isspace(ptr[0])) {
1051 ++ptr;
1052 }
1053
1054 /* max */
1055 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1056 if (kind == 0) {
1057 tmp_local_intv->value.uval.max = atoll(ptr);
1058 } else if (kind == 1) {
1059 tmp_local_intv->value.sval.max = atoll(ptr);
1060 } else if (kind == 2) {
1061 tmp_local_intv->value.fval.max = atoll(ptr);
1062 }
1063 } else if (!strncmp(ptr, "max", 3)) {
1064 if (kind == 0) {
1065 tmp_local_intv->value.uval.max = local_umax;
1066 } else if (kind == 1) {
1067 tmp_local_intv->value.sval.max = local_smax;
1068 } else if (kind == 2) {
1069 tmp_local_intv->value.fval.max = local_fmax;
1070 }
1071 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001072 LOGINT;
1073 ret = EXIT_FAILURE;
1074 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001075 }
1076 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001077 LOGINT;
1078 ret = EXIT_FAILURE;
1079 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001080 }
1081
1082 /* next segment (next OR) */
1083 seg_ptr = strchr(seg_ptr, '|');
1084 if (!seg_ptr) {
1085 break;
1086 }
1087 seg_ptr++;
1088 }
1089
1090 /* check local restrictions against superior ones */
1091 if (intv) {
1092 tmp_intv = intv;
1093 tmp_local_intv = *local_intv;
1094
1095 while (tmp_local_intv && tmp_intv) {
1096 /* reuse local variables */
1097 if (kind == 0) {
1098 local_umin = tmp_local_intv->value.uval.min;
1099 local_umax = tmp_local_intv->value.uval.max;
1100
1101 /* it must be in this interval */
1102 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1103 /* this interval is covered, next one */
1104 if (local_umax <= tmp_intv->value.uval.max) {
1105 tmp_local_intv = tmp_local_intv->next;
1106 continue;
1107 /* ascending order of restrictions -> fail */
1108 } else {
1109 ret = EXIT_FAILURE;
1110 goto cleanup;
1111 }
1112 }
1113 } else if (kind == 1) {
1114 local_smin = tmp_local_intv->value.sval.min;
1115 local_smax = tmp_local_intv->value.sval.max;
1116
1117 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1118 if (local_smax <= tmp_intv->value.sval.max) {
1119 tmp_local_intv = tmp_local_intv->next;
1120 continue;
1121 } else {
1122 ret = EXIT_FAILURE;
1123 goto cleanup;
1124 }
1125 }
1126 } else if (kind == 2) {
1127 local_fmin = tmp_local_intv->value.fval.min;
1128 local_fmax = tmp_local_intv->value.fval.max;
1129
1130 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1131 if (local_fmax <= tmp_intv->value.fval.max) {
1132 tmp_local_intv = tmp_local_intv->next;
1133 continue;
1134 } else {
1135 ret = EXIT_FAILURE;
1136 goto cleanup;
1137 }
1138 }
1139 }
1140
1141 tmp_intv = tmp_intv->next;
1142 }
1143
1144 /* some interval left uncovered -> fail */
1145 if (tmp_local_intv) {
1146 ret = EXIT_FAILURE;
1147 }
1148
1149 }
1150
1151cleanup:
1152 while (intv) {
1153 tmp_intv = intv->next;
1154 free(intv);
1155 intv = tmp_intv;
1156 }
1157
1158 /* fail */
1159 if (ret) {
1160 while (*local_intv) {
1161 tmp_local_intv = (*local_intv)->next;
1162 free(*local_intv);
1163 *local_intv = tmp_local_intv;
1164 }
1165 }
1166
1167 return ret;
1168}
1169
Michal Vasko730dfdf2015-08-11 14:48:05 +02001170/**
1171 * @brief Resolve a typedef. Does not log.
1172 *
1173 * @param[in] name Typedef name.
1174 * @param[in] prefix Typedef name prefix.
1175 * @param[in] module The main module.
1176 * @param[in] parent The parent of the resolved type definition.
1177 *
1178 * @return Typedef pointer on succes, NULL otherwise.
1179 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001180struct lys_tpdf *
Radek Krejcib8048692015-08-05 13:36:34 +02001181resolve_superior_type(const char *name, const char *prefix, struct lys_module *module, struct lys_node *parent)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001182{
1183 int i, j, found = 0;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001184 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001185 int tpdf_size;
1186
1187 if (!prefix) {
1188 /* no prefix, try built-in types */
1189 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1190 if (!strcmp(ly_types[i].def->name, name)) {
1191 return ly_types[i].def;
1192 }
1193 }
1194 } else {
1195 if (!strcmp(prefix, module->prefix)) {
1196 /* prefix refers to the current module, ignore it */
1197 prefix = NULL;
1198 }
1199 }
1200
1201 if (!prefix && parent) {
1202 /* search in local typedefs */
1203 while (parent) {
1204 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001205 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001206 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1207 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001208 break;
1209
Radek Krejci76512572015-08-04 09:47:08 +02001210 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001211 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1212 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001213 break;
1214
Radek Krejci76512572015-08-04 09:47:08 +02001215 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001216 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1217 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001218 break;
1219
Radek Krejci76512572015-08-04 09:47:08 +02001220 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001221 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1222 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001223 break;
1224
Radek Krejci76512572015-08-04 09:47:08 +02001225 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001226 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1227 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001228 break;
1229
Radek Krejci76512572015-08-04 09:47:08 +02001230 case LYS_INPUT:
1231 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001232 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1233 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001234 break;
1235
1236 default:
1237 parent = parent->parent;
1238 continue;
1239 }
1240
1241 for (i = 0; i < tpdf_size; i++) {
1242 if (!strcmp(tpdf[i].name, name)) {
1243 return &tpdf[i];
1244 }
1245 }
1246
1247 parent = parent->parent;
1248 }
1249 } else if (prefix) {
1250 /* get module where to search */
1251 for (i = 0; i < module->imp_size; i++) {
1252 if (!strcmp(module->imp[i].prefix, prefix)) {
1253 module = module->imp[i].module;
1254 found = 1;
1255 break;
1256 }
1257 }
1258 if (!found) {
1259 return NULL;
1260 }
1261 }
1262
1263 /* search in top level typedefs */
1264 for (i = 0; i < module->tpdf_size; i++) {
1265 if (!strcmp(module->tpdf[i].name, name)) {
1266 return &module->tpdf[i];
1267 }
1268 }
1269
1270 /* search in submodules */
1271 for (i = 0; i < module->inc_size; i++) {
1272 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1273 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
1274 return &module->inc[i].submodule->tpdf[j];
1275 }
1276 }
1277 }
1278
1279 return NULL;
1280}
1281
1282static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001283check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001284{
1285 /* TODO - RFC 6020, sec. 7.3.4 */
1286 (void)type;
1287 (void)value;
1288 return EXIT_SUCCESS;
1289}
1290
Michal Vasko730dfdf2015-08-11 14:48:05 +02001291/**
1292 * @brief Check a key for mandatory attributes. Logs directly.
1293 *
1294 * @param[in] key The key to check.
1295 * @param[in] flags What flags to check.
1296 * @param[in] list The list of all the keys.
1297 * @param[in] index Index of the key in the key list.
1298 * @param[in] name The name of the keys.
1299 * @param[in] len The name length.
1300 * @param[in] line The line in the input file.
1301 *
1302 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
1303 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001304static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001305check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1306 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001307{
1308 char *dup = NULL;
1309 int j;
1310
1311 /* existence */
1312 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001313 if (name[len] != '\0') {
1314 dup = strdup(name);
1315 dup[len] = '\0';
1316 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001317 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001318 LOGVAL(LYE_KEY_MISS, line, name);
1319 free(dup);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001320 return EXIT_FAILURE;
1321 }
1322
1323 /* uniqueness */
1324 for (j = index - 1; j >= 0; j--) {
1325 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001326 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001327 return EXIT_FAILURE;
1328 }
1329 }
1330
1331 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001332 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001333 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001334 return EXIT_FAILURE;
1335 }
1336
1337 /* type of the leaf is not built-in empty */
1338 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001339 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001340 return EXIT_FAILURE;
1341 }
1342
1343 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001344 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001345 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001346 return EXIT_FAILURE;
1347 }
1348
1349 return EXIT_SUCCESS;
1350}
1351
Michal Vasko730dfdf2015-08-11 14:48:05 +02001352/**
1353 * @brief Resolve (find) a prefix in a module include import. Does not log.
1354 *
1355 * @param[in] mod The module with the import.
1356 * @param[in] prefix The prefix to find.
1357 * @param[in] pref_len The prefix length.
1358 *
1359 * @return The matching module on success, NULL on error.
1360 */
Michal Vaskof02e3742015-08-05 16:27:02 +02001361static struct lys_module *
1362resolve_import_in_includes_recursive(struct lys_module *mod, const char *prefix, uint32_t pref_len)
1363{
1364 int i, j;
1365 struct lys_submodule *sub_mod;
1366 struct lys_module *ret;
1367
1368 for (i = 0; i < mod->inc_size; i++) {
1369 sub_mod = mod->inc[i].submodule;
1370 for (j = 0; j < sub_mod->imp_size; j++) {
1371 if ((pref_len == strlen(sub_mod->imp[j].prefix))
1372 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
1373 return sub_mod->imp[j].module;
1374 }
1375 }
1376 }
1377
1378 for (i = 0; i < mod->inc_size; i++) {
1379 ret = resolve_import_in_includes_recursive((struct lys_module *)mod->inc[i].submodule, prefix, pref_len);
1380 if (ret) {
1381 return ret;
1382 }
1383 }
1384
1385 return NULL;
1386}
1387
Michal Vasko730dfdf2015-08-11 14:48:05 +02001388/**
1389 * @brief Resolve (find) a prefix in a module import. Does not log.
1390 *
1391 * @param[in] mod The module with the import.
1392 * @param[in] prefix The prefix to find.
1393 * @param[in] pref_len The prefix length.
1394 *
1395 * @return The matching module on success, NULL on error.
1396 */
Michal Vaskof02e3742015-08-05 16:27:02 +02001397static struct lys_module *
1398resolve_prefixed_module(struct lys_module *mod, const char *prefix, uint32_t pref_len)
1399{
1400 int i;
1401
1402 /* module itself */
1403 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
1404 return mod;
1405 }
1406
1407 /* imported modules */
1408 for (i = 0; i < mod->imp_size; i++) {
1409 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
1410 return mod->imp[i].module;
1411 }
1412 }
1413
1414 /* imports in includes */
1415 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
1416}
1417
Michal Vasko730dfdf2015-08-11 14:48:05 +02001418/**
1419 * @brief Resolve (fill) a unique. Logs directly.
1420 *
1421 * @param[in] parent The parent node of the unique structure.
1422 * @param[in] uniq_str The value of the unique node.
1423 * @param[in] uniq_s The unique structure in question.
1424 * @param[in] line The line in the input file.
1425 *
1426 * @return EXIT_SUCCESS on succes, EXIT_FAILURE otherwise.
1427 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001428int
Michal Vaskof02e3742015-08-05 16:27:02 +02001429resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001430{
1431 char *uniq_val, *uniq_begin, *start;
1432 int i, j;
1433
1434 /* count the number of unique values */
1435 uniq_val = uniq_begin = strdup(uniq_str);
1436 uniq_s->leafs_size = 0;
1437 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1438 uniq_s->leafs_size++;
1439 while (isspace(*uniq_val)) {
1440 uniq_val++;
1441 }
1442 }
1443 uniq_s->leafs_size++;
1444 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1445
1446 /* interconnect unique values with the leafs */
1447 uniq_val = uniq_begin;
1448 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1449 start = uniq_val;
1450 if ((uniq_val = strpbrk(start, " \t\n"))) {
1451 *uniq_val = '\0'; /* add terminating NULL byte */
1452 uniq_val++;
1453 while (isspace(*uniq_val)) {
1454 uniq_val++;
1455 }
1456 } /* else only one nodeid present/left already NULL byte terminated */
1457
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001458 uniq_s->leafs[i] = (struct lys_node_leaf *)resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF);
1459 if (!uniq_s->leafs[i] || (uniq_s->leafs[i]->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001460 LOGVAL(LYE_INARG, line, start, "unique");
1461 if (!uniq_s->leafs[i]) {
1462 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
1463 } else {
1464 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001465 }
1466 goto error;
1467 }
1468
1469 for (j = 0; j < i; j++) {
1470 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001471 LOGVAL(LYE_INARG, line, start, "unique");
1472 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001473 goto error;
1474 }
1475 }
1476 }
1477
1478 free(uniq_begin);
1479 return EXIT_SUCCESS;
1480
1481error:
1482
1483 free(uniq_s->leafs);
1484 free(uniq_begin);
1485
1486 return EXIT_FAILURE;
1487}
1488
Michal Vasko730dfdf2015-08-11 14:48:05 +02001489/**
1490 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1491 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001492 * @param[in] uses The uses in question.
1493 * @param[in] line The line in the input file.
1494 *
1495 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1496 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001497static int
Radek Krejci10c760e2015-08-14 14:45:43 +02001498resolve_grouping(struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001499{
Michal Vasko58090902015-08-13 14:04:15 +02001500 struct lys_module *module = uses->module;
1501 const char *prefix, *name;
1502 int i, pref_len, nam_len;
Radek Krejci10c760e2015-08-14 14:45:43 +02001503 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001504
Michal Vasko58090902015-08-13 14:04:15 +02001505 /* parse the identifier, it must be parsed on one call */
1506 if ((i = parse_node_identifier(uses->name, &prefix, &pref_len, &name, &nam_len)) < 1) {
1507 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
1508 return EXIT_FAILURE;
1509 } else if (uses->name[i]) {
1510 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
1511 return EXIT_FAILURE;
1512 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001513
Michal Vasko58090902015-08-13 14:04:15 +02001514 if (!prefix) {
1515 /* search in local tree hierarchy */
Radek Krejci10c760e2015-08-14 14:45:43 +02001516 if (!uses->parent) {
1517 start = (struct lys_node *)uses;
1518 while (start->prev->next) {
1519 start = start->prev;
1520 }
1521 } else {
1522 start = uses->parent->child;
1523 }
1524 while (start) {
1525 uses->grp = (struct lys_node_grp *)resolve_sibling(module, start, prefix, pref_len, name, nam_len, LYS_GROUPING);
Michal Vasko58090902015-08-13 14:04:15 +02001526 if (uses->grp) {
1527 return EXIT_SUCCESS;
1528 }
Radek Krejci10c760e2015-08-14 14:45:43 +02001529 start = start->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001530 }
1531 }
1532
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001533 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001534 return EXIT_FAILURE;
1535}
1536
Michal Vasko730dfdf2015-08-11 14:48:05 +02001537/**
1538 * @brief Resolve (find) a feature definition. Logs directly.
1539 *
1540 * @param[in] name Feature name.
1541 * @param[in] module Module to search in.
1542 * @param[in] line The line in the input file.
1543 *
1544 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1545 */
Radek Krejcib8048692015-08-05 13:36:34 +02001546static struct lys_feature *
Michal Vaskof02e3742015-08-05 16:27:02 +02001547resolve_feature(const char *name, struct lys_module *module, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001548{
1549 const char *prefix;
Michal Vaskof02e3742015-08-05 16:27:02 +02001550 uint32_t prefix_len = 0;
1551 int i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001552
1553 assert(name);
1554 assert(module);
1555
1556 /* check prefix */
1557 prefix = name;
1558 name = strchr(prefix, ':');
1559 if (name) {
1560 /* there is prefix */
1561 prefix_len = name - prefix;
1562 name++;
1563
1564 /* check whether the prefix points to the current module */
1565 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1566 /* then ignore prefix and works as there is no prefix */
1567 prefix_len = 0;
1568 }
1569 } else {
1570 /* no prefix, set pointers correctly */
1571 name = prefix;
1572 }
1573
1574 if (prefix_len) {
1575 /* search in imported modules */
Michal Vaskof02e3742015-08-05 16:27:02 +02001576 module = resolve_prefixed_module(module, prefix, prefix_len);
1577 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001578 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001579 LOGVAL(LYE_INPREF, line, prefix);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001580 return NULL;
1581 }
1582 } else {
1583 /* search in submodules */
1584 for (i = 0; i < module->inc_size; i++) {
1585 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1586 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1587 return &(module->inc[i].submodule->features[j]);
1588 }
1589 }
1590 }
1591 }
1592
1593 /* search in the identified module */
1594 for (j = 0; j < module->features_size; j++) {
1595 if (!strcmp(name, module->features[j].name)) {
1596 return &module->features[j];
1597 }
1598 }
1599
1600 /* not found */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001601 LOGVAL(LYE_INRESOLV, line, "feature", prefix);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001602 return NULL;
1603}
1604
Michal Vasko730dfdf2015-08-11 14:48:05 +02001605/**
Michal Vasko58090902015-08-13 14:04:15 +02001606 * @brief Resolve (find) a valid sibling. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001607 *
Michal Vasko58090902015-08-13 14:04:15 +02001608 * Valid child means a schema pointer to a node that is part of
1609 * the data meaning uses are skipped. Includes module comparison
1610 * (can handle augments). Includes are also searched if siblings
1611 * are top-level nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001612 *
Michal Vasko58090902015-08-13 14:04:15 +02001613 * @param[in] mod Main module. Prefix is considered to be from this module.
1614 * @param[in] siblings Siblings to consider. They are first adjusted to
1615 * point to the first sibling.
1616 * @param[in] prefix Node prefix.
1617 * @param[in] pref_len Node prefix length.
1618 * @param[in] name Node name.
1619 * @param[in] nam_len Node name length.
1620 * @param[in] type ORed desired type of the node. 0 means any type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001621 *
1622 * @return Node of the desired type, NULL if no matching node was found.
1623 */
Radek Krejci76512572015-08-04 09:47:08 +02001624struct lys_node *
Michal Vasko58090902015-08-13 14:04:15 +02001625resolve_sibling(struct lys_module *mod, struct lys_node *siblings, const char *prefix, int pref_len, const char *name,
1626 int nam_len, LYS_NODE type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001627{
Michal Vasko58090902015-08-13 14:04:15 +02001628 struct lys_node *node, *result, *old_siblings = NULL;
1629 struct lys_module *prefix_mod, *cur_mod;
1630 int in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001631
Michal Vasko58090902015-08-13 14:04:15 +02001632 assert(mod && siblings && name);
1633 assert(!(type & LYS_USES));
1634
1635 /* find the beginning */
1636 while (siblings->prev->next) {
1637 siblings = siblings->prev;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001638 }
1639
Michal Vasko58090902015-08-13 14:04:15 +02001640 /* fill the name length in case the caller is so indifferent */
1641 if (!nam_len) {
1642 nam_len = strlen(name);
1643 }
1644
1645 /* we start with the module itself, submodules come later */
1646 in_submod = 0;
1647
1648 /* set prefix_mod correctly */
1649 if (prefix) {
1650 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1651 if (!prefix_mod) {
1652 return NULL;
1653 }
1654 cur_mod = prefix_mod;
1655 /* it is our module */
1656 if (cur_mod != mod) {
1657 old_siblings = siblings;
1658 siblings = cur_mod->data;
1659 }
1660 } else {
1661 prefix_mod = mod;
1662 if (prefix_mod->type) {
1663 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1664 }
1665 cur_mod = prefix_mod;
1666 }
1667
1668 while (1) {
1669 /* try to find the node */
1670 LY_TREE_FOR(siblings, node) {
1671 if (node->nodetype == LYS_USES) {
1672 /* an unresolved uses, we can still find it elsewhere */
1673 if (!node->child) {
1674 continue;
1675 }
1676
1677 /* search recursively */
1678 result = resolve_sibling(mod, node->child, prefix, pref_len, name, nam_len, type);
1679 if (result) {
1680 return result;
1681 }
1682 }
1683
1684 if (!type || (node->nodetype & type)) {
1685 /* module check */
1686 if (!node->module->type) {
1687 if (cur_mod != node->module) {
1688 continue;
1689 }
1690 } else {
1691 if (cur_mod != ((struct lys_submodule *)node->module)->belongsto) {
1692 continue;
1693 }
1694 }
1695
1696 /* direct name check */
1697 if (node->name == name || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
1698 return node;
1699 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001700 }
1701 }
1702
Michal Vasko58090902015-08-13 14:04:15 +02001703 /* The original siblings may be valid,
1704 * it's a special case when we're looking
1705 * for a node from augment.
1706 */
1707 if (old_siblings) {
1708 siblings = old_siblings;
1709 old_siblings = NULL;
1710 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001711 }
Michal Vasko58090902015-08-13 14:04:15 +02001712
1713 /* we're not top-level, search ended */
1714 if (siblings->parent) {
1715 break;
1716 }
1717
1718 /* let's try the submodules */
1719 if (in_submod == prefix_mod->inc_size) {
1720 break;
1721 }
1722 cur_mod = (struct lys_module *)prefix_mod->inc[in_submod].submodule;
1723 siblings = cur_mod->data;
1724 ++in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001725 }
1726
1727 return NULL;
1728}
1729
Michal Vasko730dfdf2015-08-11 14:48:05 +02001730/**
1731 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001732 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001733 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001734 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001735 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001736 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1737 *
1738 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
1739 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001740 *
1741 * @param[in] id Schema-nodeid string.
1742 * @param[in] start Start of the relative search.
1743 * @param[in] mod Module in question.
1744 * @param[in] node_type Decides how to modify the search.
1745 *
1746 * @return Matching node, NULL on fail.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001747 */
Radek Krejci76512572015-08-04 09:47:08 +02001748struct lys_node *
Radek Krejcib8048692015-08-05 13:36:34 +02001749resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001750{
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001751 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +02001752 struct lys_node *sibling;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001753 int ret, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +02001754 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001755 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1756 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001757 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001758 uint8_t in_mod_part = 0;
1759
1760 assert(mod);
1761 assert(id);
1762
1763 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1764 return NULL;
1765 }
1766 id += ret;
1767
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001768 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001769 return NULL;
1770 }
1771
1772 /* absolute-schema-nodeid */
1773 if (!is_relative) {
1774 if (prefix) {
1775 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
1776 if (!start_mod) {
1777 return NULL;
1778 }
1779 start = start_mod->data;
1780 } else {
1781 start = mod->data;
1782 start_mod = mod;
1783 }
1784 /* descendant-schema-nodeid */
1785 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001786 if (start) {
1787 start_mod = start->module;
1788 } else {
1789 start_mod = mod;
1790 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001791 }
1792
1793 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001794 sibling = NULL;
1795 LY_TREE_FOR(start, sibling) {
1796 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001797 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
1798 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001799 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001800 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001801
Michal Vasko1e989c02015-08-04 12:33:00 +02001802 /* prefix match check */
1803 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001804 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1805 if (!prefix_mod) {
1806 return NULL;
1807 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001808 } else {
1809 prefix_mod = mod;
1810 if (prefix_mod->type) {
1811 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1812 }
1813 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001814
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001815 /* modules need to always be checked, we want to skip augments */
1816 if (!sibling->module->type) {
1817 if (prefix_mod != sibling->module) {
1818 continue;
1819 }
1820 } else {
1821 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1822 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001823 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001824 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001825
Michal Vasko1e989c02015-08-04 12:33:00 +02001826 /* the result node? */
1827 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001828 /* we're looking only for groupings, this is a data node */
1829 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1830 continue;
1831 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001832 return sibling;
1833 }
1834
Michal Vaskodcc7a802015-08-06 11:59:47 +02001835 /* we're looking for a grouping (node_type == LYS_USES),
1836 * but this isn't it, we cannot search inside
1837 */
1838 if (sibling->nodetype == LYS_GROUPING) {
1839 continue;
1840 }
1841
Michal Vasko1e989c02015-08-04 12:33:00 +02001842 /* check for shorthand cases - then 'start' does not change */
1843 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1844 || (sibling->nodetype == LYS_CASE)) {
1845 start = sibling->child;
1846 }
1847 break;
1848 }
1849 }
1850
1851 /* we did not find the case in direct siblings */
1852 if (node_type == LYS_CHOICE) {
1853 return NULL;
1854 }
1855
1856 /* no match */
1857 if (!sibling) {
1858 /* on augment search also RPCs and notifications, if we are in top-level */
1859 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1860 /* we have searched all the data nodes */
1861 if (in_mod_part == 0) {
1862 if (!in_submod) {
1863 start = start_mod->rpc;
1864 } else {
1865 start = start_mod->inc[in_submod-1].submodule->rpc;
1866 }
1867 in_mod_part = 1;
1868 continue;
1869 }
1870 /* we have searched all the RPCs */
1871 if (in_mod_part == 1) {
1872 if (!in_submod) {
1873 start = start_mod->notif;
1874 } else {
1875 start = start_mod->inc[in_submod-1].submodule->notif;
1876 }
1877 in_mod_part = 2;
1878 continue;
1879 }
1880 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001881 }
1882
Michal Vasko1e989c02015-08-04 12:33:00 +02001883 /* are we done with the included submodules as well? */
1884 if (in_submod == start_mod->inc_size) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001885 return NULL;
1886 }
1887
Michal Vasko1e989c02015-08-04 12:33:00 +02001888 /* we aren't, check the next one */
1889 ++in_submod;
1890 in_mod_part = 0;
1891 start = start_mod->inc[in_submod-1].submodule->data;
1892 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001893 }
1894
1895 /* we found our submodule */
1896 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001897 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001898 in_submod = 0;
1899 }
1900
1901 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1902 return NULL;
1903 }
1904 id += ret;
1905 }
1906
1907 /* cannot get here */
1908 return NULL;
1909}
1910
Michal Vasko730dfdf2015-08-11 14:48:05 +02001911/**
1912 * @brief Resolve (find) a data node. Does not log.
1913 *
1914 * @param[in] prefix Prefix of the data node.
1915 * @param[in] pref_len Length of the prefix.
1916 * @param[in] name Name of the data node.
1917 * @param[in] nam_len Length of the name.
1918 * @param[in] data_source Data node that defines the prefix and the name,
1919 * to find the correct module.
1920 * @param[in,out] parents Resolved nodes. If there are some parents,
1921 * they are replaced (!!) with the resolvents.
1922 *
1923 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
1924 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001925static int
Radek Krejcic5090c32015-08-12 09:46:19 +02001926resolve_data(struct lys_module *mod, const char *name, int nam_len, struct lyd_node *start, struct unres_data **parents)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001927{
Radek Krejcic5090c32015-08-12 09:46:19 +02001928 struct unres_data *item, *par_iter, *prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001929 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001930 int flag;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001931
1932 if (!*parents) {
1933 *parents = malloc(sizeof **parents);
1934 (*parents)->dnode = NULL;
1935 (*parents)->next = NULL;
1936 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001937 for (par_iter = *parents; par_iter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001938 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001939 /* skip */
1940 continue;
1941 }
1942 flag = 0;
Radek Krejcic5090c32015-08-12 09:46:19 +02001943 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001944 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1945 && node->schema->name[nam_len] == '\0') {
1946 /* matching target */
1947 if (!flag) {
1948 /* replace leafref instead of the current parent */
1949 par_iter->dnode = node;
1950 flag = 1;
1951 } else {
1952 /* multiple matching, so create new leafref structure */
1953 item = malloc(sizeof *item);
1954 item->dnode = node;
1955 item->next = par_iter->next;
1956 par_iter->next = item;
1957 par_iter = par_iter->next;
1958 }
1959 }
1960 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001961
1962 if (!flag) {
1963 /* remove item from the parents list */
1964 if (prev) {
1965 prev->next = par_iter->next;
1966 free(par_iter);
1967 par_iter = prev->next;
1968 } else {
1969 item = par_iter->next;
1970 free(par_iter);
1971 par_iter = *parents = item;
1972 }
1973 } else {
1974 prev = par_iter;
1975 par_iter = par_iter->next;
1976 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001977 }
1978
Radek Krejcic5090c32015-08-12 09:46:19 +02001979 return *parents ? EXIT_SUCCESS : EXIT_FAILURE;
1980}
1981
1982/* does not log */
1983static int
1984resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int name_len, struct lyd_node *start,
1985 struct unres_data **parents)
1986{
1987 struct lys_module *mod;
1988
1989 if (prefix) {
1990 /* we have prefix, find appropriate module */
1991 mod = resolve_prefixed_module(start->schema->module, prefix, pref_len);
1992 if (!mod) {
1993 /* invalid prefix */
1994 return EXIT_FAILURE;
1995 }
1996 } else {
1997 /* no prefix, module is the same as of current node */
1998 mod = start->schema->module;
1999 }
2000
2001 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002002}
2003
Michal Vasko730dfdf2015-08-11 14:48:05 +02002004/**
2005 * @brief Resolve a path predicate (leafref) in data context. Logs directly.
2006 *
2007 * @param[in] pred Predicate in question.
2008 * @param[in,out] node_match Nodes satisfying the restriction
2009 * without the predicate. Nodes not
2010 * satisfying the predicate are removed.
2011 * @param[in] line Line in the input file.
2012 *
2013 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2014 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002015static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002016resolve_path_predicate_data(const char *pred, struct unres_data **node_match, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002017{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002018 /* ... /node[source = destination] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002019 struct unres_data *source_match, *dest_match, *node, *node_prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002020 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2021 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2022 int has_predicate, dest_parent_times, i;
2023
2024 do {
2025 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2026 &pke_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002027 LOGVAL(LYE_INCHAR, line, pred[-i], pred-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002028 return -parsed+i;
2029 }
2030 parsed += i;
2031 pred += i;
2032
2033 for (node = *node_match; node;) {
2034 /* source */
2035 source_match = NULL;
2036 /* must be leaf (key of a list) */
2037 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
2038 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +02002039 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002040 LOGVAL(LYE_LINE, line);
2041 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002042 return -parsed;
2043 }
2044
2045 /* destination */
2046 dest_match = calloc(1, sizeof *dest_match);
2047 dest_match->dnode = node->dnode;
2048 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2049 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002050 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002051 return -parsed+i;
2052 }
2053 pke_parsed += i;
2054 for (i = 0; i < dest_parent_times; ++i) {
2055 dest_match->dnode = dest_match->dnode->parent;
2056 if (!dest_match->dnode) {
2057 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002058 LOGVAL(LYE_LINE, line);
2059 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002060 return -parsed;
2061 }
2062 }
2063 while (1) {
2064 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
Michal Vasko1f76a282015-08-04 16:16:53 +02002065 || !dest_match->dnode || dest_match->next) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002066 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002067 LOGVAL(LYE_LINE, line);
2068 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002069 return -parsed;
2070 }
2071
2072 if (pke_len == pke_parsed) {
2073 break;
2074 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002075 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 +02002076 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002077 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002078 return -parsed+i;
2079 }
2080 pke_parsed += i;
2081 }
2082
2083 /* check match between source and destination nodes */
Radek Krejcib8048692015-08-05 13:36:34 +02002084 if (((struct lys_node_leaf *)source_match->dnode->schema)->type.base
2085 != ((struct lys_node_leaf *)dest_match->dnode->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002086 goto remove_leafref;
2087 }
2088
2089 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
2090 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
2091 goto remove_leafref;
2092 }
2093
2094 /* leafref is ok, continue check with next leafref */
2095 node_prev = node;
2096 node = node->next;
2097 continue;
2098
2099remove_leafref:
2100 /* does not fulfill conditions, remove leafref record */
2101 if (node_prev) {
2102 node_prev->next = node->next;
2103 free(node);
2104 node = node_prev->next;
2105 } else {
2106 node = (*node_match)->next;
2107 free(*node_match);
2108 *node_match = node;
2109 }
2110 }
2111 } while (has_predicate);
2112
2113 return parsed;
2114}
2115
Michal Vasko730dfdf2015-08-11 14:48:05 +02002116/**
2117 * @brief Resolve a path (leafref) in data context. Logs directly.
2118 *
2119 * @param[in] unres Nodes matching the schema path.
2120 * @param[in] path Path in question.
2121 * @param[in,out] ret Matching nodes.
2122 *
2123 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2124 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002125int
Michal Vaskof02e3742015-08-05 16:27:02 +02002126resolve_path_arg_data(struct unres_data *unres, const char *path, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002127{
Radek Krejci71b795b2015-08-10 16:20:39 +02002128 struct lyd_node *data = NULL;
Michal Vaskof02e3742015-08-05 16:27:02 +02002129 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002130 const char *prefix, *name;
Michal Vasko1f76a282015-08-04 16:16:53 +02002131 int pref_len, nam_len, has_predicate, parent_times, i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002132
2133 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 parent_times = 0;
2135
2136 /* searching for nodeset */
2137 do {
2138 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002139 LOGVAL(LYE_INCHAR, LOGLINE(unres), path[-i], path-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002140 goto error;
2141 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002142 path += i;
2143
2144 if (!*ret) {
2145 *ret = calloc(1, sizeof **ret);
2146 for (i = 0; i < parent_times; ++i) {
2147 /* relative path */
2148 if (!*ret) {
2149 /* error, too many .. */
Michal Vaskoc07187d2015-08-13 15:20:57 +02002150 LOGVAL(LYE_INVAL, LOGLINE(unres), path, unres->dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002151 goto error;
2152 } else if (!(*ret)->dnode) {
2153 /* first .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002154 data = (*ret)->dnode = unres->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002155 } else if (!(*ret)->dnode->parent) {
2156 /* we are in root */
2157 free(*ret);
2158 *ret = NULL;
2159 } else {
2160 /* multiple .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002161 data = (*ret)->dnode = (*ret)->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002162 }
2163 }
2164
2165 /* absolute path */
2166 if (parent_times == -1) {
2167 for (data = unres->dnode; data->parent; data = data->parent);
2168 for (; data->prev->next; data = data->prev);
2169 }
2170 }
2171
2172 /* node identifier */
2173 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002174 LOGVAL(LYE_INELEM_LEN, LOGLINE(unres), nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002175 goto error;
2176 }
2177
2178 if (has_predicate) {
2179 /* we have predicate, so the current results must be lists */
2180 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002181 if (riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002182 ((struct lys_node_list *)riter->dnode->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002183 /* leafref is ok, continue check with next leafref */
2184 raux = riter;
2185 riter = riter->next;
2186 continue;
2187 }
2188
2189 /* does not fulfill conditions, remove leafref record */
2190 if (raux) {
2191 raux->next = riter->next;
2192 free(riter);
2193 riter = raux->next;
2194 } else {
2195 *ret = riter->next;
2196 free(riter);
2197 riter = *ret;
2198 }
2199 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02002200 if ((i = resolve_path_predicate_data(path, ret, LOGLINE(unres))) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201 goto error;
2202 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002203 path += i;
2204
2205 if (!*ret) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002206 LOGVAL(LYE_LINE, LOGLINE(unres));
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002207 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002208 goto error;
2209 }
2210 }
2211 } while (path[0] != '\0');
2212
Michal Vaskof02e3742015-08-05 16:27:02 +02002213 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002214
2215error:
2216
2217 while (*ret) {
2218 raux = (*ret)->next;
2219 free(*ret);
2220 *ret = raux;
2221 }
2222
Michal Vaskof02e3742015-08-05 16:27:02 +02002223 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224}
2225
Michal Vasko730dfdf2015-08-11 14:48:05 +02002226/**
2227 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2228 *
2229 * @param[in] path Path in question.
2230 * @param[in] mod Schema module.
2231 * @param[in] source_node Left operand node.
2232 * @param[in] dest_node Right ooperand node.
2233 * @param[in] line Line in the input file.
2234 *
2235 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2236 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002237static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002238resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002239 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002240{
2241 struct lys_node *src_node, *dst_node;
2242 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2243 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2244 int has_predicate, dest_parent_times = 0, i;
2245
2246 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002247 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002248 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002249 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002250 return -parsed+i;
2251 }
2252 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002253 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002254
Michal Vasko58090902015-08-13 14:04:15 +02002255 /* source (must be leaf) */
2256 src_node = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF);
Michal Vasko1f76a282015-08-04 16:16:53 +02002257 if (!src_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002258 LOGVAL(LYE_LINE, line);
2259 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02002260 return -parsed;
2261 }
2262
2263 /* destination */
2264 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2265 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002266 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002267 return -parsed;
2268 }
2269 pke_parsed += i;
2270
2271 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2272 dst_node = dest_node;
2273 for (i = 1; i < dest_parent_times; ++i) {
2274 dst_node = dst_node->parent;
2275 if (!dst_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002276 LOGVAL(LYE_LINE, line);
2277 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02002278 return -parsed;
2279 }
2280 }
2281 while (1) {
Michal Vasko58090902015-08-13 14:04:15 +02002282 dst_node = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2283 LYS_CONTAINER | LYS_LIST | LYS_LEAF);
Michal Vasko1f76a282015-08-04 16:16:53 +02002284 if (!dst_node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002285 LOGVAL(LYE_LINE, line);
2286 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02002287 return -parsed;
2288 }
2289
2290 if (pke_len == pke_parsed) {
2291 break;
2292 }
2293
2294 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2295 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002296 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002297 return -parsed;
2298 }
2299 pke_parsed += i;
2300 }
2301
2302 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002303 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2304 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002305 LOGVAL(LYE_LINE, line);
2306 /* general error, the one written later will suffice */
Michal Vasko1f76a282015-08-04 16:16:53 +02002307 return -parsed;
2308 }
2309 } while (has_predicate);
2310
2311 return parsed;
2312}
2313
Michal Vasko730dfdf2015-08-11 14:48:05 +02002314/**
2315 * @brief Resolve a path (leafref) in schema context. Logs indirectly.
2316 *
2317 * @param[in] mod Module in question.
2318 * @param[in] path Path in question.
2319 * @param[in] parent_node Parent of the leafref.
2320 * @param[in] line Line in the input file.
2321 *
2322 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2323 */
Michal Vaskoa5c4ad62015-08-11 14:59:43 +02002324static struct lys_node*
Michal Vaskof02e3742015-08-05 16:27:02 +02002325resolve_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 +02002326{
Michal Vasko58090902015-08-13 14:04:15 +02002327 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002328 const char *id, *prefix, *name;
2329 int pref_len, nam_len, parent_times, has_predicate;
2330 int i, first;
2331
2332 first = 1;
2333 parent_times = 0;
2334 id = path;
2335
2336 do {
2337 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002338 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Radek Krejcib1c12512015-08-11 11:22:04 +02002339 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002340 }
2341 id += i;
2342
2343 if (first) {
2344 if (parent_times == -1) {
2345 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002346 if (!node) {
2347 LOGVAL(LYE_LINE, line);
2348 /* general error, the one written later will suffice */
2349 return NULL;
2350 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002351 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002352 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002353 node = parent_node;
2354 i = 0;
2355 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002356 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002357 LOGVAL(LYE_LINE, line);
2358 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02002359 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002360 }
Michal Vasko58090902015-08-13 14:04:15 +02002361
2362 /* this node is a wrong node, we actually need the augment target */
2363 if (node->nodetype == LYS_AUGMENT) {
2364 node = ((struct lys_node_augment *)node)->target;
2365 if (!node) {
2366 continue;
2367 }
2368 }
2369
2370 ++i;
2371 if (i == parent_times) {
2372 break;
2373 }
2374 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002375 }
2376 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002377 } else {
2378 LOGINT;
2379 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002380 }
2381 first = 0;
2382 } else {
2383 node = node->child;
2384 }
2385
Michal Vasko58090902015-08-13 14:04:15 +02002386 node = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES));
2387 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002388 LOGVAL(LYE_LINE, line);
2389 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02002390 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002391 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002392
2393 if (has_predicate) {
2394 /* we have predicate, so the current result must be list */
2395 if (node->nodetype != LYS_LIST) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002396 LOGVAL(LYE_LINE, line);
2397 /* general error, the one written later will suffice */
Radek Krejcib1c12512015-08-11 11:22:04 +02002398 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002399 }
2400
2401 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Radek Krejcib1c12512015-08-11 11:22:04 +02002402 return NULL;
Michal Vasko1f76a282015-08-04 16:16:53 +02002403 }
2404 id += i;
2405 }
2406 } while (id[0]);
2407
Radek Krejcib1c12512015-08-11 11:22:04 +02002408 /* the target must be leaf or leaf-list */
2409 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
2410 LOGVAL(LYE_LINE, line);
2411 /* general error, the one written later will suffice */
2412 return NULL;
2413 }
2414
2415 return node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002416}
2417
Michal Vasko730dfdf2015-08-11 14:48:05 +02002418/**
2419 * @brief Resolve instance-identifier predicate. Does not log.
2420 *
2421 * @param[in] pred Predicate in question.
2422 * @param[in,out] node_match Nodes matching the restriction without
2423 * the predicate. Nodes not satisfying
2424 * the predicate are removed.
2425 *
2426 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2427 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002428static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002429resolve_predicate(const char *pred, struct unres_data **node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002430{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002431 /* ... /node[target = value] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002432 struct unres_data *target_match, *node, *node_prev = NULL, *tmp;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002433 const char *prefix, *name, *value;
2434 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2435
2436 idx = -1;
2437 parsed = 0;
2438
2439 do {
2440 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
2441 return -parsed+i;
2442 }
2443 parsed += i;
2444 pred += i;
2445
2446 if (isdigit(name[0])) {
2447 idx = atoi(name);
2448 }
2449
2450 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
2451 /* target */
2452 target_match = NULL;
2453 if ((name[0] == '.') || !value) {
2454 target_match = calloc(1, sizeof *target_match);
2455 target_match->dnode = node->dnode;
2456 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002457 goto remove_instid;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002458 }
2459
2460 /* check that we have the correct type */
2461 if (name[0] == '.') {
Radek Krejci76512572015-08-04 09:47:08 +02002462 if (node->dnode->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002463 goto remove_instid;
2464 }
2465 } else if (value) {
Radek Krejci76512572015-08-04 09:47:08 +02002466 if (node->dnode->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002467 goto remove_instid;
2468 }
2469 }
2470
2471 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
2472 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
2473 || (!value && (idx != cur_idx))) {
2474 goto remove_instid;
2475 }
2476
2477 while (target_match) {
2478 tmp = target_match->next;
2479 free(target_match);
2480 target_match = tmp;
2481 }
2482
2483 /* leafref is ok, continue check with next leafref */
2484 node_prev = node;
2485 node = node->next;
2486 continue;
2487
2488remove_instid:
2489 while (target_match) {
2490 tmp = target_match->next;
2491 free(target_match);
2492 target_match = tmp;
2493 }
2494
2495 /* does not fulfill conditions, remove leafref record */
2496 if (node_prev) {
2497 node_prev->next = node->next;
2498 free(node);
2499 node = node_prev->next;
2500 } else {
2501 node = (*node_match)->next;
2502 free(*node_match);
2503 *node_match = node;
2504 }
2505 }
2506 } while (has_predicate);
2507
2508 return parsed;
2509}
2510
Michal Vasko730dfdf2015-08-11 14:48:05 +02002511/**
2512 * @brief Resolve instance-identifier. Logs directly.
2513 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002514 * @param[in] data Any node in the data tree, used to get a data tree root and context
Michal Vasko730dfdf2015-08-11 14:48:05 +02002515 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002516 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002517 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002518 * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002519 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002520struct lyd_node *
2521resolve_instid(struct lyd_node *data, const char *path, int line)
2522
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523{
Radek Krejcic5090c32015-08-12 09:46:19 +02002524 int i = 0, j;
2525 struct lyd_node *result = NULL;
2526 struct lys_module *mod = NULL;
2527 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002528 const char *prefix, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002529 char *str;
2530 int pref_len, name_len, has_predicate;
2531 struct unres_data *workingnodes = NULL;
2532 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002533
Radek Krejcic5090c32015-08-12 09:46:19 +02002534 /* we need root to resolve absolute path */
2535 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002536 for (; data->prev->next; data = data->prev);
2537
Radek Krejcic5090c32015-08-12 09:46:19 +02002538 /* search for the instance node */
2539 while (path[i]) {
2540 j = parse_instance_identifier(&path[i], &prefix, &pref_len, &name, &name_len, &has_predicate);
2541 if (j <= 0) {
2542 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002543 goto error;
2544 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002545 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002546
Radek Krejcic5090c32015-08-12 09:46:19 +02002547 if (prefix) {
2548 str = strndup(prefix, pref_len);
2549 mod = ly_ctx_get_module(ctx, str, NULL);
2550 free(str);
Michal Vaskob387c482015-08-12 09:32:59 +02002551 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002552
Radek Krejcic5090c32015-08-12 09:46:19 +02002553 if (!mod) {
2554 /* no instance exists */
2555 return NULL;
2556 }
2557
2558 if (resolve_data(mod, name, name_len, data, &workingnodes)) {
2559 /* no instance exists */
2560 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561 }
2562
2563 if (has_predicate) {
2564 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcic5090c32015-08-12 09:46:19 +02002565 for (raux = NULL, riter = workingnodes; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002566 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002567 ((struct lys_node_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +02002568 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002569 /* instid is ok, continue check with next instid */
2570 raux = riter;
2571 riter = riter->next;
2572 continue;
2573 }
2574
2575 /* does not fulfill conditions, remove inst record */
2576 if (raux) {
2577 raux->next = riter->next;
2578 free(riter);
2579 riter = raux->next;
2580 } else {
Radek Krejcic5090c32015-08-12 09:46:19 +02002581 workingnodes = riter->next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002582 free(riter);
Radek Krejcic5090c32015-08-12 09:46:19 +02002583 riter = workingnodes;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002584 }
2585 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002586
2587 j = resolve_predicate(&path[i], &workingnodes);
2588 if (j < 1) {
2589 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002590 goto error;
2591 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002592 i += j;;
Michal Vaskob387c482015-08-12 09:32:59 +02002593
Radek Krejcic5090c32015-08-12 09:46:19 +02002594 if (!workingnodes) {
2595 /* no instance exists */
2596 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002597 }
2598 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002599 }
2600
Radek Krejcic5090c32015-08-12 09:46:19 +02002601 if (!workingnodes) {
2602 /* no instance exists */
2603 return NULL;
2604 } else if (workingnodes->next) {
2605 /* instance identifier must resolve to a single node */
2606 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2607
2608 /* cleanup */
2609 while (workingnodes) {
2610 raux = workingnodes->next;
2611 free(workingnodes);
2612 workingnodes = raux;
2613 }
2614
2615 return NULL;
2616 } else {
2617 /* we have required result, remember it and cleanup */
2618 result = workingnodes->dnode;
2619 free(workingnodes);
2620
2621 return result;
2622 }
2623
2624error:
2625
2626 /* cleanup */
2627 while (workingnodes) {
2628 raux = workingnodes->next;
2629 free(workingnodes);
2630 workingnodes = raux;
2631 }
2632
2633 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002634}
2635
Michal Vasko730dfdf2015-08-11 14:48:05 +02002636/**
2637 * @brief Passes config flag down to children. Does not log.
2638 *
2639 * @param[in] node Parent node.
2640 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002642inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002644 LY_TREE_FOR(node, node) {
2645 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2646 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002647 }
2648}
2649
Michal Vasko730dfdf2015-08-11 14:48:05 +02002650/**
2651 * @brief Resolve augment target, Does not log.
2652 *
2653 * @param[in] aug Augment in question.
2654 * @param[in] siblings Nodes where to start the search in.
2655 * @param[in] module Main module.
2656 *
2657 * @return EXIT_SUCCESS on success, EXIT_FAILURE otherwise.
2658 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002659int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002660resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002661{
Radek Krejci76512572015-08-04 09:47:08 +02002662 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002663
2664 assert(module);
2665
2666 /* resolve target node */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002667 aug->target = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002668 if (!aug->target) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002669 return EXIT_FAILURE;
2670 }
2671
2672 if (!aug->child) {
2673 /* nothing to do */
2674 return EXIT_SUCCESS;
2675 }
2676
2677 /* inherit config information from parent, augment does not have
2678 * config property, but we need to keep the information for subelements
2679 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002680 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002681 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002682 inherit_config_flag(sub);
2683 }
2684
Radek Krejci07911992015-08-14 15:13:31 +02002685 /* check identifier uniquness as in lys_node_addchild() */
2686 LY_TREE_FOR(aug->child, aux) {
2687 if (lys_check_id(aux, aug->parent, NULL)) {
2688 return EXIT_FAILURE;
2689 }
2690 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002691 /* reconnect augmenting data into the target - add them to the target child list */
2692 if (aug->target->child) {
2693 aux = aug->target->child->prev; /* remember current target's last node */
2694 aux->next = aug->child; /* connect augmenting data after target's last node */
2695 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2696 aug->child->prev = aux; /* finish connecting of both child lists */
2697 } else {
2698 aug->target->child = aug->child;
2699 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002700
2701 return EXIT_SUCCESS;
2702}
2703
Michal Vasko730dfdf2015-08-11 14:48:05 +02002704/**
2705 * @brief Resolve uses, apply augments, refines. Logs directly.
2706 *
2707 * @param[in] uses Uses in question.
2708 * @param[in,out] unres List of unresolved items.
2709 * @param[in] line Line in the input file.
2710 *
2711 * @return EXIT_SUCCESS on success, EXIT_FAILURER otherwise.
2712 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002713int
Michal Vaskof02e3742015-08-05 16:27:02 +02002714resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002715{
2716 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002717 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002718 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002719 struct lys_restr *newmust;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002720 int i, j;
2721 uint8_t size;
2722
Michal Vasko71e1aa82015-08-12 12:17:51 +02002723 assert(uses->grp);
2724
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002725 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002726 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002727 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002728 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002729 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002730 return EXIT_FAILURE;
2731 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002732 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002733 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002734 lys_node_free(node_aux);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002735 return EXIT_FAILURE;
2736 }
2737 }
2738 ctx = uses->module->ctx;
2739
2740 /* apply refines */
2741 for (i = 0; i < uses->refine_size; i++) {
2742 rfn = &uses->refine[i];
Radek Krejci1d82ef62015-08-07 14:44:40 +02002743 node = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF);
2744 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002745 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002746 return EXIT_FAILURE;
2747 }
2748
Radek Krejci1d82ef62015-08-07 14:44:40 +02002749 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002750 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002751 return EXIT_FAILURE;
2752 }
2753
2754 /* description on any nodetype */
2755 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002756 lydict_remove(ctx, node->dsc);
2757 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002758 }
2759
2760 /* reference on any nodetype */
2761 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002762 lydict_remove(ctx, node->ref);
2763 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002764 }
2765
2766 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002767 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002768 node->flags &= ~LYS_CONFIG_MASK;
2769 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002770 }
2771
2772 /* default value ... */
2773 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002774 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002775 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002776 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2777 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2778 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002779 /* choice */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002780 ((struct lys_node_choice *)node)->dflt = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE);
2781 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002782 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002783 return EXIT_FAILURE;
2784 }
2785 }
2786 }
2787
2788 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002789 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002790 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002791 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002792 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002793
2794 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002795 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 }
2797 }
2798
2799 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002800 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2801 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2802 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002803 }
2804
2805 /* min/max-elements on list or leaf-list */
2806 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002807 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002809 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002810 }
2811 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002812 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002813 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002814 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002815 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002816 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 }
2818 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002819 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002820 }
2821 }
2822
2823 /* must in leaf, leaf-list, list, container or anyxml */
2824 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002825 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2826 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827 if (!newmust) {
2828 LOGMEM;
2829 return EXIT_FAILURE;
2830 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002831 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002832 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2833 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2834 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2835 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2836 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2837 }
2838
Radek Krejci1d82ef62015-08-07 14:44:40 +02002839 ((struct lys_node_leaf *)node)->must = newmust;
2840 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 }
2842 }
2843
2844 /* apply augments */
2845 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002846 if (resolve_augment(&uses->augment[i], uses->child, uses->module)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002847 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
2848 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002849 }
2850 }
2851
2852 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002853}
2854
Michal Vasko730dfdf2015-08-11 14:48:05 +02002855/**
2856 * @brief Resolve base identity recursively. Does not log.
2857 *
2858 * @param[in] module Main module.
2859 * @param[in] ident Identity in question.
2860 * @param[in] basename Base name of the identity.
2861 *
2862 * @return Pointer to the identity, NULL on error.
2863 */
Radek Krejcia52656e2015-08-05 13:41:50 +02002864static struct lys_ident *
2865resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866{
Michal Vaskof02e3742015-08-05 16:27:02 +02002867 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002868 struct lys_ident *base_iter = NULL;
2869 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870
2871 /* search module */
2872 for (i = 0; i < module->ident_size; i++) {
2873 if (!strcmp(basename, module->ident[i].name)) {
2874
2875 if (!ident) {
2876 /* just search for type, so do not modify anything, just return
2877 * the base identity pointer
2878 */
2879 return &module->ident[i];
2880 }
2881
2882 /* we are resolving identity definition, so now update structures */
2883 ident->base = base_iter = &module->ident[i];
2884
2885 break;
2886 }
2887 }
2888
2889 /* search submodules */
2890 if (!base_iter) {
2891 for (j = 0; j < module->inc_size; j++) {
2892 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2893 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2894
2895 if (!ident) {
2896 return &module->inc[j].submodule->ident[i];
2897 }
2898
2899 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2900 break;
2901 }
2902 }
2903 }
2904 }
2905
2906 /* we found it somewhere */
2907 if (base_iter) {
2908 while (base_iter) {
2909 for (der = base_iter->der; der && der->next; der = der->next);
2910 if (der) {
2911 der->next = malloc(sizeof *der);
2912 der = der->next;
2913 } else {
2914 ident->base->der = der = malloc(sizeof *der);
2915 }
2916 der->next = NULL;
2917 der->ident = ident;
2918
2919 base_iter = base_iter->base;
2920 }
2921 return ident->base;
2922 }
2923
2924 return NULL;
2925}
2926
Michal Vasko730dfdf2015-08-11 14:48:05 +02002927/**
2928 * @brief Resolve base identity. Logs directly.
2929 *
2930 * @param[in] module Main module.
2931 * @param[in] ident Identity in question.
2932 * @param[in] basename Base name of the identity.
2933 * @param[in] parent Either "type" or "ident".
2934 * @param[in] line Line in the input file.
2935 *
2936 * @return Pointer to the base identity, NULL on error.
2937 */
Radek Krejcia52656e2015-08-05 13:41:50 +02002938static struct lys_ident *
Michal Vaskof02e3742015-08-05 16:27:02 +02002939resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
2940 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002941{
2942 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02002943 int i, prefix_len = 0;
Radek Krejcia52656e2015-08-05 13:41:50 +02002944 struct lys_ident *result;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945
2946 /* search for the base identity */
2947 name = strchr(basename, ':');
2948 if (name) {
2949 /* set name to correct position after colon */
2950 prefix_len = name - basename;
2951 name++;
2952
2953 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
2954 /* prefix refers to the current module, ignore it */
2955 prefix_len = 0;
2956 }
2957 } else {
2958 name = basename;
2959 }
2960
2961 if (prefix_len) {
2962 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002963 module = resolve_prefixed_module(module, basename, prefix_len);
2964 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002965 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002966 LOGVAL(LYE_INPREF, line, basename);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967 return NULL;
2968 }
2969 } else {
2970 /* search in submodules */
2971 for (i = 0; i < module->inc_size; i++) {
Radek Krejcib8048692015-08-05 13:36:34 +02002972 result = resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002973 if (result) {
2974 return result;
2975 }
2976 }
2977 }
2978
2979 /* search in the identified module */
2980 result = resolve_base_ident_sub(module, ident, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002981 if (!result) {
2982 LOGVAL(LYE_INARG, line, basename, parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002983 }
2984
2985 return result;
2986}
2987
Michal Vasko730dfdf2015-08-11 14:48:05 +02002988/**
2989 * @brief Resolve identityref. Does not log.
2990 *
2991 * @param[in] base Base identity.
2992 * @param[in] name Identityref name.
2993 * @param[in] ns Namespace of the identityref.
2994 *
2995 * @return Pointer to the identity resolvent, NULL on error.
2996 */
Radek Krejcia52656e2015-08-05 13:41:50 +02002997struct lys_ident *
2998resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002999{
Radek Krejcia52656e2015-08-05 13:41:50 +02003000 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003001
3002 if (!base || !name || !ns) {
3003 return NULL;
3004 }
3005
3006 for(der = base->der; der; der = der->next) {
3007 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3008 /* we have match */
3009 return der->ident;
3010 }
3011 }
3012
3013 /* not found */
3014 return NULL;
3015}
3016
Michal Vasko730dfdf2015-08-11 14:48:05 +02003017/**
3018 * @brief Resolve unres identity. Logs directly.
3019 *
3020 * @param[in] mod Main module.
3021 * @param[in] ident Identity in question.
3022 * @param[in] base_name Base name of the identity.
3023 * @param[in] line Line in the input file.
3024 *
3025 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3026 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003028resolve_unres_ident(struct lys_module *mod, struct lys_ident *ident, const char *base_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003029{
Michal Vaskof02e3742015-08-05 16:27:02 +02003030 if (resolve_base_ident(mod, ident, base_name, "ident", line)) {
3031 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003032 }
3033
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003034 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identity", base_name);
3035 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003036}
3037
Michal Vasko730dfdf2015-08-11 14:48:05 +02003038/**
3039 * @brief Resolve unres identityref. Logs directly.
3040 *
3041 * @param[in] mod Main module.
3042 * @param[in] type Type in question.
3043 * @param[in] base_name Base name of the identity.
3044 * @param[in] line Line in the input file.
3045 *
3046 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3047 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003049resolve_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 +02003050{
Michal Vaskof02e3742015-08-05 16:27:02 +02003051 type->info.ident.ref = resolve_base_ident(mod, NULL, base_name, "type", line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003052 if (type->info.ident.ref) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003053 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003054 }
3055
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003056 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identityref", base_name);
3057 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003058}
3059
Michal Vasko730dfdf2015-08-11 14:48:05 +02003060/**
3061 * @brief Resolve unres leafref. Logs directly.
3062 *
3063 * @param[in] mod Main module.
3064 * @param[in] type Type in question.
3065 * @param[in] node Leafref schema node.
3066 * @param[in] line Line in the input file.
3067 *
3068 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3069 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003070static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003071resolve_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 +02003072{
Radek Krejcib1c12512015-08-11 11:22:04 +02003073 type->info.lref.target = (struct lys_node_leaf *)resolve_path_arg_schema(mod, type->info.lref.path, node, line);
3074 if (type->info.lref.target) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003075 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003076 }
3077
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003078 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "leafref", type->info.lref.path);
3079 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003080}
3081
Michal Vasko730dfdf2015-08-11 14:48:05 +02003082/**
3083 * @brief Resolve unres derived type. Logs directly.
3084 *
3085 * @param[in] mod Main module.
3086 * @param[in] type Type in question.
3087 * @param[in] type_name Derived type name,
3088 * @param[in] line Line in the input file.
3089 *
3090 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3091 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003092static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003093resolve_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 +02003094{
Radek Krejci76512572015-08-04 09:47:08 +02003095 type->der = resolve_superior_type(type_name, type->prefix, mod, (struct lys_node *)type->der);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003096 if (type->der) {
Michal Vaskoa91333d2015-08-03 16:03:06 +02003097 type->base = type->der->type.base;
Michal Vaskof02e3742015-08-05 16:27:02 +02003098 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003099 }
3100
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003101 LOGVAL(LYE_INRESOLV, line, "type", type_name);
3102 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003103}
3104
Michal Vasko730dfdf2015-08-11 14:48:05 +02003105/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02003106 * @brief Resolve unres if-feature. Logs directly.
3107 *
3108 * @param[in] mod Main module.
3109 * @param[in,out] feat_ptr Pointer to the resolved feature.
3110 * @param[in] feat_name Name of the feature.
3111 * @param[in] line Line in the input file.
3112 *
3113 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3114 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003115static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003116resolve_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 +02003117{
Michal Vaskof02e3742015-08-05 16:27:02 +02003118 *feat_ptr = resolve_feature(feat_name, mod, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119 if (*feat_ptr) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003120 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003121 }
3122
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003123 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "if-feature", feat_name);
3124 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003125}
3126
Michal Vasko730dfdf2015-08-11 14:48:05 +02003127/**
3128 * @brief Resolve unres uses. Logs directly.
3129 *
3130 * @param[in] uses Uses in question.
3131 * @param[in] unres Specific unres item.
3132 * @param[in] line Line in the input file.
3133 *
3134 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3135 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003136static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003137resolve_unres_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138{
Michal Vaskoe91afce2015-08-12 12:21:00 +02003139 struct lys_node *parent;
3140
3141 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3142 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3143
Radek Krejci10c760e2015-08-14 14:45:43 +02003144 if (uses->grp || !resolve_grouping(uses, line)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003145 if (uses->grp->nacm) {
3146 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3147 return EXIT_FAILURE;
3148 } else if (!resolve_uses(uses, unres, line)) {
3149 /* decrease unres count only if not first try */
3150 if ((line < UINT_MAX) && parent) {
3151 if (!parent->nacm) {
3152 LOGINT;
3153 return EXIT_FAILURE;
3154 }
3155 --parent->nacm;
3156 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003157 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02003158 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003159 }
3160
Michal Vaskoe91afce2015-08-12 12:21:00 +02003161 if (parent) {
3162 ++parent->nacm;
3163 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003164 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "uses", uses->name);
3165 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166}
3167
Michal Vasko730dfdf2015-08-11 14:48:05 +02003168/**
3169 * @brief Resolve unres identity. Logs directly.
3170 *
3171 * @param[in] type Type in question.
3172 * @param[in] dflt Default value.
3173 * @param[in] line Line in the input file.
3174 *
3175 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3176 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003178resolve_unres_type_dflt(struct lys_type *type, const char *dflt, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179{
Michal Vasko12e30842015-08-04 11:54:00 +02003180 if (!check_default(type, dflt)) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003181 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02003182 }
3183
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003184 LOGVAL(LYE_INRESOLV, line, "type default", dflt);
3185 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003186}
3187
Michal Vasko730dfdf2015-08-11 14:48:05 +02003188/**
3189 * @brief Resolve choice default. Logs directly.
3190 *
3191 * @param[in] choice Main module.
3192 * @param[in] dflt Default case name.
3193 * @param[in] line Line in the input file.
3194 *
3195 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3196 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197static int
Michal Vasko58090902015-08-13 14:04:15 +02003198resolve_unres_choice_dflt(struct lys_module *mod, struct lys_node_choice *choice, const char *dflt, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003199{
Michal Vasko58090902015-08-13 14:04:15 +02003200 choice->dflt = resolve_sibling(mod, choice->child, NULL, 0, dflt, 0, LYS_ANYXML | LYS_CASE
3201 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202 if (choice->dflt) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003203 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003204 }
3205
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003206 LOGVAL(LYE_INRESOLV, line, "choice default", dflt);
3207 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208}
3209
Michal Vasko730dfdf2015-08-11 14:48:05 +02003210/**
3211 * @brief Resolve unres identity. Logs directly.
3212 *
3213 * @param[in] list List in question.
3214 * @param[in] keys_str Keys node value.
3215 * @param[in] line Line in the input file.
3216 *
3217 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3218 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003219static int
Michal Vasko58090902015-08-13 14:04:15 +02003220resolve_unres_list_keys(struct lys_module *mod, struct lys_node_list *list, const char *keys_str, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221{
3222 int i, len;
3223 const char *value;
3224
3225 for (i = 0; i < list->keys_size; ++i) {
3226 /* get the key name */
3227 if ((value = strpbrk(keys_str, " \t\n"))) {
3228 len = value - keys_str;
3229 while (isspace(value[0])) {
3230 value++;
3231 }
3232 } else {
3233 len = strlen(keys_str);
3234 }
3235
Michal Vasko58090902015-08-13 14:04:15 +02003236 list->keys[i] = (struct lys_node_leaf *)resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003237
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003238 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
3239 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3240 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 }
3242
3243 /* prepare for next iteration */
3244 while (value && isspace(value[0])) {
3245 value++;
3246 }
3247 keys_str = value;
3248 }
3249
Michal Vaskof02e3742015-08-05 16:27:02 +02003250 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003251}
3252
Michal Vasko730dfdf2015-08-11 14:48:05 +02003253/**
3254 * @brief Resolve unres unique. Logs directly.
3255 *
3256 * @param[in] uniq Unique in question.
3257 * @param[in] uniq_str Unique node value.
3258 * @param[in] line Line in the input file.
3259 *
3260 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3261 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003263resolve_unres_list_uniq(struct lys_unique *uniq, const char *uniq_str, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264{
Michal Vaskof02e3742015-08-05 16:27:02 +02003265 if (!resolve_unique((struct lys_node *)uniq->leafs, uniq_str, uniq, line)) {
3266 return EXIT_SUCCESS;
Michal Vasko12e30842015-08-04 11:54:00 +02003267 }
3268
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003269 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list unique", uniq_str);
3270 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271}
3272
3273static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003274resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275{
3276 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003277 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003278}
3279
3280static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003281resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282{
3283 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003284 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285}
3286
Michal Vaskof02e3742015-08-05 16:27:02 +02003287/* logs indirectly
3288 * line == -1 means do not log, 0 means unknown */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289static int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003290resolve_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 +02003291 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003292{
3293 int ret = EXIT_FAILURE, has_str = 0;
3294
3295 switch (type) {
3296 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003297 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003298 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003300 ret = resolve_unres_ident(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003301 has_str = 1;
3302 break;
3303 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003304 ret = resolve_unres_type_identref(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003305 has_str = 1;
3306 break;
3307 case UNRES_TYPE_LEAFREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003308 ret = resolve_unres_type_leafref(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003309 has_str = 0;
3310 break;
3311 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003312 ret = resolve_unres_type_der(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003313 has_str = 1;
3314 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003315 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003316 ret = resolve_unres_iffeature(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003317 has_str = 1;
3318 break;
3319 case UNRES_USES:
Michal Vaskof02e3742015-08-05 16:27:02 +02003320 ret = resolve_unres_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003321 has_str = 0;
3322 break;
3323 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003324 ret = resolve_unres_type_dflt(item, str_node, line);
3325 /* do not remove str_node (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003326 has_str = 0;
3327 break;
3328 case UNRES_CHOICE_DFLT:
Michal Vasko58090902015-08-13 14:04:15 +02003329 ret = resolve_unres_choice_dflt(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330 has_str = 1;
3331 break;
3332 case UNRES_LIST_KEYS:
Michal Vasko58090902015-08-13 14:04:15 +02003333 ret = resolve_unres_list_keys(mod, item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003334 has_str = 1;
3335 break;
3336 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003337 ret = resolve_unres_list_uniq(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003338 has_str = 1;
3339 break;
3340 case UNRES_WHEN:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003341 ret = resolve_unres_when(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003342 has_str = 0;
3343 break;
3344 case UNRES_MUST:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003345 ret = resolve_unres_must(item, str_node, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003346 has_str = 0;
3347 break;
3348 }
3349
3350 if (has_str && !ret) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003351 lydict_remove(mod->ctx, str_node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003352 }
3353
3354 return ret;
3355}
3356
Michal Vaskof02e3742015-08-05 16:27:02 +02003357/* logs directly */
3358static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003359print_unres_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360{
Michal Vaskof02e3742015-08-05 16:27:02 +02003361 char line_str[18];
3362
3363 if (line) {
3364 sprintf(line_str, " (line %u)", line);
3365 } else {
3366 line_str[0] = '\0';
3367 }
3368
3369 switch (type) {
3370 case UNRES_RESOLVED:
3371 LOGINT;
3372 break;
3373 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003374 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003375 break;
3376 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003377 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003378 break;
3379 case UNRES_TYPE_LEAFREF:
3380 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3381 break;
3382 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003383 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 +02003384 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003385 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003386 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 +02003387 break;
3388 case UNRES_USES:
3389 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3390 break;
3391 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003392 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 +02003393 break;
3394 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003395 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 +02003396 break;
3397 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003398 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 +02003399 break;
3400 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003401 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 +02003402 break;
3403 case UNRES_WHEN:
3404 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3405 break;
3406 case UNRES_MUST:
3407 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3408 break;
3409 }
3410}
3411
Michal Vasko51054ca2015-08-12 12:20:00 +02003412/* logs directly */
Michal Vaskof02e3742015-08-05 16:27:02 +02003413int
3414resolve_unres(struct lys_module *mod, struct unres_schema *unres)
3415{
Michal Vaskoc07187d2015-08-13 15:20:57 +02003416 uint32_t i, resolved, unres_uses, res_uses, line;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417
3418 assert(unres);
3419
Michal Vaskoc07187d2015-08-13 15:20:57 +02003420 line = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003421 resolved = 0;
3422
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003424 do {
3425 unres_uses = 0;
3426 res_uses = 0;
3427
3428 for (i = 0; i < unres->count; ++i) {
3429 if (unres->type[i] != UNRES_USES) {
3430 continue;
3431 }
3432
Michal Vaskoc07187d2015-08-13 15:20:57 +02003433#ifndef NDEBUG
3434 line = unres->line[i];
3435#endif
3436
Michal Vasko51054ca2015-08-12 12:20:00 +02003437 ++unres_uses;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003438 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003439 unres->type[i] = UNRES_RESOLVED;
3440 ++resolved;
3441 ++res_uses;
3442 } else {
Michal Vaskoc07187d2015-08-13 15:20:57 +02003443 print_unres_item_fail(unres->item[i], unres->type[i], unres->str_snode[i], line);
Michal Vasko51054ca2015-08-12 12:20:00 +02003444 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003446 } while (res_uses && (res_uses < unres_uses));
3447
3448 if (res_uses < unres_uses) {
3449 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
3450 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003451 }
3452
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 /* the rest */
3454 for (i = 0; i < unres->count; ++i) {
3455 if (unres->type[i] == UNRES_RESOLVED) {
3456 continue;
3457 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003458
3459#ifndef NDEBUG
3460 line = unres->line[i];
3461#endif
3462
3463 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464 unres->type[i] = UNRES_RESOLVED;
3465 ++resolved;
3466 }
3467 }
3468
3469 if (resolved < unres->count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003470 LOGVAL(LYE_SPEC, 0, "There are unresolved items left.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471 return EXIT_FAILURE;
3472 }
3473
3474 return EXIT_SUCCESS;
3475}
3476
Michal Vaskof02e3742015-08-05 16:27:02 +02003477/* logs indirectly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003479unres_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 +02003480 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481{
3482 str = lydict_insert(mod->ctx, str, 0);
Radek Krejci1d82ef62015-08-07 14:44:40 +02003483 unres_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484}
3485
Michal Vaskof02e3742015-08-05 16:27:02 +02003486/* logs indirectly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003487void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003488unres_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
3489 struct lys_node *node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003490{
3491 assert(unres && item);
3492
Radek Krejci1d82ef62015-08-07 14:44:40 +02003493 if (!resolve_unres_item(mod, item, type, node, unres, UINT_MAX)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003494 return;
3495 }
3496
Radek Krejci1d82ef62015-08-07 14:44:40 +02003497 print_unres_item_fail(item, type, node, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003498
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003499 unres->count++;
3500 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3501 unres->item[unres->count-1] = item;
3502 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3503 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003504 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
3505 unres->str_snode[unres->count-1] = node;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003506#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3508 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003509#endif
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510}
3511
Michal Vaskof02e3742015-08-05 16:27:02 +02003512/* logs indirectly */
Michal Vaskodad19402015-08-06 09:51:53 +02003513int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003514unres_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 +02003515{
3516 int i;
3517
3518 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003519 LOGINT;
3520 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003521 }
3522
Radek Krejci1d82ef62015-08-07 14:44:40 +02003523 i = unres_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524
3525 if (i == -1) {
Michal Vaskodad19402015-08-06 09:51:53 +02003526 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 }
3528
Michal Vasko4adc10f2015-08-11 15:26:17 +02003529 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003530 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003531 unres_add_node(mod, unres, new_item, type, unres->str_snode[i], 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 } else {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003533 unres_add_str(mod, unres, new_item, type, unres->str_snode[i], 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 }
Michal Vaskodad19402015-08-06 09:51:53 +02003535
3536 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003537}
3538
Michal Vaskof02e3742015-08-05 16:27:02 +02003539/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003540int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003541unres_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542{
3543 uint32_t ret = -1, i;
3544
3545 for (i = 0; i < unres->count; ++i) {
3546 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3547 ret = i;
3548 break;
3549 }
3550 }
3551
3552 return ret;
3553}