blob: 8daef7f683ac209888951ffe9ebdeffad4fa6a25 [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 */
Michal Vasko249e6b52015-08-19 11:08:52 +020047int
Radek Krejci6dc53a22015-08-17 13:27:59 +020048parse_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/**
Michal Vasko1f2cc332015-08-19 11:18:32 +0200510 * @brief Parse instance-identifier in JSON format. That means that prefixes
511 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200512 *
513 * instance-identifier = 1*("/" (node-identifier *predicate))
514 *
515 * @param[in] id Identifier in question.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200516 * @param[out] model Points to the model name.
517 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200518 * @param[out] name Points to the node name.
519 * @param[out] nam_len Length of the node name.
520 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
521 *
522 * @return Number of characters successfully parsed,
523 * positive on success, negative on failure.
524 */
525static int
Michal Vasko1f2cc332015-08-19 11:18:32 +0200526parse_instance_identifier_json(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
527 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200528{
529 int parsed = 0, ret;
530
531 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200532 if (model) {
533 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200534 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200535 if (mod_len) {
536 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200537 }
538 if (name) {
539 *name = NULL;
540 }
541 if (nam_len) {
542 *nam_len = 0;
543 }
544 if (has_predicate) {
545 *has_predicate = 0;
546 }
547
548 if (id[0] != '/') {
549 return -parsed;
550 }
551
552 ++parsed;
553 ++id;
554
Michal Vasko1f2cc332015-08-19 11:18:32 +0200555 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200556 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200557 } else if (model && !*model) {
558 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200559 }
560
561 parsed += ret;
562 id += ret;
563
564 if ((id[0] == '[') && has_predicate) {
565 *has_predicate = 1;
566 }
567
568 return parsed;
569}
570
571/**
Michal Vasko1f2cc332015-08-19 11:18:32 +0200572 * @brief Parse predicate (instance-identifier) in JSON format. That means that prefixes
573 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574 *
575 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
576 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
577 * ((DQUOTE string DQUOTE) /
578 * (SQUOTE string SQUOTE))
579 * pos = non-negative-integer-value
580 *
581 * @param[in] id Identifier in question.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200582 * @param[out] model Points to the model name.
583 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200584 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
585 * @param[out] nam_len Length of the node name.
586 * @param[out] value Value the node-identifier must have (string from the grammar),
587 * NULL if there is not any.
588 * @param[out] val_len Length of the value, 0 if there is not any.
589 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
590 *
591 * @return Number of characters successfully parsed,
592 * positive on success, negative on failure.
593 */
594static int
Michal Vasko1f2cc332015-08-19 11:18:32 +0200595parse_predicate_json(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
596 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597{
598 const char *ptr;
599 int parsed = 0, ret;
600 char quote;
601
602 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200603 if (model) {
604 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200605 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200606 if (mod_len) {
607 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200608 }
609 if (name) {
610 *name = NULL;
611 }
612 if (nam_len) {
613 *nam_len = 0;
614 }
615 if (value) {
616 *value = NULL;
617 }
618 if (val_len) {
619 *val_len = 0;
620 }
621 if (has_predicate) {
622 *has_predicate = 0;
623 }
624
625 if (id[0] != '[') {
626 return -parsed;
627 }
628
629 ++parsed;
630 ++id;
631
632 while (isspace(id[0])) {
633 ++parsed;
634 ++id;
635 }
636
637 /* pos */
638 if (isdigit(id[0])) {
639 if (name) {
640 *name = id;
641 }
642
643 if (id[0] == '0') {
644 ++parsed;
645 ++id;
646
647 if (isdigit(id[0])) {
648 return -parsed;
649 }
650 }
651
652 while (isdigit(id[0])) {
653 ++parsed;
654 ++id;
655 }
656
657 if (nam_len) {
658 *nam_len = id-(*name);
659 }
660
661 /* "." */
662 } else if (id[0] == '.') {
663 if (name) {
664 *name = id;
665 }
666 if (nam_len) {
667 *nam_len = 1;
668 }
669
670 ++parsed;
671 ++id;
672
673 /* node-identifier */
674 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200675 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200677 } else if (model && !*model) {
678 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200679 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680
681 parsed += ret;
682 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 }
684
685 while (isspace(id[0])) {
686 ++parsed;
687 ++id;
688 }
689
690 if (id[0] != '=') {
691 return -parsed;
692 }
693
694 ++parsed;
695 ++id;
696
697 while (isspace(id[0])) {
698 ++parsed;
699 ++id;
700 }
701
702 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
703 if ((id[0] == '\"') || (id[0] == '\'')) {
704 quote = id[0];
705
706 ++parsed;
707 ++id;
708
709 if ((ptr = strchr(id, quote)) == NULL) {
710 return -parsed;
711 }
712 ret = ptr-id;
713
714 if (value) {
715 *value = id;
716 }
717 if (val_len) {
718 *val_len = ret;
719 }
720
721 parsed += ret+1;
722 id += ret+1;
723 } else {
724 return -parsed;
725 }
726
727 while (isspace(id[0])) {
728 ++parsed;
729 ++id;
730 }
731
732 if (id[0] != ']') {
733 return -parsed;
734 }
735
736 ++parsed;
737 ++id;
738
739 if ((id[0] == '[') && has_predicate) {
740 *has_predicate = 1;
741 }
742
743 return parsed;
744}
745
746/**
747 * @brief Parse schema-nodeid.
748 *
749 * schema-nodeid = absolute-schema-nodeid /
750 * descendant-schema-nodeid
751 * absolute-schema-nodeid = 1*("/" node-identifier)
752 * descendant-schema-nodeid =
753 * node-identifier
754 * absolute-schema-nodeid
755 *
756 * @param[in] id Identifier in question.
757 * @param[out] prefix Points to the prefix, NULL if there is not any.
758 * @param[out] pref_len Length of the prefix, 0 if there is not any.
759 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
760 * @param[out] nam_len Length of the node name.
761 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
762 * on the first call, must not be changed between consecutive calls.
763 *
764 * @return Number of characters successfully parsed,
765 * positive on success, negative on failure.
766 */
767static int
768parse_schema_nodeid(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *is_relative)
769{
770 int parsed = 0, ret;
771
772 assert(id);
773 assert(is_relative);
774 if (prefix) {
775 *prefix = NULL;
776 }
777 if (pref_len) {
778 *pref_len = 0;
779 }
780 if (name) {
781 *name = NULL;
782 }
783 if (nam_len) {
784 *nam_len = 0;
785 }
786
787 if (id[0] != '/') {
788 if (*is_relative != -1) {
789 return -parsed;
790 } else {
791 *is_relative = 1;
792 }
793 } else {
794 if (*is_relative == -1) {
795 *is_relative = 0;
796 }
797 ++parsed;
798 ++id;
799 }
800
801 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
802 return -parsed+ret;
803 }
804
805 return parsed+ret;
806}
807
808/**
Michal Vaskoc935fff2015-08-17 14:02:06 +0200809 * @brief Resolve (find) a prefix in a module include import. Does not log.
810 *
811 * @param[in] mod The module with the import.
812 * @param[in] prefix The prefix to find.
813 * @param[in] pref_len The prefix length.
814 *
815 * @return The matching module on success, NULL on error.
816 */
817static struct lys_module *
818resolve_import_in_includes_recursive(struct lys_module *mod, const char *prefix, uint32_t pref_len)
819{
820 int i, j;
821 struct lys_submodule *sub_mod;
822 struct lys_module *ret;
823
824 for (i = 0; i < mod->inc_size; i++) {
825 sub_mod = mod->inc[i].submodule;
826 for (j = 0; j < sub_mod->imp_size; j++) {
827 if ((pref_len == strlen(sub_mod->imp[j].prefix))
828 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
829 return sub_mod->imp[j].module;
830 }
831 }
832 }
833
834 for (i = 0; i < mod->inc_size; i++) {
835 ret = resolve_import_in_includes_recursive((struct lys_module *)mod->inc[i].submodule, prefix, pref_len);
836 if (ret) {
837 return ret;
838 }
839 }
840
841 return NULL;
842}
843
844/**
845 * @brief Resolve (find) a prefix in a module import. Does not log.
846 *
847 * @param[in] mod The module with the import.
848 * @param[in] prefix The prefix to find.
849 * @param[in] pref_len The prefix length.
850 *
851 * @return The matching module on success, NULL on error.
852 */
853static struct lys_module *
854resolve_prefixed_module(struct lys_module *mod, const char *prefix, uint32_t pref_len)
855{
856 int i;
857
858 /* module itself */
859 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
860 return mod;
861 }
862
863 /* imported modules */
864 for (i = 0; i < mod->imp_size; i++) {
865 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
866 return mod->imp[i].module;
867 }
868 }
869
870 /* imports in includes */
871 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
872}
873
874/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200875 * @brief Resolves length or range intervals. Does not log.
876 * Syntax is assumed to be correct, *local_intv MUST be NULL.
877 *
878 * @param[in] str_restr The restriction as a string.
879 * @param[in] type The type of the restriction.
880 * @param[in] superior_restr Flag whether to check superior
881 * types.
882 * @param[out] local_intv The final interval structure.
883 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200884 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200885 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200886int
887resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr, struct len_ran_intv** local_intv)
888{
889 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200890 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200891 int64_t local_smin, local_smax;
892 uint64_t local_umin, local_umax;
893 long double local_fmin, local_fmax;
894 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200895 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200896
897 switch (type->base) {
898 case LY_TYPE_BINARY:
899 kind = 0;
900 local_umin = 0;
901 local_umax = 18446744073709551615UL;
902
903 if (!str_restr && type->info.binary.length) {
904 str_restr = type->info.binary.length->expr;
905 }
906 break;
907 case LY_TYPE_DEC64:
908 kind = 2;
909 local_fmin = -9223372036854775808.0;
910 local_fmin /= 1 << type->info.dec64.dig;
911 local_fmax = 9223372036854775807.0;
912 local_fmax /= 1 << type->info.dec64.dig;
913
914 if (!str_restr && type->info.dec64.range) {
915 str_restr = type->info.dec64.range->expr;
916 }
917 break;
918 case LY_TYPE_INT8:
919 kind = 1;
920 local_smin = -128;
921 local_smax = 127;
922
923 if (!str_restr && type->info.num.range) {
924 str_restr = type->info.num.range->expr;
925 }
926 break;
927 case LY_TYPE_INT16:
928 kind = 1;
929 local_smin = -32768;
930 local_smax = 32767;
931
932 if (!str_restr && type->info.num.range) {
933 str_restr = type->info.num.range->expr;
934 }
935 break;
936 case LY_TYPE_INT32:
937 kind = 1;
938 local_smin = -2147483648;
939 local_smax = 2147483647;
940
941 if (!str_restr && type->info.num.range) {
942 str_restr = type->info.num.range->expr;
943 }
944 break;
945 case LY_TYPE_INT64:
946 kind = 1;
947 local_smin = -9223372036854775807L - 1L;
948 local_smax = 9223372036854775807L;
949
950 if (!str_restr && type->info.num.range) {
951 str_restr = type->info.num.range->expr;
952 }
953 break;
954 case LY_TYPE_UINT8:
955 kind = 0;
956 local_umin = 0;
957 local_umax = 255;
958
959 if (!str_restr && type->info.num.range) {
960 str_restr = type->info.num.range->expr;
961 }
962 break;
963 case LY_TYPE_UINT16:
964 kind = 0;
965 local_umin = 0;
966 local_umax = 65535;
967
968 if (!str_restr && type->info.num.range) {
969 str_restr = type->info.num.range->expr;
970 }
971 break;
972 case LY_TYPE_UINT32:
973 kind = 0;
974 local_umin = 0;
975 local_umax = 4294967295;
976
977 if (!str_restr && type->info.num.range) {
978 str_restr = type->info.num.range->expr;
979 }
980 break;
981 case LY_TYPE_UINT64:
982 kind = 0;
983 local_umin = 0;
984 local_umax = 18446744073709551615UL;
985
986 if (!str_restr && type->info.num.range) {
987 str_restr = type->info.num.range->expr;
988 }
989 break;
990 case LY_TYPE_STRING:
991 kind = 0;
992 local_umin = 0;
993 local_umax = 18446744073709551615UL;
994
995 if (!str_restr && type->info.str.length) {
996 str_restr = type->info.str.length->expr;
997 }
998 break;
999 default:
1000 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001001 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001002 }
1003
1004 /* process superior types */
1005 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001006 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1007 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001008 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001009 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001010 assert(!intv || (intv->kind == kind));
1011 }
1012
1013 if (!str_restr) {
1014 /* we are validating data and not have any restriction, but a superior type might have */
1015 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001016 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1017 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001018 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001019 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001020 assert(!intv || (intv->kind == kind));
1021 }
1022 *local_intv = intv;
1023 return EXIT_SUCCESS;
1024 }
1025
1026 /* adjust local min and max */
1027 if (intv) {
1028 tmp_intv = intv;
1029
1030 if (kind == 0) {
1031 local_umin = tmp_intv->value.uval.min;
1032 } else if (kind == 1) {
1033 local_smin = tmp_intv->value.sval.min;
1034 } else if (kind == 2) {
1035 local_fmin = tmp_intv->value.fval.min;
1036 }
1037
1038 while (tmp_intv->next) {
1039 tmp_intv = tmp_intv->next;
1040 }
1041
1042 if (kind == 0) {
1043 local_umax = tmp_intv->value.uval.max;
1044 } else if (kind == 1) {
1045 local_smax = tmp_intv->value.sval.max;
1046 } else if (kind == 2) {
1047 local_fmax = tmp_intv->value.fval.max;
1048 }
1049 }
1050
1051 /* finally parse our restriction */
1052 seg_ptr = str_restr;
1053 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001054 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001055 *local_intv = malloc(sizeof **local_intv);
1056 tmp_local_intv = *local_intv;
1057 } else {
1058 tmp_local_intv->next = malloc(sizeof **local_intv);
1059 tmp_local_intv = tmp_local_intv->next;
1060 }
1061
1062 tmp_local_intv->kind = kind;
1063 tmp_local_intv->next = NULL;
1064
1065 /* min */
1066 ptr = seg_ptr;
1067 while (isspace(ptr[0])) {
1068 ++ptr;
1069 }
1070 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1071 if (kind == 0) {
1072 tmp_local_intv->value.uval.min = atoll(ptr);
1073 } else if (kind == 1) {
1074 tmp_local_intv->value.sval.min = atoll(ptr);
1075 } else if (kind == 2) {
1076 tmp_local_intv->value.fval.min = atoll(ptr);
1077 }
1078
1079 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1080 ++ptr;
1081 }
1082 while (isdigit(ptr[0])) {
1083 ++ptr;
1084 }
1085 } else if (!strncmp(ptr, "min", 3)) {
1086 if (kind == 0) {
1087 tmp_local_intv->value.uval.min = local_umin;
1088 } else if (kind == 1) {
1089 tmp_local_intv->value.sval.min = local_smin;
1090 } else if (kind == 2) {
1091 tmp_local_intv->value.fval.min = local_fmin;
1092 }
1093
1094 ptr += 3;
1095 } else if (!strncmp(ptr, "max", 3)) {
1096 if (kind == 0) {
1097 tmp_local_intv->value.uval.min = local_umax;
1098 } else if (kind == 1) {
1099 tmp_local_intv->value.sval.min = local_smax;
1100 } else if (kind == 2) {
1101 tmp_local_intv->value.fval.min = local_fmax;
1102 }
1103
1104 ptr += 3;
1105 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001106 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001107 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001108 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001109 }
1110
1111 while (isspace(ptr[0])) {
1112 ptr++;
1113 }
1114
1115 /* no interval or interval */
1116 if ((ptr[0] == '|') || !ptr[0]) {
1117 if (kind == 0) {
1118 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1119 } else if (kind == 1) {
1120 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1121 } else if (kind == 2) {
1122 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1123 }
1124 } else if (!strncmp(ptr, "..", 2)) {
1125 /* skip ".." */
1126 ptr += 2;
1127 while (isspace(ptr[0])) {
1128 ++ptr;
1129 }
1130
1131 /* max */
1132 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1133 if (kind == 0) {
1134 tmp_local_intv->value.uval.max = atoll(ptr);
1135 } else if (kind == 1) {
1136 tmp_local_intv->value.sval.max = atoll(ptr);
1137 } else if (kind == 2) {
1138 tmp_local_intv->value.fval.max = atoll(ptr);
1139 }
1140 } else if (!strncmp(ptr, "max", 3)) {
1141 if (kind == 0) {
1142 tmp_local_intv->value.uval.max = local_umax;
1143 } else if (kind == 1) {
1144 tmp_local_intv->value.sval.max = local_smax;
1145 } else if (kind == 2) {
1146 tmp_local_intv->value.fval.max = local_fmax;
1147 }
1148 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001149 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001150 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001151 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001152 }
1153 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001154 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001155 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001156 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001157 }
1158
1159 /* next segment (next OR) */
1160 seg_ptr = strchr(seg_ptr, '|');
1161 if (!seg_ptr) {
1162 break;
1163 }
1164 seg_ptr++;
1165 }
1166
1167 /* check local restrictions against superior ones */
1168 if (intv) {
1169 tmp_intv = intv;
1170 tmp_local_intv = *local_intv;
1171
1172 while (tmp_local_intv && tmp_intv) {
1173 /* reuse local variables */
1174 if (kind == 0) {
1175 local_umin = tmp_local_intv->value.uval.min;
1176 local_umax = tmp_local_intv->value.uval.max;
1177
1178 /* it must be in this interval */
1179 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1180 /* this interval is covered, next one */
1181 if (local_umax <= tmp_intv->value.uval.max) {
1182 tmp_local_intv = tmp_local_intv->next;
1183 continue;
1184 /* ascending order of restrictions -> fail */
1185 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001186 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001187 goto cleanup;
1188 }
1189 }
1190 } else if (kind == 1) {
1191 local_smin = tmp_local_intv->value.sval.min;
1192 local_smax = tmp_local_intv->value.sval.max;
1193
1194 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1195 if (local_smax <= tmp_intv->value.sval.max) {
1196 tmp_local_intv = tmp_local_intv->next;
1197 continue;
1198 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001199 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001200 goto cleanup;
1201 }
1202 }
1203 } else if (kind == 2) {
1204 local_fmin = tmp_local_intv->value.fval.min;
1205 local_fmax = tmp_local_intv->value.fval.max;
1206
1207 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1208 if (local_fmax <= tmp_intv->value.fval.max) {
1209 tmp_local_intv = tmp_local_intv->next;
1210 continue;
1211 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001212 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001213 goto cleanup;
1214 }
1215 }
1216 }
1217
1218 tmp_intv = tmp_intv->next;
1219 }
1220
1221 /* some interval left uncovered -> fail */
1222 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001223 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001224 }
1225
1226 }
1227
1228cleanup:
1229 while (intv) {
1230 tmp_intv = intv->next;
1231 free(intv);
1232 intv = tmp_intv;
1233 }
1234
1235 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001236 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001237 while (*local_intv) {
1238 tmp_local_intv = (*local_intv)->next;
1239 free(*local_intv);
1240 *local_intv = tmp_local_intv;
1241 }
1242 }
1243
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001244 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001245}
1246
Michal Vasko730dfdf2015-08-11 14:48:05 +02001247/**
1248 * @brief Resolve a typedef. Does not log.
1249 *
1250 * @param[in] name Typedef name.
1251 * @param[in] prefix Typedef name prefix.
1252 * @param[in] module The main module.
1253 * @param[in] parent The parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001254 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001255 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001256 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001257 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001258int
1259resolve_superior_type(const char *name, const char *prefix, struct lys_module *module, struct lys_node *parent,
1260 struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001261{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001262 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001263 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001264 int tpdf_size;
1265
1266 if (!prefix) {
1267 /* no prefix, try built-in types */
1268 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1269 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001270 if (ret) {
1271 *ret = ly_types[i].def;
1272 }
1273 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001274 }
1275 }
1276 } else {
1277 if (!strcmp(prefix, module->prefix)) {
1278 /* prefix refers to the current module, ignore it */
1279 prefix = NULL;
1280 }
1281 }
1282
1283 if (!prefix && parent) {
1284 /* search in local typedefs */
1285 while (parent) {
1286 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001287 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001288 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1289 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001290 break;
1291
Radek Krejci76512572015-08-04 09:47:08 +02001292 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001293 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1294 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001295 break;
1296
Radek Krejci76512572015-08-04 09:47:08 +02001297 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001298 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1299 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001300 break;
1301
Radek Krejci76512572015-08-04 09:47:08 +02001302 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001303 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1304 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001305 break;
1306
Radek Krejci76512572015-08-04 09:47:08 +02001307 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001308 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1309 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001310 break;
1311
Radek Krejci76512572015-08-04 09:47:08 +02001312 case LYS_INPUT:
1313 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001314 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1315 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001316 break;
1317
1318 default:
1319 parent = parent->parent;
1320 continue;
1321 }
1322
1323 for (i = 0; i < tpdf_size; i++) {
1324 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001325 if (ret) {
1326 *ret = &tpdf[i];
1327 }
1328 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001329 }
1330 }
1331
1332 parent = parent->parent;
1333 }
1334 } else if (prefix) {
1335 /* get module where to search */
Michal Vaskoc935fff2015-08-17 14:02:06 +02001336 module = resolve_prefixed_module(module, prefix, strlen(prefix));
1337 if (!module) {
1338 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001339 }
1340 }
1341
1342 /* search in top level typedefs */
1343 for (i = 0; i < module->tpdf_size; i++) {
1344 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001345 if (ret) {
1346 *ret = &module->tpdf[i];
1347 }
1348 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001349 }
1350 }
1351
1352 /* search in submodules */
1353 for (i = 0; i < module->inc_size; i++) {
1354 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1355 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001356 if (ret) {
1357 *ret = &module->inc[i].submodule->tpdf[j];
1358 }
1359 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001360 }
1361 }
1362 }
1363
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001364 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001365}
1366
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02001367/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001368static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001369check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001370{
1371 /* TODO - RFC 6020, sec. 7.3.4 */
1372 (void)type;
1373 (void)value;
1374 return EXIT_SUCCESS;
1375}
1376
Michal Vasko730dfdf2015-08-11 14:48:05 +02001377/**
1378 * @brief Check a key for mandatory attributes. Logs directly.
1379 *
1380 * @param[in] key The key to check.
1381 * @param[in] flags What flags to check.
1382 * @param[in] list The list of all the keys.
1383 * @param[in] index Index of the key in the key list.
1384 * @param[in] name The name of the keys.
1385 * @param[in] len The name length.
1386 * @param[in] line The line in the input file.
1387 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001388 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001389 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001390static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001391check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1392 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001393{
1394 char *dup = NULL;
1395 int j;
1396
1397 /* existence */
1398 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001399 if (name[len] != '\0') {
1400 dup = strdup(name);
1401 dup[len] = '\0';
1402 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001403 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001404 LOGVAL(LYE_KEY_MISS, line, name);
1405 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001406 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001407 }
1408
1409 /* uniqueness */
1410 for (j = index - 1; j >= 0; j--) {
1411 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001412 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001413 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001414 }
1415 }
1416
1417 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001418 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001419 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001420 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001421 }
1422
1423 /* type of the leaf is not built-in empty */
1424 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001425 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001426 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001427 }
1428
1429 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001430 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001431 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001432 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001433 }
1434
1435 return EXIT_SUCCESS;
1436}
1437
Michal Vasko730dfdf2015-08-11 14:48:05 +02001438/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001439 * @brief Resolve (fill) a unique. Logs directly.
1440 *
1441 * @param[in] parent The parent node of the unique structure.
1442 * @param[in] uniq_str The value of the unique node.
1443 * @param[in] uniq_s The unique structure in question.
1444 * @param[in] line The line in the input file.
1445 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001446 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001447 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001448int
Michal Vaskof02e3742015-08-05 16:27:02 +02001449resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001450{
1451 char *uniq_val, *uniq_begin, *start;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001452 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001453
1454 /* count the number of unique values */
1455 uniq_val = uniq_begin = strdup(uniq_str);
1456 uniq_s->leafs_size = 0;
1457 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1458 uniq_s->leafs_size++;
1459 while (isspace(*uniq_val)) {
1460 uniq_val++;
1461 }
1462 }
1463 uniq_s->leafs_size++;
1464 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1465
1466 /* interconnect unique values with the leafs */
1467 uniq_val = uniq_begin;
1468 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1469 start = uniq_val;
1470 if ((uniq_val = strpbrk(start, " \t\n"))) {
1471 *uniq_val = '\0'; /* add terminating NULL byte */
1472 uniq_val++;
1473 while (isspace(*uniq_val)) {
1474 uniq_val++;
1475 }
1476 } /* else only one nodeid present/left already NULL byte terminated */
1477
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001478 rc = resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF,
1479 (struct lys_node **)&uniq_s->leafs[i]);
1480 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001481 LOGVAL(LYE_INARG, line, start, "unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001482 if (rc == EXIT_FAILURE) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001483 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001484 }
1485 goto error;
1486 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001487 if (uniq_s->leafs[i]->nodetype != LYS_LEAF) {
1488 LOGVAL(LYE_INARG, line, start, "unique");
1489 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1490 rc = -1;
1491 goto error;
1492 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001493
1494 for (j = 0; j < i; j++) {
1495 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001496 LOGVAL(LYE_INARG, line, start, "unique");
1497 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001498 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001499 goto error;
1500 }
1501 }
1502 }
1503
1504 free(uniq_begin);
1505 return EXIT_SUCCESS;
1506
1507error:
1508
1509 free(uniq_s->leafs);
1510 free(uniq_begin);
1511
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001512 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001513}
1514
Michal Vasko730dfdf2015-08-11 14:48:05 +02001515/**
1516 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1517 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001518 * @param[in] uses The uses in question.
1519 * @param[in] line The line in the input file.
1520 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001521 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001522 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001523static int
Radek Krejci10c760e2015-08-14 14:45:43 +02001524resolve_grouping(struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001525{
Michal Vasko58090902015-08-13 14:04:15 +02001526 struct lys_module *module = uses->module;
1527 const char *prefix, *name;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001528 int i, pref_len, nam_len, rc;
Radek Krejci10c760e2015-08-14 14:45:43 +02001529 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001530
Michal Vasko58090902015-08-13 14:04:15 +02001531 /* parse the identifier, it must be parsed on one call */
1532 if ((i = parse_node_identifier(uses->name, &prefix, &pref_len, &name, &nam_len)) < 1) {
1533 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001534 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001535 } else if (uses->name[i]) {
1536 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001537 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001538 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001539
Michal Vasko2bdcca92015-08-17 16:00:45 +02001540 if (prefix) {
1541 /* cannot be NULL, since there must at least be this uses */
1542 assert(module->data);
1543 start = module->data;
1544 } else {
Michal Vasko58090902015-08-13 14:04:15 +02001545 /* search in local tree hierarchy */
Radek Krejci10c760e2015-08-14 14:45:43 +02001546 if (!uses->parent) {
1547 start = (struct lys_node *)uses;
1548 while (start->prev->next) {
1549 start = start->prev;
1550 }
1551 } else {
1552 start = uses->parent->child;
1553 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001554 }
1555
1556 while (start) {
1557 rc = resolve_sibling(module, start, prefix, pref_len, name, nam_len, LYS_GROUPING, (struct lys_node **)&uses->grp);
1558 if (rc != EXIT_FAILURE) {
1559 if (rc == -1) {
1560 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko58090902015-08-13 14:04:15 +02001561 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001562 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001563 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001564 start = start->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001565 }
1566
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001567 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001568 return EXIT_FAILURE;
1569}
1570
Michal Vasko730dfdf2015-08-11 14:48:05 +02001571/**
1572 * @brief Resolve (find) a feature definition. Logs directly.
1573 *
1574 * @param[in] name Feature name.
1575 * @param[in] module Module to search in.
1576 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001577 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001578 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001579 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001580 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001581static int
1582resolve_feature(const char *id, struct lys_module *module, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001583{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001584 const char *prefix, *name;
1585 int pref_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001586
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001587 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001588 assert(module);
1589
1590 /* check prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001591 if ((i = parse_node_identifier(id, &prefix, &pref_len, &name, &nam_len)) < 1) {
1592 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1593 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001594 }
1595
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001596 if (prefix) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001597 /* search in imported modules */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001598 module = resolve_prefixed_module(module, prefix, pref_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001599 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001600 /* identity refers unknown data model */
Michal Vaskod9173342015-08-17 14:35:36 +02001601 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001602 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001603 }
1604 } else {
1605 /* search in submodules */
1606 for (i = 0; i < module->inc_size; i++) {
1607 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1608 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001609 if (ret) {
1610 *ret = &(module->inc[i].submodule->features[j]);
1611 }
1612 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001613 }
1614 }
1615 }
1616 }
1617
1618 /* search in the identified module */
1619 for (j = 0; j < module->features_size; j++) {
1620 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001621 if (ret) {
1622 *ret = &module->features[j];
1623 }
1624 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001625 }
1626 }
1627
1628 /* not found */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001629 LOGVAL(LYE_INRESOLV, line, "feature", id);
1630 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001631}
1632
Michal Vasko730dfdf2015-08-11 14:48:05 +02001633/**
Michal Vasko58090902015-08-13 14:04:15 +02001634 * @brief Resolve (find) a valid sibling. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001635 *
Michal Vasko58090902015-08-13 14:04:15 +02001636 * Valid child means a schema pointer to a node that is part of
1637 * the data meaning uses are skipped. Includes module comparison
Michal Vaskobbfcfaa2015-08-17 16:00:19 +02001638 * (can handle augments). Module is adjusted based on the prefix.
1639 * Includes are also searched if siblings are top-level nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001640 *
Michal Vasko58090902015-08-13 14:04:15 +02001641 * @param[in] mod Main module. Prefix is considered to be from this module.
1642 * @param[in] siblings Siblings to consider. They are first adjusted to
1643 * point to the first sibling.
1644 * @param[in] prefix Node prefix.
1645 * @param[in] pref_len Node prefix length.
1646 * @param[in] name Node name.
1647 * @param[in] nam_len Node name length.
1648 * @param[in] type ORed desired type of the node. 0 means any type.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001649 * @param[out] ret Pointer to the node of the desired type. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001650 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001651 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001652 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001653int
Michal Vasko58090902015-08-13 14:04:15 +02001654resolve_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 +02001655 int nam_len, LYS_NODE type, struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001656{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001657 struct lys_node *node, *old_siblings = NULL;
Michal Vasko58090902015-08-13 14:04:15 +02001658 struct lys_module *prefix_mod, *cur_mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001659 int in_submod, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001660
Michal Vasko58090902015-08-13 14:04:15 +02001661 assert(mod && siblings && name);
1662 assert(!(type & LYS_USES));
1663
1664 /* find the beginning */
1665 while (siblings->prev->next) {
1666 siblings = siblings->prev;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001667 }
1668
Michal Vasko58090902015-08-13 14:04:15 +02001669 /* fill the name length in case the caller is so indifferent */
1670 if (!nam_len) {
1671 nam_len = strlen(name);
1672 }
1673
1674 /* we start with the module itself, submodules come later */
1675 in_submod = 0;
1676
1677 /* set prefix_mod correctly */
1678 if (prefix) {
1679 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1680 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001681 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001682 }
1683 cur_mod = prefix_mod;
1684 /* it is our module */
1685 if (cur_mod != mod) {
1686 old_siblings = siblings;
1687 siblings = cur_mod->data;
1688 }
1689 } else {
1690 prefix_mod = mod;
1691 if (prefix_mod->type) {
1692 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1693 }
1694 cur_mod = prefix_mod;
1695 }
1696
1697 while (1) {
1698 /* try to find the node */
1699 LY_TREE_FOR(siblings, node) {
1700 if (node->nodetype == LYS_USES) {
1701 /* an unresolved uses, we can still find it elsewhere */
1702 if (!node->child) {
1703 continue;
1704 }
1705
1706 /* search recursively */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001707 rc = resolve_sibling(mod, node->child, prefix, pref_len, name, nam_len, type, ret);
1708 if (rc != EXIT_FAILURE) {
1709 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001710 }
1711 }
1712
1713 if (!type || (node->nodetype & type)) {
1714 /* module check */
1715 if (!node->module->type) {
1716 if (cur_mod != node->module) {
1717 continue;
1718 }
1719 } else {
1720 if (cur_mod != ((struct lys_submodule *)node->module)->belongsto) {
1721 continue;
1722 }
1723 }
1724
1725 /* direct name check */
1726 if (node->name == name || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001727 if (ret) {
1728 *ret = node;
1729 }
1730 return EXIT_SUCCESS;
Michal Vasko58090902015-08-13 14:04:15 +02001731 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001732 }
1733 }
1734
Michal Vasko58090902015-08-13 14:04:15 +02001735 /* The original siblings may be valid,
1736 * it's a special case when we're looking
1737 * for a node from augment.
1738 */
1739 if (old_siblings) {
1740 siblings = old_siblings;
1741 old_siblings = NULL;
1742 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001743 }
Michal Vasko58090902015-08-13 14:04:15 +02001744
1745 /* we're not top-level, search ended */
1746 if (siblings->parent) {
1747 break;
1748 }
1749
1750 /* let's try the submodules */
1751 if (in_submod == prefix_mod->inc_size) {
1752 break;
1753 }
1754 cur_mod = (struct lys_module *)prefix_mod->inc[in_submod].submodule;
1755 siblings = cur_mod->data;
1756 ++in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001757 }
1758
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001759 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001760}
1761
Michal Vasko730dfdf2015-08-11 14:48:05 +02001762/**
1763 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001764 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001765 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001766 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001767 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001768 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1769 *
1770 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
1771 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001772 *
1773 * @param[in] id Schema-nodeid string.
1774 * @param[in] start Start of the relative search.
1775 * @param[in] mod Module in question.
1776 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001777 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001778 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001779 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001780 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001781int
1782resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1783 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001784{
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001785 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +02001786 struct lys_node *sibling;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001787 int i, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +02001788 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001789 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1790 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001791 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001792 uint8_t in_mod_part = 0;
1793
1794 assert(mod);
1795 assert(id);
1796
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001797 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1798 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001799 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001800 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001801
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001802 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001803 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001804 }
1805
1806 /* absolute-schema-nodeid */
1807 if (!is_relative) {
1808 if (prefix) {
1809 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
1810 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001811 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001812 }
1813 start = start_mod->data;
1814 } else {
1815 start = mod->data;
1816 start_mod = mod;
1817 }
1818 /* descendant-schema-nodeid */
1819 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001820 if (start) {
1821 start_mod = start->module;
1822 } else {
1823 start_mod = mod;
1824 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001825 }
1826
1827 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001828 sibling = NULL;
1829 LY_TREE_FOR(start, sibling) {
1830 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001831 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
1832 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001833 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001834 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001835
Michal Vasko1e989c02015-08-04 12:33:00 +02001836 /* prefix match check */
1837 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001838 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1839 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001840 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001841 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001842 } else {
1843 prefix_mod = mod;
1844 if (prefix_mod->type) {
1845 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1846 }
1847 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001848
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001849 /* modules need to always be checked, we want to skip augments */
1850 if (!sibling->module->type) {
1851 if (prefix_mod != sibling->module) {
1852 continue;
1853 }
1854 } else {
1855 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1856 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001857 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001858 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001859
Michal Vasko1e989c02015-08-04 12:33:00 +02001860 /* the result node? */
1861 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001862 /* we're looking only for groupings, this is a data node */
1863 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1864 continue;
1865 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001866 if (ret) {
1867 *ret = sibling;
1868 }
1869 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001870 }
1871
Michal Vaskodcc7a802015-08-06 11:59:47 +02001872 /* we're looking for a grouping (node_type == LYS_USES),
1873 * but this isn't it, we cannot search inside
1874 */
1875 if (sibling->nodetype == LYS_GROUPING) {
1876 continue;
1877 }
1878
Michal Vasko1e989c02015-08-04 12:33:00 +02001879 /* check for shorthand cases - then 'start' does not change */
1880 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1881 || (sibling->nodetype == LYS_CASE)) {
1882 start = sibling->child;
1883 }
1884 break;
1885 }
1886 }
1887
1888 /* we did not find the case in direct siblings */
1889 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001890 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001891 }
1892
1893 /* no match */
1894 if (!sibling) {
1895 /* on augment search also RPCs and notifications, if we are in top-level */
1896 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1897 /* we have searched all the data nodes */
1898 if (in_mod_part == 0) {
1899 if (!in_submod) {
1900 start = start_mod->rpc;
1901 } else {
1902 start = start_mod->inc[in_submod-1].submodule->rpc;
1903 }
1904 in_mod_part = 1;
1905 continue;
1906 }
1907 /* we have searched all the RPCs */
1908 if (in_mod_part == 1) {
1909 if (!in_submod) {
1910 start = start_mod->notif;
1911 } else {
1912 start = start_mod->inc[in_submod-1].submodule->notif;
1913 }
1914 in_mod_part = 2;
1915 continue;
1916 }
1917 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001918 }
1919
Michal Vasko1e989c02015-08-04 12:33:00 +02001920 /* are we done with the included submodules as well? */
1921 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001922 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001923 }
1924
Michal Vasko1e989c02015-08-04 12:33:00 +02001925 /* we aren't, check the next one */
1926 ++in_submod;
1927 in_mod_part = 0;
1928 start = start_mod->inc[in_submod-1].submodule->data;
1929 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001930 }
1931
1932 /* we found our submodule */
1933 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001934 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001935 in_submod = 0;
1936 }
1937
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001938 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1939 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001940 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001941 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001942 }
1943
1944 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001945 LOGINT;
1946 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001947}
1948
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001949/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001950static int
Radek Krejcic5090c32015-08-12 09:46:19 +02001951resolve_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 +02001952{
Radek Krejcic5090c32015-08-12 09:46:19 +02001953 struct unres_data *item, *par_iter, *prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001954 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001955 int flag;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001956
1957 if (!*parents) {
1958 *parents = malloc(sizeof **parents);
1959 (*parents)->dnode = NULL;
1960 (*parents)->next = NULL;
1961 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001962 for (par_iter = *parents; par_iter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02001963 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001964 /* skip */
1965 continue;
1966 }
1967 flag = 0;
Radek Krejcic5090c32015-08-12 09:46:19 +02001968 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001969 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1970 && node->schema->name[nam_len] == '\0') {
1971 /* matching target */
1972 if (!flag) {
1973 /* replace leafref instead of the current parent */
1974 par_iter->dnode = node;
1975 flag = 1;
1976 } else {
1977 /* multiple matching, so create new leafref structure */
1978 item = malloc(sizeof *item);
1979 item->dnode = node;
1980 item->next = par_iter->next;
1981 par_iter->next = item;
1982 par_iter = par_iter->next;
1983 }
1984 }
1985 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001986
1987 if (!flag) {
1988 /* remove item from the parents list */
1989 if (prev) {
1990 prev->next = par_iter->next;
1991 free(par_iter);
1992 par_iter = prev->next;
1993 } else {
1994 item = par_iter->next;
1995 free(par_iter);
1996 par_iter = *parents = item;
1997 }
1998 } else {
1999 prev = par_iter;
2000 par_iter = par_iter->next;
2001 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002002 }
2003
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002004 return *parents ? EXIT_SUCCESS : -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002005}
2006
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002007/**
2008 * @brief Resolve (find) a data node. Does not log.
2009 *
2010 * @param[in] prefix Prefix of the data node.
2011 * @param[in] pref_len Length of the prefix.
2012 * @param[in] name Name of the data node.
2013 * @param[in] nam_len Length of the name.
2014 * @param[in] start Data node to start the search from.
2015 * @param[in,out] parents Resolved nodes. If there are some parents,
2016 * they are replaced (!!) with the resolvents.
2017 *
2018 * @return EXIT_SUCCESS on success, -1 otherwise.
2019 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002020static int
2021resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int name_len, struct lyd_node *start,
2022 struct unres_data **parents)
2023{
2024 struct lys_module *mod;
2025
2026 if (prefix) {
2027 /* we have prefix, find appropriate module */
2028 mod = resolve_prefixed_module(start->schema->module, prefix, pref_len);
2029 if (!mod) {
2030 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002031 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002032 }
2033 } else {
2034 /* no prefix, module is the same as of current node */
2035 mod = start->schema->module;
2036 }
2037
2038 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002039}
2040
Michal Vasko730dfdf2015-08-11 14:48:05 +02002041/**
Michal Vaskod9173342015-08-17 14:35:36 +02002042 * @brief Resolve a path predicate (leafref) in data context. Logs directly
2043 * only specific errors, general no-resolvent error is left to the caller,
2044 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002045 *
2046 * @param[in] pred Predicate in question.
2047 * @param[in,out] node_match Nodes satisfying the restriction
2048 * without the predicate. Nodes not
2049 * satisfying the predicate are removed.
2050 * @param[in] line Line in the input file.
2051 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002052 * @return Number of characters successfully parsed,
2053 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002054 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002055static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002056resolve_path_predicate_data(const char *pred, struct unres_data **node_match, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002057{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002058 /* ... /node[source = destination] ... */
Michal Vaskof02e3742015-08-05 16:27:02 +02002059 struct unres_data *source_match, *dest_match, *node, *node_prev = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002060 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2061 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2062 int has_predicate, dest_parent_times, i;
2063
2064 do {
2065 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2066 &pke_len, &has_predicate)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002067 LOGVAL(LYE_INCHAR, line, pred[-i], pred-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002068 return -parsed+i;
2069 }
2070 parsed += i;
2071 pred += i;
2072
2073 for (node = *node_match; node;) {
2074 /* source */
2075 source_match = NULL;
2076 /* must be leaf (key of a list) */
2077 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
2078 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +02002079 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002080 LOGVAL(LYE_LINE, line);
2081 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002082 return -parsed;
2083 }
2084
2085 /* destination */
2086 dest_match = calloc(1, sizeof *dest_match);
2087 dest_match->dnode = node->dnode;
2088 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2089 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002090 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002091 return -parsed+i;
2092 }
2093 pke_parsed += i;
2094 for (i = 0; i < dest_parent_times; ++i) {
2095 dest_match->dnode = dest_match->dnode->parent;
2096 if (!dest_match->dnode) {
2097 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002098 LOGVAL(LYE_LINE, line);
2099 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002100 return -parsed;
2101 }
2102 }
2103 while (1) {
2104 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
Michal Vasko1f76a282015-08-04 16:16:53 +02002105 || !dest_match->dnode || dest_match->next) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002106 free(dest_match);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002107 LOGVAL(LYE_LINE, line);
2108 /* general error, the one written later will suffice */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002109 return -parsed;
2110 }
2111
2112 if (pke_len == pke_parsed) {
2113 break;
2114 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002115 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 +02002116 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002117 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002118 return -parsed+i;
2119 }
2120 pke_parsed += i;
2121 }
2122
2123 /* check match between source and destination nodes */
Radek Krejcib8048692015-08-05 13:36:34 +02002124 if (((struct lys_node_leaf *)source_match->dnode->schema)->type.base
2125 != ((struct lys_node_leaf *)dest_match->dnode->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002126 goto remove_leafref;
2127 }
2128
2129 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
2130 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
2131 goto remove_leafref;
2132 }
2133
2134 /* leafref is ok, continue check with next leafref */
2135 node_prev = node;
2136 node = node->next;
2137 continue;
2138
2139remove_leafref:
2140 /* does not fulfill conditions, remove leafref record */
2141 if (node_prev) {
2142 node_prev->next = node->next;
2143 free(node);
2144 node = node_prev->next;
2145 } else {
2146 node = (*node_match)->next;
2147 free(*node_match);
2148 *node_match = node;
2149 }
2150 }
2151 } while (has_predicate);
2152
2153 return parsed;
2154}
2155
Michal Vasko730dfdf2015-08-11 14:48:05 +02002156/**
2157 * @brief Resolve a path (leafref) in data context. Logs directly.
2158 *
2159 * @param[in] unres Nodes matching the schema path.
2160 * @param[in] path Path in question.
2161 * @param[in,out] ret Matching nodes.
2162 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002163 * @return EXIT_SUCCESS on success, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002164 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002165int
Michal Vaskof02e3742015-08-05 16:27:02 +02002166resolve_path_arg_data(struct unres_data *unres, const char *path, struct unres_data **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002167{
Radek Krejci71b795b2015-08-10 16:20:39 +02002168 struct lyd_node *data = NULL;
Michal Vaskof02e3742015-08-05 16:27:02 +02002169 struct unres_data *riter = NULL, *raux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002170 const char *prefix, *name;
Michal Vaskod9173342015-08-17 14:35:36 +02002171 int pref_len, nam_len, has_predicate, parent_times, i, parsed;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002172
2173 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002174 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002175 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002176
2177 /* searching for nodeset */
2178 do {
2179 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002180 LOGVAL(LYE_INCHAR, LOGLINE(unres), path[-i], path-i);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002181 goto error;
2182 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002183 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002184 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002185
2186 if (!*ret) {
2187 *ret = calloc(1, sizeof **ret);
2188 for (i = 0; i < parent_times; ++i) {
2189 /* relative path */
2190 if (!*ret) {
2191 /* error, too many .. */
Michal Vaskoc07187d2015-08-13 15:20:57 +02002192 LOGVAL(LYE_INVAL, LOGLINE(unres), path, unres->dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002193 goto error;
2194 } else if (!(*ret)->dnode) {
2195 /* first .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002196 data = (*ret)->dnode = unres->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002197 } else if (!(*ret)->dnode->parent) {
2198 /* we are in root */
2199 free(*ret);
2200 *ret = NULL;
2201 } else {
2202 /* multiple .. */
Radek Krejci71b795b2015-08-10 16:20:39 +02002203 data = (*ret)->dnode = (*ret)->dnode->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002204 }
2205 }
2206
2207 /* absolute path */
2208 if (parent_times == -1) {
2209 for (data = unres->dnode; data->parent; data = data->parent);
2210 for (; data->prev->next; data = data->prev);
2211 }
2212 }
2213
2214 /* node identifier */
2215 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vaskoc07187d2015-08-13 15:20:57 +02002216 LOGVAL(LYE_INELEM_LEN, LOGLINE(unres), nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002217 goto error;
2218 }
2219
2220 if (has_predicate) {
2221 /* we have predicate, so the current results must be lists */
2222 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002223 if (riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002224 ((struct lys_node_list *)riter->dnode->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002225 /* leafref is ok, continue check with next leafref */
2226 raux = riter;
2227 riter = riter->next;
2228 continue;
2229 }
2230
2231 /* does not fulfill conditions, remove leafref record */
2232 if (raux) {
2233 raux->next = riter->next;
2234 free(riter);
2235 riter = raux->next;
2236 } else {
2237 *ret = riter->next;
2238 free(riter);
2239 riter = *ret;
2240 }
2241 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02002242 if ((i = resolve_path_predicate_data(path, ret, LOGLINE(unres))) < 1) {
Michal Vaskod9173342015-08-17 14:35:36 +02002243 /* line was already displayed */
2244 LOGVAL(LYE_NORESOLV, 0, path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002245 goto error;
2246 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002247 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002248 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002249
2250 if (!*ret) {
Michal Vaskod9173342015-08-17 14:35:36 +02002251 LOGVAL(LYE_NORESOLV, LOGLINE(unres), path-parsed);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002252 goto error;
2253 }
2254 }
2255 } while (path[0] != '\0');
2256
Michal Vaskof02e3742015-08-05 16:27:02 +02002257 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002258
2259error:
2260
2261 while (*ret) {
2262 raux = (*ret)->next;
2263 free(*ret);
2264 *ret = raux;
2265 }
2266
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002267 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002268}
2269
Michal Vasko730dfdf2015-08-11 14:48:05 +02002270/**
2271 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2272 *
2273 * @param[in] path Path in question.
2274 * @param[in] mod Schema module.
2275 * @param[in] source_node Left operand node.
2276 * @param[in] dest_node Right ooperand node.
2277 * @param[in] line Line in the input file.
2278 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002279 * @return Number of characters successfully parsed,
2280 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002281 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002282static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002283resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002284 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002285{
2286 struct lys_node *src_node, *dst_node;
2287 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2288 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 +02002289 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002290
2291 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002292 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002293 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002294 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002295 return -parsed+i;
2296 }
2297 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002298 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002299
Michal Vasko58090902015-08-13 14:04:15 +02002300 /* source (must be leaf) */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002301 rc = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
2302 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002303 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002304 return -parsed;
2305 }
2306
2307 /* destination */
2308 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2309 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002310 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002311 return -parsed;
2312 }
2313 pke_parsed += i;
2314
2315 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2316 dst_node = dest_node;
2317 for (i = 1; i < dest_parent_times; ++i) {
2318 dst_node = dst_node->parent;
2319 if (!dst_node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002320 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002321 return -parsed;
2322 }
2323 }
2324 while (1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002325 rc = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2326 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2327 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002328 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002329 return -parsed;
2330 }
2331
2332 if (pke_len == pke_parsed) {
2333 break;
2334 }
2335
2336 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2337 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002338 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002339 return -parsed;
2340 }
2341 pke_parsed += i;
2342 }
2343
2344 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002345 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2346 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskod9173342015-08-17 14:35:36 +02002347 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002348 return -parsed;
2349 }
2350 } while (has_predicate);
2351
2352 return parsed;
2353}
2354
Michal Vasko730dfdf2015-08-11 14:48:05 +02002355/**
Michal Vaskod9173342015-08-17 14:35:36 +02002356 * @brief Resolve a path (leafref) in schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002357 *
2358 * @param[in] mod Module in question.
2359 * @param[in] path Path in question.
2360 * @param[in] parent_node Parent of the leafref.
2361 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002362 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002363 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002364 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002365 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002366static int
2367resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line,
2368 struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002369{
Michal Vasko58090902015-08-13 14:04:15 +02002370 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002371 const char *id, *prefix, *name;
2372 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002373 int i, first, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002374
2375 first = 1;
2376 parent_times = 0;
2377 id = path;
2378
2379 do {
2380 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002381 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002382 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002383 }
2384 id += i;
2385
2386 if (first) {
2387 if (parent_times == -1) {
2388 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002389 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002390 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002391 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002392 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002393 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002394 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002395 node = parent_node;
2396 i = 0;
2397 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002398 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002399 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002400 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002401 }
Michal Vasko58090902015-08-13 14:04:15 +02002402
2403 /* this node is a wrong node, we actually need the augment target */
2404 if (node->nodetype == LYS_AUGMENT) {
2405 node = ((struct lys_node_augment *)node)->target;
2406 if (!node) {
2407 continue;
2408 }
2409 }
2410
2411 ++i;
2412 if (i == parent_times) {
2413 break;
2414 }
2415 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002416 }
2417 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002418 } else {
2419 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002420 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002421 }
2422 first = 0;
2423 } else {
2424 node = node->child;
2425 }
2426
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002427 rc = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES), &node);
2428 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002429 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002430 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002431 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002432
2433 if (has_predicate) {
2434 /* we have predicate, so the current result must be list */
2435 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002436 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002437 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002438 }
2439
2440 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002441 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002442 }
2443 id += i;
2444 }
2445 } while (id[0]);
2446
Radek Krejcib1c12512015-08-11 11:22:04 +02002447 /* the target must be leaf or leaf-list */
2448 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002449 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002450 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002451 }
2452
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002453 if (ret) {
2454 *ret = node;
2455 }
2456 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002457}
2458
Michal Vasko730dfdf2015-08-11 14:48:05 +02002459/**
2460 * @brief Resolve instance-identifier predicate. Does not log.
2461 *
2462 * @param[in] pred Predicate in question.
2463 * @param[in,out] node_match Nodes matching the restriction without
2464 * the predicate. Nodes not satisfying
2465 * the predicate are removed.
2466 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002467 * @return Number of characters successfully parsed,
2468 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002469 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002470static int
Michal Vasko1f2cc332015-08-19 11:18:32 +02002471resolve_predicate_json(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002472{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002473 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002474 struct unres_data target_match;
2475 struct ly_ctx *ctx;
2476 struct lys_module *mod;
2477 const char *model, *name, *value;
2478 char *str;
2479 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2480 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002481
Michal Vasko1f2cc332015-08-19 11:18:32 +02002482 assert(pred && node_match->count);
2483
2484 ctx = node_match->dnode[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002485 idx = -1;
2486 parsed = 0;
2487
2488 do {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002489 if ((i = parse_predicate_json(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002490 return -parsed+i;
2491 }
2492 parsed += i;
2493 pred += i;
2494
Michal Vasko1f2cc332015-08-19 11:18:32 +02002495 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002496 if (isdigit(name[0])) {
2497 idx = atoi(name);
2498 }
2499
Michal Vasko1f2cc332015-08-19 11:18:32 +02002500 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002501 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002502 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002503 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002504 target_match.count = 1;
2505 target_match.dnode = malloc(sizeof *target_match.dnode);
2506 target_match.dnode[0] = node_match->dnode[j];
2507 } else {
2508 str = strndup(model, mod_len);
2509 mod = ly_ctx_get_module(ctx, str, NULL);
2510 free(str);
2511
2512 if (resolve_data(mod, name, nam_len, node_match->dnode[j], &target_match)) {
2513 goto remove_instid;
2514 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002515 }
2516
2517 /* check that we have the correct type */
2518 if (name[0] == '.') {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002519 if (node_match->dnode[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002520 goto remove_instid;
2521 }
2522 } else if (value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002523 if (node_match->dnode[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002524 goto remove_instid;
2525 }
2526 }
2527
Michal Vasko1f2cc332015-08-19 11:18:32 +02002528 if ((value && (strncmp(((struct lyd_node_leaf *)target_match.dnode[0])->value_str, value, val_len)
2529 || ((struct lyd_node_leaf *)target_match.dnode[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002530 || (!value && (idx != cur_idx))) {
2531 goto remove_instid;
2532 }
2533
Michal Vasko1f2cc332015-08-19 11:18:32 +02002534 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002535
2536 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002537 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002538 continue;
2539
2540remove_instid:
Michal Vasko1f2cc332015-08-19 11:18:32 +02002541 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002542
2543 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002544 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002545 }
2546 } while (has_predicate);
2547
2548 return parsed;
2549}
2550
Michal Vasko730dfdf2015-08-11 14:48:05 +02002551/**
2552 * @brief Resolve instance-identifier. Logs directly.
2553 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002554 * @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 +02002555 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002556 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002557 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002558 * @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 +02002559 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002560struct lyd_node *
Michal Vasko1f2cc332015-08-19 11:18:32 +02002561resolve_instid_json(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002562{
Radek Krejcic5090c32015-08-12 09:46:19 +02002563 int i = 0, j;
2564 struct lyd_node *result = NULL;
2565 struct lys_module *mod = NULL;
2566 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002567 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002568 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002569 int mod_len, name_len, has_predicate;
2570 struct unres_data node_match;
2571 uint32_t k;
2572
2573 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002574
Radek Krejcic5090c32015-08-12 09:46:19 +02002575 /* we need root to resolve absolute path */
2576 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002577 for (; data->prev->next; data = data->prev);
2578
Radek Krejcic5090c32015-08-12 09:46:19 +02002579 /* search for the instance node */
2580 while (path[i]) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002581 j = parse_instance_identifier_json(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002582 if (j <= 0) {
2583 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002584 goto error;
2585 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002586 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002587
Michal Vasko1f2cc332015-08-19 11:18:32 +02002588 str = strndup(model, mod_len);
2589 mod = ly_ctx_get_module(ctx, str, NULL);
2590 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002591
Radek Krejcic5090c32015-08-12 09:46:19 +02002592 if (!mod) {
2593 /* no instance exists */
2594 return NULL;
2595 }
2596
Michal Vasko1f2cc332015-08-19 11:18:32 +02002597 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002598 /* no instance exists */
2599 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002600 }
2601
2602 if (has_predicate) {
2603 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcic5090c32015-08-12 09:46:19 +02002604 for (raux = NULL, riter = workingnodes; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +02002605 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Radek Krejcib8048692015-08-05 13:36:34 +02002606 ((struct lys_node_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +02002607 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002608 /* instid is ok, continue check with next instid */
2609 raux = riter;
2610 riter = riter->next;
2611 continue;
2612 }
2613
2614 /* does not fulfill conditions, remove inst record */
2615 if (raux) {
2616 raux->next = riter->next;
2617 free(riter);
2618 riter = raux->next;
2619 } else {
Radek Krejcic5090c32015-08-12 09:46:19 +02002620 workingnodes = riter->next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621 free(riter);
Radek Krejcic5090c32015-08-12 09:46:19 +02002622 riter = workingnodes;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002623 }
2624 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002625
Michal Vasko1f2cc332015-08-19 11:18:32 +02002626 j = resolve_predicate_json(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002627 if (j < 1) {
2628 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002629 goto error;
2630 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002631 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002632
Michal Vasko1f2cc332015-08-19 11:18:32 +02002633 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002634 /* no instance exists */
2635 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002636 }
2637 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002638 }
2639
Michal Vasko1f2cc332015-08-19 11:18:32 +02002640 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002641 /* no instance exists */
2642 return NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002643 } else if (node_match->next) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002644 /* instance identifier must resolve to a single node */
2645 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2646
2647 /* cleanup */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002648 while(node_match) {
2649 raux = nodes_match->next;
2650 free(node_match);
2651 node_match = raux;
Radek Krejcic5090c32015-08-12 09:46:19 +02002652 }
2653
2654 return NULL;
2655 } else {
2656 /* we have required result, remember it and cleanup */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002657 result = node_match->dnode;
2658 free(node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002659
2660 return result;
2661 }
2662
2663error:
2664
2665 /* cleanup */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002666 while (node_match) {
2667 raux = node_match->next;
2668 free(node_match);
2669 node_match = raux;
Radek Krejcic5090c32015-08-12 09:46:19 +02002670 }
2671
2672 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002673}
2674
Michal Vasko730dfdf2015-08-11 14:48:05 +02002675/**
2676 * @brief Passes config flag down to children. Does not log.
2677 *
2678 * @param[in] node Parent node.
2679 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002680static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002681inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002682{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002683 LY_TREE_FOR(node, node) {
2684 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2685 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002686 }
2687}
2688
Michal Vasko730dfdf2015-08-11 14:48:05 +02002689/**
Michal Vaskod9173342015-08-17 14:35:36 +02002690 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002691 *
2692 * @param[in] aug Augment in question.
2693 * @param[in] siblings Nodes where to start the search in.
2694 * @param[in] module Main module.
2695 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002696 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002697 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002698int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002699resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002700{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002701 int rc;
Radek Krejci76512572015-08-04 09:47:08 +02002702 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002703
2704 assert(module);
2705
2706 /* resolve target node */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002707 rc = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT, &aug->target);
2708 if (rc) {
2709 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002710 }
2711
2712 if (!aug->child) {
2713 /* nothing to do */
2714 return EXIT_SUCCESS;
2715 }
2716
2717 /* inherit config information from parent, augment does not have
2718 * config property, but we need to keep the information for subelements
2719 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002720 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002721 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002722 inherit_config_flag(sub);
2723 }
2724
Radek Krejci07911992015-08-14 15:13:31 +02002725 /* check identifier uniquness as in lys_node_addchild() */
2726 LY_TREE_FOR(aug->child, aux) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002727 if (lys_check_id(aux, aug->parent, module)) {
2728 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002729 }
2730 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002731 /* reconnect augmenting data into the target - add them to the target child list */
2732 if (aug->target->child) {
2733 aux = aug->target->child->prev; /* remember current target's last node */
2734 aux->next = aug->child; /* connect augmenting data after target's last node */
2735 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2736 aug->child->prev = aux; /* finish connecting of both child lists */
2737 } else {
2738 aug->target->child = aug->child;
2739 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002740
2741 return EXIT_SUCCESS;
2742}
2743
Michal Vasko730dfdf2015-08-11 14:48:05 +02002744/**
2745 * @brief Resolve uses, apply augments, refines. Logs directly.
2746 *
2747 * @param[in] uses Uses in question.
2748 * @param[in,out] unres List of unresolved items.
2749 * @param[in] line Line in the input file.
2750 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002751 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward ereference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002752 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002753int
Michal Vaskof02e3742015-08-05 16:27:02 +02002754resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002755{
2756 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002757 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002758 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002759 struct lys_restr *newmust;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002760 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002761 uint8_t size;
2762
Michal Vasko71e1aa82015-08-12 12:17:51 +02002763 assert(uses->grp);
2764
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002765 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002766 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002767 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002768 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002769 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002770 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002772 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002773 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002774 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002775 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002776 }
2777 }
2778 ctx = uses->module->ctx;
2779
2780 /* apply refines */
2781 for (i = 0; i < uses->refine_size; i++) {
2782 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002783 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2784 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002785 if (rc == -1) {
2786 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2787 } else {
2788 LOGVAL(LYE_NORESOLV, line, rfn->target_name);
2789 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002790 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002791 }
2792
Radek Krejci1d82ef62015-08-07 14:44:40 +02002793 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002794 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002795 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 }
2797
2798 /* description on any nodetype */
2799 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002800 lydict_remove(ctx, node->dsc);
2801 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802 }
2803
2804 /* reference on any nodetype */
2805 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002806 lydict_remove(ctx, node->ref);
2807 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 }
2809
2810 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002811 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002812 node->flags &= ~LYS_CONFIG_MASK;
2813 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002814 }
2815
2816 /* default value ... */
2817 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002818 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002819 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002820 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2821 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2822 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002824 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2825 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002826 if (rc == -1) {
2827 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2828 } else {
2829 LOGVAL(LYE_NORESOLV, line, rfn->mod.dflt);
2830 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002831 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002832 }
2833 }
2834 }
2835
2836 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002837 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002838 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002839 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002840 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841
2842 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002843 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 }
2845 }
2846
2847 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002848 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2849 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2850 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851 }
2852
2853 /* min/max-elements on list or leaf-list */
2854 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002855 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002857 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002858 }
2859 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002860 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002862 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002864 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 }
2866 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002867 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002868 }
2869 }
2870
2871 /* must in leaf, leaf-list, list, container or anyxml */
2872 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002873 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2874 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 if (!newmust) {
2876 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002877 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002879 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2881 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2882 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2883 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2884 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2885 }
2886
Radek Krejci1d82ef62015-08-07 14:44:40 +02002887 ((struct lys_node_leaf *)node)->must = newmust;
2888 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 }
2890 }
2891
2892 /* apply augments */
2893 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002894 rc = resolve_augment(&uses->augment[i], uses->child, uses->module);
2895 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002896 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002897 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 }
2899 }
2900
2901 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002902}
2903
Michal Vasko730dfdf2015-08-11 14:48:05 +02002904/**
2905 * @brief Resolve base identity recursively. Does not log.
2906 *
2907 * @param[in] module Main module.
2908 * @param[in] ident Identity in question.
2909 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002910 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002911 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002912 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002913 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002914static int
2915resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2916 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917{
Michal Vaskof02e3742015-08-05 16:27:02 +02002918 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002919 struct lys_ident *base_iter = NULL;
2920 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002921
2922 /* search module */
2923 for (i = 0; i < module->ident_size; i++) {
2924 if (!strcmp(basename, module->ident[i].name)) {
2925
2926 if (!ident) {
2927 /* just search for type, so do not modify anything, just return
2928 * the base identity pointer
2929 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002930 if (ret) {
2931 *ret = &module->ident[i];
2932 }
2933 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002934 }
2935
2936 /* we are resolving identity definition, so now update structures */
2937 ident->base = base_iter = &module->ident[i];
2938
2939 break;
2940 }
2941 }
2942
2943 /* search submodules */
2944 if (!base_iter) {
2945 for (j = 0; j < module->inc_size; j++) {
2946 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2947 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2948
2949 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002950 if (ret) {
2951 *ret = &module->inc[j].submodule->ident[i];
2952 }
2953 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002954 }
2955
2956 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2957 break;
2958 }
2959 }
2960 }
2961 }
2962
2963 /* we found it somewhere */
2964 if (base_iter) {
2965 while (base_iter) {
2966 for (der = base_iter->der; der && der->next; der = der->next);
2967 if (der) {
2968 der->next = malloc(sizeof *der);
2969 der = der->next;
2970 } else {
2971 ident->base->der = der = malloc(sizeof *der);
2972 }
2973 der->next = NULL;
2974 der->ident = ident;
2975
2976 base_iter = base_iter->base;
2977 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002978 if (ret) {
2979 *ret = ident->base;
2980 }
2981 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002982 }
2983
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002984 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002985}
2986
Michal Vasko730dfdf2015-08-11 14:48:05 +02002987/**
2988 * @brief Resolve base identity. Logs directly.
2989 *
2990 * @param[in] module Main module.
2991 * @param[in] ident Identity in question.
2992 * @param[in] basename Base name of the identity.
2993 * @param[in] parent Either "type" or "ident".
2994 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002995 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002996 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002997 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002998 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002999static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003000resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003001 uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003002{
3003 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02003004 int i, prefix_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003005
3006 /* search for the base identity */
3007 name = strchr(basename, ':');
3008 if (name) {
3009 /* set name to correct position after colon */
3010 prefix_len = name - basename;
3011 name++;
3012
3013 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3014 /* prefix refers to the current module, ignore it */
3015 prefix_len = 0;
3016 }
3017 } else {
3018 name = basename;
3019 }
3020
3021 if (prefix_len) {
3022 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003023 module = resolve_prefixed_module(module, basename, prefix_len);
3024 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003025 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003026 LOGVAL(LYE_INPREF, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003027 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003028 }
3029 } else {
3030 /* search in submodules */
3031 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003032 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3033 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003034 }
3035 }
3036 }
3037
3038 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003039 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3040 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003041 }
3042
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003043 LOGVAL(LYE_INARG, line, basename, parent);
3044 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003045}
3046
Michal Vasko730dfdf2015-08-11 14:48:05 +02003047/**
3048 * @brief Resolve identityref. Does not log.
3049 *
3050 * @param[in] base Base identity.
3051 * @param[in] name Identityref name.
3052 * @param[in] ns Namespace of the identityref.
3053 *
3054 * @return Pointer to the identity resolvent, NULL on error.
3055 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003056struct lys_ident *
3057resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003058{
Radek Krejcia52656e2015-08-05 13:41:50 +02003059 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003060
3061 if (!base || !name || !ns) {
3062 return NULL;
3063 }
3064
3065 for(der = base->der; der; der = der->next) {
3066 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3067 /* we have match */
3068 return der->ident;
3069 }
3070 }
3071
3072 /* not found */
3073 return NULL;
3074}
3075
Michal Vasko730dfdf2015-08-11 14:48:05 +02003076/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02003077 * @brief Resolve unres uses. Logs directly.
3078 *
3079 * @param[in] uses Uses in question.
3080 * @param[in] unres Specific unres item.
3081 * @param[in] line Line in the input file.
3082 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003083 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003084 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003086resolve_unres_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003088 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003089 struct lys_node *parent;
3090
3091 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3092 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3093
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003094 if (!uses->grp) {
3095 rc = resolve_grouping(uses, line);
3096 if (rc) {
3097 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003098 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003099 }
3100
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003101 if (uses->grp->nacm) {
3102 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3103 return EXIT_FAILURE;
3104 }
3105
3106 rc = resolve_uses(uses, unres, line);
3107 if (!rc) {
3108 /* decrease unres count only if not first try */
3109 if ((line < UINT_MAX) && parent) {
3110 if (!parent->nacm) {
3111 LOGINT;
3112 return -1;
3113 }
3114 --parent->nacm;
3115 }
3116 return EXIT_SUCCESS;
3117 }
3118
3119 if ((rc == EXIT_FAILURE) && parent) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003120 ++parent->nacm;
3121 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003122 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003123}
3124
Michal Vasko730dfdf2015-08-11 14:48:05 +02003125/**
Michal Vasko9957e592015-08-17 15:04:09 +02003126 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003127 *
3128 * @param[in] list List in question.
3129 * @param[in] keys_str Keys node value.
3130 * @param[in] line Line in the input file.
3131 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003132 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003133 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003134static int
Michal Vasko9957e592015-08-17 15:04:09 +02003135resolve_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 +02003136{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003137 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138 const char *value;
3139
3140 for (i = 0; i < list->keys_size; ++i) {
3141 /* get the key name */
3142 if ((value = strpbrk(keys_str, " \t\n"))) {
3143 len = value - keys_str;
3144 while (isspace(value[0])) {
3145 value++;
3146 }
3147 } else {
3148 len = strlen(keys_str);
3149 }
3150
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003151 rc = resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
3152 if (rc) {
3153 if (rc == EXIT_FAILURE) {
3154 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3155 }
3156 return rc;
3157 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003159 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003160 /* check_key logs */
3161 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162 }
3163
3164 /* prepare for next iteration */
3165 while (value && isspace(value[0])) {
3166 value++;
3167 }
3168 keys_str = value;
3169 }
3170
Michal Vaskof02e3742015-08-05 16:27:02 +02003171 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172}
3173
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003174/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003176resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177{
3178 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003179 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180}
3181
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003182/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003183static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003184resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003185{
3186 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003187 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188}
3189
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003190/**
3191 * @brief Resolve a single unres item. Logs indirectly.
3192 *
3193 * @param[in] mod Main module.
3194 * @param[in] item Item to resolve. Type determined by \p type.
3195 * @param[in] type Type of the unresolved item.
3196 * @param[in] str_snode String, a schema node, or NULL.
3197 * @param[in] unres Unres structure in question.
3198 * @param[in] line Line in the input file. -1 turns logging off, 0 skips line print.
3199 *
3200 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3201 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202static int
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003203resolve_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 +02003204 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003206 int rc = -1, has_str = 0;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003207 struct lys_node *snode;
3208 const char *base_name;
3209
3210 struct lys_ident *ident;
3211 struct lys_type *stype;
3212 struct lys_feature **feat_ptr;
3213 struct lys_node_choice *choic;
3214 struct lys_unique *uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003215
3216 switch (type) {
3217 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003218 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003219 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003220 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003221 base_name = str_snode;
3222 ident = item;
3223
3224 rc = resolve_base_ident(mod, ident, base_name, "ident", line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003225 has_str = 1;
3226 break;
3227 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003228 base_name = str_snode;
3229 stype = item;
3230
3231 rc = resolve_base_ident(mod, NULL, base_name, "type", line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003232 has_str = 1;
3233 break;
3234 case UNRES_TYPE_LEAFREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003235 snode = str_snode;
3236 stype = item;
3237
3238 rc = resolve_path_arg_schema(mod, stype->info.lref.path, snode, line,
3239 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240 has_str = 0;
3241 break;
3242 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003243 base_name = str_snode;
3244 stype = item;
3245
3246 /* HACK type->der is temporarily its parent */
3247 rc = resolve_superior_type(base_name, stype->prefix, mod, (struct lys_node *)stype->der, &stype->der);
3248 if (!rc) {
3249 stype->base = stype->der->type.base;
3250 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003251 has_str = 1;
3252 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003254 base_name = str_snode;
3255 feat_ptr = item;
3256
3257 rc = resolve_feature(base_name, mod, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003258 has_str = 1;
3259 break;
3260 case UNRES_USES:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003261 rc = resolve_unres_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 has_str = 0;
3263 break;
3264 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003265 base_name = str_snode;
3266 stype = item;
3267
3268 rc = check_default(stype, base_name);
3269 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003270 has_str = 0;
3271 break;
3272 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003273 base_name = str_snode;
3274 choic = item;
3275
3276 rc = resolve_sibling(mod, choic->child, NULL, 0, base_name, 0, LYS_ANYXML | LYS_CASE
3277 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST, &choic->dflt);
3278 /* there is no prefix, that is the only error */
3279 assert(rc != -1);
3280 if (rc == EXIT_FAILURE) {
3281 LOGVAL(LYE_INRESOLV, line, "choice default", base_name);
3282 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003283 has_str = 1;
3284 break;
3285 case UNRES_LIST_KEYS:
Michal Vasko9957e592015-08-17 15:04:09 +02003286 rc = resolve_list_keys(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003287 has_str = 1;
3288 break;
3289 case UNRES_LIST_UNIQ:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003290 /* actually the unique string */
3291 base_name = str_snode;
3292 uniq = item;
3293
3294 rc = resolve_unique((struct lys_node *)uniq->leafs, base_name, uniq, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003295 has_str = 1;
3296 break;
3297 case UNRES_WHEN:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003298 rc = resolve_unres_when(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 has_str = 0;
3300 break;
3301 case UNRES_MUST:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003302 rc = resolve_unres_must(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303 has_str = 0;
3304 break;
3305 }
3306
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003307 if (has_str && !rc) {
3308 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003309 }
3310
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003311 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003312}
3313
Michal Vaskof02e3742015-08-05 16:27:02 +02003314/* logs directly */
3315static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003316print_unres_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003317{
Michal Vaskof02e3742015-08-05 16:27:02 +02003318 char line_str[18];
3319
3320 if (line) {
3321 sprintf(line_str, " (line %u)", line);
3322 } else {
3323 line_str[0] = '\0';
3324 }
3325
3326 switch (type) {
3327 case UNRES_RESOLVED:
3328 LOGINT;
3329 break;
3330 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003331 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003332 break;
3333 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003334 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003335 break;
3336 case UNRES_TYPE_LEAFREF:
3337 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3338 break;
3339 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003340 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 +02003341 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003342 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003343 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 +02003344 break;
3345 case UNRES_USES:
3346 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3347 break;
3348 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003349 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 +02003350 break;
3351 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003352 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 +02003353 break;
3354 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003355 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 +02003356 break;
3357 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003358 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 +02003359 break;
3360 case UNRES_WHEN:
3361 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3362 break;
3363 case UNRES_MUST:
3364 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3365 break;
3366 }
3367}
3368
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003369/**
3370 * @brief Resolve every unres item in the structure. Logs directly.
3371 *
3372 * @param[in] mod Main module.
3373 * @param[in] unres Unres structure in question.
3374 *
3375 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3376 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003377int
3378resolve_unres(struct lys_module *mod, struct unres_schema *unres)
3379{
Michal Vaskoc07187d2015-08-13 15:20:57 +02003380 uint32_t i, resolved, unres_uses, res_uses, line;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003381 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382
3383 assert(unres);
3384
Michal Vaskoc07187d2015-08-13 15:20:57 +02003385 line = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003386 resolved = 0;
3387
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003389 do {
3390 unres_uses = 0;
3391 res_uses = 0;
3392
3393 for (i = 0; i < unres->count; ++i) {
3394 if (unres->type[i] != UNRES_USES) {
3395 continue;
3396 }
3397
3398 ++unres_uses;
Michal Vasko4129bc32015-08-18 16:28:46 +02003399 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003400 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003401 unres->type[i] = UNRES_RESOLVED;
3402 ++resolved;
3403 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003404 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003405 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003406 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003408 } while (res_uses && (res_uses < unres_uses));
3409
3410 if (res_uses < unres_uses) {
3411 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
3412 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003413 }
3414
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003415 /* the rest */
3416 for (i = 0; i < unres->count; ++i) {
3417 if (unres->type[i] == UNRES_RESOLVED) {
3418 continue;
3419 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003420
Michal Vasko4129bc32015-08-18 16:28:46 +02003421 rc = resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003422 if (!rc) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 unres->type[i] = UNRES_RESOLVED;
3424 ++resolved;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003425 } else if (rc == -1) {
3426 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 }
3428 }
3429
3430 if (resolved < unres->count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003431 LOGVAL(LYE_SPEC, 0, "There are unresolved items left.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432 return EXIT_FAILURE;
3433 }
3434
3435 return EXIT_SUCCESS;
3436}
3437
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003438/**
3439 * @brief Try to resolve an unres item with a string argument. Logs indirectly.
3440 *
3441 * @param[in] mod Main module.
3442 * @param[in] unres Unres structure to use.
3443 * @param[in] item Item to resolve. Type determined by \p type.
3444 * @param[in] type Type of the unresolved item.
3445 * @param[in] str String argument.
3446 * @param[in] line Line in the input file.
3447 *
3448 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3449 */
3450int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003451unres_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 +02003452 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453{
3454 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003455 return unres_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456}
3457
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003458/**
3459 * @brief Try to resolve an unres item with a schema node argument. Logs indirectly.
3460 *
3461 * @param[in] mod Main module.
3462 * @param[in] unres Unres structure to use.
3463 * @param[in] item Item to resolve. Type determined by \p type.
3464 * @param[in] type Type of the unresolved item.
3465 * @param[in] snode Schema node argument.
3466 * @param[in] line Line in the input file.
3467 *
3468 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3469 */
3470int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003471unres_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003472 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003474 int rc;
3475
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476 assert(unres && item);
3477
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003478 rc = resolve_unres_item(mod, item, type, snode, unres, UINT_MAX);
3479 if (rc != EXIT_FAILURE) {
3480 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481 }
3482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003483 print_unres_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003484
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485 unres->count++;
3486 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3487 unres->item[unres->count-1] = item;
3488 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3489 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003490 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003491 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003492#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3494 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003495#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003496
3497 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498}
3499
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003500/**
3501 * @brief Duplicate an unres item. Logs indirectly.
3502 *
3503 * @param[in] mod Main module.
3504 * @param[in] unres Unres structure to use.
3505 * @param[in] item Old item to be resolved.
3506 * @param[in] type Type of the old unresolved item.
3507 * @param[in] new_item New item to use in the duplicate.
3508 *
3509 * @return EXIT_SUCCESS on success, -1 on error.
3510 */
Michal Vaskodad19402015-08-06 09:51:53 +02003511int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003512unres_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 +02003513{
3514 int i;
3515
3516 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003517 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003518 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 }
3520
Radek Krejci1d82ef62015-08-07 14:44:40 +02003521 i = unres_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522
3523 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003524 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003525 }
3526
Michal Vasko4adc10f2015-08-11 15:26:17 +02003527 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003529 if (unres_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3530 LOGINT;
3531 return -1;
3532 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003533 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003534 if (unres_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
3535 LOGINT;
3536 return -1;
3537 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538 }
Michal Vaskodad19402015-08-06 09:51:53 +02003539
3540 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541}
3542
Michal Vaskof02e3742015-08-05 16:27:02 +02003543/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544int
Radek Krejci1d82ef62015-08-07 14:44:40 +02003545unres_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003546{
3547 uint32_t ret = -1, i;
3548
3549 for (i = 0; i < unres->count; ++i) {
3550 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3551 ret = i;
3552 break;
3553 }
3554 }
3555
3556 return ret;
3557}