blob: cd3923bed92c16b1019e3e183ccac0ca1591ab98 [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
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02001356/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001357static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001358check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001359{
1360 /* TODO - RFC 6020, sec. 7.3.4 */
1361 (void)type;
1362 (void)value;
1363 return EXIT_SUCCESS;
1364}
1365
Michal Vasko730dfdf2015-08-11 14:48:05 +02001366/**
1367 * @brief Check a key for mandatory attributes. Logs directly.
1368 *
1369 * @param[in] key The key to check.
1370 * @param[in] flags What flags to check.
1371 * @param[in] list The list of all the keys.
1372 * @param[in] index Index of the key in the key list.
1373 * @param[in] name The name of the keys.
1374 * @param[in] len The name length.
1375 * @param[in] line The line in the input file.
1376 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001377 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001378 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001379static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001380check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1381 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001382{
1383 char *dup = NULL;
1384 int j;
1385
1386 /* existence */
1387 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001388 if (name[len] != '\0') {
1389 dup = strdup(name);
1390 dup[len] = '\0';
1391 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001392 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001393 LOGVAL(LYE_KEY_MISS, line, name);
1394 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001395 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001396 }
1397
1398 /* uniqueness */
1399 for (j = index - 1; j >= 0; j--) {
1400 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001401 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001402 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001403 }
1404 }
1405
1406 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001407 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001408 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001409 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001410 }
1411
1412 /* type of the leaf is not built-in empty */
1413 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001414 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001415 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001416 }
1417
1418 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001419 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001420 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001421 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001422 }
1423
1424 return EXIT_SUCCESS;
1425}
1426
Michal Vasko730dfdf2015-08-11 14:48:05 +02001427/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001428 * @brief Resolve (fill) a unique. Logs directly.
1429 *
1430 * @param[in] parent The parent node of the unique structure.
1431 * @param[in] uniq_str The value of the unique node.
1432 * @param[in] uniq_s The unique structure in question.
1433 * @param[in] line The line in the input file.
1434 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001435 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001436 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001437int
Michal Vaskof02e3742015-08-05 16:27:02 +02001438resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001439{
1440 char *uniq_val, *uniq_begin, *start;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001441 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001442
1443 /* count the number of unique values */
1444 uniq_val = uniq_begin = strdup(uniq_str);
1445 uniq_s->leafs_size = 0;
1446 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1447 uniq_s->leafs_size++;
1448 while (isspace(*uniq_val)) {
1449 uniq_val++;
1450 }
1451 }
1452 uniq_s->leafs_size++;
1453 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1454
1455 /* interconnect unique values with the leafs */
1456 uniq_val = uniq_begin;
1457 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1458 start = uniq_val;
1459 if ((uniq_val = strpbrk(start, " \t\n"))) {
1460 *uniq_val = '\0'; /* add terminating NULL byte */
1461 uniq_val++;
1462 while (isspace(*uniq_val)) {
1463 uniq_val++;
1464 }
1465 } /* else only one nodeid present/left already NULL byte terminated */
1466
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001467 rc = resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF,
1468 (struct lys_node **)&uniq_s->leafs[i]);
1469 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001470 LOGVAL(LYE_INARG, line, start, "unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001471 if (rc == EXIT_FAILURE) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001472 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001473 }
1474 goto error;
1475 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001476 if (uniq_s->leafs[i]->nodetype != LYS_LEAF) {
1477 LOGVAL(LYE_INARG, line, start, "unique");
1478 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1479 rc = -1;
1480 goto error;
1481 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001482
1483 for (j = 0; j < i; j++) {
1484 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001485 LOGVAL(LYE_INARG, line, start, "unique");
1486 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001487 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001488 goto error;
1489 }
1490 }
1491 }
1492
1493 free(uniq_begin);
1494 return EXIT_SUCCESS;
1495
1496error:
1497
1498 free(uniq_s->leafs);
1499 free(uniq_begin);
1500
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001501 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001502}
1503
Michal Vasko730dfdf2015-08-11 14:48:05 +02001504/**
1505 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1506 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001507 * @param[in] uses The uses in question.
1508 * @param[in] line The line in the input file.
1509 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001510 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001511 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001512static int
Radek Krejci10c760e2015-08-14 14:45:43 +02001513resolve_grouping(struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001514{
Michal Vasko58090902015-08-13 14:04:15 +02001515 struct lys_module *module = uses->module;
1516 const char *prefix, *name;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001517 int i, pref_len, nam_len, rc;
Radek Krejci10c760e2015-08-14 14:45:43 +02001518 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001519
Michal Vasko58090902015-08-13 14:04:15 +02001520 /* parse the identifier, it must be parsed on one call */
1521 if ((i = parse_node_identifier(uses->name, &prefix, &pref_len, &name, &nam_len)) < 1) {
1522 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001523 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001524 } else if (uses->name[i]) {
1525 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001526 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001527 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001528
Michal Vasko58090902015-08-13 14:04:15 +02001529 if (!prefix) {
1530 /* search in local tree hierarchy */
Radek Krejci10c760e2015-08-14 14:45:43 +02001531 if (!uses->parent) {
1532 start = (struct lys_node *)uses;
1533 while (start->prev->next) {
1534 start = start->prev;
1535 }
1536 } else {
1537 start = uses->parent->child;
1538 }
1539 while (start) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001540 rc = resolve_sibling(module, start, prefix, pref_len, name, nam_len, LYS_GROUPING, (struct lys_node **)&uses->grp);
1541 if (rc != EXIT_FAILURE) {
Michal Vaskod9173342015-08-17 14:35:36 +02001542 if (rc == -1) {
1543 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
1544 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001545 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001546 }
Radek Krejci10c760e2015-08-14 14:45:43 +02001547 start = start->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001548 }
1549 }
1550
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001551 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001552 return EXIT_FAILURE;
1553}
1554
Michal Vasko730dfdf2015-08-11 14:48:05 +02001555/**
1556 * @brief Resolve (find) a feature definition. Logs directly.
1557 *
1558 * @param[in] name Feature name.
1559 * @param[in] module Module to search in.
1560 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001561 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001562 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001563 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001564 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001565static int
1566resolve_feature(const char *id, struct lys_module *module, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001567{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001568 const char *prefix, *name;
1569 int pref_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001570
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001571 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001572 assert(module);
1573
1574 /* check prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001575 if ((i = parse_node_identifier(id, &prefix, &pref_len, &name, &nam_len)) < 1) {
1576 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1577 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001578 }
1579
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001580 if (prefix) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001581 /* search in imported modules */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001582 module = resolve_prefixed_module(module, prefix, pref_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001583 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001584 /* identity refers unknown data model */
Michal Vaskod9173342015-08-17 14:35:36 +02001585 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001586 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001587 }
1588 } else {
1589 /* search in submodules */
1590 for (i = 0; i < module->inc_size; i++) {
1591 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1592 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001593 if (ret) {
1594 *ret = &(module->inc[i].submodule->features[j]);
1595 }
1596 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001597 }
1598 }
1599 }
1600 }
1601
1602 /* search in the identified module */
1603 for (j = 0; j < module->features_size; j++) {
1604 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001605 if (ret) {
1606 *ret = &module->features[j];
1607 }
1608 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001609 }
1610 }
1611
1612 /* not found */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001613 LOGVAL(LYE_INRESOLV, line, "feature", id);
1614 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001615}
1616
Michal Vasko730dfdf2015-08-11 14:48:05 +02001617/**
Michal Vasko58090902015-08-13 14:04:15 +02001618 * @brief Resolve (find) a valid sibling. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001619 *
Michal Vasko58090902015-08-13 14:04:15 +02001620 * Valid child means a schema pointer to a node that is part of
1621 * the data meaning uses are skipped. Includes module comparison
Michal Vaskobbfcfaa2015-08-17 16:00:19 +02001622 * (can handle augments). Module is adjusted based on the prefix.
1623 * Includes are also searched if siblings are top-level nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001624 *
Michal Vasko58090902015-08-13 14:04:15 +02001625 * @param[in] mod Main module. Prefix is considered to be from this module.
1626 * @param[in] siblings Siblings to consider. They are first adjusted to
1627 * point to the first sibling.
1628 * @param[in] prefix Node prefix.
1629 * @param[in] pref_len Node prefix length.
1630 * @param[in] name Node name.
1631 * @param[in] nam_len Node name length.
1632 * @param[in] type ORed desired type of the node. 0 means any type.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001633 * @param[out] ret Pointer to the node of the desired type. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001634 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001635 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001636 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001637int
Michal Vasko58090902015-08-13 14:04:15 +02001638resolve_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 +02001639 int nam_len, LYS_NODE type, struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001640{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001641 struct lys_node *node, *old_siblings = NULL;
Michal Vasko58090902015-08-13 14:04:15 +02001642 struct lys_module *prefix_mod, *cur_mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001643 int in_submod, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001644
Michal Vasko58090902015-08-13 14:04:15 +02001645 assert(mod && siblings && name);
1646 assert(!(type & LYS_USES));
1647
1648 /* find the beginning */
1649 while (siblings->prev->next) {
1650 siblings = siblings->prev;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001651 }
1652
Michal Vasko58090902015-08-13 14:04:15 +02001653 /* fill the name length in case the caller is so indifferent */
1654 if (!nam_len) {
1655 nam_len = strlen(name);
1656 }
1657
1658 /* we start with the module itself, submodules come later */
1659 in_submod = 0;
1660
1661 /* set prefix_mod correctly */
1662 if (prefix) {
1663 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1664 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001665 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001666 }
1667 cur_mod = prefix_mod;
1668 /* it is our module */
1669 if (cur_mod != mod) {
1670 old_siblings = siblings;
1671 siblings = cur_mod->data;
1672 }
1673 } else {
1674 prefix_mod = mod;
1675 if (prefix_mod->type) {
1676 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1677 }
1678 cur_mod = prefix_mod;
1679 }
1680
1681 while (1) {
1682 /* try to find the node */
1683 LY_TREE_FOR(siblings, node) {
1684 if (node->nodetype == LYS_USES) {
1685 /* an unresolved uses, we can still find it elsewhere */
1686 if (!node->child) {
1687 continue;
1688 }
1689
1690 /* search recursively */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001691 rc = resolve_sibling(mod, node->child, prefix, pref_len, name, nam_len, type, ret);
1692 if (rc != EXIT_FAILURE) {
1693 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001694 }
1695 }
1696
1697 if (!type || (node->nodetype & type)) {
1698 /* module check */
1699 if (!node->module->type) {
1700 if (cur_mod != node->module) {
1701 continue;
1702 }
1703 } else {
1704 if (cur_mod != ((struct lys_submodule *)node->module)->belongsto) {
1705 continue;
1706 }
1707 }
1708
1709 /* direct name check */
1710 if (node->name == name || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001711 if (ret) {
1712 *ret = node;
1713 }
1714 return EXIT_SUCCESS;
Michal Vasko58090902015-08-13 14:04:15 +02001715 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001716 }
1717 }
1718
Michal Vasko58090902015-08-13 14:04:15 +02001719 /* The original siblings may be valid,
1720 * it's a special case when we're looking
1721 * for a node from augment.
1722 */
1723 if (old_siblings) {
1724 siblings = old_siblings;
1725 old_siblings = NULL;
1726 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001727 }
Michal Vasko58090902015-08-13 14:04:15 +02001728
1729 /* we're not top-level, search ended */
1730 if (siblings->parent) {
1731 break;
1732 }
1733
1734 /* let's try the submodules */
1735 if (in_submod == prefix_mod->inc_size) {
1736 break;
1737 }
1738 cur_mod = (struct lys_module *)prefix_mod->inc[in_submod].submodule;
1739 siblings = cur_mod->data;
1740 ++in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001741 }
1742
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001743 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001744}
1745
Michal Vasko730dfdf2015-08-11 14:48:05 +02001746/**
1747 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001748 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001749 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001750 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001751 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001752 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1753 *
1754 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
1755 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001756 *
1757 * @param[in] id Schema-nodeid string.
1758 * @param[in] start Start of the relative search.
1759 * @param[in] mod Module in question.
1760 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001761 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001762 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001763 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001764 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001765int
1766resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1767 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001768{
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001769 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +02001770 struct lys_node *sibling;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001771 int i, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +02001772 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001773 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1774 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001775 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001776 uint8_t in_mod_part = 0;
1777
1778 assert(mod);
1779 assert(id);
1780
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001781 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1782 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001783 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001784 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001785
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001786 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001787 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001788 }
1789
1790 /* absolute-schema-nodeid */
1791 if (!is_relative) {
1792 if (prefix) {
1793 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
1794 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001795 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001796 }
1797 start = start_mod->data;
1798 } else {
1799 start = mod->data;
1800 start_mod = mod;
1801 }
1802 /* descendant-schema-nodeid */
1803 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001804 if (start) {
1805 start_mod = start->module;
1806 } else {
1807 start_mod = mod;
1808 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001809 }
1810
1811 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001812 sibling = NULL;
1813 LY_TREE_FOR(start, sibling) {
1814 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001815 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
1816 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001817 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001818 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001819
Michal Vasko1e989c02015-08-04 12:33:00 +02001820 /* prefix match check */
1821 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001822 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1823 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001824 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001825 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001826 } else {
1827 prefix_mod = mod;
1828 if (prefix_mod->type) {
1829 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1830 }
1831 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001832
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001833 /* modules need to always be checked, we want to skip augments */
1834 if (!sibling->module->type) {
1835 if (prefix_mod != sibling->module) {
1836 continue;
1837 }
1838 } else {
1839 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1840 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001842 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001843
Michal Vasko1e989c02015-08-04 12:33:00 +02001844 /* the result node? */
1845 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001846 /* we're looking only for groupings, this is a data node */
1847 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1848 continue;
1849 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001850 if (ret) {
1851 *ret = sibling;
1852 }
1853 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001854 }
1855
Michal Vaskodcc7a802015-08-06 11:59:47 +02001856 /* we're looking for a grouping (node_type == LYS_USES),
1857 * but this isn't it, we cannot search inside
1858 */
1859 if (sibling->nodetype == LYS_GROUPING) {
1860 continue;
1861 }
1862
Michal Vasko1e989c02015-08-04 12:33:00 +02001863 /* check for shorthand cases - then 'start' does not change */
1864 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1865 || (sibling->nodetype == LYS_CASE)) {
1866 start = sibling->child;
1867 }
1868 break;
1869 }
1870 }
1871
1872 /* we did not find the case in direct siblings */
1873 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001874 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001875 }
1876
1877 /* no match */
1878 if (!sibling) {
1879 /* on augment search also RPCs and notifications, if we are in top-level */
1880 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1881 /* we have searched all the data nodes */
1882 if (in_mod_part == 0) {
1883 if (!in_submod) {
1884 start = start_mod->rpc;
1885 } else {
1886 start = start_mod->inc[in_submod-1].submodule->rpc;
1887 }
1888 in_mod_part = 1;
1889 continue;
1890 }
1891 /* we have searched all the RPCs */
1892 if (in_mod_part == 1) {
1893 if (!in_submod) {
1894 start = start_mod->notif;
1895 } else {
1896 start = start_mod->inc[in_submod-1].submodule->notif;
1897 }
1898 in_mod_part = 2;
1899 continue;
1900 }
1901 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001902 }
1903
Michal Vasko1e989c02015-08-04 12:33:00 +02001904 /* are we done with the included submodules as well? */
1905 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001906 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001907 }
1908
Michal Vasko1e989c02015-08-04 12:33:00 +02001909 /* we aren't, check the next one */
1910 ++in_submod;
1911 in_mod_part = 0;
1912 start = start_mod->inc[in_submod-1].submodule->data;
1913 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001914 }
1915
1916 /* we found our submodule */
1917 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001918 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001919 in_submod = 0;
1920 }
1921
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001922 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1923 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001924 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001925 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001926 }
1927
1928 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001929 LOGINT;
1930 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001931}
1932
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001933/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001934static int
Radek Krejcic5090c32015-08-12 09:46:19 +02001935resolve_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 +02001936{
Radek Krejcic5090c32015-08-12 09:46:19 +02001937 struct unres_data *item, *par_iter, *prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001938 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001939 int flag;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001940
1941 if (!*parents) {
1942 *parents = malloc(sizeof **parents);
1943 (*parents)->dnode = NULL;
1944 (*parents)->next = NULL;
1945 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001946 for (par_iter = *parents; par_iter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001947 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001948 /* skip */
1949 continue;
1950 }
1951 flag = 0;
Radek Krejcic5090c32015-08-12 09:46:19 +02001952 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001953 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1954 && node->schema->name[nam_len] == '\0') {
1955 /* matching target */
1956 if (!flag) {
1957 /* replace leafref instead of the current parent */
1958 par_iter->dnode = node;
1959 flag = 1;
1960 } else {
1961 /* multiple matching, so create new leafref structure */
1962 item = malloc(sizeof *item);
1963 item->dnode = node;
1964 item->next = par_iter->next;
1965 par_iter->next = item;
1966 par_iter = par_iter->next;
1967 }
1968 }
1969 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001970
1971 if (!flag) {
1972 /* remove item from the parents list */
1973 if (prev) {
1974 prev->next = par_iter->next;
1975 free(par_iter);
1976 par_iter = prev->next;
1977 } else {
1978 item = par_iter->next;
1979 free(par_iter);
1980 par_iter = *parents = item;
1981 }
1982 } else {
1983 prev = par_iter;
1984 par_iter = par_iter->next;
1985 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001986 }
1987
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001988 return *parents ? EXIT_SUCCESS : -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001989}
1990
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001991/**
1992 * @brief Resolve (find) a data node. Does not log.
1993 *
1994 * @param[in] prefix Prefix of the data node.
1995 * @param[in] pref_len Length of the prefix.
1996 * @param[in] name Name of the data node.
1997 * @param[in] nam_len Length of the name.
1998 * @param[in] start Data node to start the search from.
1999 * @param[in,out] parents Resolved nodes. If there are some parents,
2000 * they are replaced (!!) with the resolvents.
2001 *
2002 * @return EXIT_SUCCESS on success, -1 otherwise.
2003 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002004static int
2005resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int name_len, struct lyd_node *start,
2006 struct unres_data **parents)
2007{
2008 struct lys_module *mod;
2009
2010 if (prefix) {
2011 /* we have prefix, find appropriate module */
2012 mod = resolve_prefixed_module(start->schema->module, prefix, pref_len);
2013 if (!mod) {
2014 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002015 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002016 }
2017 } else {
2018 /* no prefix, module is the same as of current node */
2019 mod = start->schema->module;
2020 }
2021
2022 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002023}
2024
Michal Vasko730dfdf2015-08-11 14:48:05 +02002025/**
Michal Vaskod9173342015-08-17 14:35:36 +02002026 * @brief Resolve a path predicate (leafref) in data context. Logs directly
2027 * only specific errors, general no-resolvent error is left to the caller,
2028 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002029 *
2030 * @param[in] pred Predicate in question.
2031 * @param[in,out] node_match Nodes satisfying the restriction
2032 * without the predicate. Nodes not
2033 * satisfying the predicate are removed.
2034 * @param[in] line Line in the input file.
2035 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002036 * @return Number of characters successfully parsed,
2037 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002038 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002039static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002040resolve_path_predicate_data(const char *pred, struct unres_data **node_match, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002041{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002042 /* ... /node[source = destination] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002043 struct unres_data *source_match, *dest_match, *node, *node_prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002044 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2045 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2046 int has_predicate, dest_parent_times, i;
2047
2048 do {
2049 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2050 &pke_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002051 LOGVAL(LYE_INCHAR, line, pred[-i], pred-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002052 return -parsed+i;
2053 }
2054 parsed += i;
2055 pred += i;
2056
2057 for (node = *node_match; node;) {
2058 /* source */
2059 source_match = NULL;
2060 /* must be leaf (key of a list) */
2061 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
2062 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +02002063 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002064 LOGVAL(LYE_LINE, line);
2065 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002066 return -parsed;
2067 }
2068
2069 /* destination */
2070 dest_match = calloc(1, sizeof *dest_match);
2071 dest_match->dnode = node->dnode;
2072 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2073 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002074 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002075 return -parsed+i;
2076 }
2077 pke_parsed += i;
2078 for (i = 0; i < dest_parent_times; ++i) {
2079 dest_match->dnode = dest_match->dnode->parent;
2080 if (!dest_match->dnode) {
2081 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002082 LOGVAL(LYE_LINE, line);
2083 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002084 return -parsed;
2085 }
2086 }
2087 while (1) {
2088 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
Michal Vasko1f76a282015-08-04 16:16:53 +02002089 || !dest_match->dnode || dest_match->next) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002090 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002091 LOGVAL(LYE_LINE, line);
2092 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002093 return -parsed;
2094 }
2095
2096 if (pke_len == pke_parsed) {
2097 break;
2098 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002099 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 +02002100 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002101 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002102 return -parsed+i;
2103 }
2104 pke_parsed += i;
2105 }
2106
2107 /* check match between source and destination nodes */
Radek Krejcib8048692015-08-05 13:36:34 +02002108 if (((struct lys_node_leaf *)source_match->dnode->schema)->type.base
2109 != ((struct lys_node_leaf *)dest_match->dnode->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002110 goto remove_leafref;
2111 }
2112
2113 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
2114 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
2115 goto remove_leafref;
2116 }
2117
2118 /* leafref is ok, continue check with next leafref */
2119 node_prev = node;
2120 node = node->next;
2121 continue;
2122
2123remove_leafref:
2124 /* does not fulfill conditions, remove leafref record */
2125 if (node_prev) {
2126 node_prev->next = node->next;
2127 free(node);
2128 node = node_prev->next;
2129 } else {
2130 node = (*node_match)->next;
2131 free(*node_match);
2132 *node_match = node;
2133 }
2134 }
2135 } while (has_predicate);
2136
2137 return parsed;
2138}
2139
Michal Vasko730dfdf2015-08-11 14:48:05 +02002140/**
2141 * @brief Resolve a path (leafref) in data context. Logs directly.
2142 *
2143 * @param[in] unres Nodes matching the schema path.
2144 * @param[in] path Path in question.
2145 * @param[in,out] ret Matching nodes.
2146 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002147 * @return EXIT_SUCCESS on success, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002148 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002149int
Michal Vaskof02e3742015-08-05 16:27:02 +02002150resolve_path_arg_data(struct unres_data *unres, const char *path, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002151{
Radek Krejci71b795b2015-08-10 16:20:39 +02002152 struct lyd_node *data = NULL;
Michal Vaskof02e3742015-08-05 16:27:02 +02002153 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002154 const char *prefix, *name;
Michal Vaskod9173342015-08-17 14:35:36 +02002155 int pref_len, nam_len, has_predicate, parent_times, i, parsed;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002156
2157 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002158 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002159 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002160
2161 /* searching for nodeset */
2162 do {
2163 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002164 LOGVAL(LYE_INCHAR, LOGLINE(unres), path[-i], path-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002165 goto error;
2166 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002167 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002168 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002169
2170 if (!*ret) {
2171 *ret = calloc(1, sizeof **ret);
2172 for (i = 0; i < parent_times; ++i) {
2173 /* relative path */
2174 if (!*ret) {
2175 /* error, too many .. */
Michal Vaskoc07187d2015-08-13 15:20:57 +02002176 LOGVAL(LYE_INVAL, LOGLINE(unres), path, unres->dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002177 goto error;
2178 } else if (!(*ret)->dnode) {
2179 /* first .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002180 data = (*ret)->dnode = unres->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002181 } else if (!(*ret)->dnode->parent) {
2182 /* we are in root */
2183 free(*ret);
2184 *ret = NULL;
2185 } else {
2186 /* multiple .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002187 data = (*ret)->dnode = (*ret)->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002188 }
2189 }
2190
2191 /* absolute path */
2192 if (parent_times == -1) {
2193 for (data = unres->dnode; data->parent; data = data->parent);
2194 for (; data->prev->next; data = data->prev);
2195 }
2196 }
2197
2198 /* node identifier */
2199 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002200 LOGVAL(LYE_INELEM_LEN, LOGLINE(unres), nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201 goto error;
2202 }
2203
2204 if (has_predicate) {
2205 /* we have predicate, so the current results must be lists */
2206 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002207 if (riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002208 ((struct lys_node_list *)riter->dnode->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002209 /* leafref is ok, continue check with next leafref */
2210 raux = riter;
2211 riter = riter->next;
2212 continue;
2213 }
2214
2215 /* does not fulfill conditions, remove leafref record */
2216 if (raux) {
2217 raux->next = riter->next;
2218 free(riter);
2219 riter = raux->next;
2220 } else {
2221 *ret = riter->next;
2222 free(riter);
2223 riter = *ret;
2224 }
2225 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02002226 if ((i = resolve_path_predicate_data(path, ret, LOGLINE(unres))) < 1) {
Michal Vaskod9173342015-08-17 14:35:36 +02002227 /* line was already displayed */
2228 LOGVAL(LYE_NORESOLV, 0, path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002229 goto error;
2230 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002231 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002232 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002233
2234 if (!*ret) {
Michal Vaskod9173342015-08-17 14:35:36 +02002235 LOGVAL(LYE_NORESOLV, LOGLINE(unres), path-parsed);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002236 goto error;
2237 }
2238 }
2239 } while (path[0] != '\0');
2240
Michal Vaskof02e3742015-08-05 16:27:02 +02002241 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002242
2243error:
2244
2245 while (*ret) {
2246 raux = (*ret)->next;
2247 free(*ret);
2248 *ret = raux;
2249 }
2250
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002251 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002252}
2253
Michal Vasko730dfdf2015-08-11 14:48:05 +02002254/**
2255 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2256 *
2257 * @param[in] path Path in question.
2258 * @param[in] mod Schema module.
2259 * @param[in] source_node Left operand node.
2260 * @param[in] dest_node Right ooperand node.
2261 * @param[in] line Line in the input file.
2262 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002263 * @return Number of characters successfully parsed,
2264 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002265 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002266static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002267resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002268 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002269{
2270 struct lys_node *src_node, *dst_node;
2271 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2272 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 +02002273 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002274
2275 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002276 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002277 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002278 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002279 return -parsed+i;
2280 }
2281 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002282 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002283
Michal Vasko58090902015-08-13 14:04:15 +02002284 /* source (must be leaf) */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002285 rc = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
2286 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002287 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002288 return -parsed;
2289 }
2290
2291 /* destination */
2292 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2293 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002294 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002295 return -parsed;
2296 }
2297 pke_parsed += i;
2298
2299 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2300 dst_node = dest_node;
2301 for (i = 1; i < dest_parent_times; ++i) {
2302 dst_node = dst_node->parent;
2303 if (!dst_node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002304 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002305 return -parsed;
2306 }
2307 }
2308 while (1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002309 rc = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2310 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2311 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002312 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002313 return -parsed;
2314 }
2315
2316 if (pke_len == pke_parsed) {
2317 break;
2318 }
2319
2320 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2321 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002322 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002323 return -parsed;
2324 }
2325 pke_parsed += i;
2326 }
2327
2328 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002329 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2330 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskod9173342015-08-17 14:35:36 +02002331 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002332 return -parsed;
2333 }
2334 } while (has_predicate);
2335
2336 return parsed;
2337}
2338
Michal Vasko730dfdf2015-08-11 14:48:05 +02002339/**
Michal Vaskod9173342015-08-17 14:35:36 +02002340 * @brief Resolve a path (leafref) in schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002341 *
2342 * @param[in] mod Module in question.
2343 * @param[in] path Path in question.
2344 * @param[in] parent_node Parent of the leafref.
2345 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002346 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002347 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002348 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002349 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002350static int
2351resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line,
2352 struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002353{
Michal Vasko58090902015-08-13 14:04:15 +02002354 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002355 const char *id, *prefix, *name;
2356 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002357 int i, first, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002358
2359 first = 1;
2360 parent_times = 0;
2361 id = path;
2362
2363 do {
2364 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002365 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002366 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002367 }
2368 id += i;
2369
2370 if (first) {
2371 if (parent_times == -1) {
2372 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002373 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002374 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002375 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002376 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002377 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002378 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002379 node = parent_node;
2380 i = 0;
2381 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002382 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002383 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002384 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002385 }
Michal Vasko58090902015-08-13 14:04:15 +02002386
2387 /* this node is a wrong node, we actually need the augment target */
2388 if (node->nodetype == LYS_AUGMENT) {
2389 node = ((struct lys_node_augment *)node)->target;
2390 if (!node) {
2391 continue;
2392 }
2393 }
2394
2395 ++i;
2396 if (i == parent_times) {
2397 break;
2398 }
2399 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002400 }
2401 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002402 } else {
2403 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002404 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002405 }
2406 first = 0;
2407 } else {
2408 node = node->child;
2409 }
2410
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002411 rc = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES), &node);
2412 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002413 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002414 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002415 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002416
2417 if (has_predicate) {
2418 /* we have predicate, so the current result must be list */
2419 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002420 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002421 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002422 }
2423
2424 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002425 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002426 }
2427 id += i;
2428 }
2429 } while (id[0]);
2430
Radek Krejcib1c12512015-08-11 11:22:04 +02002431 /* the target must be leaf or leaf-list */
2432 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002433 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002434 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002435 }
2436
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002437 if (ret) {
2438 *ret = node;
2439 }
2440 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002441}
2442
Michal Vasko730dfdf2015-08-11 14:48:05 +02002443/**
2444 * @brief Resolve instance-identifier predicate. Does not log.
2445 *
2446 * @param[in] pred Predicate in question.
2447 * @param[in,out] node_match Nodes matching the restriction without
2448 * the predicate. Nodes not satisfying
2449 * the predicate are removed.
2450 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002451 * @return Number of characters successfully parsed,
2452 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002453 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002454static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002455resolve_predicate(const char *pred, struct unres_data **node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002457 /* ... /node[target = value] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002458 struct unres_data *target_match, *node, *node_prev = NULL, *tmp;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002459 const char *prefix, *name, *value;
2460 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2461
2462 idx = -1;
2463 parsed = 0;
2464
2465 do {
2466 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
2467 return -parsed+i;
2468 }
2469 parsed += i;
2470 pred += i;
2471
2472 if (isdigit(name[0])) {
2473 idx = atoi(name);
2474 }
2475
2476 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
2477 /* target */
2478 target_match = NULL;
2479 if ((name[0] == '.') || !value) {
2480 target_match = calloc(1, sizeof *target_match);
2481 target_match->dnode = node->dnode;
2482 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002483 goto remove_instid;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002484 }
2485
2486 /* check that we have the correct type */
2487 if (name[0] == '.') {
Radek Krejci76512572015-08-04 09:47:08 +02002488 if (node->dnode->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002489 goto remove_instid;
2490 }
2491 } else if (value) {
Radek Krejci76512572015-08-04 09:47:08 +02002492 if (node->dnode->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002493 goto remove_instid;
2494 }
2495 }
2496
2497 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
2498 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
2499 || (!value && (idx != cur_idx))) {
2500 goto remove_instid;
2501 }
2502
2503 while (target_match) {
2504 tmp = target_match->next;
2505 free(target_match);
2506 target_match = tmp;
2507 }
2508
2509 /* leafref is ok, continue check with next leafref */
2510 node_prev = node;
2511 node = node->next;
2512 continue;
2513
2514remove_instid:
2515 while (target_match) {
2516 tmp = target_match->next;
2517 free(target_match);
2518 target_match = tmp;
2519 }
2520
2521 /* does not fulfill conditions, remove leafref record */
2522 if (node_prev) {
2523 node_prev->next = node->next;
2524 free(node);
2525 node = node_prev->next;
2526 } else {
2527 node = (*node_match)->next;
2528 free(*node_match);
2529 *node_match = node;
2530 }
2531 }
2532 } while (has_predicate);
2533
2534 return parsed;
2535}
2536
Michal Vasko730dfdf2015-08-11 14:48:05 +02002537/**
2538 * @brief Resolve instance-identifier. Logs directly.
2539 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002540 * @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 +02002541 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002542 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002543 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002544 * @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 +02002545 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002546struct lyd_node *
2547resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002548{
Radek Krejcic5090c32015-08-12 09:46:19 +02002549 int i = 0, j;
2550 struct lyd_node *result = NULL;
2551 struct lys_module *mod = NULL;
2552 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002553 const char *prefix, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002554 char *str;
2555 int pref_len, name_len, has_predicate;
2556 struct unres_data *workingnodes = NULL;
2557 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002558
Radek Krejcic5090c32015-08-12 09:46:19 +02002559 /* we need root to resolve absolute path */
2560 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561 for (; data->prev->next; data = data->prev);
2562
Radek Krejcic5090c32015-08-12 09:46:19 +02002563 /* search for the instance node */
2564 while (path[i]) {
2565 j = parse_instance_identifier(&path[i], &prefix, &pref_len, &name, &name_len, &has_predicate);
2566 if (j <= 0) {
2567 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002568 goto error;
2569 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002570 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002571
Radek Krejcic5090c32015-08-12 09:46:19 +02002572 if (prefix) {
2573 str = strndup(prefix, pref_len);
2574 mod = ly_ctx_get_module(ctx, str, NULL);
2575 free(str);
Michal Vaskob387c482015-08-12 09:32:59 +02002576 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002577
Radek Krejcic5090c32015-08-12 09:46:19 +02002578 if (!mod) {
2579 /* no instance exists */
2580 return NULL;
2581 }
2582
2583 if (resolve_data(mod, name, name_len, data, &workingnodes)) {
2584 /* no instance exists */
2585 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002586 }
2587
2588 if (has_predicate) {
2589 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcic5090c32015-08-12 09:46:19 +02002590 for (raux = NULL, riter = workingnodes; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002591 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002592 ((struct lys_node_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +02002593 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002594 /* instid is ok, continue check with next instid */
2595 raux = riter;
2596 riter = riter->next;
2597 continue;
2598 }
2599
2600 /* does not fulfill conditions, remove inst record */
2601 if (raux) {
2602 raux->next = riter->next;
2603 free(riter);
2604 riter = raux->next;
2605 } else {
Radek Krejcic5090c32015-08-12 09:46:19 +02002606 workingnodes = riter->next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002607 free(riter);
Radek Krejcic5090c32015-08-12 09:46:19 +02002608 riter = workingnodes;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002609 }
2610 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002611
2612 j = resolve_predicate(&path[i], &workingnodes);
2613 if (j < 1) {
2614 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002615 goto error;
2616 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002617 i += j;;
Michal Vaskob387c482015-08-12 09:32:59 +02002618
Radek Krejcic5090c32015-08-12 09:46:19 +02002619 if (!workingnodes) {
2620 /* no instance exists */
2621 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002622 }
2623 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002624 }
2625
Radek Krejcic5090c32015-08-12 09:46:19 +02002626 if (!workingnodes) {
2627 /* no instance exists */
2628 return NULL;
2629 } else if (workingnodes->next) {
2630 /* instance identifier must resolve to a single node */
2631 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2632
2633 /* cleanup */
2634 while (workingnodes) {
2635 raux = workingnodes->next;
2636 free(workingnodes);
2637 workingnodes = raux;
2638 }
2639
2640 return NULL;
2641 } else {
2642 /* we have required result, remember it and cleanup */
2643 result = workingnodes->dnode;
2644 free(workingnodes);
2645
2646 return result;
2647 }
2648
2649error:
2650
2651 /* cleanup */
2652 while (workingnodes) {
2653 raux = workingnodes->next;
2654 free(workingnodes);
2655 workingnodes = raux;
2656 }
2657
2658 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002659}
2660
Michal Vasko730dfdf2015-08-11 14:48:05 +02002661/**
2662 * @brief Passes config flag down to children. Does not log.
2663 *
2664 * @param[in] node Parent node.
2665 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002666static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002667inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002668{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002669 LY_TREE_FOR(node, node) {
2670 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2671 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002672 }
2673}
2674
Michal Vasko730dfdf2015-08-11 14:48:05 +02002675/**
Michal Vaskod9173342015-08-17 14:35:36 +02002676 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002677 *
2678 * @param[in] aug Augment in question.
2679 * @param[in] siblings Nodes where to start the search in.
2680 * @param[in] module Main module.
2681 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002682 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002683 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002684int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002685resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002686{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002687 int rc;
Radek Krejci76512572015-08-04 09:47:08 +02002688 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002689
2690 assert(module);
2691
2692 /* resolve target node */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002693 rc = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT, &aug->target);
2694 if (rc) {
2695 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002696 }
2697
2698 if (!aug->child) {
2699 /* nothing to do */
2700 return EXIT_SUCCESS;
2701 }
2702
2703 /* inherit config information from parent, augment does not have
2704 * config property, but we need to keep the information for subelements
2705 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002706 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002707 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002708 inherit_config_flag(sub);
2709 }
2710
Radek Krejci07911992015-08-14 15:13:31 +02002711 /* check identifier uniquness as in lys_node_addchild() */
2712 LY_TREE_FOR(aug->child, aux) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002713 if (lys_check_id(aux, aug->parent, module)) {
2714 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002715 }
2716 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002717 /* reconnect augmenting data into the target - add them to the target child list */
2718 if (aug->target->child) {
2719 aux = aug->target->child->prev; /* remember current target's last node */
2720 aux->next = aug->child; /* connect augmenting data after target's last node */
2721 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2722 aug->child->prev = aux; /* finish connecting of both child lists */
2723 } else {
2724 aug->target->child = aug->child;
2725 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002726
2727 return EXIT_SUCCESS;
2728}
2729
Michal Vasko730dfdf2015-08-11 14:48:05 +02002730/**
2731 * @brief Resolve uses, apply augments, refines. Logs directly.
2732 *
2733 * @param[in] uses Uses in question.
2734 * @param[in,out] unres List of unresolved items.
2735 * @param[in] line Line in the input file.
2736 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002737 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward ereference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002738 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002739int
Michal Vaskof02e3742015-08-05 16:27:02 +02002740resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002741{
2742 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002743 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002744 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002745 struct lys_restr *newmust;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002746 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002747 uint8_t size;
2748
Michal Vasko71e1aa82015-08-12 12:17:51 +02002749 assert(uses->grp);
2750
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002751 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002752 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002753 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002754 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002755 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002756 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002757 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002758 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002759 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002760 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002761 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002762 }
2763 }
2764 ctx = uses->module->ctx;
2765
2766 /* apply refines */
2767 for (i = 0; i < uses->refine_size; i++) {
2768 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002769 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2770 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002771 if (rc == -1) {
2772 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2773 } else {
2774 LOGVAL(LYE_NORESOLV, line, rfn->target_name);
2775 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002776 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002777 }
2778
Radek Krejci1d82ef62015-08-07 14:44:40 +02002779 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002780 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002781 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002782 }
2783
2784 /* description on any nodetype */
2785 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002786 lydict_remove(ctx, node->dsc);
2787 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002788 }
2789
2790 /* reference on any nodetype */
2791 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002792 lydict_remove(ctx, node->ref);
2793 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002794 }
2795
2796 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002797 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002798 node->flags &= ~LYS_CONFIG_MASK;
2799 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 }
2801
2802 /* default value ... */
2803 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002804 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002805 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002806 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2807 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2808 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002809 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002810 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2811 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002812 if (rc == -1) {
2813 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2814 } else {
2815 LOGVAL(LYE_NORESOLV, line, rfn->mod.dflt);
2816 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002817 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002818 }
2819 }
2820 }
2821
2822 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002823 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002824 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002825 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002826 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827
2828 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002829 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002830 }
2831 }
2832
2833 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002834 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2835 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2836 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002837 }
2838
2839 /* min/max-elements on list or leaf-list */
2840 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002841 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002842 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002843 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 }
2845 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002846 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002848 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002849 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002850 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851 }
2852 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002853 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002854 }
2855 }
2856
2857 /* must in leaf, leaf-list, list, container or anyxml */
2858 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002859 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2860 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 if (!newmust) {
2862 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002863 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002864 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002865 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2867 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2868 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2869 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2870 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2871 }
2872
Radek Krejci1d82ef62015-08-07 14:44:40 +02002873 ((struct lys_node_leaf *)node)->must = newmust;
2874 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 }
2876 }
2877
2878 /* apply augments */
2879 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002880 rc = resolve_augment(&uses->augment[i], uses->child, uses->module);
2881 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002882 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002883 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884 }
2885 }
2886
2887 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002888}
2889
Michal Vasko730dfdf2015-08-11 14:48:05 +02002890/**
2891 * @brief Resolve base identity recursively. Does not log.
2892 *
2893 * @param[in] module Main module.
2894 * @param[in] ident Identity in question.
2895 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002896 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002897 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002898 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002899 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002900static int
2901resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2902 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002903{
Michal Vaskof02e3742015-08-05 16:27:02 +02002904 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002905 struct lys_ident *base_iter = NULL;
2906 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002907
2908 /* search module */
2909 for (i = 0; i < module->ident_size; i++) {
2910 if (!strcmp(basename, module->ident[i].name)) {
2911
2912 if (!ident) {
2913 /* just search for type, so do not modify anything, just return
2914 * the base identity pointer
2915 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002916 if (ret) {
2917 *ret = &module->ident[i];
2918 }
2919 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002920 }
2921
2922 /* we are resolving identity definition, so now update structures */
2923 ident->base = base_iter = &module->ident[i];
2924
2925 break;
2926 }
2927 }
2928
2929 /* search submodules */
2930 if (!base_iter) {
2931 for (j = 0; j < module->inc_size; j++) {
2932 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2933 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2934
2935 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002936 if (ret) {
2937 *ret = &module->inc[j].submodule->ident[i];
2938 }
2939 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002940 }
2941
2942 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2943 break;
2944 }
2945 }
2946 }
2947 }
2948
2949 /* we found it somewhere */
2950 if (base_iter) {
2951 while (base_iter) {
2952 for (der = base_iter->der; der && der->next; der = der->next);
2953 if (der) {
2954 der->next = malloc(sizeof *der);
2955 der = der->next;
2956 } else {
2957 ident->base->der = der = malloc(sizeof *der);
2958 }
2959 der->next = NULL;
2960 der->ident = ident;
2961
2962 base_iter = base_iter->base;
2963 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002964 if (ret) {
2965 *ret = ident->base;
2966 }
2967 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002968 }
2969
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002970 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002971}
2972
Michal Vasko730dfdf2015-08-11 14:48:05 +02002973/**
2974 * @brief Resolve base identity. Logs directly.
2975 *
2976 * @param[in] module Main module.
2977 * @param[in] ident Identity in question.
2978 * @param[in] basename Base name of the identity.
2979 * @param[in] parent Either "type" or "ident".
2980 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002981 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002982 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002983 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002984 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002985static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002986resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002987 uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988{
2989 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02002990 int i, prefix_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002991
2992 /* search for the base identity */
2993 name = strchr(basename, ':');
2994 if (name) {
2995 /* set name to correct position after colon */
2996 prefix_len = name - basename;
2997 name++;
2998
2999 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3000 /* prefix refers to the current module, ignore it */
3001 prefix_len = 0;
3002 }
3003 } else {
3004 name = basename;
3005 }
3006
3007 if (prefix_len) {
3008 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003009 module = resolve_prefixed_module(module, basename, prefix_len);
3010 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003011 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003012 LOGVAL(LYE_INPREF, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003013 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014 }
3015 } else {
3016 /* search in submodules */
3017 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003018 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3019 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003020 }
3021 }
3022 }
3023
3024 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003025 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3026 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027 }
3028
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003029 LOGVAL(LYE_INARG, line, basename, parent);
3030 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003031}
3032
Michal Vasko730dfdf2015-08-11 14:48:05 +02003033/**
3034 * @brief Resolve identityref. Does not log.
3035 *
3036 * @param[in] base Base identity.
3037 * @param[in] name Identityref name.
3038 * @param[in] ns Namespace of the identityref.
3039 *
3040 * @return Pointer to the identity resolvent, NULL on error.
3041 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003042struct lys_ident *
3043resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003044{
Radek Krejcia52656e2015-08-05 13:41:50 +02003045 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003046
3047 if (!base || !name || !ns) {
3048 return NULL;
3049 }
3050
3051 for(der = base->der; der; der = der->next) {
3052 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3053 /* we have match */
3054 return der->ident;
3055 }
3056 }
3057
3058 /* not found */
3059 return NULL;
3060}
3061
Michal Vasko730dfdf2015-08-11 14:48:05 +02003062/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02003063 * @brief Resolve unres uses. Logs directly.
3064 *
3065 * @param[in] uses Uses in question.
3066 * @param[in] unres Specific unres item.
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_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003074 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003075 struct lys_node *parent;
3076
3077 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3078 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3079
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003080 if (!uses->grp) {
3081 rc = resolve_grouping(uses, line);
3082 if (rc) {
3083 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003084 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085 }
3086
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003087 if (uses->grp->nacm) {
3088 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3089 return EXIT_FAILURE;
3090 }
3091
3092 rc = resolve_uses(uses, unres, line);
3093 if (!rc) {
3094 /* decrease unres count only if not first try */
3095 if ((line < UINT_MAX) && parent) {
3096 if (!parent->nacm) {
3097 LOGINT;
3098 return -1;
3099 }
3100 --parent->nacm;
3101 }
3102 return EXIT_SUCCESS;
3103 }
3104
3105 if ((rc == EXIT_FAILURE) && parent) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003106 ++parent->nacm;
3107 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003108 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003109}
3110
Michal Vasko730dfdf2015-08-11 14:48:05 +02003111/**
Michal Vasko9957e592015-08-17 15:04:09 +02003112 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003113 *
3114 * @param[in] list List in question.
3115 * @param[in] keys_str Keys node value.
3116 * @param[in] line Line in the input file.
3117 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003118 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003119 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120static int
Michal Vasko9957e592015-08-17 15:04:09 +02003121resolve_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 +02003122{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003123 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003124 const char *value;
3125
3126 for (i = 0; i < list->keys_size; ++i) {
3127 /* get the key name */
3128 if ((value = strpbrk(keys_str, " \t\n"))) {
3129 len = value - keys_str;
3130 while (isspace(value[0])) {
3131 value++;
3132 }
3133 } else {
3134 len = strlen(keys_str);
3135 }
3136
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003137 rc = resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
3138 if (rc) {
3139 if (rc == EXIT_FAILURE) {
3140 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3141 }
3142 return rc;
3143 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003145 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003146 /* check_key logs */
3147 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148 }
3149
3150 /* prepare for next iteration */
3151 while (value && isspace(value[0])) {
3152 value++;
3153 }
3154 keys_str = value;
3155 }
3156
Michal Vaskof02e3742015-08-05 16:27:02 +02003157 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158}
3159
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003160/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003161static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003162resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003163{
3164 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003165 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166}
3167
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003168/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003169static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003170resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003171{
3172 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003173 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174}
3175
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003176/**
3177 * @brief Resolve a single unres item. Logs indirectly.
3178 *
3179 * @param[in] mod Main module.
3180 * @param[in] item Item to resolve. Type determined by \p type.
3181 * @param[in] type Type of the unresolved item.
3182 * @param[in] str_snode String, a schema node, or NULL.
3183 * @param[in] unres Unres structure in question.
3184 * @param[in] line Line in the input file. -1 turns logging off, 0 skips line print.
3185 *
3186 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3187 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188static int
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003189resolve_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 +02003190 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003191{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003192 int rc = -1, has_str = 0;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003193 struct lys_node *snode;
3194 const char *base_name;
3195
3196 struct lys_ident *ident;
3197 struct lys_type *stype;
3198 struct lys_feature **feat_ptr;
3199 struct lys_node_choice *choic;
3200 struct lys_unique *uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003201
3202 switch (type) {
3203 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003204 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003205 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003206 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003207 base_name = str_snode;
3208 ident = item;
3209
3210 rc = resolve_base_ident(mod, ident, base_name, "ident", line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003211 has_str = 1;
3212 break;
3213 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003214 base_name = str_snode;
3215 stype = item;
3216
3217 rc = resolve_base_ident(mod, NULL, base_name, "type", line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003218 has_str = 1;
3219 break;
3220 case UNRES_TYPE_LEAFREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003221 snode = str_snode;
3222 stype = item;
3223
3224 rc = resolve_path_arg_schema(mod, stype->info.lref.path, snode, line,
3225 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003226 has_str = 0;
3227 break;
3228 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003229 base_name = str_snode;
3230 stype = item;
3231
3232 /* HACK type->der is temporarily its parent */
3233 rc = resolve_superior_type(base_name, stype->prefix, mod, (struct lys_node *)stype->der, &stype->der);
3234 if (!rc) {
3235 stype->base = stype->der->type.base;
3236 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003237 has_str = 1;
3238 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003240 base_name = str_snode;
3241 feat_ptr = item;
3242
3243 rc = resolve_feature(base_name, mod, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003244 has_str = 1;
3245 break;
3246 case UNRES_USES:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003247 rc = resolve_unres_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 has_str = 0;
3249 break;
3250 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003251 base_name = str_snode;
3252 stype = item;
3253
3254 rc = check_default(stype, base_name);
3255 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256 has_str = 0;
3257 break;
3258 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003259 base_name = str_snode;
3260 choic = item;
3261
3262 rc = resolve_sibling(mod, choic->child, NULL, 0, base_name, 0, LYS_ANYXML | LYS_CASE
3263 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST, &choic->dflt);
3264 /* there is no prefix, that is the only error */
3265 assert(rc != -1);
3266 if (rc == EXIT_FAILURE) {
3267 LOGVAL(LYE_INRESOLV, line, "choice default", base_name);
3268 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269 has_str = 1;
3270 break;
3271 case UNRES_LIST_KEYS:
Michal Vasko9957e592015-08-17 15:04:09 +02003272 rc = resolve_list_keys(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 has_str = 1;
3274 break;
3275 case UNRES_LIST_UNIQ:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003276 /* actually the unique string */
3277 base_name = str_snode;
3278 uniq = item;
3279
3280 rc = resolve_unique((struct lys_node *)uniq->leafs, base_name, uniq, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003281 has_str = 1;
3282 break;
3283 case UNRES_WHEN:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003284 rc = resolve_unres_when(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285 has_str = 0;
3286 break;
3287 case UNRES_MUST:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003288 rc = resolve_unres_must(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 has_str = 0;
3290 break;
3291 }
3292
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003293 if (has_str && !rc) {
3294 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003295 }
3296
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003297 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298}
3299
Michal Vaskof02e3742015-08-05 16:27:02 +02003300/* logs directly */
3301static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003302print_unres_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303{
Michal Vaskof02e3742015-08-05 16:27:02 +02003304 char line_str[18];
3305
3306 if (line) {
3307 sprintf(line_str, " (line %u)", line);
3308 } else {
3309 line_str[0] = '\0';
3310 }
3311
3312 switch (type) {
3313 case UNRES_RESOLVED:
3314 LOGINT;
3315 break;
3316 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003317 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003318 break;
3319 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003320 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003321 break;
3322 case UNRES_TYPE_LEAFREF:
3323 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3324 break;
3325 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003326 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 +02003327 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003328 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003329 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 +02003330 break;
3331 case UNRES_USES:
3332 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3333 break;
3334 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003335 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 +02003336 break;
3337 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003338 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 +02003339 break;
3340 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003341 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 +02003342 break;
3343 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003344 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 +02003345 break;
3346 case UNRES_WHEN:
3347 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3348 break;
3349 case UNRES_MUST:
3350 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3351 break;
3352 }
3353}
3354
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003355/**
3356 * @brief Resolve every unres item in the structure. Logs directly.
3357 *
3358 * @param[in] mod Main module.
3359 * @param[in] unres Unres structure in question.
3360 *
3361 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3362 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003363int
3364resolve_unres(struct lys_module *mod, struct unres_schema *unres)
3365{
Michal Vaskoc07187d2015-08-13 15:20:57 +02003366 uint32_t i, resolved, unres_uses, res_uses, line;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003367 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003368
3369 assert(unres);
3370
Michal Vaskoc07187d2015-08-13 15:20:57 +02003371 line = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003372 resolved = 0;
3373
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003374 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003375 do {
3376 unres_uses = 0;
3377 res_uses = 0;
3378
3379 for (i = 0; i < unres->count; ++i) {
3380 if (unres->type[i] != UNRES_USES) {
3381 continue;
3382 }
3383
Michal Vaskoc07187d2015-08-13 15:20:57 +02003384#ifndef NDEBUG
3385 line = unres->line[i];
3386#endif
3387
Michal Vasko51054ca2015-08-12 12:20:00 +02003388 ++unres_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003389 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line);
3390 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003391 unres->type[i] = UNRES_RESOLVED;
3392 ++resolved;
3393 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003394 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003395 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003396 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003397 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003398 } while (res_uses && (res_uses < unres_uses));
3399
3400 if (res_uses < unres_uses) {
3401 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
3402 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003403 }
3404
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003405 /* the rest */
3406 for (i = 0; i < unres->count; ++i) {
3407 if (unres->type[i] == UNRES_RESOLVED) {
3408 continue;
3409 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003410
3411#ifndef NDEBUG
3412 line = unres->line[i];
3413#endif
3414
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003415 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, line);
3416 if (!rc) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417 unres->type[i] = UNRES_RESOLVED;
3418 ++resolved;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003419 } else if (rc == -1) {
3420 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003421 }
3422 }
3423
3424 if (resolved < unres->count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003425 LOGVAL(LYE_SPEC, 0, "There are unresolved items left.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 return EXIT_FAILURE;
3427 }
3428
3429 return EXIT_SUCCESS;
3430}
3431
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003432/**
3433 * @brief Try to resolve an unres item with a string argument. Logs indirectly.
3434 *
3435 * @param[in] mod Main module.
3436 * @param[in] unres Unres structure to use.
3437 * @param[in] item Item to resolve. Type determined by \p type.
3438 * @param[in] type Type of the unresolved item.
3439 * @param[in] str String argument.
3440 * @param[in] line Line in the input file.
3441 *
3442 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3443 */
3444int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003445unres_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 +02003446 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003447{
3448 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003449 return unres_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450}
3451
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003452/**
3453 * @brief Try to resolve an unres item with a schema node argument. Logs indirectly.
3454 *
3455 * @param[in] mod Main module.
3456 * @param[in] unres Unres structure to use.
3457 * @param[in] item Item to resolve. Type determined by \p type.
3458 * @param[in] type Type of the unresolved item.
3459 * @param[in] snode Schema node argument.
3460 * @param[in] line Line in the input file.
3461 *
3462 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3463 */
3464int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003465unres_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003466 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003468 int rc;
3469
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 assert(unres && item);
3471
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003472 rc = resolve_unres_item(mod, item, type, snode, unres, UINT_MAX);
3473 if (rc != EXIT_FAILURE) {
3474 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003475 }
3476
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003477 print_unres_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003478
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479 unres->count++;
3480 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3481 unres->item[unres->count-1] = item;
3482 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3483 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003484 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003485 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003486#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003487 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3488 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003489#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003490
3491 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003492}
3493
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003494/**
3495 * @brief Duplicate an unres item. Logs indirectly.
3496 *
3497 * @param[in] mod Main module.
3498 * @param[in] unres Unres structure to use.
3499 * @param[in] item Old item to be resolved.
3500 * @param[in] type Type of the old unresolved item.
3501 * @param[in] new_item New item to use in the duplicate.
3502 *
3503 * @return EXIT_SUCCESS on success, -1 on error.
3504 */
Michal Vaskodad19402015-08-06 09:51:53 +02003505int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003506unres_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 +02003507{
3508 int i;
3509
3510 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003511 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003512 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003513 }
3514
Radek Krejci1d82ef62015-08-07 14:44:40 +02003515 i = unres_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516
3517 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003518 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 }
3520
Michal Vasko4adc10f2015-08-11 15:26:17 +02003521 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003523 if (unres_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3524 LOGINT;
3525 return -1;
3526 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003528 if (unres_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3529 LOGINT;
3530 return -1;
3531 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 }
Michal Vaskodad19402015-08-06 09:51:53 +02003533
3534 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003535}
3536
Michal Vaskof02e3742015-08-05 16:27:02 +02003537/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003539unres_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003540{
3541 uint32_t ret = -1, i;
3542
3543 for (i = 0; i < unres->count; ++i) {
3544 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3545 ret = i;
3546 break;
3547 }
3548 }
3549
3550 return ret;
3551}