blob: 14f2c603800cf43e21cff66c39ae5bd7c2ee7c95 [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 Vaskoc935fff2015-08-17 14:02:06 +0200798 * @brief Resolve (find) a prefix in a module include import. Does not log.
799 *
800 * @param[in] mod The module with the import.
801 * @param[in] prefix The prefix to find.
802 * @param[in] pref_len The prefix length.
803 *
804 * @return The matching module on success, NULL on error.
805 */
806static struct lys_module *
807resolve_import_in_includes_recursive(struct lys_module *mod, const char *prefix, uint32_t pref_len)
808{
809 int i, j;
810 struct lys_submodule *sub_mod;
811 struct lys_module *ret;
812
813 for (i = 0; i < mod->inc_size; i++) {
814 sub_mod = mod->inc[i].submodule;
815 for (j = 0; j < sub_mod->imp_size; j++) {
816 if ((pref_len == strlen(sub_mod->imp[j].prefix))
817 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
818 return sub_mod->imp[j].module;
819 }
820 }
821 }
822
823 for (i = 0; i < mod->inc_size; i++) {
824 ret = resolve_import_in_includes_recursive((struct lys_module *)mod->inc[i].submodule, prefix, pref_len);
825 if (ret) {
826 return ret;
827 }
828 }
829
830 return NULL;
831}
832
833/**
834 * @brief Resolve (find) a prefix in a module import. Does not log.
835 *
836 * @param[in] mod The module with the import.
837 * @param[in] prefix The prefix to find.
838 * @param[in] pref_len The prefix length.
839 *
840 * @return The matching module on success, NULL on error.
841 */
842static struct lys_module *
843resolve_prefixed_module(struct lys_module *mod, const char *prefix, uint32_t pref_len)
844{
845 int i;
846
847 /* module itself */
848 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
849 return mod;
850 }
851
852 /* imported modules */
853 for (i = 0; i < mod->imp_size; i++) {
854 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
855 return mod->imp[i].module;
856 }
857 }
858
859 /* imports in includes */
860 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
861}
862
863/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200864 * @brief Resolves length or range intervals. Does not log.
865 * Syntax is assumed to be correct, *local_intv MUST be NULL.
866 *
867 * @param[in] str_restr The restriction as a string.
868 * @param[in] type The type of the restriction.
869 * @param[in] superior_restr Flag whether to check superior
870 * types.
871 * @param[out] local_intv The final interval structure.
872 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200873 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200874 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200875int
876resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr, struct len_ran_intv** local_intv)
877{
878 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200879 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200880 int64_t local_smin, local_smax;
881 uint64_t local_umin, local_umax;
882 long double local_fmin, local_fmax;
883 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200884 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200885
886 switch (type->base) {
887 case LY_TYPE_BINARY:
888 kind = 0;
889 local_umin = 0;
890 local_umax = 18446744073709551615UL;
891
892 if (!str_restr && type->info.binary.length) {
893 str_restr = type->info.binary.length->expr;
894 }
895 break;
896 case LY_TYPE_DEC64:
897 kind = 2;
898 local_fmin = -9223372036854775808.0;
899 local_fmin /= 1 << type->info.dec64.dig;
900 local_fmax = 9223372036854775807.0;
901 local_fmax /= 1 << type->info.dec64.dig;
902
903 if (!str_restr && type->info.dec64.range) {
904 str_restr = type->info.dec64.range->expr;
905 }
906 break;
907 case LY_TYPE_INT8:
908 kind = 1;
909 local_smin = -128;
910 local_smax = 127;
911
912 if (!str_restr && type->info.num.range) {
913 str_restr = type->info.num.range->expr;
914 }
915 break;
916 case LY_TYPE_INT16:
917 kind = 1;
918 local_smin = -32768;
919 local_smax = 32767;
920
921 if (!str_restr && type->info.num.range) {
922 str_restr = type->info.num.range->expr;
923 }
924 break;
925 case LY_TYPE_INT32:
926 kind = 1;
927 local_smin = -2147483648;
928 local_smax = 2147483647;
929
930 if (!str_restr && type->info.num.range) {
931 str_restr = type->info.num.range->expr;
932 }
933 break;
934 case LY_TYPE_INT64:
935 kind = 1;
936 local_smin = -9223372036854775807L - 1L;
937 local_smax = 9223372036854775807L;
938
939 if (!str_restr && type->info.num.range) {
940 str_restr = type->info.num.range->expr;
941 }
942 break;
943 case LY_TYPE_UINT8:
944 kind = 0;
945 local_umin = 0;
946 local_umax = 255;
947
948 if (!str_restr && type->info.num.range) {
949 str_restr = type->info.num.range->expr;
950 }
951 break;
952 case LY_TYPE_UINT16:
953 kind = 0;
954 local_umin = 0;
955 local_umax = 65535;
956
957 if (!str_restr && type->info.num.range) {
958 str_restr = type->info.num.range->expr;
959 }
960 break;
961 case LY_TYPE_UINT32:
962 kind = 0;
963 local_umin = 0;
964 local_umax = 4294967295;
965
966 if (!str_restr && type->info.num.range) {
967 str_restr = type->info.num.range->expr;
968 }
969 break;
970 case LY_TYPE_UINT64:
971 kind = 0;
972 local_umin = 0;
973 local_umax = 18446744073709551615UL;
974
975 if (!str_restr && type->info.num.range) {
976 str_restr = type->info.num.range->expr;
977 }
978 break;
979 case LY_TYPE_STRING:
980 kind = 0;
981 local_umin = 0;
982 local_umax = 18446744073709551615UL;
983
984 if (!str_restr && type->info.str.length) {
985 str_restr = type->info.str.length->expr;
986 }
987 break;
988 default:
989 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200990 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200991 }
992
993 /* process superior types */
994 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200995 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
996 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200997 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200998 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200999 assert(!intv || (intv->kind == kind));
1000 }
1001
1002 if (!str_restr) {
1003 /* we are validating data and not have any restriction, but a superior type might have */
1004 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001005 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1006 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001007 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001008 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001009 assert(!intv || (intv->kind == kind));
1010 }
1011 *local_intv = intv;
1012 return EXIT_SUCCESS;
1013 }
1014
1015 /* adjust local min and max */
1016 if (intv) {
1017 tmp_intv = intv;
1018
1019 if (kind == 0) {
1020 local_umin = tmp_intv->value.uval.min;
1021 } else if (kind == 1) {
1022 local_smin = tmp_intv->value.sval.min;
1023 } else if (kind == 2) {
1024 local_fmin = tmp_intv->value.fval.min;
1025 }
1026
1027 while (tmp_intv->next) {
1028 tmp_intv = tmp_intv->next;
1029 }
1030
1031 if (kind == 0) {
1032 local_umax = tmp_intv->value.uval.max;
1033 } else if (kind == 1) {
1034 local_smax = tmp_intv->value.sval.max;
1035 } else if (kind == 2) {
1036 local_fmax = tmp_intv->value.fval.max;
1037 }
1038 }
1039
1040 /* finally parse our restriction */
1041 seg_ptr = str_restr;
1042 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001043 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001044 *local_intv = malloc(sizeof **local_intv);
1045 tmp_local_intv = *local_intv;
1046 } else {
1047 tmp_local_intv->next = malloc(sizeof **local_intv);
1048 tmp_local_intv = tmp_local_intv->next;
1049 }
1050
1051 tmp_local_intv->kind = kind;
1052 tmp_local_intv->next = NULL;
1053
1054 /* min */
1055 ptr = seg_ptr;
1056 while (isspace(ptr[0])) {
1057 ++ptr;
1058 }
1059 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1060 if (kind == 0) {
1061 tmp_local_intv->value.uval.min = atoll(ptr);
1062 } else if (kind == 1) {
1063 tmp_local_intv->value.sval.min = atoll(ptr);
1064 } else if (kind == 2) {
1065 tmp_local_intv->value.fval.min = atoll(ptr);
1066 }
1067
1068 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1069 ++ptr;
1070 }
1071 while (isdigit(ptr[0])) {
1072 ++ptr;
1073 }
1074 } else if (!strncmp(ptr, "min", 3)) {
1075 if (kind == 0) {
1076 tmp_local_intv->value.uval.min = local_umin;
1077 } else if (kind == 1) {
1078 tmp_local_intv->value.sval.min = local_smin;
1079 } else if (kind == 2) {
1080 tmp_local_intv->value.fval.min = local_fmin;
1081 }
1082
1083 ptr += 3;
1084 } else if (!strncmp(ptr, "max", 3)) {
1085 if (kind == 0) {
1086 tmp_local_intv->value.uval.min = local_umax;
1087 } else if (kind == 1) {
1088 tmp_local_intv->value.sval.min = local_smax;
1089 } else if (kind == 2) {
1090 tmp_local_intv->value.fval.min = local_fmax;
1091 }
1092
1093 ptr += 3;
1094 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001095 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001096 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001097 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001098 }
1099
1100 while (isspace(ptr[0])) {
1101 ptr++;
1102 }
1103
1104 /* no interval or interval */
1105 if ((ptr[0] == '|') || !ptr[0]) {
1106 if (kind == 0) {
1107 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1108 } else if (kind == 1) {
1109 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1110 } else if (kind == 2) {
1111 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1112 }
1113 } else if (!strncmp(ptr, "..", 2)) {
1114 /* skip ".." */
1115 ptr += 2;
1116 while (isspace(ptr[0])) {
1117 ++ptr;
1118 }
1119
1120 /* max */
1121 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1122 if (kind == 0) {
1123 tmp_local_intv->value.uval.max = atoll(ptr);
1124 } else if (kind == 1) {
1125 tmp_local_intv->value.sval.max = atoll(ptr);
1126 } else if (kind == 2) {
1127 tmp_local_intv->value.fval.max = atoll(ptr);
1128 }
1129 } else if (!strncmp(ptr, "max", 3)) {
1130 if (kind == 0) {
1131 tmp_local_intv->value.uval.max = local_umax;
1132 } else if (kind == 1) {
1133 tmp_local_intv->value.sval.max = local_smax;
1134 } else if (kind == 2) {
1135 tmp_local_intv->value.fval.max = local_fmax;
1136 }
1137 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001138 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001139 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001140 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001141 }
1142 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001143 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001144 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001145 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001146 }
1147
1148 /* next segment (next OR) */
1149 seg_ptr = strchr(seg_ptr, '|');
1150 if (!seg_ptr) {
1151 break;
1152 }
1153 seg_ptr++;
1154 }
1155
1156 /* check local restrictions against superior ones */
1157 if (intv) {
1158 tmp_intv = intv;
1159 tmp_local_intv = *local_intv;
1160
1161 while (tmp_local_intv && tmp_intv) {
1162 /* reuse local variables */
1163 if (kind == 0) {
1164 local_umin = tmp_local_intv->value.uval.min;
1165 local_umax = tmp_local_intv->value.uval.max;
1166
1167 /* it must be in this interval */
1168 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1169 /* this interval is covered, next one */
1170 if (local_umax <= tmp_intv->value.uval.max) {
1171 tmp_local_intv = tmp_local_intv->next;
1172 continue;
1173 /* ascending order of restrictions -> fail */
1174 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001175 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001176 goto cleanup;
1177 }
1178 }
1179 } else if (kind == 1) {
1180 local_smin = tmp_local_intv->value.sval.min;
1181 local_smax = tmp_local_intv->value.sval.max;
1182
1183 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1184 if (local_smax <= tmp_intv->value.sval.max) {
1185 tmp_local_intv = tmp_local_intv->next;
1186 continue;
1187 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001188 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001189 goto cleanup;
1190 }
1191 }
1192 } else if (kind == 2) {
1193 local_fmin = tmp_local_intv->value.fval.min;
1194 local_fmax = tmp_local_intv->value.fval.max;
1195
1196 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1197 if (local_fmax <= tmp_intv->value.fval.max) {
1198 tmp_local_intv = tmp_local_intv->next;
1199 continue;
1200 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001201 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001202 goto cleanup;
1203 }
1204 }
1205 }
1206
1207 tmp_intv = tmp_intv->next;
1208 }
1209
1210 /* some interval left uncovered -> fail */
1211 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001212 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001213 }
1214
1215 }
1216
1217cleanup:
1218 while (intv) {
1219 tmp_intv = intv->next;
1220 free(intv);
1221 intv = tmp_intv;
1222 }
1223
1224 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001225 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001226 while (*local_intv) {
1227 tmp_local_intv = (*local_intv)->next;
1228 free(*local_intv);
1229 *local_intv = tmp_local_intv;
1230 }
1231 }
1232
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001233 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001234}
1235
Michal Vasko730dfdf2015-08-11 14:48:05 +02001236/**
1237 * @brief Resolve a typedef. Does not log.
1238 *
1239 * @param[in] name Typedef name.
1240 * @param[in] prefix Typedef name prefix.
1241 * @param[in] module The main module.
1242 * @param[in] parent The parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001243 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001244 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001245 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001246 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001247int
1248resolve_superior_type(const char *name, const char *prefix, struct lys_module *module, struct lys_node *parent,
1249 struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001250{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001251 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001252 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001253 int tpdf_size;
1254
1255 if (!prefix) {
1256 /* no prefix, try built-in types */
1257 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1258 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001259 if (ret) {
1260 *ret = ly_types[i].def;
1261 }
1262 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001263 }
1264 }
1265 } else {
1266 if (!strcmp(prefix, module->prefix)) {
1267 /* prefix refers to the current module, ignore it */
1268 prefix = NULL;
1269 }
1270 }
1271
1272 if (!prefix && parent) {
1273 /* search in local typedefs */
1274 while (parent) {
1275 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001276 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001277 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1278 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001279 break;
1280
Radek Krejci76512572015-08-04 09:47:08 +02001281 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001282 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1283 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001284 break;
1285
Radek Krejci76512572015-08-04 09:47:08 +02001286 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001287 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1288 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001289 break;
1290
Radek Krejci76512572015-08-04 09:47:08 +02001291 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001292 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1293 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001294 break;
1295
Radek Krejci76512572015-08-04 09:47:08 +02001296 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001297 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1298 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001299 break;
1300
Radek Krejci76512572015-08-04 09:47:08 +02001301 case LYS_INPUT:
1302 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001303 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1304 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001305 break;
1306
1307 default:
1308 parent = parent->parent;
1309 continue;
1310 }
1311
1312 for (i = 0; i < tpdf_size; i++) {
1313 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001314 if (ret) {
1315 *ret = &tpdf[i];
1316 }
1317 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001318 }
1319 }
1320
1321 parent = parent->parent;
1322 }
1323 } else if (prefix) {
1324 /* get module where to search */
Michal Vaskoc935fff2015-08-17 14:02:06 +02001325 module = resolve_prefixed_module(module, prefix, strlen(prefix));
1326 if (!module) {
1327 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001328 }
1329 }
1330
1331 /* search in top level typedefs */
1332 for (i = 0; i < module->tpdf_size; i++) {
1333 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001334 if (ret) {
1335 *ret = &module->tpdf[i];
1336 }
1337 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001338 }
1339 }
1340
1341 /* search in submodules */
1342 for (i = 0; i < module->inc_size; i++) {
1343 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1344 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001345 if (ret) {
1346 *ret = &module->inc[i].submodule->tpdf[j];
1347 }
1348 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001349 }
1350 }
1351 }
1352
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001353 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001354}
1355
1356static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001357check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001358{
1359 /* TODO - RFC 6020, sec. 7.3.4 */
1360 (void)type;
1361 (void)value;
1362 return EXIT_SUCCESS;
1363}
1364
Michal Vasko730dfdf2015-08-11 14:48:05 +02001365/**
1366 * @brief Check a key for mandatory attributes. Logs directly.
1367 *
1368 * @param[in] key The key to check.
1369 * @param[in] flags What flags to check.
1370 * @param[in] list The list of all the keys.
1371 * @param[in] index Index of the key in the key list.
1372 * @param[in] name The name of the keys.
1373 * @param[in] len The name length.
1374 * @param[in] line The line in the input file.
1375 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001376 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001377 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001378static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001379check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1380 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001381{
1382 char *dup = NULL;
1383 int j;
1384
1385 /* existence */
1386 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001387 if (name[len] != '\0') {
1388 dup = strdup(name);
1389 dup[len] = '\0';
1390 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001391 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001392 LOGVAL(LYE_KEY_MISS, line, name);
1393 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001394 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001395 }
1396
1397 /* uniqueness */
1398 for (j = index - 1; j >= 0; j--) {
1399 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001400 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001401 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001402 }
1403 }
1404
1405 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001406 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001407 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001408 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001409 }
1410
1411 /* type of the leaf is not built-in empty */
1412 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001413 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001414 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001415 }
1416
1417 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001418 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001419 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001420 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001421 }
1422
1423 return EXIT_SUCCESS;
1424}
1425
Michal Vasko730dfdf2015-08-11 14:48:05 +02001426/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001427 * @brief Resolve (fill) a unique. Logs directly.
1428 *
1429 * @param[in] parent The parent node of the unique structure.
1430 * @param[in] uniq_str The value of the unique node.
1431 * @param[in] uniq_s The unique structure in question.
1432 * @param[in] line The line in the input file.
1433 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001434 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001435 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001436int
Michal Vaskof02e3742015-08-05 16:27:02 +02001437resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001438{
1439 char *uniq_val, *uniq_begin, *start;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001440 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001441
1442 /* count the number of unique values */
1443 uniq_val = uniq_begin = strdup(uniq_str);
1444 uniq_s->leafs_size = 0;
1445 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1446 uniq_s->leafs_size++;
1447 while (isspace(*uniq_val)) {
1448 uniq_val++;
1449 }
1450 }
1451 uniq_s->leafs_size++;
1452 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1453
1454 /* interconnect unique values with the leafs */
1455 uniq_val = uniq_begin;
1456 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1457 start = uniq_val;
1458 if ((uniq_val = strpbrk(start, " \t\n"))) {
1459 *uniq_val = '\0'; /* add terminating NULL byte */
1460 uniq_val++;
1461 while (isspace(*uniq_val)) {
1462 uniq_val++;
1463 }
1464 } /* else only one nodeid present/left already NULL byte terminated */
1465
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001466 rc = resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF,
1467 (struct lys_node **)&uniq_s->leafs[i]);
1468 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001469 LOGVAL(LYE_INARG, line, start, "unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001470 if (rc == EXIT_FAILURE) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001471 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001472 }
1473 goto error;
1474 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001475 if (uniq_s->leafs[i]->nodetype != LYS_LEAF) {
1476 LOGVAL(LYE_INARG, line, start, "unique");
1477 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1478 rc = -1;
1479 goto error;
1480 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001481
1482 for (j = 0; j < i; j++) {
1483 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001484 LOGVAL(LYE_INARG, line, start, "unique");
1485 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001486 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001487 goto error;
1488 }
1489 }
1490 }
1491
1492 free(uniq_begin);
1493 return EXIT_SUCCESS;
1494
1495error:
1496
1497 free(uniq_s->leafs);
1498 free(uniq_begin);
1499
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001500 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001501}
1502
Michal Vasko730dfdf2015-08-11 14:48:05 +02001503/**
1504 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1505 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001506 * @param[in] uses The uses in question.
1507 * @param[in] line The line in the input file.
1508 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001509 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001510 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001511static int
Radek Krejci10c760e2015-08-14 14:45:43 +02001512resolve_grouping(struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001513{
Michal Vasko58090902015-08-13 14:04:15 +02001514 struct lys_module *module = uses->module;
1515 const char *prefix, *name;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001516 int i, pref_len, nam_len, rc;
Radek Krejci10c760e2015-08-14 14:45:43 +02001517 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001518
Michal Vasko58090902015-08-13 14:04:15 +02001519 /* parse the identifier, it must be parsed on one call */
1520 if ((i = parse_node_identifier(uses->name, &prefix, &pref_len, &name, &nam_len)) < 1) {
1521 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001522 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001523 } else if (uses->name[i]) {
1524 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001525 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001526 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001527
Michal Vasko58090902015-08-13 14:04:15 +02001528 if (!prefix) {
1529 /* search in local tree hierarchy */
Radek Krejci10c760e2015-08-14 14:45:43 +02001530 if (!uses->parent) {
1531 start = (struct lys_node *)uses;
1532 while (start->prev->next) {
1533 start = start->prev;
1534 }
1535 } else {
1536 start = uses->parent->child;
1537 }
1538 while (start) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001539 rc = resolve_sibling(module, start, prefix, pref_len, name, nam_len, LYS_GROUPING, (struct lys_node **)&uses->grp);
1540 if (rc != EXIT_FAILURE) {
Michal Vaskod9173342015-08-17 14:35:36 +02001541 if (rc == -1) {
1542 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
1543 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001544 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001545 }
Radek Krejci10c760e2015-08-14 14:45:43 +02001546 start = start->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001547 }
1548 }
1549
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001550 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001551 return EXIT_FAILURE;
1552}
1553
Michal Vasko730dfdf2015-08-11 14:48:05 +02001554/**
1555 * @brief Resolve (find) a feature definition. Logs directly.
1556 *
1557 * @param[in] name Feature name.
1558 * @param[in] module Module to search in.
1559 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001560 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001561 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001562 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001563 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001564static int
1565resolve_feature(const char *id, struct lys_module *module, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001566{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001567 const char *prefix, *name;
1568 int pref_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001569
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001570 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001571 assert(module);
1572
1573 /* check prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001574 if ((i = parse_node_identifier(id, &prefix, &pref_len, &name, &nam_len)) < 1) {
1575 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1576 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001577 }
1578
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001579 if (prefix) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001580 /* search in imported modules */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001581 module = resolve_prefixed_module(module, prefix, pref_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001582 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001583 /* identity refers unknown data model */
Michal Vaskod9173342015-08-17 14:35:36 +02001584 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001585 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001586 }
1587 } else {
1588 /* search in submodules */
1589 for (i = 0; i < module->inc_size; i++) {
1590 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1591 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001592 if (ret) {
1593 *ret = &(module->inc[i].submodule->features[j]);
1594 }
1595 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001596 }
1597 }
1598 }
1599 }
1600
1601 /* search in the identified module */
1602 for (j = 0; j < module->features_size; j++) {
1603 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001604 if (ret) {
1605 *ret = &module->features[j];
1606 }
1607 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001608 }
1609 }
1610
1611 /* not found */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001612 LOGVAL(LYE_INRESOLV, line, "feature", id);
1613 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001614}
1615
Michal Vasko730dfdf2015-08-11 14:48:05 +02001616/**
Michal Vasko58090902015-08-13 14:04:15 +02001617 * @brief Resolve (find) a valid sibling. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001618 *
Michal Vasko58090902015-08-13 14:04:15 +02001619 * Valid child means a schema pointer to a node that is part of
1620 * the data meaning uses are skipped. Includes module comparison
1621 * (can handle augments). Includes are also searched if siblings
1622 * are top-level nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001623 *
Michal Vasko58090902015-08-13 14:04:15 +02001624 * @param[in] mod Main module. Prefix is considered to be from this module.
1625 * @param[in] siblings Siblings to consider. They are first adjusted to
1626 * point to the first sibling.
1627 * @param[in] prefix Node prefix.
1628 * @param[in] pref_len Node prefix length.
1629 * @param[in] name Node name.
1630 * @param[in] nam_len Node name length.
1631 * @param[in] type ORed desired type of the node. 0 means any type.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001632 * @param[out] ret Pointer to the node of the desired type. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001633 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001634 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001635 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001636int
Michal Vasko58090902015-08-13 14:04:15 +02001637resolve_sibling(struct lys_module *mod, struct lys_node *siblings, const char *prefix, int pref_len, const char *name,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001638 int nam_len, LYS_NODE type, struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001639{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001640 struct lys_node *node, *old_siblings = NULL;
Michal Vasko58090902015-08-13 14:04:15 +02001641 struct lys_module *prefix_mod, *cur_mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001642 int in_submod, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001643
Michal Vasko58090902015-08-13 14:04:15 +02001644 assert(mod && siblings && name);
1645 assert(!(type & LYS_USES));
1646
1647 /* find the beginning */
1648 while (siblings->prev->next) {
1649 siblings = siblings->prev;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001650 }
1651
Michal Vasko58090902015-08-13 14:04:15 +02001652 /* fill the name length in case the caller is so indifferent */
1653 if (!nam_len) {
1654 nam_len = strlen(name);
1655 }
1656
1657 /* we start with the module itself, submodules come later */
1658 in_submod = 0;
1659
1660 /* set prefix_mod correctly */
1661 if (prefix) {
1662 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1663 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001664 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001665 }
1666 cur_mod = prefix_mod;
1667 /* it is our module */
1668 if (cur_mod != mod) {
1669 old_siblings = siblings;
1670 siblings = cur_mod->data;
1671 }
1672 } else {
1673 prefix_mod = mod;
1674 if (prefix_mod->type) {
1675 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1676 }
1677 cur_mod = prefix_mod;
1678 }
1679
1680 while (1) {
1681 /* try to find the node */
1682 LY_TREE_FOR(siblings, node) {
1683 if (node->nodetype == LYS_USES) {
1684 /* an unresolved uses, we can still find it elsewhere */
1685 if (!node->child) {
1686 continue;
1687 }
1688
1689 /* search recursively */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001690 rc = resolve_sibling(mod, node->child, prefix, pref_len, name, nam_len, type, ret);
1691 if (rc != EXIT_FAILURE) {
1692 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001693 }
1694 }
1695
1696 if (!type || (node->nodetype & type)) {
1697 /* module check */
1698 if (!node->module->type) {
1699 if (cur_mod != node->module) {
1700 continue;
1701 }
1702 } else {
1703 if (cur_mod != ((struct lys_submodule *)node->module)->belongsto) {
1704 continue;
1705 }
1706 }
1707
1708 /* direct name check */
1709 if (node->name == name || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001710 if (ret) {
1711 *ret = node;
1712 }
1713 return EXIT_SUCCESS;
Michal Vasko58090902015-08-13 14:04:15 +02001714 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001715 }
1716 }
1717
Michal Vasko58090902015-08-13 14:04:15 +02001718 /* The original siblings may be valid,
1719 * it's a special case when we're looking
1720 * for a node from augment.
1721 */
1722 if (old_siblings) {
1723 siblings = old_siblings;
1724 old_siblings = NULL;
1725 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001726 }
Michal Vasko58090902015-08-13 14:04:15 +02001727
1728 /* we're not top-level, search ended */
1729 if (siblings->parent) {
1730 break;
1731 }
1732
1733 /* let's try the submodules */
1734 if (in_submod == prefix_mod->inc_size) {
1735 break;
1736 }
1737 cur_mod = (struct lys_module *)prefix_mod->inc[in_submod].submodule;
1738 siblings = cur_mod->data;
1739 ++in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001740 }
1741
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001742 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001743}
1744
Michal Vasko730dfdf2015-08-11 14:48:05 +02001745/**
1746 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001747 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001748 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001749 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001750 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001751 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1752 *
1753 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
1754 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001755 *
1756 * @param[in] id Schema-nodeid string.
1757 * @param[in] start Start of the relative search.
1758 * @param[in] mod Module in question.
1759 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001760 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001761 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001762 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001763 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001764int
1765resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1766 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001767{
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001768 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +02001769 struct lys_node *sibling;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001770 int i, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +02001771 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001772 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1773 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001774 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001775 uint8_t in_mod_part = 0;
1776
1777 assert(mod);
1778 assert(id);
1779
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001780 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1781 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001782 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001783 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001784
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001785 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001786 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001787 }
1788
1789 /* absolute-schema-nodeid */
1790 if (!is_relative) {
1791 if (prefix) {
1792 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
1793 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001794 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001795 }
1796 start = start_mod->data;
1797 } else {
1798 start = mod->data;
1799 start_mod = mod;
1800 }
1801 /* descendant-schema-nodeid */
1802 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001803 if (start) {
1804 start_mod = start->module;
1805 } else {
1806 start_mod = mod;
1807 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001808 }
1809
1810 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001811 sibling = NULL;
1812 LY_TREE_FOR(start, sibling) {
1813 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001814 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
1815 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001816 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001817 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001818
Michal Vasko1e989c02015-08-04 12:33:00 +02001819 /* prefix match check */
1820 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001821 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1822 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001823 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001824 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001825 } else {
1826 prefix_mod = mod;
1827 if (prefix_mod->type) {
1828 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1829 }
1830 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001831
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001832 /* modules need to always be checked, we want to skip augments */
1833 if (!sibling->module->type) {
1834 if (prefix_mod != sibling->module) {
1835 continue;
1836 }
1837 } else {
1838 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1839 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001840 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001842
Michal Vasko1e989c02015-08-04 12:33:00 +02001843 /* the result node? */
1844 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001845 /* we're looking only for groupings, this is a data node */
1846 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1847 continue;
1848 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001849 if (ret) {
1850 *ret = sibling;
1851 }
1852 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001853 }
1854
Michal Vaskodcc7a802015-08-06 11:59:47 +02001855 /* we're looking for a grouping (node_type == LYS_USES),
1856 * but this isn't it, we cannot search inside
1857 */
1858 if (sibling->nodetype == LYS_GROUPING) {
1859 continue;
1860 }
1861
Michal Vasko1e989c02015-08-04 12:33:00 +02001862 /* check for shorthand cases - then 'start' does not change */
1863 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1864 || (sibling->nodetype == LYS_CASE)) {
1865 start = sibling->child;
1866 }
1867 break;
1868 }
1869 }
1870
1871 /* we did not find the case in direct siblings */
1872 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001873 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001874 }
1875
1876 /* no match */
1877 if (!sibling) {
1878 /* on augment search also RPCs and notifications, if we are in top-level */
1879 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1880 /* we have searched all the data nodes */
1881 if (in_mod_part == 0) {
1882 if (!in_submod) {
1883 start = start_mod->rpc;
1884 } else {
1885 start = start_mod->inc[in_submod-1].submodule->rpc;
1886 }
1887 in_mod_part = 1;
1888 continue;
1889 }
1890 /* we have searched all the RPCs */
1891 if (in_mod_part == 1) {
1892 if (!in_submod) {
1893 start = start_mod->notif;
1894 } else {
1895 start = start_mod->inc[in_submod-1].submodule->notif;
1896 }
1897 in_mod_part = 2;
1898 continue;
1899 }
1900 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001901 }
1902
Michal Vasko1e989c02015-08-04 12:33:00 +02001903 /* are we done with the included submodules as well? */
1904 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001905 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001906 }
1907
Michal Vasko1e989c02015-08-04 12:33:00 +02001908 /* we aren't, check the next one */
1909 ++in_submod;
1910 in_mod_part = 0;
1911 start = start_mod->inc[in_submod-1].submodule->data;
1912 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001913 }
1914
1915 /* we found our submodule */
1916 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001917 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001918 in_submod = 0;
1919 }
1920
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001921 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1922 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001923 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001924 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001925 }
1926
1927 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001928 LOGINT;
1929 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001930}
1931
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001932/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001933static int
Radek Krejcic5090c32015-08-12 09:46:19 +02001934resolve_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 +02001935{
Radek Krejcic5090c32015-08-12 09:46:19 +02001936 struct unres_data *item, *par_iter, *prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001937 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001938 int flag;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001939
1940 if (!*parents) {
1941 *parents = malloc(sizeof **parents);
1942 (*parents)->dnode = NULL;
1943 (*parents)->next = NULL;
1944 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001945 for (par_iter = *parents; par_iter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001946 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001947 /* skip */
1948 continue;
1949 }
1950 flag = 0;
Radek Krejcic5090c32015-08-12 09:46:19 +02001951 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001952 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1953 && node->schema->name[nam_len] == '\0') {
1954 /* matching target */
1955 if (!flag) {
1956 /* replace leafref instead of the current parent */
1957 par_iter->dnode = node;
1958 flag = 1;
1959 } else {
1960 /* multiple matching, so create new leafref structure */
1961 item = malloc(sizeof *item);
1962 item->dnode = node;
1963 item->next = par_iter->next;
1964 par_iter->next = item;
1965 par_iter = par_iter->next;
1966 }
1967 }
1968 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001969
1970 if (!flag) {
1971 /* remove item from the parents list */
1972 if (prev) {
1973 prev->next = par_iter->next;
1974 free(par_iter);
1975 par_iter = prev->next;
1976 } else {
1977 item = par_iter->next;
1978 free(par_iter);
1979 par_iter = *parents = item;
1980 }
1981 } else {
1982 prev = par_iter;
1983 par_iter = par_iter->next;
1984 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001985 }
1986
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001987 return *parents ? EXIT_SUCCESS : -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001988}
1989
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001990/**
1991 * @brief Resolve (find) a data node. Does not log.
1992 *
1993 * @param[in] prefix Prefix of the data node.
1994 * @param[in] pref_len Length of the prefix.
1995 * @param[in] name Name of the data node.
1996 * @param[in] nam_len Length of the name.
1997 * @param[in] start Data node to start the search from.
1998 * @param[in,out] parents Resolved nodes. If there are some parents,
1999 * they are replaced (!!) with the resolvents.
2000 *
2001 * @return EXIT_SUCCESS on success, -1 otherwise.
2002 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002003static int
2004resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int name_len, struct lyd_node *start,
2005 struct unres_data **parents)
2006{
2007 struct lys_module *mod;
2008
2009 if (prefix) {
2010 /* we have prefix, find appropriate module */
2011 mod = resolve_prefixed_module(start->schema->module, prefix, pref_len);
2012 if (!mod) {
2013 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002014 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002015 }
2016 } else {
2017 /* no prefix, module is the same as of current node */
2018 mod = start->schema->module;
2019 }
2020
2021 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002022}
2023
Michal Vasko730dfdf2015-08-11 14:48:05 +02002024/**
Michal Vaskod9173342015-08-17 14:35:36 +02002025 * @brief Resolve a path predicate (leafref) in data context. Logs directly
2026 * only specific errors, general no-resolvent error is left to the caller,
2027 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002028 *
2029 * @param[in] pred Predicate in question.
2030 * @param[in,out] node_match Nodes satisfying the restriction
2031 * without the predicate. Nodes not
2032 * satisfying the predicate are removed.
2033 * @param[in] line Line in the input file.
2034 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002035 * @return Number of characters successfully parsed,
2036 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002037 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002038static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002039resolve_path_predicate_data(const char *pred, struct unres_data **node_match, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002040{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002041 /* ... /node[source = destination] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002042 struct unres_data *source_match, *dest_match, *node, *node_prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002043 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2044 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2045 int has_predicate, dest_parent_times, i;
2046
2047 do {
2048 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2049 &pke_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002050 LOGVAL(LYE_INCHAR, line, pred[-i], pred-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002051 return -parsed+i;
2052 }
2053 parsed += i;
2054 pred += i;
2055
2056 for (node = *node_match; node;) {
2057 /* source */
2058 source_match = NULL;
2059 /* must be leaf (key of a list) */
2060 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
2061 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +02002062 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002063 LOGVAL(LYE_LINE, line);
2064 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002065 return -parsed;
2066 }
2067
2068 /* destination */
2069 dest_match = calloc(1, sizeof *dest_match);
2070 dest_match->dnode = node->dnode;
2071 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2072 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002073 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002074 return -parsed+i;
2075 }
2076 pke_parsed += i;
2077 for (i = 0; i < dest_parent_times; ++i) {
2078 dest_match->dnode = dest_match->dnode->parent;
2079 if (!dest_match->dnode) {
2080 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002081 LOGVAL(LYE_LINE, line);
2082 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002083 return -parsed;
2084 }
2085 }
2086 while (1) {
2087 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
Michal Vasko1f76a282015-08-04 16:16:53 +02002088 || !dest_match->dnode || dest_match->next) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002089 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002090 LOGVAL(LYE_LINE, line);
2091 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002092 return -parsed;
2093 }
2094
2095 if (pke_len == pke_parsed) {
2096 break;
2097 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002098 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 +02002099 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002100 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101 return -parsed+i;
2102 }
2103 pke_parsed += i;
2104 }
2105
2106 /* check match between source and destination nodes */
Radek Krejcib8048692015-08-05 13:36:34 +02002107 if (((struct lys_node_leaf *)source_match->dnode->schema)->type.base
2108 != ((struct lys_node_leaf *)dest_match->dnode->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002109 goto remove_leafref;
2110 }
2111
2112 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
2113 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
2114 goto remove_leafref;
2115 }
2116
2117 /* leafref is ok, continue check with next leafref */
2118 node_prev = node;
2119 node = node->next;
2120 continue;
2121
2122remove_leafref:
2123 /* does not fulfill conditions, remove leafref record */
2124 if (node_prev) {
2125 node_prev->next = node->next;
2126 free(node);
2127 node = node_prev->next;
2128 } else {
2129 node = (*node_match)->next;
2130 free(*node_match);
2131 *node_match = node;
2132 }
2133 }
2134 } while (has_predicate);
2135
2136 return parsed;
2137}
2138
Michal Vasko730dfdf2015-08-11 14:48:05 +02002139/**
2140 * @brief Resolve a path (leafref) in data context. Logs directly.
2141 *
2142 * @param[in] unres Nodes matching the schema path.
2143 * @param[in] path Path in question.
2144 * @param[in,out] ret Matching nodes.
2145 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002146 * @return EXIT_SUCCESS on success, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002147 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002148int
Michal Vaskof02e3742015-08-05 16:27:02 +02002149resolve_path_arg_data(struct unres_data *unres, const char *path, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002150{
Radek Krejci71b795b2015-08-10 16:20:39 +02002151 struct lyd_node *data = NULL;
Michal Vaskof02e3742015-08-05 16:27:02 +02002152 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002153 const char *prefix, *name;
Michal Vaskod9173342015-08-17 14:35:36 +02002154 int pref_len, nam_len, has_predicate, parent_times, i, parsed;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002155
2156 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002157 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002158 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002159
2160 /* searching for nodeset */
2161 do {
2162 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002163 LOGVAL(LYE_INCHAR, LOGLINE(unres), path[-i], path-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002164 goto error;
2165 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002167 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002168
2169 if (!*ret) {
2170 *ret = calloc(1, sizeof **ret);
2171 for (i = 0; i < parent_times; ++i) {
2172 /* relative path */
2173 if (!*ret) {
2174 /* error, too many .. */
Michal Vaskoc07187d2015-08-13 15:20:57 +02002175 LOGVAL(LYE_INVAL, LOGLINE(unres), path, unres->dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002176 goto error;
2177 } else if (!(*ret)->dnode) {
2178 /* first .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002179 data = (*ret)->dnode = unres->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002180 } else if (!(*ret)->dnode->parent) {
2181 /* we are in root */
2182 free(*ret);
2183 *ret = NULL;
2184 } else {
2185 /* multiple .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002186 data = (*ret)->dnode = (*ret)->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002187 }
2188 }
2189
2190 /* absolute path */
2191 if (parent_times == -1) {
2192 for (data = unres->dnode; data->parent; data = data->parent);
2193 for (; data->prev->next; data = data->prev);
2194 }
2195 }
2196
2197 /* node identifier */
2198 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002199 LOGVAL(LYE_INELEM_LEN, LOGLINE(unres), nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002200 goto error;
2201 }
2202
2203 if (has_predicate) {
2204 /* we have predicate, so the current results must be lists */
2205 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002206 if (riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002207 ((struct lys_node_list *)riter->dnode->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002208 /* leafref is ok, continue check with next leafref */
2209 raux = riter;
2210 riter = riter->next;
2211 continue;
2212 }
2213
2214 /* does not fulfill conditions, remove leafref record */
2215 if (raux) {
2216 raux->next = riter->next;
2217 free(riter);
2218 riter = raux->next;
2219 } else {
2220 *ret = riter->next;
2221 free(riter);
2222 riter = *ret;
2223 }
2224 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02002225 if ((i = resolve_path_predicate_data(path, ret, LOGLINE(unres))) < 1) {
Michal Vaskod9173342015-08-17 14:35:36 +02002226 /* line was already displayed */
2227 LOGVAL(LYE_NORESOLV, 0, path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002228 goto error;
2229 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002230 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002231 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002232
2233 if (!*ret) {
Michal Vaskod9173342015-08-17 14:35:36 +02002234 LOGVAL(LYE_NORESOLV, LOGLINE(unres), path-parsed);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002235 goto error;
2236 }
2237 }
2238 } while (path[0] != '\0');
2239
Michal Vaskof02e3742015-08-05 16:27:02 +02002240 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002241
2242error:
2243
2244 while (*ret) {
2245 raux = (*ret)->next;
2246 free(*ret);
2247 *ret = raux;
2248 }
2249
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002250 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002251}
2252
Michal Vasko730dfdf2015-08-11 14:48:05 +02002253/**
2254 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2255 *
2256 * @param[in] path Path in question.
2257 * @param[in] mod Schema module.
2258 * @param[in] source_node Left operand node.
2259 * @param[in] dest_node Right ooperand node.
2260 * @param[in] line Line in the input file.
2261 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002262 * @return Number of characters successfully parsed,
2263 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002264 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002265static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002266resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002267 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002268{
2269 struct lys_node *src_node, *dst_node;
2270 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2271 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002272 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002273
2274 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002275 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002276 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002277 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002278 return -parsed+i;
2279 }
2280 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002281 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002282
Michal Vasko58090902015-08-13 14:04:15 +02002283 /* source (must be leaf) */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002284 rc = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
2285 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002286 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002287 return -parsed;
2288 }
2289
2290 /* destination */
2291 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2292 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002293 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002294 return -parsed;
2295 }
2296 pke_parsed += i;
2297
2298 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2299 dst_node = dest_node;
2300 for (i = 1; i < dest_parent_times; ++i) {
2301 dst_node = dst_node->parent;
2302 if (!dst_node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002303 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002304 return -parsed;
2305 }
2306 }
2307 while (1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002308 rc = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2309 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2310 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002311 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002312 return -parsed;
2313 }
2314
2315 if (pke_len == pke_parsed) {
2316 break;
2317 }
2318
2319 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2320 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002321 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002322 return -parsed;
2323 }
2324 pke_parsed += i;
2325 }
2326
2327 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002328 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2329 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskod9173342015-08-17 14:35:36 +02002330 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002331 return -parsed;
2332 }
2333 } while (has_predicate);
2334
2335 return parsed;
2336}
2337
Michal Vasko730dfdf2015-08-11 14:48:05 +02002338/**
Michal Vaskod9173342015-08-17 14:35:36 +02002339 * @brief Resolve a path (leafref) in schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002340 *
2341 * @param[in] mod Module in question.
2342 * @param[in] path Path in question.
2343 * @param[in] parent_node Parent of the leafref.
2344 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002345 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002346 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002347 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002348 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002349static int
2350resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line,
2351 struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002352{
Michal Vasko58090902015-08-13 14:04:15 +02002353 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002354 const char *id, *prefix, *name;
2355 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002356 int i, first, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002357
2358 first = 1;
2359 parent_times = 0;
2360 id = path;
2361
2362 do {
2363 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002364 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002365 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002366 }
2367 id += i;
2368
2369 if (first) {
2370 if (parent_times == -1) {
2371 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002372 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002373 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002374 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002375 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002376 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002377 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002378 node = parent_node;
2379 i = 0;
2380 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002381 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002382 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002383 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002384 }
Michal Vasko58090902015-08-13 14:04:15 +02002385
2386 /* this node is a wrong node, we actually need the augment target */
2387 if (node->nodetype == LYS_AUGMENT) {
2388 node = ((struct lys_node_augment *)node)->target;
2389 if (!node) {
2390 continue;
2391 }
2392 }
2393
2394 ++i;
2395 if (i == parent_times) {
2396 break;
2397 }
2398 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002399 }
2400 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002401 } else {
2402 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002403 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002404 }
2405 first = 0;
2406 } else {
2407 node = node->child;
2408 }
2409
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002410 rc = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES), &node);
2411 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002412 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002413 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002414 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002415
2416 if (has_predicate) {
2417 /* we have predicate, so the current result must be list */
2418 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002419 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002420 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002421 }
2422
2423 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002424 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002425 }
2426 id += i;
2427 }
2428 } while (id[0]);
2429
Radek Krejcib1c12512015-08-11 11:22:04 +02002430 /* the target must be leaf or leaf-list */
2431 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002432 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002433 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002434 }
2435
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002436 if (ret) {
2437 *ret = node;
2438 }
2439 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002440}
2441
Michal Vasko730dfdf2015-08-11 14:48:05 +02002442/**
2443 * @brief Resolve instance-identifier predicate. Does not log.
2444 *
2445 * @param[in] pred Predicate in question.
2446 * @param[in,out] node_match Nodes matching the restriction without
2447 * the predicate. Nodes not satisfying
2448 * the predicate are removed.
2449 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002450 * @return Number of characters successfully parsed,
2451 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002452 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002453static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002454resolve_predicate(const char *pred, struct unres_data **node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002455{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002456 /* ... /node[target = value] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002457 struct unres_data *target_match, *node, *node_prev = NULL, *tmp;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002458 const char *prefix, *name, *value;
2459 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2460
2461 idx = -1;
2462 parsed = 0;
2463
2464 do {
2465 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
2466 return -parsed+i;
2467 }
2468 parsed += i;
2469 pred += i;
2470
2471 if (isdigit(name[0])) {
2472 idx = atoi(name);
2473 }
2474
2475 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
2476 /* target */
2477 target_match = NULL;
2478 if ((name[0] == '.') || !value) {
2479 target_match = calloc(1, sizeof *target_match);
2480 target_match->dnode = node->dnode;
2481 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002482 goto remove_instid;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002483 }
2484
2485 /* check that we have the correct type */
2486 if (name[0] == '.') {
Radek Krejci76512572015-08-04 09:47:08 +02002487 if (node->dnode->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002488 goto remove_instid;
2489 }
2490 } else if (value) {
Radek Krejci76512572015-08-04 09:47:08 +02002491 if (node->dnode->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002492 goto remove_instid;
2493 }
2494 }
2495
2496 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
2497 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
2498 || (!value && (idx != cur_idx))) {
2499 goto remove_instid;
2500 }
2501
2502 while (target_match) {
2503 tmp = target_match->next;
2504 free(target_match);
2505 target_match = tmp;
2506 }
2507
2508 /* leafref is ok, continue check with next leafref */
2509 node_prev = node;
2510 node = node->next;
2511 continue;
2512
2513remove_instid:
2514 while (target_match) {
2515 tmp = target_match->next;
2516 free(target_match);
2517 target_match = tmp;
2518 }
2519
2520 /* does not fulfill conditions, remove leafref record */
2521 if (node_prev) {
2522 node_prev->next = node->next;
2523 free(node);
2524 node = node_prev->next;
2525 } else {
2526 node = (*node_match)->next;
2527 free(*node_match);
2528 *node_match = node;
2529 }
2530 }
2531 } while (has_predicate);
2532
2533 return parsed;
2534}
2535
Michal Vasko730dfdf2015-08-11 14:48:05 +02002536/**
2537 * @brief Resolve instance-identifier. Logs directly.
2538 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002539 * @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 +02002540 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002541 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002542 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002543 * @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 +02002544 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002545struct lyd_node *
2546resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002547{
Radek Krejcic5090c32015-08-12 09:46:19 +02002548 int i = 0, j;
2549 struct lyd_node *result = NULL;
2550 struct lys_module *mod = NULL;
2551 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002552 const char *prefix, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002553 char *str;
2554 int pref_len, name_len, has_predicate;
2555 struct unres_data *workingnodes = NULL;
2556 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002557
Radek Krejcic5090c32015-08-12 09:46:19 +02002558 /* we need root to resolve absolute path */
2559 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002560 for (; data->prev->next; data = data->prev);
2561
Radek Krejcic5090c32015-08-12 09:46:19 +02002562 /* search for the instance node */
2563 while (path[i]) {
2564 j = parse_instance_identifier(&path[i], &prefix, &pref_len, &name, &name_len, &has_predicate);
2565 if (j <= 0) {
2566 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002567 goto error;
2568 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002569 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002570
Radek Krejcic5090c32015-08-12 09:46:19 +02002571 if (prefix) {
2572 str = strndup(prefix, pref_len);
2573 mod = ly_ctx_get_module(ctx, str, NULL);
2574 free(str);
Michal Vaskob387c482015-08-12 09:32:59 +02002575 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002576
Radek Krejcic5090c32015-08-12 09:46:19 +02002577 if (!mod) {
2578 /* no instance exists */
2579 return NULL;
2580 }
2581
2582 if (resolve_data(mod, name, name_len, data, &workingnodes)) {
2583 /* no instance exists */
2584 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002585 }
2586
2587 if (has_predicate) {
2588 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcic5090c32015-08-12 09:46:19 +02002589 for (raux = NULL, riter = workingnodes; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002590 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002591 ((struct lys_node_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +02002592 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593 /* instid is ok, continue check with next instid */
2594 raux = riter;
2595 riter = riter->next;
2596 continue;
2597 }
2598
2599 /* does not fulfill conditions, remove inst record */
2600 if (raux) {
2601 raux->next = riter->next;
2602 free(riter);
2603 riter = raux->next;
2604 } else {
Radek Krejcic5090c32015-08-12 09:46:19 +02002605 workingnodes = riter->next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002606 free(riter);
Radek Krejcic5090c32015-08-12 09:46:19 +02002607 riter = workingnodes;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002608 }
2609 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002610
2611 j = resolve_predicate(&path[i], &workingnodes);
2612 if (j < 1) {
2613 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002614 goto error;
2615 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002616 i += j;;
Michal Vaskob387c482015-08-12 09:32:59 +02002617
Radek Krejcic5090c32015-08-12 09:46:19 +02002618 if (!workingnodes) {
2619 /* no instance exists */
2620 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621 }
2622 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002623 }
2624
Radek Krejcic5090c32015-08-12 09:46:19 +02002625 if (!workingnodes) {
2626 /* no instance exists */
2627 return NULL;
2628 } else if (workingnodes->next) {
2629 /* instance identifier must resolve to a single node */
2630 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2631
2632 /* cleanup */
2633 while (workingnodes) {
2634 raux = workingnodes->next;
2635 free(workingnodes);
2636 workingnodes = raux;
2637 }
2638
2639 return NULL;
2640 } else {
2641 /* we have required result, remember it and cleanup */
2642 result = workingnodes->dnode;
2643 free(workingnodes);
2644
2645 return result;
2646 }
2647
2648error:
2649
2650 /* cleanup */
2651 while (workingnodes) {
2652 raux = workingnodes->next;
2653 free(workingnodes);
2654 workingnodes = raux;
2655 }
2656
2657 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002658}
2659
Michal Vasko730dfdf2015-08-11 14:48:05 +02002660/**
2661 * @brief Passes config flag down to children. Does not log.
2662 *
2663 * @param[in] node Parent node.
2664 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002665static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002666inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002667{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002668 LY_TREE_FOR(node, node) {
2669 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2670 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002671 }
2672}
2673
Michal Vasko730dfdf2015-08-11 14:48:05 +02002674/**
Michal Vaskod9173342015-08-17 14:35:36 +02002675 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002676 *
2677 * @param[in] aug Augment in question.
2678 * @param[in] siblings Nodes where to start the search in.
2679 * @param[in] module Main module.
2680 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002681 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002682 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002683int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002684resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002685{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002686 int rc;
Radek Krejci76512572015-08-04 09:47:08 +02002687 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002688
2689 assert(module);
2690
2691 /* resolve target node */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002692 rc = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT, &aug->target);
2693 if (rc) {
2694 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002695 }
2696
2697 if (!aug->child) {
2698 /* nothing to do */
2699 return EXIT_SUCCESS;
2700 }
2701
2702 /* inherit config information from parent, augment does not have
2703 * config property, but we need to keep the information for subelements
2704 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002705 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002706 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002707 inherit_config_flag(sub);
2708 }
2709
Radek Krejci07911992015-08-14 15:13:31 +02002710 /* check identifier uniquness as in lys_node_addchild() */
2711 LY_TREE_FOR(aug->child, aux) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002712 if (lys_check_id(aux, aug->parent, module)) {
2713 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002714 }
2715 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002716 /* reconnect augmenting data into the target - add them to the target child list */
2717 if (aug->target->child) {
2718 aux = aug->target->child->prev; /* remember current target's last node */
2719 aux->next = aug->child; /* connect augmenting data after target's last node */
2720 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2721 aug->child->prev = aux; /* finish connecting of both child lists */
2722 } else {
2723 aug->target->child = aug->child;
2724 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002725
2726 return EXIT_SUCCESS;
2727}
2728
Michal Vasko730dfdf2015-08-11 14:48:05 +02002729/**
2730 * @brief Resolve uses, apply augments, refines. Logs directly.
2731 *
2732 * @param[in] uses Uses in question.
2733 * @param[in,out] unres List of unresolved items.
2734 * @param[in] line Line in the input file.
2735 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002736 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward ereference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002737 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002738int
Michal Vaskof02e3742015-08-05 16:27:02 +02002739resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002740{
2741 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002742 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002743 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002744 struct lys_restr *newmust;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002745 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002746 uint8_t size;
2747
Michal Vasko71e1aa82015-08-12 12:17:51 +02002748 assert(uses->grp);
2749
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002750 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002751 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002752 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002753 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002754 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002755 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002756 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002757 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002758 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002759 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002760 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002761 }
2762 }
2763 ctx = uses->module->ctx;
2764
2765 /* apply refines */
2766 for (i = 0; i < uses->refine_size; i++) {
2767 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002768 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2769 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002770 if (rc == -1) {
2771 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2772 } else {
2773 LOGVAL(LYE_NORESOLV, line, rfn->target_name);
2774 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002775 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002776 }
2777
Radek Krejci1d82ef62015-08-07 14:44:40 +02002778 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002779 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002780 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002781 }
2782
2783 /* description on any nodetype */
2784 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002785 lydict_remove(ctx, node->dsc);
2786 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002787 }
2788
2789 /* reference on any nodetype */
2790 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002791 lydict_remove(ctx, node->ref);
2792 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002793 }
2794
2795 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002796 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002797 node->flags &= ~LYS_CONFIG_MASK;
2798 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002799 }
2800
2801 /* default value ... */
2802 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002803 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002804 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002805 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2806 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2807 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002809 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2810 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002811 if (rc == -1) {
2812 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2813 } else {
2814 LOGVAL(LYE_NORESOLV, line, rfn->mod.dflt);
2815 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002816 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 }
2818 }
2819 }
2820
2821 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002822 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002823 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002824 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002825 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002826
2827 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002828 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002829 }
2830 }
2831
2832 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002833 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2834 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2835 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002836 }
2837
2838 /* min/max-elements on list or leaf-list */
2839 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002840 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002842 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002843 }
2844 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002845 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002846 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002847 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002849 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002850 }
2851 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002852 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002853 }
2854 }
2855
2856 /* must in leaf, leaf-list, list, container or anyxml */
2857 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002858 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2859 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 if (!newmust) {
2861 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002862 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002864 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2866 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2867 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2868 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2869 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2870 }
2871
Radek Krejci1d82ef62015-08-07 14:44:40 +02002872 ((struct lys_node_leaf *)node)->must = newmust;
2873 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002874 }
2875 }
2876
2877 /* apply augments */
2878 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002879 rc = resolve_augment(&uses->augment[i], uses->child, uses->module);
2880 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002881 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002882 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 }
2884 }
2885
2886 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887}
2888
Michal Vasko730dfdf2015-08-11 14:48:05 +02002889/**
2890 * @brief Resolve base identity recursively. Does not log.
2891 *
2892 * @param[in] module Main module.
2893 * @param[in] ident Identity in question.
2894 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002895 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002896 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002897 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002898 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002899static int
2900resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2901 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002902{
Michal Vaskof02e3742015-08-05 16:27:02 +02002903 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002904 struct lys_ident *base_iter = NULL;
2905 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906
2907 /* search module */
2908 for (i = 0; i < module->ident_size; i++) {
2909 if (!strcmp(basename, module->ident[i].name)) {
2910
2911 if (!ident) {
2912 /* just search for type, so do not modify anything, just return
2913 * the base identity pointer
2914 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002915 if (ret) {
2916 *ret = &module->ident[i];
2917 }
2918 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002919 }
2920
2921 /* we are resolving identity definition, so now update structures */
2922 ident->base = base_iter = &module->ident[i];
2923
2924 break;
2925 }
2926 }
2927
2928 /* search submodules */
2929 if (!base_iter) {
2930 for (j = 0; j < module->inc_size; j++) {
2931 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2932 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2933
2934 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002935 if (ret) {
2936 *ret = &module->inc[j].submodule->ident[i];
2937 }
2938 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939 }
2940
2941 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2942 break;
2943 }
2944 }
2945 }
2946 }
2947
2948 /* we found it somewhere */
2949 if (base_iter) {
2950 while (base_iter) {
2951 for (der = base_iter->der; der && der->next; der = der->next);
2952 if (der) {
2953 der->next = malloc(sizeof *der);
2954 der = der->next;
2955 } else {
2956 ident->base->der = der = malloc(sizeof *der);
2957 }
2958 der->next = NULL;
2959 der->ident = ident;
2960
2961 base_iter = base_iter->base;
2962 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002963 if (ret) {
2964 *ret = ident->base;
2965 }
2966 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967 }
2968
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002969 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970}
2971
Michal Vasko730dfdf2015-08-11 14:48:05 +02002972/**
2973 * @brief Resolve base identity. Logs directly.
2974 *
2975 * @param[in] module Main module.
2976 * @param[in] ident Identity in question.
2977 * @param[in] basename Base name of the identity.
2978 * @param[in] parent Either "type" or "ident".
2979 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002980 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002981 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002982 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002983 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002984static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002985resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002986 uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002987{
2988 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02002989 int i, prefix_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002990
2991 /* search for the base identity */
2992 name = strchr(basename, ':');
2993 if (name) {
2994 /* set name to correct position after colon */
2995 prefix_len = name - basename;
2996 name++;
2997
2998 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
2999 /* prefix refers to the current module, ignore it */
3000 prefix_len = 0;
3001 }
3002 } else {
3003 name = basename;
3004 }
3005
3006 if (prefix_len) {
3007 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003008 module = resolve_prefixed_module(module, basename, prefix_len);
3009 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003010 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003011 LOGVAL(LYE_INPREF, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003012 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003013 }
3014 } else {
3015 /* search in submodules */
3016 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003017 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3018 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003019 }
3020 }
3021 }
3022
3023 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003024 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3025 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003026 }
3027
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003028 LOGVAL(LYE_INARG, line, basename, parent);
3029 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003030}
3031
Michal Vasko730dfdf2015-08-11 14:48:05 +02003032/**
3033 * @brief Resolve identityref. Does not log.
3034 *
3035 * @param[in] base Base identity.
3036 * @param[in] name Identityref name.
3037 * @param[in] ns Namespace of the identityref.
3038 *
3039 * @return Pointer to the identity resolvent, NULL on error.
3040 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003041struct lys_ident *
3042resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003043{
Radek Krejcia52656e2015-08-05 13:41:50 +02003044 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003045
3046 if (!base || !name || !ns) {
3047 return NULL;
3048 }
3049
3050 for(der = base->der; der; der = der->next) {
3051 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3052 /* we have match */
3053 return der->ident;
3054 }
3055 }
3056
3057 /* not found */
3058 return NULL;
3059}
3060
Michal Vasko730dfdf2015-08-11 14:48:05 +02003061/**
3062 * @brief Resolve unres identity. Logs directly.
3063 *
3064 * @param[in] mod Main module.
3065 * @param[in] ident Identity in question.
3066 * @param[in] base_name Base name of the identity.
3067 * @param[in] line Line in the input file.
3068 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003069 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003070 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003071static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003072resolve_unres_ident(struct lys_module *mod, struct lys_ident *ident, const char *base_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003074 int rc;
3075
3076 rc = resolve_base_ident(mod, ident, base_name, "ident", line, NULL);
3077 if (rc == EXIT_FAILURE) {
3078 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identity", base_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003079 }
3080
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003081 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003082}
3083
Michal Vasko730dfdf2015-08-11 14:48:05 +02003084/**
3085 * @brief Resolve unres identityref. Logs directly.
3086 *
3087 * @param[in] mod Main module.
3088 * @param[in] type Type in question.
3089 * @param[in] base_name Base name of the identity.
3090 * @param[in] line Line in the input file.
3091 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003093 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003095resolve_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 +02003096{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003097 int rc;
3098
3099 rc = resolve_base_ident(mod, NULL, base_name, "type", line, &type->info.ident.ref);
3100 if (rc == EXIT_FAILURE) {
3101 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "identityref", base_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 }
3103
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003104 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003105}
3106
Michal Vasko730dfdf2015-08-11 14:48:05 +02003107/**
3108 * @brief Resolve unres leafref. Logs directly.
3109 *
3110 * @param[in] mod Main module.
3111 * @param[in] type Type in question.
3112 * @param[in] node Leafref schema node.
3113 * @param[in] line Line in the input file.
3114 *
3115 * @return EXIT_SUCCESS on success, EXIT_FAILURE on error.
3116 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003118resolve_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 +02003119{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003120 int rc;
3121
3122 rc = resolve_path_arg_schema(mod, type->info.lref.path, node, line, (struct lys_node **)&type->info.lref.target);
3123 if (rc == EXIT_FAILURE) {
3124 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "leafref", type->info.lref.path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003125 }
3126
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003127 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003128}
3129
Michal Vasko730dfdf2015-08-11 14:48:05 +02003130/**
3131 * @brief Resolve unres derived type. Logs directly.
3132 *
3133 * @param[in] mod Main module.
3134 * @param[in] type Type in question.
3135 * @param[in] type_name Derived type name,
3136 * @param[in] line Line in the input file.
3137 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003138 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003139 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003141resolve_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 +02003142{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003143 int rc;
3144
3145 /* HACK type->der is temporarily its parent */
3146 rc = resolve_superior_type(type_name, type->prefix, mod, (struct lys_node *)type->der, &type->der);
3147 if (!rc) {
Michal Vaskoa91333d2015-08-03 16:03:06 +02003148 type->base = type->der->type.base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003149 }
3150 if (rc == EXIT_FAILURE) {
3151 LOGVAL(LYE_INRESOLV, line, "type", type_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152 }
3153
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003154 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155}
3156
Michal Vasko730dfdf2015-08-11 14:48:05 +02003157/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02003158 * @brief Resolve unres if-feature. Logs directly.
3159 *
3160 * @param[in] mod Main module.
3161 * @param[in,out] feat_ptr Pointer to the resolved feature.
3162 * @param[in] feat_name Name of the feature.
3163 * @param[in] line Line in the input file.
3164 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003165 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003166 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003167static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003168resolve_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 +02003169{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003170 int rc;
3171
3172 rc = resolve_feature(feat_name, mod, line, feat_ptr);
3173 if (rc == EXIT_FAILURE) {
3174 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "if-feature", feat_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175 }
3176
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003177 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003178}
3179
Michal Vasko730dfdf2015-08-11 14:48:05 +02003180/**
3181 * @brief Resolve unres uses. Logs directly.
3182 *
3183 * @param[in] uses Uses in question.
3184 * @param[in] unres Specific unres item.
3185 * @param[in] line Line in the input file.
3186 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003187 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003188 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003189static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003190resolve_unres_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003191{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003192 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003193 struct lys_node *parent;
3194
3195 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3196 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3197
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 if (!uses->grp) {
3199 rc = resolve_grouping(uses, line);
3200 if (rc) {
3201 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003202 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
3204
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003205 if (uses->grp->nacm) {
3206 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3207 return EXIT_FAILURE;
3208 }
3209
3210 rc = resolve_uses(uses, unres, line);
3211 if (!rc) {
3212 /* decrease unres count only if not first try */
3213 if ((line < UINT_MAX) && parent) {
3214 if (!parent->nacm) {
3215 LOGINT;
3216 return -1;
3217 }
3218 --parent->nacm;
3219 }
3220 return EXIT_SUCCESS;
3221 }
3222
3223 if ((rc == EXIT_FAILURE) && parent) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003224 ++parent->nacm;
3225 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003226 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003227 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003228}
3229
Michal Vasko730dfdf2015-08-11 14:48:05 +02003230/**
3231 * @brief Resolve unres identity. Logs directly.
3232 *
3233 * @param[in] type Type in question.
3234 * @param[in] dflt Default value.
3235 * @param[in] line Line in the input file.
3236 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003237 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003238 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003240resolve_unres_type_dflt(struct lys_type *type, const char *dflt, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003242 int rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003243
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003244 rc = check_default(type, dflt);
3245
3246 if (rc) {
3247 LOGVAL(LYE_INRESOLV, line, "type default", dflt);
3248 }
3249 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250}
3251
Michal Vasko730dfdf2015-08-11 14:48:05 +02003252/**
3253 * @brief Resolve choice default. Logs directly.
3254 *
3255 * @param[in] choice Main module.
3256 * @param[in] dflt Default case name.
3257 * @param[in] line Line in the input file.
3258 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003259 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003260 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003261static int
Michal Vasko58090902015-08-13 14:04:15 +02003262resolve_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 +02003263{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003264 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003266 rc = resolve_sibling(mod, choice->child, NULL, 0, dflt, 0, LYS_ANYXML | LYS_CASE
3267 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST, &choice->dflt);
3268
3269 if (rc) {
3270 LOGVAL(LYE_INRESOLV, line, "choice default", dflt);
3271 }
3272 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273}
3274
Michal Vasko730dfdf2015-08-11 14:48:05 +02003275/**
3276 * @brief Resolve unres identity. Logs directly.
3277 *
3278 * @param[in] list List in question.
3279 * @param[in] keys_str Keys node value.
3280 * @param[in] line Line in the input file.
3281 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003282 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003283 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284static int
Michal Vasko58090902015-08-13 14:04:15 +02003285resolve_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 +02003286{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003287 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003288 const char *value;
3289
3290 for (i = 0; i < list->keys_size; ++i) {
3291 /* get the key name */
3292 if ((value = strpbrk(keys_str, " \t\n"))) {
3293 len = value - keys_str;
3294 while (isspace(value[0])) {
3295 value++;
3296 }
3297 } else {
3298 len = strlen(keys_str);
3299 }
3300
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003301 rc = resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
3302 if (rc) {
3303 if (rc == EXIT_FAILURE) {
3304 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3305 }
3306 return rc;
3307 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003308
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003309 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003310 /* check_key logs */
3311 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003312 }
3313
3314 /* prepare for next iteration */
3315 while (value && isspace(value[0])) {
3316 value++;
3317 }
3318 keys_str = value;
3319 }
3320
Michal Vaskof02e3742015-08-05 16:27:02 +02003321 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003322}
3323
Michal Vasko730dfdf2015-08-11 14:48:05 +02003324/**
3325 * @brief Resolve unres unique. Logs directly.
3326 *
3327 * @param[in] uniq Unique in question.
3328 * @param[in] uniq_str Unique node value.
3329 * @param[in] line Line in the input file.
3330 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003331 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003332 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003334resolve_unres_list_uniq(struct lys_unique *uniq, const char *uniq_str, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003336 int rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003337
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003338 rc = resolve_unique((struct lys_node *)uniq->leafs, uniq_str, uniq, line);
3339
3340 if (rc) {
3341 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list unique", uniq_str);
3342 }
3343 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003344}
3345
3346static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003347resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003348{
3349 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003350 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351}
3352
3353static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003354resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003355{
3356 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003357 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003358}
3359
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003360/**
3361 * @brief Resolve a single unres item. Logs indirectly.
3362 *
3363 * @param[in] mod Main module.
3364 * @param[in] item Item to resolve. Type determined by \p type.
3365 * @param[in] type Type of the unresolved item.
3366 * @param[in] str_snode String, a schema node, or NULL.
3367 * @param[in] unres Unres structure in question.
3368 * @param[in] line Line in the input file. -1 turns logging off, 0 skips line print.
3369 *
3370 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3371 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372static int
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003373resolve_unres_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode, struct unres_schema *unres,
Michal Vaskof02e3742015-08-05 16:27:02 +02003374 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003375{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003376 int rc = -1, has_str = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377
3378 switch (type) {
3379 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003380 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003381 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382 case UNRES_IDENT:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003383 rc = resolve_unres_ident(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 has_str = 1;
3385 break;
3386 case UNRES_TYPE_IDENTREF:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003387 rc = resolve_unres_type_identref(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 has_str = 1;
3389 break;
3390 case UNRES_TYPE_LEAFREF:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003391 rc = resolve_unres_type_leafref(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 has_str = 0;
3393 break;
3394 case UNRES_TYPE_DER:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003395 rc = resolve_unres_type_der(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396 has_str = 1;
3397 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003398 case UNRES_IFFEAT:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003399 rc = resolve_unres_iffeature(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 has_str = 1;
3401 break;
3402 case UNRES_USES:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 rc = resolve_unres_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 has_str = 0;
3405 break;
3406 case UNRES_TYPE_DFLT:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003407 rc = resolve_unres_type_dflt(item, str_snode, line);
Radek Krejci1d82ef62015-08-07 14:44:40 +02003408 /* do not remove str_node (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 has_str = 0;
3410 break;
3411 case UNRES_CHOICE_DFLT:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003412 rc = resolve_unres_choice_dflt(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003413 has_str = 1;
3414 break;
3415 case UNRES_LIST_KEYS:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003416 rc = resolve_unres_list_keys(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417 has_str = 1;
3418 break;
3419 case UNRES_LIST_UNIQ:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003420 rc = resolve_unres_list_uniq(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003421 has_str = 1;
3422 break;
3423 case UNRES_WHEN:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003424 rc = resolve_unres_when(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003425 has_str = 0;
3426 break;
3427 case UNRES_MUST:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003428 rc = resolve_unres_must(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003429 has_str = 0;
3430 break;
3431 }
3432
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003433 if (has_str && !rc) {
3434 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435 }
3436
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003437 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438}
3439
Michal Vaskof02e3742015-08-05 16:27:02 +02003440/* logs directly */
3441static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003442print_unres_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003443{
Michal Vaskof02e3742015-08-05 16:27:02 +02003444 char line_str[18];
3445
3446 if (line) {
3447 sprintf(line_str, " (line %u)", line);
3448 } else {
3449 line_str[0] = '\0';
3450 }
3451
3452 switch (type) {
3453 case UNRES_RESOLVED:
3454 LOGINT;
3455 break;
3456 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003457 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003458 break;
3459 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003460 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003461 break;
3462 case UNRES_TYPE_LEAFREF:
3463 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3464 break;
3465 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003466 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 +02003467 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003468 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003469 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 +02003470 break;
3471 case UNRES_USES:
3472 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3473 break;
3474 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003475 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 +02003476 break;
3477 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003478 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 +02003479 break;
3480 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003481 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 +02003482 break;
3483 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003484 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 +02003485 break;
3486 case UNRES_WHEN:
3487 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3488 break;
3489 case UNRES_MUST:
3490 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3491 break;
3492 }
3493}
3494
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003495/**
3496 * @brief Resolve every unres item in the structure. Logs directly.
3497 *
3498 * @param[in] mod Main module.
3499 * @param[in] unres Unres structure in question.
3500 *
3501 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3502 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003503int
3504resolve_unres(struct lys_module *mod, struct unres_schema *unres)
3505{
Michal Vaskoc07187d2015-08-13 15:20:57 +02003506 uint32_t i, resolved, unres_uses, res_uses, line;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003507 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508
3509 assert(unres);
3510
Michal Vaskoc07187d2015-08-13 15:20:57 +02003511 line = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003512 resolved = 0;
3513
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003515 do {
3516 unres_uses = 0;
3517 res_uses = 0;
3518
3519 for (i = 0; i < unres->count; ++i) {
3520 if (unres->type[i] != UNRES_USES) {
3521 continue;
3522 }
3523
Michal Vaskoc07187d2015-08-13 15:20:57 +02003524#ifndef NDEBUG
3525 line = unres->line[i];
3526#endif
3527
Michal Vasko51054ca2015-08-12 12:20:00 +02003528 ++unres_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003529 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line);
3530 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003531 unres->type[i] = UNRES_RESOLVED;
3532 ++resolved;
3533 ++res_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003534 } else if (rc == EXIT_FAILURE) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02003535 print_unres_item_fail(unres->item[i], unres->type[i], unres->str_snode[i], line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003536 } else {
3537 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003538 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003539 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003540 } while (res_uses && (res_uses < unres_uses));
3541
3542 if (res_uses < unres_uses) {
3543 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
3544 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 }
3546
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547 /* the rest */
3548 for (i = 0; i < unres->count; ++i) {
3549 if (unres->type[i] == UNRES_RESOLVED) {
3550 continue;
3551 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003552
3553#ifndef NDEBUG
3554 line = unres->line[i];
3555#endif
3556
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003557 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line);
3558 if (!rc) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003559 unres->type[i] = UNRES_RESOLVED;
3560 ++resolved;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003561 } else if (rc == -1) {
3562 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003563 }
3564 }
3565
3566 if (resolved < unres->count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003567 LOGVAL(LYE_SPEC, 0, "There are unresolved items left.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568 return EXIT_FAILURE;
3569 }
3570
3571 return EXIT_SUCCESS;
3572}
3573
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003574/**
3575 * @brief Try to resolve an unres item with a string argument. Logs indirectly.
3576 *
3577 * @param[in] mod Main module.
3578 * @param[in] unres Unres structure to use.
3579 * @param[in] item Item to resolve. Type determined by \p type.
3580 * @param[in] type Type of the unresolved item.
3581 * @param[in] str String argument.
3582 * @param[in] line Line in the input file.
3583 *
3584 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3585 */
3586int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003587unres_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 +02003588 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003589{
3590 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003591 return unres_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003592}
3593
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003594/**
3595 * @brief Try to resolve an unres item with a schema node argument. Logs indirectly.
3596 *
3597 * @param[in] mod Main module.
3598 * @param[in] unres Unres structure to use.
3599 * @param[in] item Item to resolve. Type determined by \p type.
3600 * @param[in] type Type of the unresolved item.
3601 * @param[in] snode Schema node argument.
3602 * @param[in] line Line in the input file.
3603 *
3604 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3605 */
3606int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003607unres_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003608 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003610 int rc;
3611
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003612 assert(unres && item);
3613
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003614 rc = resolve_unres_item(mod, item, type, snode, unres, UINT_MAX);
3615 if (rc != EXIT_FAILURE) {
3616 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617 }
3618
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003619 print_unres_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003620
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003621 unres->count++;
3622 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3623 unres->item[unres->count-1] = item;
3624 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3625 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003626 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003627 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003628#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003629 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3630 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003631#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003632
3633 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003634}
3635
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003636/**
3637 * @brief Duplicate an unres item. Logs indirectly.
3638 *
3639 * @param[in] mod Main module.
3640 * @param[in] unres Unres structure to use.
3641 * @param[in] item Old item to be resolved.
3642 * @param[in] type Type of the old unresolved item.
3643 * @param[in] new_item New item to use in the duplicate.
3644 *
3645 * @return EXIT_SUCCESS on success, -1 on error.
3646 */
Michal Vaskodad19402015-08-06 09:51:53 +02003647int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003648unres_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 +02003649{
3650 int i;
3651
3652 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003653 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003655 }
3656
Radek Krejci1d82ef62015-08-07 14:44:40 +02003657 i = unres_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658
3659 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003660 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003661 }
3662
Michal Vasko4adc10f2015-08-11 15:26:17 +02003663 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003665 if (unres_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3666 LOGINT;
3667 return -1;
3668 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003670 if (unres_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3671 LOGINT;
3672 return -1;
3673 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003674 }
Michal Vaskodad19402015-08-06 09:51:53 +02003675
3676 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677}
3678
Michal Vaskof02e3742015-08-05 16:27:02 +02003679/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003680int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003681unres_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682{
3683 uint32_t ret = -1, i;
3684
3685 for (i = 0; i < unres->count; ++i) {
3686 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3687 ret = i;
3688 break;
3689 }
3690 }
3691
3692 return ret;
3693}