blob: 39c3b10a5d15454cc66a033e49b624208f6a77ff [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 *
Michal Vaskobb211122015-08-19 14:03:11 +020043 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020044 *
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 *
Michal Vaskobb211122015-08-19 14:03:11 +020078 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020079 * @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 *
Michal Vaskobb211122015-08-19 14:03:11 +0200165 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200166 * @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
Michal Vasko23b61ec2015-08-19 11:19:50 +0200178parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
179 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200180{
181 const char *ptr;
182 int parsed = 0, ret;
183
184 assert(id);
185 if (prefix) {
186 *prefix = NULL;
187 }
188 if (pref_len) {
189 *pref_len = 0;
190 }
191 if (name) {
192 *name = NULL;
193 }
194 if (nam_len) {
195 *nam_len = 0;
196 }
197 if (path_key_expr) {
198 *path_key_expr = NULL;
199 }
200 if (pke_len) {
201 *pke_len = 0;
202 }
203 if (has_predicate) {
204 *has_predicate = 0;
205 }
206
207 if (id[0] != '[') {
208 return -parsed;
209 }
210
211 ++parsed;
212 ++id;
213
214 while (isspace(id[0])) {
215 ++parsed;
216 ++id;
217 }
218
219 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
220 return -parsed+ret;
221 }
222
223 parsed += ret;
224 id += ret;
225
226 while (isspace(id[0])) {
227 ++parsed;
228 ++id;
229 }
230
231 if (id[0] != '=') {
232 return -parsed;
233 }
234
235 ++parsed;
236 ++id;
237
238 while (isspace(id[0])) {
239 ++parsed;
240 ++id;
241 }
242
243 if ((ptr = strchr(id, ']')) == NULL) {
244 return -parsed;
245 }
246
247 --ptr;
248 while (isspace(ptr[0])) {
249 --ptr;
250 }
251 ++ptr;
252
253 ret = ptr-id;
254 if (path_key_expr) {
255 *path_key_expr = id;
256 }
257 if (pke_len) {
258 *pke_len = ret;
259 }
260
261 parsed += ret;
262 id += ret;
263
264 while (isspace(id[0])) {
265 ++parsed;
266 ++id;
267 }
268
269 assert(id[0] == ']');
270
271 if (id[1] == '[') {
272 *has_predicate = 1;
273 }
274
275 return parsed+1;
276}
277
278/**
279 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
280 * the ".." and the first node-identifier, other calls parse a single
281 * node-identifier each.
282 *
283 * path-key-expr = current-function-invocation *WSP "/" *WSP
284 * rel-path-keyexpr
285 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
286 * *(node-identifier *WSP "/" *WSP)
287 * node-identifier
288 *
Michal Vaskobb211122015-08-19 14:03:11 +0200289 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200290 * @param[out] prefix Points to the prefix, NULL if there is not any.
291 * @param[out] pref_len Length of the prefix, 0 if there is not any.
292 * @param[out] name Points to the node name.
293 * @param[out] nam_len Length of the node name.
294 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
295 * must not be changed between consecutive calls.
296 * @return Number of characters successfully parsed,
297 * positive on success, negative on failure.
298 */
299static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200300parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
301 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200302{
303 int parsed = 0, ret, par_times = 0;
304
305 assert(id);
306 assert(parent_times);
307 if (prefix) {
308 *prefix = NULL;
309 }
310 if (pref_len) {
311 *pref_len = 0;
312 }
313 if (name) {
314 *name = NULL;
315 }
316 if (nam_len) {
317 *nam_len = 0;
318 }
319
320 if (!*parent_times) {
321 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
322 if (strncmp(id, "current()", 9)) {
323 return -parsed;
324 }
325
326 parsed += 9;
327 id += 9;
328
329 while (isspace(id[0])) {
330 ++parsed;
331 ++id;
332 }
333
334 if (id[0] != '/') {
335 return -parsed;
336 }
337
338 ++parsed;
339 ++id;
340
341 while (isspace(id[0])) {
342 ++parsed;
343 ++id;
344 }
345
346 /* rel-path-keyexpr */
347 if (strncmp(id, "..", 2)) {
348 return -parsed;
349 }
350 ++par_times;
351
352 parsed += 2;
353 id += 2;
354
355 while (isspace(id[0])) {
356 ++parsed;
357 ++id;
358 }
359 }
360
361 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
362 *
363 * first parent reference with whitespaces already parsed
364 */
365 if (id[0] != '/') {
366 return -parsed;
367 }
368
369 ++parsed;
370 ++id;
371
372 while (isspace(id[0])) {
373 ++parsed;
374 ++id;
375 }
376
377 while (!strncmp(id, "..", 2) && !*parent_times) {
378 ++par_times;
379
380 parsed += 2;
381 id += 2;
382
383 while (isspace(id[0])) {
384 ++parsed;
385 ++id;
386 }
387
388 if (id[0] != '/') {
389 return -parsed;
390 }
391
392 ++parsed;
393 ++id;
394
395 while (isspace(id[0])) {
396 ++parsed;
397 ++id;
398 }
399 }
400
401 if (!*parent_times) {
402 *parent_times = par_times;
403 }
404
405 /* all parent references must be parsed at this point */
406 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
407 return -parsed+ret;
408 }
409
410 parsed += ret;
411 id += ret;
412
413 return parsed;
414}
415
416/**
417 * @brief Parse path-arg (leafref).
418 *
419 * path-arg = absolute-path / relative-path
420 * absolute-path = 1*("/" (node-identifier *path-predicate))
421 * relative-path = 1*(".." "/") descendant-path
422 *
Michal Vaskobb211122015-08-19 14:03:11 +0200423 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200424 * @param[out] prefix Points to the prefix, NULL if there is not any.
425 * @param[out] pref_len Length of the prefix, 0 if there is not any.
426 * @param[out] name Points to the node name.
427 * @param[out] nam_len Length of the node name.
428 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
429 * must not be changed between consecutive calls. -1 if the
430 * path is relative.
431 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
432 *
433 * @return Number of characters successfully parsed,
434 * positive on success, negative on failure.
435 */
436static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200437parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
438 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200439{
440 int parsed = 0, ret, par_times = 0;
441
442 assert(id);
443 assert(parent_times);
444 if (prefix) {
445 *prefix = NULL;
446 }
447 if (pref_len) {
448 *pref_len = 0;
449 }
450 if (name) {
451 *name = NULL;
452 }
453 if (nam_len) {
454 *nam_len = 0;
455 }
456 if (has_predicate) {
457 *has_predicate = 0;
458 }
459
460 if (!*parent_times && !strncmp(id, "..", 2)) {
461 ++par_times;
462
463 parsed += 2;
464 id += 2;
465
466 while (!strncmp(id, "/..", 3)) {
467 ++par_times;
468
469 parsed += 3;
470 id += 3;
471 }
472 }
473
474 if (!*parent_times) {
475 if (par_times) {
476 *parent_times = par_times;
477 } else {
478 *parent_times = -1;
479 }
480 }
481
482 if (id[0] != '/') {
483 return -parsed;
484 }
485
486 /* skip '/' */
487 ++parsed;
488 ++id;
489
490 /* node-identifier ([prefix:]identifier) */
491 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
492 return -parsed-ret;
493 }
494
495 parsed += ret;
496 id += ret;
497
498 /* there is no predicate */
499 if ((id[0] == '/') || !id[0]) {
500 return parsed;
501 } else if (id[0] != '[') {
502 return -parsed;
503 }
504
505 if (has_predicate) {
506 *has_predicate = 1;
507 }
508
509 return parsed;
510}
511
512/**
Michal Vasko1f2cc332015-08-19 11:18:32 +0200513 * @brief Parse instance-identifier in JSON format. That means that prefixes
514 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200515 *
516 * instance-identifier = 1*("/" (node-identifier *predicate))
517 *
Michal Vaskobb211122015-08-19 14:03:11 +0200518 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200519 * @param[out] model Points to the model name.
520 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200521 * @param[out] name Points to the node name.
522 * @param[out] nam_len Length of the node name.
523 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
524 *
525 * @return Number of characters successfully parsed,
526 * positive on success, negative on failure.
527 */
528static int
Michal Vasko1f2cc332015-08-19 11:18:32 +0200529parse_instance_identifier_json(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
530 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200531{
532 int parsed = 0, ret;
533
534 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200535 if (model) {
536 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200537 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200538 if (mod_len) {
539 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200540 }
541 if (name) {
542 *name = NULL;
543 }
544 if (nam_len) {
545 *nam_len = 0;
546 }
547 if (has_predicate) {
548 *has_predicate = 0;
549 }
550
551 if (id[0] != '/') {
552 return -parsed;
553 }
554
555 ++parsed;
556 ++id;
557
Michal Vasko1f2cc332015-08-19 11:18:32 +0200558 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200559 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200560 } else if (model && !*model) {
561 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200562 }
563
564 parsed += ret;
565 id += ret;
566
567 if ((id[0] == '[') && has_predicate) {
568 *has_predicate = 1;
569 }
570
571 return parsed;
572}
573
574/**
Michal Vasko1f2cc332015-08-19 11:18:32 +0200575 * @brief Parse predicate (instance-identifier) in JSON format. That means that prefixes
576 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200577 *
578 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
579 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
580 * ((DQUOTE string DQUOTE) /
581 * (SQUOTE string SQUOTE))
582 * pos = non-negative-integer-value
583 *
Michal Vaskobb211122015-08-19 14:03:11 +0200584 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200585 * @param[out] model Points to the model name.
586 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200587 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
588 * @param[out] nam_len Length of the node name.
589 * @param[out] value Value the node-identifier must have (string from the grammar),
590 * NULL if there is not any.
591 * @param[out] val_len Length of the value, 0 if there is not any.
592 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
593 *
594 * @return Number of characters successfully parsed,
595 * positive on success, negative on failure.
596 */
597static int
Michal Vasko1f2cc332015-08-19 11:18:32 +0200598parse_predicate_json(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
599 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200600{
601 const char *ptr;
602 int parsed = 0, ret;
603 char quote;
604
605 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200606 if (model) {
607 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200608 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200609 if (mod_len) {
610 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611 }
612 if (name) {
613 *name = NULL;
614 }
615 if (nam_len) {
616 *nam_len = 0;
617 }
618 if (value) {
619 *value = NULL;
620 }
621 if (val_len) {
622 *val_len = 0;
623 }
624 if (has_predicate) {
625 *has_predicate = 0;
626 }
627
628 if (id[0] != '[') {
629 return -parsed;
630 }
631
632 ++parsed;
633 ++id;
634
635 while (isspace(id[0])) {
636 ++parsed;
637 ++id;
638 }
639
640 /* pos */
641 if (isdigit(id[0])) {
642 if (name) {
643 *name = id;
644 }
645
646 if (id[0] == '0') {
647 ++parsed;
648 ++id;
649
650 if (isdigit(id[0])) {
651 return -parsed;
652 }
653 }
654
655 while (isdigit(id[0])) {
656 ++parsed;
657 ++id;
658 }
659
660 if (nam_len) {
661 *nam_len = id-(*name);
662 }
663
664 /* "." */
665 } else if (id[0] == '.') {
666 if (name) {
667 *name = id;
668 }
669 if (nam_len) {
670 *nam_len = 1;
671 }
672
673 ++parsed;
674 ++id;
675
676 /* node-identifier */
677 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200678 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200679 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680 } else if (model && !*model) {
681 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200682 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200683
684 parsed += ret;
685 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686 }
687
688 while (isspace(id[0])) {
689 ++parsed;
690 ++id;
691 }
692
693 if (id[0] != '=') {
694 return -parsed;
695 }
696
697 ++parsed;
698 ++id;
699
700 while (isspace(id[0])) {
701 ++parsed;
702 ++id;
703 }
704
705 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
706 if ((id[0] == '\"') || (id[0] == '\'')) {
707 quote = id[0];
708
709 ++parsed;
710 ++id;
711
712 if ((ptr = strchr(id, quote)) == NULL) {
713 return -parsed;
714 }
715 ret = ptr-id;
716
717 if (value) {
718 *value = id;
719 }
720 if (val_len) {
721 *val_len = ret;
722 }
723
724 parsed += ret+1;
725 id += ret+1;
726 } else {
727 return -parsed;
728 }
729
730 while (isspace(id[0])) {
731 ++parsed;
732 ++id;
733 }
734
735 if (id[0] != ']') {
736 return -parsed;
737 }
738
739 ++parsed;
740 ++id;
741
742 if ((id[0] == '[') && has_predicate) {
743 *has_predicate = 1;
744 }
745
746 return parsed;
747}
748
749/**
750 * @brief Parse schema-nodeid.
751 *
752 * schema-nodeid = absolute-schema-nodeid /
753 * descendant-schema-nodeid
754 * absolute-schema-nodeid = 1*("/" node-identifier)
755 * descendant-schema-nodeid =
756 * node-identifier
757 * absolute-schema-nodeid
758 *
Michal Vaskobb211122015-08-19 14:03:11 +0200759 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] prefix Points to the prefix, NULL if there is not any.
761 * @param[out] pref_len Length of the prefix, 0 if there is not any.
762 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
763 * @param[out] nam_len Length of the node name.
764 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
765 * on the first call, must not be changed between consecutive calls.
766 *
767 * @return Number of characters successfully parsed,
768 * positive on success, negative on failure.
769 */
770static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200771parse_schema_nodeid(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
772 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200773{
774 int parsed = 0, ret;
775
776 assert(id);
777 assert(is_relative);
778 if (prefix) {
779 *prefix = NULL;
780 }
781 if (pref_len) {
782 *pref_len = 0;
783 }
784 if (name) {
785 *name = NULL;
786 }
787 if (nam_len) {
788 *nam_len = 0;
789 }
790
791 if (id[0] != '/') {
792 if (*is_relative != -1) {
793 return -parsed;
794 } else {
795 *is_relative = 1;
796 }
797 } else {
798 if (*is_relative == -1) {
799 *is_relative = 0;
800 }
801 ++parsed;
802 ++id;
803 }
804
805 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
806 return -parsed+ret;
807 }
808
809 return parsed+ret;
810}
811
812/**
Michal Vaskoc935fff2015-08-17 14:02:06 +0200813 * @brief Resolve (find) a prefix in a module include import. Does not log.
814 *
815 * @param[in] mod The module with the import.
816 * @param[in] prefix The prefix to find.
817 * @param[in] pref_len The prefix length.
818 *
819 * @return The matching module on success, NULL on error.
820 */
821static struct lys_module *
822resolve_import_in_includes_recursive(struct lys_module *mod, const char *prefix, uint32_t pref_len)
823{
824 int i, j;
825 struct lys_submodule *sub_mod;
826 struct lys_module *ret;
827
828 for (i = 0; i < mod->inc_size; i++) {
829 sub_mod = mod->inc[i].submodule;
830 for (j = 0; j < sub_mod->imp_size; j++) {
831 if ((pref_len == strlen(sub_mod->imp[j].prefix))
832 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
833 return sub_mod->imp[j].module;
834 }
835 }
836 }
837
838 for (i = 0; i < mod->inc_size; i++) {
839 ret = resolve_import_in_includes_recursive((struct lys_module *)mod->inc[i].submodule, prefix, pref_len);
840 if (ret) {
841 return ret;
842 }
843 }
844
845 return NULL;
846}
847
848/**
849 * @brief Resolve (find) a prefix in a module import. Does not log.
850 *
851 * @param[in] mod The module with the import.
852 * @param[in] prefix The prefix to find.
853 * @param[in] pref_len The prefix length.
854 *
855 * @return The matching module on success, NULL on error.
856 */
857static struct lys_module *
858resolve_prefixed_module(struct lys_module *mod, const char *prefix, uint32_t pref_len)
859{
860 int i;
861
862 /* module itself */
863 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
864 return mod;
865 }
866
867 /* imported modules */
868 for (i = 0; i < mod->imp_size; i++) {
869 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
870 return mod->imp[i].module;
871 }
872 }
873
874 /* imports in includes */
875 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
876}
877
878/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200879 * @brief Resolves length or range intervals. Does not log.
880 * Syntax is assumed to be correct, *local_intv MUST be NULL.
881 *
882 * @param[in] str_restr The restriction as a string.
883 * @param[in] type The type of the restriction.
884 * @param[in] superior_restr Flag whether to check superior
885 * types.
886 * @param[out] local_intv The final interval structure.
887 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200888 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200889 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200890int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200891resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
892 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200893{
894 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200895 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200896 int64_t local_smin, local_smax;
897 uint64_t local_umin, local_umax;
898 long double local_fmin, local_fmax;
899 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200900 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200901
902 switch (type->base) {
903 case LY_TYPE_BINARY:
904 kind = 0;
905 local_umin = 0;
906 local_umax = 18446744073709551615UL;
907
908 if (!str_restr && type->info.binary.length) {
909 str_restr = type->info.binary.length->expr;
910 }
911 break;
912 case LY_TYPE_DEC64:
913 kind = 2;
914 local_fmin = -9223372036854775808.0;
915 local_fmin /= 1 << type->info.dec64.dig;
916 local_fmax = 9223372036854775807.0;
917 local_fmax /= 1 << type->info.dec64.dig;
918
919 if (!str_restr && type->info.dec64.range) {
920 str_restr = type->info.dec64.range->expr;
921 }
922 break;
923 case LY_TYPE_INT8:
924 kind = 1;
925 local_smin = -128;
926 local_smax = 127;
927
928 if (!str_restr && type->info.num.range) {
929 str_restr = type->info.num.range->expr;
930 }
931 break;
932 case LY_TYPE_INT16:
933 kind = 1;
934 local_smin = -32768;
935 local_smax = 32767;
936
937 if (!str_restr && type->info.num.range) {
938 str_restr = type->info.num.range->expr;
939 }
940 break;
941 case LY_TYPE_INT32:
942 kind = 1;
943 local_smin = -2147483648;
944 local_smax = 2147483647;
945
946 if (!str_restr && type->info.num.range) {
947 str_restr = type->info.num.range->expr;
948 }
949 break;
950 case LY_TYPE_INT64:
951 kind = 1;
952 local_smin = -9223372036854775807L - 1L;
953 local_smax = 9223372036854775807L;
954
955 if (!str_restr && type->info.num.range) {
956 str_restr = type->info.num.range->expr;
957 }
958 break;
959 case LY_TYPE_UINT8:
960 kind = 0;
961 local_umin = 0;
962 local_umax = 255;
963
964 if (!str_restr && type->info.num.range) {
965 str_restr = type->info.num.range->expr;
966 }
967 break;
968 case LY_TYPE_UINT16:
969 kind = 0;
970 local_umin = 0;
971 local_umax = 65535;
972
973 if (!str_restr && type->info.num.range) {
974 str_restr = type->info.num.range->expr;
975 }
976 break;
977 case LY_TYPE_UINT32:
978 kind = 0;
979 local_umin = 0;
980 local_umax = 4294967295;
981
982 if (!str_restr && type->info.num.range) {
983 str_restr = type->info.num.range->expr;
984 }
985 break;
986 case LY_TYPE_UINT64:
987 kind = 0;
988 local_umin = 0;
989 local_umax = 18446744073709551615UL;
990
991 if (!str_restr && type->info.num.range) {
992 str_restr = type->info.num.range->expr;
993 }
994 break;
995 case LY_TYPE_STRING:
996 kind = 0;
997 local_umin = 0;
998 local_umax = 18446744073709551615UL;
999
1000 if (!str_restr && type->info.str.length) {
1001 str_restr = type->info.str.length->expr;
1002 }
1003 break;
1004 default:
1005 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001006 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001007 }
1008
1009 /* process superior types */
1010 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001011 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1012 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001013 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001014 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001015 assert(!intv || (intv->kind == kind));
1016 }
1017
1018 if (!str_restr) {
1019 /* we are validating data and not have any restriction, but a superior type might have */
1020 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001021 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1022 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001023 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001024 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001025 assert(!intv || (intv->kind == kind));
1026 }
1027 *local_intv = intv;
1028 return EXIT_SUCCESS;
1029 }
1030
1031 /* adjust local min and max */
1032 if (intv) {
1033 tmp_intv = intv;
1034
1035 if (kind == 0) {
1036 local_umin = tmp_intv->value.uval.min;
1037 } else if (kind == 1) {
1038 local_smin = tmp_intv->value.sval.min;
1039 } else if (kind == 2) {
1040 local_fmin = tmp_intv->value.fval.min;
1041 }
1042
1043 while (tmp_intv->next) {
1044 tmp_intv = tmp_intv->next;
1045 }
1046
1047 if (kind == 0) {
1048 local_umax = tmp_intv->value.uval.max;
1049 } else if (kind == 1) {
1050 local_smax = tmp_intv->value.sval.max;
1051 } else if (kind == 2) {
1052 local_fmax = tmp_intv->value.fval.max;
1053 }
1054 }
1055
1056 /* finally parse our restriction */
1057 seg_ptr = str_restr;
1058 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001059 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001060 *local_intv = malloc(sizeof **local_intv);
1061 tmp_local_intv = *local_intv;
1062 } else {
1063 tmp_local_intv->next = malloc(sizeof **local_intv);
1064 tmp_local_intv = tmp_local_intv->next;
1065 }
1066
1067 tmp_local_intv->kind = kind;
1068 tmp_local_intv->next = NULL;
1069
1070 /* min */
1071 ptr = seg_ptr;
1072 while (isspace(ptr[0])) {
1073 ++ptr;
1074 }
1075 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1076 if (kind == 0) {
1077 tmp_local_intv->value.uval.min = atoll(ptr);
1078 } else if (kind == 1) {
1079 tmp_local_intv->value.sval.min = atoll(ptr);
1080 } else if (kind == 2) {
1081 tmp_local_intv->value.fval.min = atoll(ptr);
1082 }
1083
1084 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1085 ++ptr;
1086 }
1087 while (isdigit(ptr[0])) {
1088 ++ptr;
1089 }
1090 } else if (!strncmp(ptr, "min", 3)) {
1091 if (kind == 0) {
1092 tmp_local_intv->value.uval.min = local_umin;
1093 } else if (kind == 1) {
1094 tmp_local_intv->value.sval.min = local_smin;
1095 } else if (kind == 2) {
1096 tmp_local_intv->value.fval.min = local_fmin;
1097 }
1098
1099 ptr += 3;
1100 } else if (!strncmp(ptr, "max", 3)) {
1101 if (kind == 0) {
1102 tmp_local_intv->value.uval.min = local_umax;
1103 } else if (kind == 1) {
1104 tmp_local_intv->value.sval.min = local_smax;
1105 } else if (kind == 2) {
1106 tmp_local_intv->value.fval.min = local_fmax;
1107 }
1108
1109 ptr += 3;
1110 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001111 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001112 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001113 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001114 }
1115
1116 while (isspace(ptr[0])) {
1117 ptr++;
1118 }
1119
1120 /* no interval or interval */
1121 if ((ptr[0] == '|') || !ptr[0]) {
1122 if (kind == 0) {
1123 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1124 } else if (kind == 1) {
1125 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1126 } else if (kind == 2) {
1127 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1128 }
1129 } else if (!strncmp(ptr, "..", 2)) {
1130 /* skip ".." */
1131 ptr += 2;
1132 while (isspace(ptr[0])) {
1133 ++ptr;
1134 }
1135
1136 /* max */
1137 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1138 if (kind == 0) {
1139 tmp_local_intv->value.uval.max = atoll(ptr);
1140 } else if (kind == 1) {
1141 tmp_local_intv->value.sval.max = atoll(ptr);
1142 } else if (kind == 2) {
1143 tmp_local_intv->value.fval.max = atoll(ptr);
1144 }
1145 } else if (!strncmp(ptr, "max", 3)) {
1146 if (kind == 0) {
1147 tmp_local_intv->value.uval.max = local_umax;
1148 } else if (kind == 1) {
1149 tmp_local_intv->value.sval.max = local_smax;
1150 } else if (kind == 2) {
1151 tmp_local_intv->value.fval.max = local_fmax;
1152 }
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 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001159 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001160 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001161 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001162 }
1163
1164 /* next segment (next OR) */
1165 seg_ptr = strchr(seg_ptr, '|');
1166 if (!seg_ptr) {
1167 break;
1168 }
1169 seg_ptr++;
1170 }
1171
1172 /* check local restrictions against superior ones */
1173 if (intv) {
1174 tmp_intv = intv;
1175 tmp_local_intv = *local_intv;
1176
1177 while (tmp_local_intv && tmp_intv) {
1178 /* reuse local variables */
1179 if (kind == 0) {
1180 local_umin = tmp_local_intv->value.uval.min;
1181 local_umax = tmp_local_intv->value.uval.max;
1182
1183 /* it must be in this interval */
1184 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1185 /* this interval is covered, next one */
1186 if (local_umax <= tmp_intv->value.uval.max) {
1187 tmp_local_intv = tmp_local_intv->next;
1188 continue;
1189 /* ascending order of restrictions -> fail */
1190 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001191 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001192 goto cleanup;
1193 }
1194 }
1195 } else if (kind == 1) {
1196 local_smin = tmp_local_intv->value.sval.min;
1197 local_smax = tmp_local_intv->value.sval.max;
1198
1199 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1200 if (local_smax <= tmp_intv->value.sval.max) {
1201 tmp_local_intv = tmp_local_intv->next;
1202 continue;
1203 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001204 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001205 goto cleanup;
1206 }
1207 }
1208 } else if (kind == 2) {
1209 local_fmin = tmp_local_intv->value.fval.min;
1210 local_fmax = tmp_local_intv->value.fval.max;
1211
1212 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1213 if (local_fmax <= tmp_intv->value.fval.max) {
1214 tmp_local_intv = tmp_local_intv->next;
1215 continue;
1216 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001217 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001218 goto cleanup;
1219 }
1220 }
1221 }
1222
1223 tmp_intv = tmp_intv->next;
1224 }
1225
1226 /* some interval left uncovered -> fail */
1227 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001228 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001229 }
1230
1231 }
1232
1233cleanup:
1234 while (intv) {
1235 tmp_intv = intv->next;
1236 free(intv);
1237 intv = tmp_intv;
1238 }
1239
1240 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001241 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001242 while (*local_intv) {
1243 tmp_local_intv = (*local_intv)->next;
1244 free(*local_intv);
1245 *local_intv = tmp_local_intv;
1246 }
1247 }
1248
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001249 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001250}
1251
Michal Vasko730dfdf2015-08-11 14:48:05 +02001252/**
1253 * @brief Resolve a typedef. Does not log.
1254 *
1255 * @param[in] name Typedef name.
1256 * @param[in] prefix Typedef name prefix.
1257 * @param[in] module The main module.
1258 * @param[in] parent The parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001259 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001260 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001261 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001262 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001263int
1264resolve_superior_type(const char *name, const char *prefix, struct lys_module *module, struct lys_node *parent,
1265 struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001266{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001267 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001268 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001269 int tpdf_size;
1270
1271 if (!prefix) {
1272 /* no prefix, try built-in types */
1273 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1274 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001275 if (ret) {
1276 *ret = ly_types[i].def;
1277 }
1278 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001279 }
1280 }
1281 } else {
1282 if (!strcmp(prefix, module->prefix)) {
1283 /* prefix refers to the current module, ignore it */
1284 prefix = NULL;
1285 }
1286 }
1287
1288 if (!prefix && parent) {
1289 /* search in local typedefs */
1290 while (parent) {
1291 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001292 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001293 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1294 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001295 break;
1296
Radek Krejci76512572015-08-04 09:47:08 +02001297 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001298 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1299 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001300 break;
1301
Radek Krejci76512572015-08-04 09:47:08 +02001302 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001303 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1304 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001305 break;
1306
Radek Krejci76512572015-08-04 09:47:08 +02001307 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001308 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1309 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001310 break;
1311
Radek Krejci76512572015-08-04 09:47:08 +02001312 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001313 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1314 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001315 break;
1316
Radek Krejci76512572015-08-04 09:47:08 +02001317 case LYS_INPUT:
1318 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001319 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1320 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001321 break;
1322
1323 default:
1324 parent = parent->parent;
1325 continue;
1326 }
1327
1328 for (i = 0; i < tpdf_size; i++) {
1329 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001330 if (ret) {
1331 *ret = &tpdf[i];
1332 }
1333 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001334 }
1335 }
1336
1337 parent = parent->parent;
1338 }
1339 } else if (prefix) {
1340 /* get module where to search */
Michal Vaskoc935fff2015-08-17 14:02:06 +02001341 module = resolve_prefixed_module(module, prefix, strlen(prefix));
1342 if (!module) {
1343 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001344 }
1345 }
1346
1347 /* search in top level typedefs */
1348 for (i = 0; i < module->tpdf_size; i++) {
1349 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001350 if (ret) {
1351 *ret = &module->tpdf[i];
1352 }
1353 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001354 }
1355 }
1356
1357 /* search in submodules */
1358 for (i = 0; i < module->inc_size; i++) {
1359 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1360 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001361 if (ret) {
1362 *ret = &module->inc[i].submodule->tpdf[j];
1363 }
1364 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001365 }
1366 }
1367 }
1368
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001369 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001370}
1371
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02001372/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001373static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001374check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001375{
1376 /* TODO - RFC 6020, sec. 7.3.4 */
1377 (void)type;
1378 (void)value;
1379 return EXIT_SUCCESS;
1380}
1381
Michal Vasko730dfdf2015-08-11 14:48:05 +02001382/**
1383 * @brief Check a key for mandatory attributes. Logs directly.
1384 *
1385 * @param[in] key The key to check.
1386 * @param[in] flags What flags to check.
1387 * @param[in] list The list of all the keys.
1388 * @param[in] index Index of the key in the key list.
1389 * @param[in] name The name of the keys.
1390 * @param[in] len The name length.
1391 * @param[in] line The line in the input file.
1392 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001393 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001394 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001395static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001396check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1397 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001398{
1399 char *dup = NULL;
1400 int j;
1401
1402 /* existence */
1403 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001404 if (name[len] != '\0') {
1405 dup = strdup(name);
1406 dup[len] = '\0';
1407 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001408 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001409 LOGVAL(LYE_KEY_MISS, line, name);
1410 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001411 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001412 }
1413
1414 /* uniqueness */
1415 for (j = index - 1; j >= 0; j--) {
1416 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001417 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001418 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001419 }
1420 }
1421
1422 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001423 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001424 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001425 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001426 }
1427
1428 /* type of the leaf is not built-in empty */
1429 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001430 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001431 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001432 }
1433
1434 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001435 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001436 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001437 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001438 }
1439
1440 return EXIT_SUCCESS;
1441}
1442
Michal Vasko730dfdf2015-08-11 14:48:05 +02001443/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001444 * @brief Resolve (fill) a unique. Logs directly.
1445 *
1446 * @param[in] parent The parent node of the unique structure.
1447 * @param[in] uniq_str The value of the unique node.
Michal Vaskobb211122015-08-19 14:03:11 +02001448 * @param[in] uniq_s The unique structure to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001449 * @param[in] line The line in the input file.
1450 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001451 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001452 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001453int
Michal Vaskof02e3742015-08-05 16:27:02 +02001454resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001455{
1456 char *uniq_val, *uniq_begin, *start;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001457 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001458
1459 /* count the number of unique values */
1460 uniq_val = uniq_begin = strdup(uniq_str);
1461 uniq_s->leafs_size = 0;
1462 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1463 uniq_s->leafs_size++;
1464 while (isspace(*uniq_val)) {
1465 uniq_val++;
1466 }
1467 }
1468 uniq_s->leafs_size++;
1469 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1470
1471 /* interconnect unique values with the leafs */
1472 uniq_val = uniq_begin;
1473 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1474 start = uniq_val;
1475 if ((uniq_val = strpbrk(start, " \t\n"))) {
1476 *uniq_val = '\0'; /* add terminating NULL byte */
1477 uniq_val++;
1478 while (isspace(*uniq_val)) {
1479 uniq_val++;
1480 }
1481 } /* else only one nodeid present/left already NULL byte terminated */
1482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001483 rc = resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF,
1484 (struct lys_node **)&uniq_s->leafs[i]);
1485 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001486 LOGVAL(LYE_INARG, line, start, "unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001487 if (rc == EXIT_FAILURE) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001488 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001489 }
1490 goto error;
1491 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001492 if (uniq_s->leafs[i]->nodetype != LYS_LEAF) {
1493 LOGVAL(LYE_INARG, line, start, "unique");
1494 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1495 rc = -1;
1496 goto error;
1497 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001498
1499 for (j = 0; j < i; j++) {
1500 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001501 LOGVAL(LYE_INARG, line, start, "unique");
1502 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001503 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001504 goto error;
1505 }
1506 }
1507 }
1508
1509 free(uniq_begin);
1510 return EXIT_SUCCESS;
1511
1512error:
1513
1514 free(uniq_s->leafs);
1515 free(uniq_begin);
1516
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001517 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001518}
1519
Michal Vasko730dfdf2015-08-11 14:48:05 +02001520/**
1521 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1522 *
Michal Vaskobb211122015-08-19 14:03:11 +02001523 * @param[in] uses The uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001524 * @param[in] line The line in the input file.
1525 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001526 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001527 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001528static int
Radek Krejci10c760e2015-08-14 14:45:43 +02001529resolve_grouping(struct lys_node_uses *uses, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001530{
Michal Vasko58090902015-08-13 14:04:15 +02001531 struct lys_module *module = uses->module;
1532 const char *prefix, *name;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001533 int i, pref_len, nam_len, rc;
Radek Krejci10c760e2015-08-14 14:45:43 +02001534 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001535
Michal Vasko58090902015-08-13 14:04:15 +02001536 /* parse the identifier, it must be parsed on one call */
1537 if ((i = parse_node_identifier(uses->name, &prefix, &pref_len, &name, &nam_len)) < 1) {
1538 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001539 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001540 } else if (uses->name[i]) {
1541 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001542 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001543 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001544
Michal Vasko2bdcca92015-08-17 16:00:45 +02001545 if (prefix) {
1546 /* cannot be NULL, since there must at least be this uses */
1547 assert(module->data);
1548 start = module->data;
1549 } else {
Michal Vasko58090902015-08-13 14:04:15 +02001550 /* search in local tree hierarchy */
Radek Krejci10c760e2015-08-14 14:45:43 +02001551 if (!uses->parent) {
1552 start = (struct lys_node *)uses;
1553 while (start->prev->next) {
1554 start = start->prev;
1555 }
1556 } else {
1557 start = uses->parent->child;
1558 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001559 }
1560
1561 while (start) {
1562 rc = resolve_sibling(module, start, prefix, pref_len, name, nam_len, LYS_GROUPING, (struct lys_node **)&uses->grp);
1563 if (rc != EXIT_FAILURE) {
1564 if (rc == -1) {
1565 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko58090902015-08-13 14:04:15 +02001566 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001567 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001568 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001569 start = start->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001570 }
1571
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001572 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001573 return EXIT_FAILURE;
1574}
1575
Michal Vasko730dfdf2015-08-11 14:48:05 +02001576/**
1577 * @brief Resolve (find) a feature definition. Logs directly.
1578 *
1579 * @param[in] name Feature name.
1580 * @param[in] module Module to search in.
1581 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001582 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001583 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001584 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001585 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001586static int
1587resolve_feature(const char *id, struct lys_module *module, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001588{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001589 const char *prefix, *name;
1590 int pref_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001591
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001592 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001593 assert(module);
1594
1595 /* check prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001596 if ((i = parse_node_identifier(id, &prefix, &pref_len, &name, &nam_len)) < 1) {
1597 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1598 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001599 }
1600
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001601 if (prefix) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001602 /* search in imported modules */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001603 module = resolve_prefixed_module(module, prefix, pref_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001604 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001605 /* identity refers unknown data model */
Michal Vaskod9173342015-08-17 14:35:36 +02001606 LOGVAL(LYE_INPREF_LEN, line, pref_len, prefix);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001607 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001608 }
1609 } else {
1610 /* search in submodules */
1611 for (i = 0; i < module->inc_size; i++) {
1612 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1613 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001614 if (ret) {
1615 *ret = &(module->inc[i].submodule->features[j]);
1616 }
1617 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001618 }
1619 }
1620 }
1621 }
1622
1623 /* search in the identified module */
1624 for (j = 0; j < module->features_size; j++) {
1625 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001626 if (ret) {
1627 *ret = &module->features[j];
1628 }
1629 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001630 }
1631 }
1632
1633 /* not found */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001634 LOGVAL(LYE_INRESOLV, line, "feature", id);
1635 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001636}
1637
Michal Vasko730dfdf2015-08-11 14:48:05 +02001638/**
Michal Vasko58090902015-08-13 14:04:15 +02001639 * @brief Resolve (find) a valid sibling. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001640 *
Michal Vasko58090902015-08-13 14:04:15 +02001641 * Valid child means a schema pointer to a node that is part of
1642 * the data meaning uses are skipped. Includes module comparison
Michal Vaskobbfcfaa2015-08-17 16:00:19 +02001643 * (can handle augments). Module is adjusted based on the prefix.
1644 * Includes are also searched if siblings are top-level nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001645 *
Michal Vasko58090902015-08-13 14:04:15 +02001646 * @param[in] mod Main module. Prefix is considered to be from this module.
1647 * @param[in] siblings Siblings to consider. They are first adjusted to
1648 * point to the first sibling.
1649 * @param[in] prefix Node prefix.
1650 * @param[in] pref_len Node prefix length.
1651 * @param[in] name Node name.
1652 * @param[in] nam_len Node name length.
1653 * @param[in] type ORed desired type of the node. 0 means any type.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001654 * @param[out] ret Pointer to the node of the desired type. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001655 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001656 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001657 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001658int
Michal Vasko58090902015-08-13 14:04:15 +02001659resolve_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 +02001660 int nam_len, LYS_NODE type, struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001661{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001662 struct lys_node *node, *old_siblings = NULL;
Michal Vasko58090902015-08-13 14:04:15 +02001663 struct lys_module *prefix_mod, *cur_mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001664 int in_submod, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001665
Michal Vasko58090902015-08-13 14:04:15 +02001666 assert(mod && siblings && name);
1667 assert(!(type & LYS_USES));
1668
1669 /* find the beginning */
1670 while (siblings->prev->next) {
1671 siblings = siblings->prev;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001672 }
1673
Michal Vasko58090902015-08-13 14:04:15 +02001674 /* fill the name length in case the caller is so indifferent */
1675 if (!nam_len) {
1676 nam_len = strlen(name);
1677 }
1678
1679 /* we start with the module itself, submodules come later */
1680 in_submod = 0;
1681
1682 /* set prefix_mod correctly */
1683 if (prefix) {
1684 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1685 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001686 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001687 }
1688 cur_mod = prefix_mod;
1689 /* it is our module */
1690 if (cur_mod != mod) {
1691 old_siblings = siblings;
1692 siblings = cur_mod->data;
1693 }
1694 } else {
1695 prefix_mod = mod;
1696 if (prefix_mod->type) {
1697 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1698 }
1699 cur_mod = prefix_mod;
1700 }
1701
1702 while (1) {
1703 /* try to find the node */
1704 LY_TREE_FOR(siblings, node) {
1705 if (node->nodetype == LYS_USES) {
1706 /* an unresolved uses, we can still find it elsewhere */
1707 if (!node->child) {
1708 continue;
1709 }
1710
1711 /* search recursively */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001712 rc = resolve_sibling(mod, node->child, prefix, pref_len, name, nam_len, type, ret);
1713 if (rc != EXIT_FAILURE) {
1714 return rc;
Michal Vasko58090902015-08-13 14:04:15 +02001715 }
1716 }
1717
1718 if (!type || (node->nodetype & type)) {
1719 /* module check */
1720 if (!node->module->type) {
1721 if (cur_mod != node->module) {
1722 continue;
1723 }
1724 } else {
1725 if (cur_mod != ((struct lys_submodule *)node->module)->belongsto) {
1726 continue;
1727 }
1728 }
1729
1730 /* direct name check */
1731 if (node->name == name || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001732 if (ret) {
1733 *ret = node;
1734 }
1735 return EXIT_SUCCESS;
Michal Vasko58090902015-08-13 14:04:15 +02001736 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001737 }
1738 }
1739
Michal Vasko58090902015-08-13 14:04:15 +02001740 /* The original siblings may be valid,
1741 * it's a special case when we're looking
1742 * for a node from augment.
1743 */
1744 if (old_siblings) {
1745 siblings = old_siblings;
1746 old_siblings = NULL;
1747 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001748 }
Michal Vasko58090902015-08-13 14:04:15 +02001749
1750 /* we're not top-level, search ended */
1751 if (siblings->parent) {
1752 break;
1753 }
1754
1755 /* let's try the submodules */
1756 if (in_submod == prefix_mod->inc_size) {
1757 break;
1758 }
1759 cur_mod = (struct lys_module *)prefix_mod->inc[in_submod].submodule;
1760 siblings = cur_mod->data;
1761 ++in_submod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001762 }
1763
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001764 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001765}
1766
Michal Vasko730dfdf2015-08-11 14:48:05 +02001767/**
1768 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001769 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001770 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001771 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001772 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001773 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1774 *
1775 * If id is absolute, start is ignored. If id is relative, start must be the first child to be searched
1776 * continuing with its siblings.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001777 *
1778 * @param[in] id Schema-nodeid string.
1779 * @param[in] start Start of the relative search.
Michal Vaskobb211122015-08-19 14:03:11 +02001780 * @param[in] mod Module to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001781 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001782 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001783 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001784 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001785 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001786int
1787resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1788 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001789{
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001790 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +02001791 struct lys_node *sibling;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001792 int i, nam_len, pref_len, is_relative = -1;
Radek Krejcib8048692015-08-05 13:36:34 +02001793 struct lys_module *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001794 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1795 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001796 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001797 uint8_t in_mod_part = 0;
1798
1799 assert(mod);
1800 assert(id);
1801
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001802 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1803 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001804 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001805 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001806
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001807 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001808 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001809 }
1810
1811 /* absolute-schema-nodeid */
1812 if (!is_relative) {
1813 if (prefix) {
1814 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
1815 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001816 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001817 }
1818 start = start_mod->data;
1819 } else {
1820 start = mod->data;
1821 start_mod = mod;
1822 }
1823 /* descendant-schema-nodeid */
1824 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001825 if (start) {
1826 start_mod = start->module;
1827 } else {
1828 start_mod = mod;
1829 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001830 }
1831
1832 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001833 sibling = NULL;
1834 LY_TREE_FOR(start, sibling) {
1835 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001836 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
1837 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001838 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001839 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001840
Michal Vasko1e989c02015-08-04 12:33:00 +02001841 /* prefix match check */
1842 if (prefix) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001843 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
1844 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001845 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001846 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001847 } else {
1848 prefix_mod = mod;
1849 if (prefix_mod->type) {
1850 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1851 }
1852 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001853
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001854 /* modules need to always be checked, we want to skip augments */
1855 if (!sibling->module->type) {
1856 if (prefix_mod != sibling->module) {
1857 continue;
1858 }
1859 } else {
1860 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1861 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001862 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001863 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001864
Michal Vasko1e989c02015-08-04 12:33:00 +02001865 /* the result node? */
1866 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001867 /* we're looking only for groupings, this is a data node */
1868 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
1869 continue;
1870 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001871 if (ret) {
1872 *ret = sibling;
1873 }
1874 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001875 }
1876
Michal Vaskodcc7a802015-08-06 11:59:47 +02001877 /* we're looking for a grouping (node_type == LYS_USES),
1878 * but this isn't it, we cannot search inside
1879 */
1880 if (sibling->nodetype == LYS_GROUPING) {
1881 continue;
1882 }
1883
Michal Vasko1e989c02015-08-04 12:33:00 +02001884 /* check for shorthand cases - then 'start' does not change */
1885 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1886 || (sibling->nodetype == LYS_CASE)) {
1887 start = sibling->child;
1888 }
1889 break;
1890 }
1891 }
1892
1893 /* we did not find the case in direct siblings */
1894 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001895 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001896 }
1897
1898 /* no match */
1899 if (!sibling) {
1900 /* on augment search also RPCs and notifications, if we are in top-level */
1901 if ((node_type == LYS_AUGMENT) && (!start || !start->parent)) {
1902 /* we have searched all the data nodes */
1903 if (in_mod_part == 0) {
1904 if (!in_submod) {
1905 start = start_mod->rpc;
1906 } else {
1907 start = start_mod->inc[in_submod-1].submodule->rpc;
1908 }
1909 in_mod_part = 1;
1910 continue;
1911 }
1912 /* we have searched all the RPCs */
1913 if (in_mod_part == 1) {
1914 if (!in_submod) {
1915 start = start_mod->notif;
1916 } else {
1917 start = start_mod->inc[in_submod-1].submodule->notif;
1918 }
1919 in_mod_part = 2;
1920 continue;
1921 }
1922 /* we have searched all the notifications, nothing else to search in this module */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001923 }
1924
Michal Vasko1e989c02015-08-04 12:33:00 +02001925 /* are we done with the included submodules as well? */
1926 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001927 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001928 }
1929
Michal Vasko1e989c02015-08-04 12:33:00 +02001930 /* we aren't, check the next one */
1931 ++in_submod;
1932 in_mod_part = 0;
1933 start = start_mod->inc[in_submod-1].submodule->data;
1934 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001935 }
1936
1937 /* we found our submodule */
1938 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001939 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001940 in_submod = 0;
1941 }
1942
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001943 if ((i = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
1944 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001945 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001946 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001947 }
1948
1949 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001950 LOGINT;
1951 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001952}
1953
Michal Vasko23b61ec2015-08-19 11:19:50 +02001954/* ignores line */
1955static void
1956unres_data_del(struct unres_data *unres, uint32_t i)
1957{
1958 /* there are items after the one deleted */
1959 if (i+1 < unres->count) {
1960 /* we only move the data, memory is left allocated, why bother */
1961 memmove(&unres->dnode[i], &unres->dnode[i+1], (unres->count-(i+1)) * sizeof *unres->dnode);
1962
1963 /* deleting the last item */
1964 } else if (i == 0) {
1965 free(unres->dnode);
1966 unres->dnode = NULL;
1967 }
1968
1969 /* if there are no items after and it is not the last one, just move the counter */
1970 --unres->count;
1971}
1972
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001973/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001974static int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001975resolve_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 +02001976{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001977 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001978 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001979 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001980
Michal Vasko23b61ec2015-08-19 11:19:50 +02001981 if (!parents->count) {
1982 parents->count = 1;
1983 parents->dnode = malloc(sizeof *parents->dnode);
1984 parents->dnode[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001985 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001986 for (i = 0; i < parents->count;) {
1987 if (parents->dnode[i] && (parents->dnode[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001988 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001989 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001990 continue;
1991 }
1992 flag = 0;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001993 LY_TREE_FOR(parents->dnode[i] ? parents->dnode[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001994 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1995 && node->schema->name[nam_len] == '\0') {
1996 /* matching target */
1997 if (!flag) {
1998 /* replace leafref instead of the current parent */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001999 parents->dnode[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002000 flag = 1;
2001 } else {
2002 /* multiple matching, so create new leafref structure */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002003 ++parents->count;
2004 parents->dnode = realloc(parents->dnode, parents->count * sizeof *parents->dnode);
2005 parents->dnode[parents->count-1] = node;
2006 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002007 }
2008 }
2009 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002010
2011 if (!flag) {
2012 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002013 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002014 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002015 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002016 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002017 }
2018
Michal Vasko23b61ec2015-08-19 11:19:50 +02002019 return parents->count ? EXIT_SUCCESS : -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002020}
2021
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002022/**
2023 * @brief Resolve (find) a data node. Does not log.
2024 *
2025 * @param[in] prefix Prefix of the data node.
2026 * @param[in] pref_len Length of the prefix.
2027 * @param[in] name Name of the data node.
2028 * @param[in] nam_len Length of the name.
2029 * @param[in] start Data node to start the search from.
2030 * @param[in,out] parents Resolved nodes. If there are some parents,
2031 * they are replaced (!!) with the resolvents.
2032 *
2033 * @return EXIT_SUCCESS on success, -1 otherwise.
2034 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002035static int
2036resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02002037 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002038{
2039 struct lys_module *mod;
2040
Michal Vasko23b61ec2015-08-19 11:19:50 +02002041 assert(start);
2042
Radek Krejcic5090c32015-08-12 09:46:19 +02002043 if (prefix) {
2044 /* we have prefix, find appropriate module */
2045 mod = resolve_prefixed_module(start->schema->module, prefix, pref_len);
2046 if (!mod) {
2047 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002048 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002049 }
2050 } else {
2051 /* no prefix, module is the same as of current node */
2052 mod = start->schema->module;
2053 }
2054
2055 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002056}
2057
Michal Vasko730dfdf2015-08-11 14:48:05 +02002058/**
Michal Vaskod9173342015-08-17 14:35:36 +02002059 * @brief Resolve a path predicate (leafref) in data context. Logs directly
2060 * only specific errors, general no-resolvent error is left to the caller,
2061 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002062 *
Michal Vaskobb211122015-08-19 14:03:11 +02002063 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002064 * @param[in,out] node_match Nodes satisfying the restriction
2065 * without the predicate. Nodes not
2066 * satisfying the predicate are removed.
2067 * @param[in] line Line in the input file.
2068 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002069 * @return Number of characters successfully parsed,
2070 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002071 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002072static int
Michal Vasko23b61ec2015-08-19 11:19:50 +02002073resolve_path_predicate_data(const char *pred, uint32_t line, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002074{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002075 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002076 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002077 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2078 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
2079 int has_predicate, dest_parent_times, i;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002080 uint32_t j;
2081
2082 source_match.count = 1;
2083 source_match.dnode = malloc(sizeof *source_match.dnode);
2084 dest_match.count = 1;
2085 dest_match.dnode = malloc(sizeof *dest_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002086
2087 do {
2088 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2089 &pke_len, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002090 LOGVAL(LYE_INCHAR, line, pred[-i], &pred[-i]);
2091 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002092 }
2093 parsed += i;
2094 pred += i;
2095
Michal Vasko23b61ec2015-08-19 11:19:50 +02002096 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002097 /* source */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002098 source_match.dnode[0] = node_match->dnode[j];
2099
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002100 /* must be leaf (key of a list) */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002101 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node_match->dnode[j], &source_match)
2102 || (source_match.count != 1) || (source_match.dnode[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002103 /* general error, the one written later will suffice */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002104 LOGVAL(LYE_LINE, line);
2105 i = 0;
2106 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002107 }
2108
2109 /* destination */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002110 dest_match.dnode[0] = node_match->dnode[j];
2111 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002112 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2113 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002114 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002115 return -parsed+i;
2116 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002117 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002118 for (i = 0; i < dest_parent_times; ++i) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002119 dest_match.dnode[0] = dest_match.dnode[0]->parent;
2120 if (!dest_match.dnode[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002121 /* general error, the one written later will suffice */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002122 LOGVAL(LYE_LINE, line);
2123 i = 0;
2124 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002125 }
2126 }
2127 while (1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002128 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match.dnode[0], &dest_match)
2129 || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002130 /* general error, the one written later will suffice */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002131 LOGVAL(LYE_LINE, line);
2132 i = 0;
2133 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 }
2135
2136 if (pke_len == pke_parsed) {
2137 break;
2138 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002139 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 +02002140 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002141 free(dest_match.dnode);
2142 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
2143 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002144 }
2145 pke_parsed += i;
2146 }
2147
2148 /* check match between source and destination nodes */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002149 if (((struct lys_node_leaf *)source_match.dnode[0]->schema)->type.base
2150 != ((struct lys_node_leaf *)dest_match.dnode[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002151 goto remove_leafref;
2152 }
2153
Michal Vasko23b61ec2015-08-19 11:19:50 +02002154 if (((struct lyd_node_leaf *)source_match.dnode[0])->value_str
2155 != ((struct lyd_node_leaf *)dest_match.dnode[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002156 goto remove_leafref;
2157 }
2158
2159 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002160 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002161 continue;
2162
2163remove_leafref:
2164 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002165 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166 }
2167 } while (has_predicate);
2168
Michal Vasko23b61ec2015-08-19 11:19:50 +02002169 free(source_match.dnode);
2170 free(dest_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002171 return parsed;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002172
2173error:
2174
2175 if (source_match.count) {
2176 free(source_match.dnode);
2177 }
2178 if (dest_match.count) {
2179 free(dest_match.dnode);
2180 }
2181 return -parsed+i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002182}
2183
Michal Vasko730dfdf2015-08-11 14:48:05 +02002184/**
2185 * @brief Resolve a path (leafref) in data context. Logs directly.
2186 *
Michal Vasko23b61ec2015-08-19 11:19:50 +02002187 * @param[in] dnode Leafref data node.
2188 * @param[in] path Path of the leafref.
2189 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002190 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002191 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002192 * @return EXIT_SUCCESS on success, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002193 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002194int
Michal Vasko23b61ec2015-08-19 11:19:50 +02002195resolve_path_arg_data(struct lyd_node *dnode, const char *path, uint32_t line, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002196{
Radek Krejci71b795b2015-08-10 16:20:39 +02002197 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002198 const char *prefix, *name;
Michal Vaskod9173342015-08-17 14:35:36 +02002199 int pref_len, nam_len, has_predicate, parent_times, i, parsed;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002200 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201
Michal Vasko23b61ec2015-08-19 11:19:50 +02002202 assert(dnode && path && ret && !ret->count);
2203
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002204 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002205 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002206
2207 /* searching for nodeset */
2208 do {
2209 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002210 LOGVAL(LYE_INCHAR, line, path[-i], &path[-i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002211 goto error;
2212 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002213 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002214 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002215
Michal Vasko23b61ec2015-08-19 11:19:50 +02002216 if (!ret->count) {
2217 ret->count = 1;
2218 ret->dnode = calloc(1, sizeof *ret->dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002219 for (i = 0; i < parent_times; ++i) {
2220 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002221 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002222 /* error, too many .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002223 LOGVAL(LYE_INVAL, line, path, dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224 goto error;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002225 } else if (!ret->dnode[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002226 /* first .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002227 data = ret->dnode[0] = dnode->parent;
2228 } else if (!ret->dnode[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002229 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002230 ret->count = 0;
2231 free(ret->dnode);
2232 ret->dnode = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002233 } else {
2234 /* multiple .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002235 data = ret->dnode[0] = ret->dnode[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002236 }
2237 }
2238
2239 /* absolute path */
2240 if (parent_times == -1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002241 for (data = dnode; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002242 for (; data->prev->next; data = data->prev);
2243 }
2244 }
2245
2246 /* node identifier */
2247 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002248 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002249 goto error;
2250 }
2251
2252 if (has_predicate) {
2253 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002254 for (j = 0; j < ret->count;) {
2255 if (ret->dnode[j]->schema->nodetype == LYS_LIST &&
2256 ((struct lys_node_list *)ret->dnode[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002257 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002258 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002259 continue;
2260 }
2261
2262 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002263 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002264 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002265 if ((i = resolve_path_predicate_data(path, line, ret)) < 1) {
Michal Vaskod9173342015-08-17 14:35:36 +02002266 /* line was already displayed */
2267 LOGVAL(LYE_NORESOLV, 0, path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002268 goto error;
2269 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002270 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002271 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002272
Michal Vasko23b61ec2015-08-19 11:19:50 +02002273 if (!ret->count) {
2274 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002275 goto error;
2276 }
2277 }
2278 } while (path[0] != '\0');
2279
Michal Vaskof02e3742015-08-05 16:27:02 +02002280 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002281
2282error:
2283
Michal Vasko23b61ec2015-08-19 11:19:50 +02002284 free(ret->dnode);
2285 ret->dnode = NULL;
2286 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002287
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002288 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002289}
2290
Michal Vasko730dfdf2015-08-11 14:48:05 +02002291/**
2292 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2293 *
Michal Vaskobb211122015-08-19 14:03:11 +02002294 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002295 * @param[in] mod Schema module.
2296 * @param[in] source_node Left operand node.
2297 * @param[in] dest_node Right ooperand node.
2298 * @param[in] line Line in the input file.
2299 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002300 * @return Number of characters successfully parsed,
2301 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002302 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002303static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002304resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002305 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002306{
2307 struct lys_node *src_node, *dst_node;
2308 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2309 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 +02002310 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002311
2312 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002313 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002314 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002315 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002316 return -parsed+i;
2317 }
2318 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002319 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002320
Michal Vasko58090902015-08-13 14:04:15 +02002321 /* source (must be leaf) */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002322 rc = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
2323 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002324 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002325 return -parsed;
2326 }
2327
2328 /* destination */
2329 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2330 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002331 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002332 return -parsed;
2333 }
2334 pke_parsed += i;
2335
2336 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2337 dst_node = dest_node;
2338 for (i = 1; i < dest_parent_times; ++i) {
2339 dst_node = dst_node->parent;
2340 if (!dst_node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002341 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002342 return -parsed;
2343 }
2344 }
2345 while (1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002346 rc = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2347 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2348 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002349 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002350 return -parsed;
2351 }
2352
2353 if (pke_len == pke_parsed) {
2354 break;
2355 }
2356
2357 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2358 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002359 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002360 return -parsed;
2361 }
2362 pke_parsed += i;
2363 }
2364
2365 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002366 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2367 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskod9173342015-08-17 14:35:36 +02002368 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002369 return -parsed;
2370 }
2371 } while (has_predicate);
2372
2373 return parsed;
2374}
2375
Michal Vasko730dfdf2015-08-11 14:48:05 +02002376/**
Michal Vaskod9173342015-08-17 14:35:36 +02002377 * @brief Resolve a path (leafref) in schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002378 *
Michal Vaskobb211122015-08-19 14:03:11 +02002379 * @param[in] mod Module to use.
2380 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002381 * @param[in] parent_node Parent of the leafref.
2382 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002383 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002384 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002385 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002386 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002387static int
2388resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line,
2389 struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002390{
Michal Vasko58090902015-08-13 14:04:15 +02002391 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002392 const char *id, *prefix, *name;
2393 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002394 int i, first, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002395
2396 first = 1;
2397 parent_times = 0;
2398 id = path;
2399
2400 do {
2401 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002402 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002403 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002404 }
2405 id += i;
2406
2407 if (first) {
2408 if (parent_times == -1) {
2409 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002410 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002411 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002412 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002413 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002414 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002415 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002416 node = parent_node;
2417 i = 0;
2418 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002419 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002420 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002421 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002422 }
Michal Vasko58090902015-08-13 14:04:15 +02002423
2424 /* this node is a wrong node, we actually need the augment target */
2425 if (node->nodetype == LYS_AUGMENT) {
2426 node = ((struct lys_node_augment *)node)->target;
2427 if (!node) {
2428 continue;
2429 }
2430 }
2431
2432 ++i;
2433 if (i == parent_times) {
2434 break;
2435 }
2436 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002437 }
2438 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002439 } else {
2440 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002441 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002442 }
2443 first = 0;
2444 } else {
2445 node = node->child;
2446 }
2447
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002448 rc = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES), &node);
2449 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002450 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002451 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002452 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002453
2454 if (has_predicate) {
2455 /* we have predicate, so the current result must be list */
2456 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002457 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002458 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002459 }
2460
2461 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002462 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002463 }
2464 id += i;
2465 }
2466 } while (id[0]);
2467
Radek Krejcib1c12512015-08-11 11:22:04 +02002468 /* the target must be leaf or leaf-list */
2469 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002470 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002471 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002472 }
2473
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002474 if (ret) {
2475 *ret = node;
2476 }
2477 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002478}
2479
Michal Vasko730dfdf2015-08-11 14:48:05 +02002480/**
2481 * @brief Resolve instance-identifier predicate. Does not log.
2482 *
Michal Vaskobb211122015-08-19 14:03:11 +02002483 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002484 * @param[in,out] node_match Nodes matching the restriction without
2485 * the predicate. Nodes not satisfying
2486 * the predicate are removed.
2487 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002488 * @return Number of characters successfully parsed,
2489 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002490 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002491static int
Michal Vasko1f2cc332015-08-19 11:18:32 +02002492resolve_predicate_json(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002493{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002494 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002495 struct unres_data target_match;
2496 struct ly_ctx *ctx;
2497 struct lys_module *mod;
2498 const char *model, *name, *value;
2499 char *str;
2500 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2501 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002502
Michal Vasko1f2cc332015-08-19 11:18:32 +02002503 assert(pred && node_match->count);
2504
2505 ctx = node_match->dnode[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002506 idx = -1;
2507 parsed = 0;
2508
2509 do {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002510 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 +02002511 return -parsed+i;
2512 }
2513 parsed += i;
2514 pred += i;
2515
Michal Vasko1f2cc332015-08-19 11:18:32 +02002516 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002517 if (isdigit(name[0])) {
2518 idx = atoi(name);
2519 }
2520
Michal Vasko1f2cc332015-08-19 11:18:32 +02002521 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002522 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002523 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002524 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002525 target_match.count = 1;
2526 target_match.dnode = malloc(sizeof *target_match.dnode);
2527 target_match.dnode[0] = node_match->dnode[j];
2528 } else {
2529 str = strndup(model, mod_len);
2530 mod = ly_ctx_get_module(ctx, str, NULL);
2531 free(str);
2532
2533 if (resolve_data(mod, name, nam_len, node_match->dnode[j], &target_match)) {
2534 goto remove_instid;
2535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002536 }
2537
2538 /* check that we have the correct type */
2539 if (name[0] == '.') {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002540 if (node_match->dnode[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002541 goto remove_instid;
2542 }
2543 } else if (value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002544 if (node_match->dnode[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002545 goto remove_instid;
2546 }
2547 }
2548
Michal Vasko1f2cc332015-08-19 11:18:32 +02002549 if ((value && (strncmp(((struct lyd_node_leaf *)target_match.dnode[0])->value_str, value, val_len)
2550 || ((struct lyd_node_leaf *)target_match.dnode[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002551 || (!value && (idx != cur_idx))) {
2552 goto remove_instid;
2553 }
2554
Michal Vasko1f2cc332015-08-19 11:18:32 +02002555 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002556
2557 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002558 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002559 continue;
2560
2561remove_instid:
Michal Vasko1f2cc332015-08-19 11:18:32 +02002562 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002563
2564 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002565 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002566 }
2567 } while (has_predicate);
2568
2569 return parsed;
2570}
2571
Michal Vasko730dfdf2015-08-11 14:48:05 +02002572/**
2573 * @brief Resolve instance-identifier. Logs directly.
2574 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002575 * @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 +02002576 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002577 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002578 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002579 * @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 +02002580 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002581struct lyd_node *
Michal Vasko1f2cc332015-08-19 11:18:32 +02002582resolve_instid_json(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002583{
Radek Krejcic5090c32015-08-12 09:46:19 +02002584 int i = 0, j;
2585 struct lyd_node *result = NULL;
2586 struct lys_module *mod = NULL;
2587 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002588 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002589 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002590 int mod_len, name_len, has_predicate;
2591 struct unres_data node_match;
2592 uint32_t k;
2593
2594 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002595
Radek Krejcic5090c32015-08-12 09:46:19 +02002596 /* we need root to resolve absolute path */
2597 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002598 for (; data->prev->next; data = data->prev);
2599
Radek Krejcic5090c32015-08-12 09:46:19 +02002600 /* search for the instance node */
2601 while (path[i]) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002602 j = parse_instance_identifier_json(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002603 if (j <= 0) {
2604 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002605 goto error;
2606 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002607 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002608
Michal Vasko1f2cc332015-08-19 11:18:32 +02002609 str = strndup(model, mod_len);
2610 mod = ly_ctx_get_module(ctx, str, NULL);
2611 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002612
Radek Krejcic5090c32015-08-12 09:46:19 +02002613 if (!mod) {
2614 /* no instance exists */
2615 return NULL;
2616 }
2617
Michal Vasko1f2cc332015-08-19 11:18:32 +02002618 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002619 /* no instance exists */
2620 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621 }
2622
2623 if (has_predicate) {
2624 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002625 for (k = 0; k < node_match.count;) {
2626 if ((node_match.dnode[k]->schema->nodetype == LYS_LIST &&
2627 ((struct lys_node_list *)node_match.dnode[k]->schema)->keys)
2628 || (node_match.dnode[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002629 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002630 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002631 continue;
2632 }
2633
2634 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002635 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002636 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002637
Michal Vasko1f2cc332015-08-19 11:18:32 +02002638 j = resolve_predicate_json(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002639 if (j < 1) {
2640 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641 goto error;
2642 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002643 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002644
Michal Vasko1f2cc332015-08-19 11:18:32 +02002645 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002646 /* no instance exists */
2647 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002648 }
2649 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002650 }
2651
Michal Vasko1f2cc332015-08-19 11:18:32 +02002652 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002653 /* no instance exists */
2654 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002655 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002656 /* instance identifier must resolve to a single node */
2657 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2658
2659 /* cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002660 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002661
2662 return NULL;
2663 } else {
2664 /* we have required result, remember it and cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002665 result = node_match.dnode[0];
2666 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002667
2668 return result;
2669 }
2670
2671error:
2672
2673 /* cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002674 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002675
2676 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002677}
2678
Michal Vasko730dfdf2015-08-11 14:48:05 +02002679/**
2680 * @brief Passes config flag down to children. Does not log.
2681 *
2682 * @param[in] node Parent node.
2683 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002684static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002685inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002686{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002687 LY_TREE_FOR(node, node) {
2688 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2689 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002690 }
2691}
2692
Michal Vasko730dfdf2015-08-11 14:48:05 +02002693/**
Michal Vaskod9173342015-08-17 14:35:36 +02002694 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002695 *
Michal Vaskobb211122015-08-19 14:03:11 +02002696 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002697 * @param[in] siblings Nodes where to start the search in.
2698 * @param[in] module Main module.
2699 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002700 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002701 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002702int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002703resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002704{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002705 int rc;
Radek Krejci76512572015-08-04 09:47:08 +02002706 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002707
2708 assert(module);
2709
2710 /* resolve target node */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002711 rc = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT, &aug->target);
2712 if (rc) {
2713 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002714 }
2715
2716 if (!aug->child) {
2717 /* nothing to do */
2718 return EXIT_SUCCESS;
2719 }
2720
2721 /* inherit config information from parent, augment does not have
2722 * config property, but we need to keep the information for subelements
2723 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002724 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002725 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002726 inherit_config_flag(sub);
2727 }
2728
Radek Krejci07911992015-08-14 15:13:31 +02002729 /* check identifier uniquness as in lys_node_addchild() */
2730 LY_TREE_FOR(aug->child, aux) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002731 if (lys_check_id(aux, aug->parent, module)) {
2732 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002733 }
2734 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002735 /* reconnect augmenting data into the target - add them to the target child list */
2736 if (aug->target->child) {
2737 aux = aug->target->child->prev; /* remember current target's last node */
2738 aux->next = aug->child; /* connect augmenting data after target's last node */
2739 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2740 aug->child->prev = aux; /* finish connecting of both child lists */
2741 } else {
2742 aug->target->child = aug->child;
2743 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002744
2745 return EXIT_SUCCESS;
2746}
2747
Michal Vasko730dfdf2015-08-11 14:48:05 +02002748/**
2749 * @brief Resolve uses, apply augments, refines. Logs directly.
2750 *
Michal Vaskobb211122015-08-19 14:03:11 +02002751 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002752 * @param[in,out] unres List of unresolved items.
2753 * @param[in] line Line in the input file.
2754 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002755 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward ereference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002756 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002757int
Michal Vaskof02e3742015-08-05 16:27:02 +02002758resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002759{
2760 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002761 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002762 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002763 struct lys_restr *newmust;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002764 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002765 uint8_t size;
2766
Michal Vasko71e1aa82015-08-12 12:17:51 +02002767 assert(uses->grp);
2768
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002769 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002770 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002771 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002772 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002773 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002774 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002775 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002776 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002777 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002778 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002779 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780 }
2781 }
2782 ctx = uses->module->ctx;
2783
2784 /* apply refines */
2785 for (i = 0; i < uses->refine_size; i++) {
2786 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002787 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2788 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002789 if (rc == -1) {
2790 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2791 } else {
2792 LOGVAL(LYE_NORESOLV, line, rfn->target_name);
2793 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002794 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002795 }
2796
Radek Krejci1d82ef62015-08-07 14:44:40 +02002797 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002798 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 }
2801
2802 /* description on any nodetype */
2803 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002804 lydict_remove(ctx, node->dsc);
2805 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002806 }
2807
2808 /* reference on any nodetype */
2809 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002810 lydict_remove(ctx, node->ref);
2811 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002812 }
2813
2814 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002815 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002816 node->flags &= ~LYS_CONFIG_MASK;
2817 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002818 }
2819
2820 /* default value ... */
2821 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002822 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002824 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2825 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2826 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002828 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2829 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002830 if (rc == -1) {
2831 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2832 } else {
2833 LOGVAL(LYE_NORESOLV, line, rfn->mod.dflt);
2834 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002835 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002836 }
2837 }
2838 }
2839
2840 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002841 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002842 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002843 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002844 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002845
2846 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002847 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 }
2849 }
2850
2851 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002852 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2853 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2854 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002855 }
2856
2857 /* min/max-elements on list or leaf-list */
2858 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002859 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002861 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 }
2863 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002864 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002866 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002867 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002868 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002869 }
2870 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002871 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872 }
2873 }
2874
2875 /* must in leaf, leaf-list, list, container or anyxml */
2876 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002877 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2878 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 if (!newmust) {
2880 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002881 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002882 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002883 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2885 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2886 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2887 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2888 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2889 }
2890
Radek Krejci1d82ef62015-08-07 14:44:40 +02002891 ((struct lys_node_leaf *)node)->must = newmust;
2892 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002893 }
2894 }
2895
2896 /* apply augments */
2897 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002898 rc = resolve_augment(&uses->augment[i], uses->child, uses->module);
2899 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002900 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002901 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002902 }
2903 }
2904
2905 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906}
2907
Michal Vasko730dfdf2015-08-11 14:48:05 +02002908/**
2909 * @brief Resolve base identity recursively. Does not log.
2910 *
2911 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002912 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002913 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002914 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002915 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002916 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002917 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002918static int
2919resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2920 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002921{
Michal Vaskof02e3742015-08-05 16:27:02 +02002922 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002923 struct lys_ident *base_iter = NULL;
2924 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002925
2926 /* search module */
2927 for (i = 0; i < module->ident_size; i++) {
2928 if (!strcmp(basename, module->ident[i].name)) {
2929
2930 if (!ident) {
2931 /* just search for type, so do not modify anything, just return
2932 * the base identity pointer
2933 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002934 if (ret) {
2935 *ret = &module->ident[i];
2936 }
2937 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002938 }
2939
2940 /* we are resolving identity definition, so now update structures */
2941 ident->base = base_iter = &module->ident[i];
2942
2943 break;
2944 }
2945 }
2946
2947 /* search submodules */
2948 if (!base_iter) {
2949 for (j = 0; j < module->inc_size; j++) {
2950 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2951 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2952
2953 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002954 if (ret) {
2955 *ret = &module->inc[j].submodule->ident[i];
2956 }
2957 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002958 }
2959
2960 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2961 break;
2962 }
2963 }
2964 }
2965 }
2966
2967 /* we found it somewhere */
2968 if (base_iter) {
2969 while (base_iter) {
2970 for (der = base_iter->der; der && der->next; der = der->next);
2971 if (der) {
2972 der->next = malloc(sizeof *der);
2973 der = der->next;
2974 } else {
2975 ident->base->der = der = malloc(sizeof *der);
2976 }
2977 der->next = NULL;
2978 der->ident = ident;
2979
2980 base_iter = base_iter->base;
2981 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002982 if (ret) {
2983 *ret = ident->base;
2984 }
2985 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986 }
2987
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002988 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002989}
2990
Michal Vasko730dfdf2015-08-11 14:48:05 +02002991/**
2992 * @brief Resolve base identity. Logs directly.
2993 *
2994 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002995 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002996 * @param[in] basename Base name of the identity.
2997 * @param[in] parent Either "type" or "ident".
2998 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002999 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003000 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003001 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003002 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003003static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003004resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003005 uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003006{
3007 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02003008 int i, prefix_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003009
3010 /* search for the base identity */
3011 name = strchr(basename, ':');
3012 if (name) {
3013 /* set name to correct position after colon */
3014 prefix_len = name - basename;
3015 name++;
3016
3017 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3018 /* prefix refers to the current module, ignore it */
3019 prefix_len = 0;
3020 }
3021 } else {
3022 name = basename;
3023 }
3024
3025 if (prefix_len) {
3026 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003027 module = resolve_prefixed_module(module, basename, prefix_len);
3028 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003029 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003030 LOGVAL(LYE_INPREF, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003031 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003032 }
3033 } else {
3034 /* search in submodules */
3035 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003036 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3037 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003038 }
3039 }
3040 }
3041
3042 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003043 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3044 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003045 }
3046
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003047 LOGVAL(LYE_INARG, line, basename, parent);
3048 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003049}
3050
Michal Vasko730dfdf2015-08-11 14:48:05 +02003051/**
3052 * @brief Resolve identityref. Does not log.
3053 *
3054 * @param[in] base Base identity.
3055 * @param[in] name Identityref name.
3056 * @param[in] ns Namespace of the identityref.
3057 *
3058 * @return Pointer to the identity resolvent, NULL on error.
3059 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003060struct lys_ident *
3061resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003062{
Radek Krejcia52656e2015-08-05 13:41:50 +02003063 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003064
3065 if (!base || !name || !ns) {
3066 return NULL;
3067 }
3068
3069 for(der = base->der; der; der = der->next) {
3070 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3071 /* we have match */
3072 return der->ident;
3073 }
3074 }
3075
3076 /* not found */
3077 return NULL;
3078}
3079
Michal Vasko730dfdf2015-08-11 14:48:05 +02003080/**
Michal Vaskobb211122015-08-19 14:03:11 +02003081 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003082 *
Michal Vaskobb211122015-08-19 14:03:11 +02003083 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003084 * @param[in] unres Specific unres item.
3085 * @param[in] line Line in the input file.
3086 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003087 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003088 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003089static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003090resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003091{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003093 struct lys_node *parent;
3094
3095 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3096 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3097
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003098 if (!uses->grp) {
3099 rc = resolve_grouping(uses, line);
3100 if (rc) {
3101 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003102 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003103 }
3104
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003105 if (uses->grp->nacm) {
3106 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3107 return EXIT_FAILURE;
3108 }
3109
3110 rc = resolve_uses(uses, unres, line);
3111 if (!rc) {
3112 /* decrease unres count only if not first try */
3113 if ((line < UINT_MAX) && parent) {
3114 if (!parent->nacm) {
3115 LOGINT;
3116 return -1;
3117 }
3118 --parent->nacm;
3119 }
3120 return EXIT_SUCCESS;
3121 }
3122
3123 if ((rc == EXIT_FAILURE) && parent) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003124 ++parent->nacm;
3125 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003126 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127}
3128
Michal Vasko730dfdf2015-08-11 14:48:05 +02003129/**
Michal Vasko9957e592015-08-17 15:04:09 +02003130 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003131 *
Michal Vaskobb211122015-08-19 14:03:11 +02003132 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003133 * @param[in] keys_str Keys node value.
3134 * @param[in] line Line in the input file.
3135 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003136 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003137 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138static int
Michal Vasko9957e592015-08-17 15:04:09 +02003139resolve_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 +02003140{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003141 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003142 const char *value;
3143
3144 for (i = 0; i < list->keys_size; ++i) {
3145 /* get the key name */
3146 if ((value = strpbrk(keys_str, " \t\n"))) {
3147 len = value - keys_str;
3148 while (isspace(value[0])) {
3149 value++;
3150 }
3151 } else {
3152 len = strlen(keys_str);
3153 }
3154
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003155 rc = resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
3156 if (rc) {
3157 if (rc == EXIT_FAILURE) {
3158 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3159 }
3160 return rc;
3161 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003163 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003164 /* check_key logs */
3165 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166 }
3167
3168 /* prepare for next iteration */
3169 while (value && isspace(value[0])) {
3170 value++;
3171 }
3172 keys_str = value;
3173 }
3174
Michal Vaskof02e3742015-08-05 16:27:02 +02003175 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003176}
3177
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003178/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003180resolve_unres_schema_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003181{
3182 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003183 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184}
3185
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003186/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003188resolve_unres_schema_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003189{
3190 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003191 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003192}
3193
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003194/**
Michal Vaskobb211122015-08-19 14:03:11 +02003195 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003196 *
3197 * @param[in] mod Main module.
3198 * @param[in] item Item to resolve. Type determined by \p type.
3199 * @param[in] type Type of the unresolved item.
3200 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003201 * @param[in] unres Unres schema structure to use.
3202 * @param[in] line Line in the input file. UINT_MAX turns logging off, 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003203 *
3204 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3205 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003206static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003207resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003208 struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003210 int rc = -1, has_str = 0;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003211 struct lys_node *snode;
3212 const char *base_name;
3213
3214 struct lys_ident *ident;
3215 struct lys_type *stype;
3216 struct lys_feature **feat_ptr;
3217 struct lys_node_choice *choic;
3218 struct lys_unique *uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003219
3220 switch (type) {
3221 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003222 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003223 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003224 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003225 base_name = str_snode;
3226 ident = item;
3227
3228 rc = resolve_base_ident(mod, ident, base_name, "ident", line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 has_str = 1;
3230 break;
3231 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003232 base_name = str_snode;
3233 stype = item;
3234
3235 rc = resolve_base_ident(mod, NULL, base_name, "type", line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003236 has_str = 1;
3237 break;
3238 case UNRES_TYPE_LEAFREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003239 snode = str_snode;
3240 stype = item;
3241
3242 rc = resolve_path_arg_schema(mod, stype->info.lref.path, snode, line,
3243 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003244 has_str = 0;
3245 break;
3246 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003247 base_name = str_snode;
3248 stype = item;
3249
3250 /* HACK type->der is temporarily its parent */
3251 rc = resolve_superior_type(base_name, stype->prefix, mod, (struct lys_node *)stype->der, &stype->der);
3252 if (!rc) {
3253 stype->base = stype->der->type.base;
3254 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255 has_str = 1;
3256 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003258 base_name = str_snode;
3259 feat_ptr = item;
3260
3261 rc = resolve_feature(base_name, mod, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 has_str = 1;
3263 break;
3264 case UNRES_USES:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003265 rc = resolve_unres_schema_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 has_str = 0;
3267 break;
3268 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003269 base_name = str_snode;
3270 stype = item;
3271
3272 rc = check_default(stype, base_name);
3273 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003274 has_str = 0;
3275 break;
3276 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003277 base_name = str_snode;
3278 choic = item;
3279
3280 rc = resolve_sibling(mod, choic->child, NULL, 0, base_name, 0, LYS_ANYXML | LYS_CASE
3281 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST, &choic->dflt);
3282 /* there is no prefix, that is the only error */
3283 assert(rc != -1);
3284 if (rc == EXIT_FAILURE) {
3285 LOGVAL(LYE_INRESOLV, line, "choice default", base_name);
3286 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003287 has_str = 1;
3288 break;
3289 case UNRES_LIST_KEYS:
Michal Vasko9957e592015-08-17 15:04:09 +02003290 rc = resolve_list_keys(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 has_str = 1;
3292 break;
3293 case UNRES_LIST_UNIQ:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003294 /* actually the unique string */
3295 base_name = str_snode;
3296 uniq = item;
3297
3298 rc = resolve_unique((struct lys_node *)uniq->leafs, base_name, uniq, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 has_str = 1;
3300 break;
3301 case UNRES_WHEN:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003302 rc = resolve_unres_schema_when(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303 has_str = 0;
3304 break;
3305 case UNRES_MUST:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003306 rc = resolve_unres_schema_must(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003307 has_str = 0;
3308 break;
3309 }
3310
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003311 if (has_str && !rc) {
3312 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003313 }
3314
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003315 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003316}
3317
Michal Vaskof02e3742015-08-05 16:27:02 +02003318/* logs directly */
3319static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003320print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003321{
Michal Vaskof02e3742015-08-05 16:27:02 +02003322 char line_str[18];
3323
3324 if (line) {
3325 sprintf(line_str, " (line %u)", line);
3326 } else {
3327 line_str[0] = '\0';
3328 }
3329
3330 switch (type) {
3331 case UNRES_RESOLVED:
3332 LOGINT;
3333 break;
3334 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003335 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003336 break;
3337 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003338 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003339 break;
3340 case UNRES_TYPE_LEAFREF:
3341 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3342 break;
3343 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003344 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 +02003345 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003346 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003347 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 +02003348 break;
3349 case UNRES_USES:
3350 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3351 break;
3352 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003353 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 +02003354 break;
3355 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003356 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 +02003357 break;
3358 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003359 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 +02003360 break;
3361 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003362 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 +02003363 break;
3364 case UNRES_WHEN:
3365 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3366 break;
3367 case UNRES_MUST:
3368 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3369 break;
3370 }
3371}
3372
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003373/**
Michal Vaskobb211122015-08-19 14:03:11 +02003374 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003375 *
3376 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003377 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003378 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003379 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003380 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003381int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003382resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003383{
Michal Vasko1c4e0ef2015-08-19 11:19:28 +02003384 uint32_t i, resolved, unres_uses, res_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003385 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003386
3387 assert(unres);
3388
Michal Vasko51054ca2015-08-12 12:20:00 +02003389 resolved = 0;
3390
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003392 do {
3393 unres_uses = 0;
3394 res_uses = 0;
3395
3396 for (i = 0; i < unres->count; ++i) {
3397 if (unres->type[i] != UNRES_USES) {
3398 continue;
3399 }
3400
3401 ++unres_uses;
Michal Vasko0bd29d12015-08-19 11:45:49 +02003402 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003404 unres->type[i] = UNRES_RESOLVED;
3405 ++resolved;
3406 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003407 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003408 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003409 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003411 } while (res_uses && (res_uses < unres_uses));
3412
3413 if (res_uses < unres_uses) {
3414 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003415 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003416 }
3417
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 /* the rest */
3419 for (i = 0; i < unres->count; ++i) {
3420 if (unres->type[i] == UNRES_RESOLVED) {
3421 continue;
3422 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003423
Michal Vasko0bd29d12015-08-19 11:45:49 +02003424 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003425 if (!rc) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 unres->type[i] = UNRES_RESOLVED;
3427 ++resolved;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003428 } else if (rc == -1) {
3429 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003430 }
3431 }
3432
3433 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003434 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3435 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003436 }
3437
3438 return EXIT_SUCCESS;
3439}
3440
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003441/**
Michal Vaskobb211122015-08-19 14:03:11 +02003442 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003443 *
3444 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003445 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003446 * @param[in] item Item to resolve. Type determined by \p type.
3447 * @param[in] type Type of the unresolved item.
3448 * @param[in] str String argument.
3449 * @param[in] line Line in the input file.
3450 *
3451 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3452 */
3453int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003454unres_schema_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 +02003455 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456{
3457 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003458 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003459}
3460
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003461/**
Michal Vaskobb211122015-08-19 14:03:11 +02003462 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003463 *
3464 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003465 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003466 * @param[in] item Item to resolve. Type determined by \p type.
3467 * @param[in] type Type of the unresolved item.
3468 * @param[in] snode Schema node argument.
3469 * @param[in] line Line in the input file.
3470 *
3471 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3472 */
3473int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003474unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003475 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003477 int rc;
3478
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479 assert(unres && item);
3480
Michal Vasko0bd29d12015-08-19 11:45:49 +02003481 rc = resolve_unres_schema_item(mod, item, type, snode, unres, UINT_MAX);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003482 if (rc != EXIT_FAILURE) {
3483 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484 }
3485
Michal Vasko0bd29d12015-08-19 11:45:49 +02003486 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003487
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003488 unres->count++;
3489 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3490 unres->item[unres->count-1] = item;
3491 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3492 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003493 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003494 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003495#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003496 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3497 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003498#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003499
3500 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501}
3502
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003503/**
Michal Vaskobb211122015-08-19 14:03:11 +02003504 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003505 *
3506 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003507 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 * @param[in] item Old item to be resolved.
3509 * @param[in] type Type of the old unresolved item.
3510 * @param[in] new_item New item to use in the duplicate.
3511 *
3512 * @return EXIT_SUCCESS on success, -1 on error.
3513 */
Michal Vaskodad19402015-08-06 09:51:53 +02003514int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003515unres_schema_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 +02003516{
3517 int i;
3518
3519 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003520 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003521 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 }
3523
Michal Vasko0bd29d12015-08-19 11:45:49 +02003524 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003525
3526 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003527 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 }
3529
Michal Vasko4adc10f2015-08-11 15:26:17 +02003530 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003531 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003532 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003533 LOGINT;
3534 return -1;
3535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003537 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003538 LOGINT;
3539 return -1;
3540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 }
Michal Vaskodad19402015-08-06 09:51:53 +02003542
3543 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544}
3545
Michal Vaskof02e3742015-08-05 16:27:02 +02003546/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003548unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549{
3550 uint32_t ret = -1, i;
3551
3552 for (i = 0; i < unres->count; ++i) {
3553 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3554 ret = i;
3555 break;
3556 }
3557 }
3558
3559 return ret;
3560}