blob: 9efdf31753291867011021b5467691321b580cc0 [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) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002217 if (parent_times != -1) {
2218 ret->count = 1;
2219 ret->dnode = calloc(1, sizeof *ret->dnode);
2220 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002221 for (i = 0; i < parent_times; ++i) {
2222 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002223 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224 /* error, too many .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002225 LOGVAL(LYE_INVAL, line, path, dnode->schema->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002226 goto error;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002227 } else if (!ret->dnode[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002228 /* first .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002229 data = ret->dnode[0] = dnode->parent;
2230 } else if (!ret->dnode[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002231 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002232 ret->count = 0;
2233 free(ret->dnode);
2234 ret->dnode = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002235 } else {
2236 /* multiple .. */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002237 data = ret->dnode[0] = ret->dnode[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002238 }
2239 }
2240
2241 /* absolute path */
2242 if (parent_times == -1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002243 for (data = dnode; data->parent; data = data->parent);
Michal Vasko8bcdf292015-08-19 14:04:43 +02002244 /* TODO (may change!) we're still parsing it and the pointer is not correct yet */
2245 if (data->prev) {
2246 for (; data->prev->next; data = data->prev);
2247 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002248 }
2249 }
2250
2251 /* node identifier */
2252 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002253 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002254 goto error;
2255 }
2256
2257 if (has_predicate) {
2258 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002259 for (j = 0; j < ret->count;) {
2260 if (ret->dnode[j]->schema->nodetype == LYS_LIST &&
2261 ((struct lys_node_list *)ret->dnode[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002262 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002263 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002264 continue;
2265 }
2266
2267 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002268 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002269 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002270 if ((i = resolve_path_predicate_data(path, line, ret)) < 1) {
Michal Vaskod9173342015-08-17 14:35:36 +02002271 /* line was already displayed */
2272 LOGVAL(LYE_NORESOLV, 0, path);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002273 goto error;
2274 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002275 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002276 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002277
Michal Vasko23b61ec2015-08-19 11:19:50 +02002278 if (!ret->count) {
2279 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002280 goto error;
2281 }
2282 }
2283 } while (path[0] != '\0');
2284
Michal Vaskof02e3742015-08-05 16:27:02 +02002285 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002286
2287error:
2288
Michal Vasko23b61ec2015-08-19 11:19:50 +02002289 free(ret->dnode);
2290 ret->dnode = NULL;
2291 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002292
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002293 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002294}
2295
Michal Vasko730dfdf2015-08-11 14:48:05 +02002296/**
2297 * @brief Resolve a path (leafref) predicate in schema context. Logs directly.
2298 *
Michal Vaskobb211122015-08-19 14:03:11 +02002299 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002300 * @param[in] mod Schema module.
2301 * @param[in] source_node Left operand node.
2302 * @param[in] dest_node Right ooperand node.
2303 * @param[in] line Line in the input file.
2304 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002305 * @return Number of characters successfully parsed,
2306 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002307 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002308static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002309resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vaskof02e3742015-08-05 16:27:02 +02002310 struct lys_node *dest_node, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002311{
2312 struct lys_node *src_node, *dst_node;
2313 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2314 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 +02002315 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002316
2317 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002318 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002319 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002320 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002321 return -parsed+i;
2322 }
2323 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002324 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002325
Michal Vasko58090902015-08-13 14:04:15 +02002326 /* source (must be leaf) */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002327 rc = resolve_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
2328 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002329 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002330 return -parsed;
2331 }
2332
2333 /* destination */
2334 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2335 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002336 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002337 return -parsed;
2338 }
2339 pke_parsed += i;
2340
2341 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2342 dst_node = dest_node;
2343 for (i = 1; i < dest_parent_times; ++i) {
2344 dst_node = dst_node->parent;
2345 if (!dst_node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002346 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002347 return -parsed;
2348 }
2349 }
2350 while (1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002351 rc = resolve_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2352 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2353 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002354 LOGVAL(LYE_NORESOLV, line, path_key_expr);
Michal Vasko1f76a282015-08-04 16:16:53 +02002355 return -parsed;
2356 }
2357
2358 if (pke_len == pke_parsed) {
2359 break;
2360 }
2361
2362 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2363 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002364 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002365 return -parsed;
2366 }
2367 pke_parsed += i;
2368 }
2369
2370 /* check source - dest match */
Radek Krejcib8048692015-08-05 13:36:34 +02002371 if ((dst_node->nodetype != LYS_LEAF) || ((struct lys_node_leaf *)dst_node)->type.base
2372 != ((struct lys_node_leaf *)src_node)->type.base) {
Michal Vaskod9173342015-08-17 14:35:36 +02002373 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko1f76a282015-08-04 16:16:53 +02002374 return -parsed;
2375 }
2376 } while (has_predicate);
2377
2378 return parsed;
2379}
2380
Michal Vasko730dfdf2015-08-11 14:48:05 +02002381/**
Michal Vaskod9173342015-08-17 14:35:36 +02002382 * @brief Resolve a path (leafref) in schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002383 *
Michal Vaskobb211122015-08-19 14:03:11 +02002384 * @param[in] mod Module to use.
2385 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002386 * @param[in] parent_node Parent of the leafref.
2387 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002388 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002389 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002390 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002391 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002392static int
2393resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, uint32_t line,
2394 struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002395{
Michal Vasko58090902015-08-13 14:04:15 +02002396 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002397 const char *id, *prefix, *name;
2398 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002399 int i, first, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002400
2401 first = 1;
2402 parent_times = 0;
2403 id = path;
2404
2405 do {
2406 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002407 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002408 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002409 }
2410 id += i;
2411
2412 if (first) {
2413 if (parent_times == -1) {
2414 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002415 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002416 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002417 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002418 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002419 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002420 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002421 node = parent_node;
2422 i = 0;
2423 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002424 if (!node) {
Michal Vaskod9173342015-08-17 14:35:36 +02002425 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002426 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002427 }
Michal Vasko58090902015-08-13 14:04:15 +02002428
2429 /* this node is a wrong node, we actually need the augment target */
2430 if (node->nodetype == LYS_AUGMENT) {
2431 node = ((struct lys_node_augment *)node)->target;
2432 if (!node) {
2433 continue;
2434 }
2435 }
2436
2437 ++i;
2438 if (i == parent_times) {
2439 break;
2440 }
2441 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002442 }
2443 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002444 } else {
2445 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002446 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002447 }
2448 first = 0;
2449 } else {
2450 node = node->child;
2451 }
2452
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002453 rc = resolve_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_GROUPING | LYS_USES), &node);
2454 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002455 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002456 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002457 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002458
2459 if (has_predicate) {
2460 /* we have predicate, so the current result must be list */
2461 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002462 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002463 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002464 }
2465
2466 if ((i = resolve_path_predicate_schema(id, mod, node, parent_node, line)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002467 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002468 }
2469 id += i;
2470 }
2471 } while (id[0]);
2472
Radek Krejcib1c12512015-08-11 11:22:04 +02002473 /* the target must be leaf or leaf-list */
2474 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002475 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002476 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002477 }
2478
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002479 if (ret) {
2480 *ret = node;
2481 }
2482 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002483}
2484
Michal Vasko730dfdf2015-08-11 14:48:05 +02002485/**
2486 * @brief Resolve instance-identifier predicate. Does not log.
2487 *
Michal Vaskobb211122015-08-19 14:03:11 +02002488 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002489 * @param[in,out] node_match Nodes matching the restriction without
2490 * the predicate. Nodes not satisfying
2491 * the predicate are removed.
2492 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002493 * @return Number of characters successfully parsed,
2494 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002495 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002496static int
Michal Vasko1f2cc332015-08-19 11:18:32 +02002497resolve_predicate_json(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002498{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002499 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002500 struct unres_data target_match;
2501 struct ly_ctx *ctx;
2502 struct lys_module *mod;
2503 const char *model, *name, *value;
2504 char *str;
2505 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2506 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002507
Michal Vasko1f2cc332015-08-19 11:18:32 +02002508 assert(pred && node_match->count);
2509
2510 ctx = node_match->dnode[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002511 idx = -1;
2512 parsed = 0;
2513
2514 do {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002515 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 +02002516 return -parsed+i;
2517 }
2518 parsed += i;
2519 pred += i;
2520
Michal Vasko1f2cc332015-08-19 11:18:32 +02002521 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002522 if (isdigit(name[0])) {
2523 idx = atoi(name);
2524 }
2525
Michal Vasko1f2cc332015-08-19 11:18:32 +02002526 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002527 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002528 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002529 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002530 target_match.count = 1;
2531 target_match.dnode = malloc(sizeof *target_match.dnode);
2532 target_match.dnode[0] = node_match->dnode[j];
2533 } else {
2534 str = strndup(model, mod_len);
2535 mod = ly_ctx_get_module(ctx, str, NULL);
2536 free(str);
2537
2538 if (resolve_data(mod, name, nam_len, node_match->dnode[j], &target_match)) {
2539 goto remove_instid;
2540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002541 }
2542
2543 /* check that we have the correct type */
2544 if (name[0] == '.') {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002545 if (node_match->dnode[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002546 goto remove_instid;
2547 }
2548 } else if (value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002549 if (node_match->dnode[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002550 goto remove_instid;
2551 }
2552 }
2553
Michal Vasko1f2cc332015-08-19 11:18:32 +02002554 if ((value && (strncmp(((struct lyd_node_leaf *)target_match.dnode[0])->value_str, value, val_len)
2555 || ((struct lyd_node_leaf *)target_match.dnode[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002556 || (!value && (idx != cur_idx))) {
2557 goto remove_instid;
2558 }
2559
Michal Vasko1f2cc332015-08-19 11:18:32 +02002560 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561
2562 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002563 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002564 continue;
2565
2566remove_instid:
Michal Vasko1f2cc332015-08-19 11:18:32 +02002567 free(target_match.dnode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002568
2569 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002570 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002571 }
2572 } while (has_predicate);
2573
2574 return parsed;
2575}
2576
Michal Vasko730dfdf2015-08-11 14:48:05 +02002577/**
2578 * @brief Resolve instance-identifier. Logs directly.
2579 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002580 * @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 +02002581 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002582 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002583 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002584 * @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 +02002585 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002586struct lyd_node *
Michal Vasko1f2cc332015-08-19 11:18:32 +02002587resolve_instid_json(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002588{
Radek Krejcic5090c32015-08-12 09:46:19 +02002589 int i = 0, j;
2590 struct lyd_node *result = NULL;
2591 struct lys_module *mod = NULL;
2592 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002593 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002594 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002595 int mod_len, name_len, has_predicate;
2596 struct unres_data node_match;
2597 uint32_t k;
2598
2599 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002600
Radek Krejcic5090c32015-08-12 09:46:19 +02002601 /* we need root to resolve absolute path */
2602 for (; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002603 for (; data->prev->next; data = data->prev);
2604
Radek Krejcic5090c32015-08-12 09:46:19 +02002605 /* search for the instance node */
2606 while (path[i]) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002607 j = parse_instance_identifier_json(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002608 if (j <= 0) {
2609 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002610 goto error;
2611 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002612 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002613
Michal Vasko1f2cc332015-08-19 11:18:32 +02002614 str = strndup(model, mod_len);
2615 mod = ly_ctx_get_module(ctx, str, NULL);
2616 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002617
Radek Krejcic5090c32015-08-12 09:46:19 +02002618 if (!mod) {
2619 /* no instance exists */
2620 return NULL;
2621 }
2622
Michal Vasko1f2cc332015-08-19 11:18:32 +02002623 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002624 /* no instance exists */
2625 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002626 }
2627
2628 if (has_predicate) {
2629 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002630 for (k = 0; k < node_match.count;) {
2631 if ((node_match.dnode[k]->schema->nodetype == LYS_LIST &&
2632 ((struct lys_node_list *)node_match.dnode[k]->schema)->keys)
2633 || (node_match.dnode[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002634 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002635 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002636 continue;
2637 }
2638
2639 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002640 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002642
Michal Vasko1f2cc332015-08-19 11:18:32 +02002643 j = resolve_predicate_json(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002644 if (j < 1) {
2645 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002646 goto error;
2647 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002648 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002649
Michal Vasko1f2cc332015-08-19 11:18:32 +02002650 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002651 /* no instance exists */
2652 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002653 }
2654 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002655 }
2656
Michal Vasko1f2cc332015-08-19 11:18:32 +02002657 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002658 /* no instance exists */
2659 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002660 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002661 /* instance identifier must resolve to a single node */
2662 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2663
2664 /* cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002665 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002666
2667 return NULL;
2668 } else {
2669 /* we have required result, remember it and cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002670 result = node_match.dnode[0];
2671 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002672
2673 return result;
2674 }
2675
2676error:
2677
2678 /* cleanup */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002679 free(node_match.dnode);
Radek Krejcic5090c32015-08-12 09:46:19 +02002680
2681 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002682}
2683
Michal Vasko730dfdf2015-08-11 14:48:05 +02002684/**
2685 * @brief Passes config flag down to children. Does not log.
2686 *
2687 * @param[in] node Parent node.
2688 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002689static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002690inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002691{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002692 LY_TREE_FOR(node, node) {
2693 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2694 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002695 }
2696}
2697
Michal Vasko730dfdf2015-08-11 14:48:05 +02002698/**
Michal Vaskod9173342015-08-17 14:35:36 +02002699 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002700 *
Michal Vaskobb211122015-08-19 14:03:11 +02002701 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002702 * @param[in] siblings Nodes where to start the search in.
2703 * @param[in] module Main module.
2704 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002705 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002706 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002707int
Michal Vasko2e1a7e42015-08-06 15:08:32 +02002708resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002709{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002710 int rc;
Radek Krejci76512572015-08-04 09:47:08 +02002711 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002712
2713 assert(module);
2714
2715 /* resolve target node */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002716 rc = resolve_schema_nodeid(aug->target_name, siblings, module, LYS_AUGMENT, &aug->target);
2717 if (rc) {
2718 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002719 }
2720
2721 if (!aug->child) {
2722 /* nothing to do */
2723 return EXIT_SUCCESS;
2724 }
2725
2726 /* inherit config information from parent, augment does not have
2727 * config property, but we need to keep the information for subelements
2728 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002729 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002730 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002731 inherit_config_flag(sub);
2732 }
2733
Radek Krejci07911992015-08-14 15:13:31 +02002734 /* check identifier uniquness as in lys_node_addchild() */
2735 LY_TREE_FOR(aug->child, aux) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002736 if (lys_check_id(aux, aug->parent, module)) {
2737 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002738 }
2739 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002740 /* reconnect augmenting data into the target - add them to the target child list */
2741 if (aug->target->child) {
2742 aux = aug->target->child->prev; /* remember current target's last node */
2743 aux->next = aug->child; /* connect augmenting data after target's last node */
2744 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
2745 aug->child->prev = aux; /* finish connecting of both child lists */
2746 } else {
2747 aug->target->child = aug->child;
2748 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002749
2750 return EXIT_SUCCESS;
2751}
2752
Michal Vasko730dfdf2015-08-11 14:48:05 +02002753/**
2754 * @brief Resolve uses, apply augments, refines. Logs directly.
2755 *
Michal Vaskobb211122015-08-19 14:03:11 +02002756 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002757 * @param[in,out] unres List of unresolved items.
2758 * @param[in] line Line in the input file.
2759 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002760 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward ereference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002761 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002762int
Michal Vaskof02e3742015-08-05 16:27:02 +02002763resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002764{
2765 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002766 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002767 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002768 struct lys_restr *newmust;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002769 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002770 uint8_t size;
2771
Michal Vasko71e1aa82015-08-12 12:17:51 +02002772 assert(uses->grp);
2773
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002774 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002775 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002776 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002777 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002778 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002779 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002781 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002782 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002783 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002784 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002785 }
2786 }
2787 ctx = uses->module->ctx;
2788
2789 /* apply refines */
2790 for (i = 0; i < uses->refine_size; i++) {
2791 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002792 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2793 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002794 if (rc == -1) {
2795 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2796 } else {
2797 LOGVAL(LYE_NORESOLV, line, rfn->target_name);
2798 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 }
2801
Radek Krejci1d82ef62015-08-07 14:44:40 +02002802 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002803 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002804 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002805 }
2806
2807 /* description on any nodetype */
2808 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002809 lydict_remove(ctx, node->dsc);
2810 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002811 }
2812
2813 /* reference on any nodetype */
2814 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002815 lydict_remove(ctx, node->ref);
2816 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 }
2818
2819 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002820 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002821 node->flags &= ~LYS_CONFIG_MASK;
2822 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 }
2824
2825 /* default value ... */
2826 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002827 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002828 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002829 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2830 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2831 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002832 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002833 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2834 if (rc) {
Michal Vaskod9173342015-08-17 14:35:36 +02002835 if (rc == -1) {
2836 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2837 } else {
2838 LOGVAL(LYE_NORESOLV, line, rfn->mod.dflt);
2839 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002840 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 }
2842 }
2843 }
2844
2845 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002846 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002847 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002849 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002850
2851 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002852 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002853 }
2854 }
2855
2856 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002857 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2858 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2859 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 }
2861
2862 /* min/max-elements on list or leaf-list */
2863 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002864 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002866 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002867 }
2868 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002869 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002871 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002873 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002874 }
2875 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002876 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 }
2878 }
2879
2880 /* must in leaf, leaf-list, list, container or anyxml */
2881 if (rfn->must_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002882 size = ((struct lys_node_leaf *)node)->must_size + rfn->must_size;
2883 newmust = realloc(((struct lys_node_leaf *)node)->must, size * sizeof *rfn->must);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884 if (!newmust) {
2885 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002886 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002888 for (i = 0, j = ((struct lys_node_leaf *)node)->must_size; i < rfn->must_size; i++, j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2890 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2891 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2892 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2893 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
2894 }
2895
Radek Krejci1d82ef62015-08-07 14:44:40 +02002896 ((struct lys_node_leaf *)node)->must = newmust;
2897 ((struct lys_node_leaf *)node)->must_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 }
2899 }
2900
2901 /* apply augments */
2902 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002903 rc = resolve_augment(&uses->augment[i], uses->child, uses->module);
2904 if (rc) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002905 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002906 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002907 }
2908 }
2909
2910 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002911}
2912
Michal Vasko730dfdf2015-08-11 14:48:05 +02002913/**
2914 * @brief Resolve base identity recursively. Does not log.
2915 *
2916 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002917 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002918 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002919 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002920 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002921 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002922 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002923static int
2924resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2925 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926{
Michal Vaskof02e3742015-08-05 16:27:02 +02002927 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002928 struct lys_ident *base_iter = NULL;
2929 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930
2931 /* search module */
2932 for (i = 0; i < module->ident_size; i++) {
2933 if (!strcmp(basename, module->ident[i].name)) {
2934
2935 if (!ident) {
2936 /* just search for type, so do not modify anything, just return
2937 * the base identity pointer
2938 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002939 if (ret) {
2940 *ret = &module->ident[i];
2941 }
2942 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002943 }
2944
2945 /* we are resolving identity definition, so now update structures */
2946 ident->base = base_iter = &module->ident[i];
2947
2948 break;
2949 }
2950 }
2951
2952 /* search submodules */
2953 if (!base_iter) {
2954 for (j = 0; j < module->inc_size; j++) {
2955 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2956 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2957
2958 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002959 if (ret) {
2960 *ret = &module->inc[j].submodule->ident[i];
2961 }
2962 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963 }
2964
2965 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2966 break;
2967 }
2968 }
2969 }
2970 }
2971
2972 /* we found it somewhere */
2973 if (base_iter) {
2974 while (base_iter) {
2975 for (der = base_iter->der; der && der->next; der = der->next);
2976 if (der) {
2977 der->next = malloc(sizeof *der);
2978 der = der->next;
2979 } else {
2980 ident->base->der = der = malloc(sizeof *der);
2981 }
2982 der->next = NULL;
2983 der->ident = ident;
2984
2985 base_iter = base_iter->base;
2986 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002987 if (ret) {
2988 *ret = ident->base;
2989 }
2990 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002991 }
2992
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002993 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002994}
2995
Michal Vasko730dfdf2015-08-11 14:48:05 +02002996/**
2997 * @brief Resolve base identity. Logs directly.
2998 *
2999 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003000 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003001 * @param[in] basename Base name of the identity.
3002 * @param[in] parent Either "type" or "ident".
3003 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003004 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003005 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003006 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003007 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003008static int
Michal Vaskof02e3742015-08-05 16:27:02 +02003009resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003010 uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003011{
3012 const char *name;
Michal Vaskof02e3742015-08-05 16:27:02 +02003013 int i, prefix_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014
3015 /* search for the base identity */
3016 name = strchr(basename, ':');
3017 if (name) {
3018 /* set name to correct position after colon */
3019 prefix_len = name - basename;
3020 name++;
3021
3022 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
3023 /* prefix refers to the current module, ignore it */
3024 prefix_len = 0;
3025 }
3026 } else {
3027 name = basename;
3028 }
3029
3030 if (prefix_len) {
3031 /* get module where to search */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003032 module = resolve_prefixed_module(module, basename, prefix_len);
3033 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003034 /* identity refers unknown data model */
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003035 LOGVAL(LYE_INPREF, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003036 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003037 }
3038 } else {
3039 /* search in submodules */
3040 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003041 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3042 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003043 }
3044 }
3045 }
3046
3047 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003048 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3049 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050 }
3051
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003052 LOGVAL(LYE_INARG, line, basename, parent);
3053 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003054}
3055
Michal Vasko730dfdf2015-08-11 14:48:05 +02003056/**
3057 * @brief Resolve identityref. Does not log.
3058 *
3059 * @param[in] base Base identity.
3060 * @param[in] name Identityref name.
3061 * @param[in] ns Namespace of the identityref.
3062 *
3063 * @return Pointer to the identity resolvent, NULL on error.
3064 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003065struct lys_ident *
3066resolve_identityref(struct lys_ident *base, const char *name, const char *ns)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067{
Radek Krejcia52656e2015-08-05 13:41:50 +02003068 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003069
3070 if (!base || !name || !ns) {
3071 return NULL;
3072 }
3073
3074 for(der = base->der; der; der = der->next) {
3075 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
3076 /* we have match */
3077 return der->ident;
3078 }
3079 }
3080
3081 /* not found */
3082 return NULL;
3083}
3084
Michal Vasko730dfdf2015-08-11 14:48:05 +02003085/**
Michal Vaskobb211122015-08-19 14:03:11 +02003086 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003087 *
Michal Vaskobb211122015-08-19 14:03:11 +02003088 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003089 * @param[in] unres Specific unres item.
3090 * @param[in] line Line in the input file.
3091 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003093 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003095resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003096{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003097 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003098 struct lys_node *parent;
3099
3100 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3101 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3102
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003103 if (!uses->grp) {
3104 rc = resolve_grouping(uses, line);
3105 if (rc) {
3106 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003107 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003108 }
3109
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003110 if (uses->grp->nacm) {
3111 LOGVRB("Cannot copy the grouping, it is not fully resolved yet.");
3112 return EXIT_FAILURE;
3113 }
3114
3115 rc = resolve_uses(uses, unres, line);
3116 if (!rc) {
3117 /* decrease unres count only if not first try */
3118 if ((line < UINT_MAX) && parent) {
3119 if (!parent->nacm) {
3120 LOGINT;
3121 return -1;
3122 }
3123 --parent->nacm;
3124 }
3125 return EXIT_SUCCESS;
3126 }
3127
3128 if ((rc == EXIT_FAILURE) && parent) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003129 ++parent->nacm;
3130 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003131 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003132}
3133
Michal Vasko730dfdf2015-08-11 14:48:05 +02003134/**
Michal Vasko9957e592015-08-17 15:04:09 +02003135 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003136 *
Michal Vaskobb211122015-08-19 14:03:11 +02003137 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003138 * @param[in] keys_str Keys node value.
3139 * @param[in] line Line in the input file.
3140 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003141 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003142 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003143static int
Michal Vasko9957e592015-08-17 15:04:09 +02003144resolve_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 +02003145{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003146 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003147 const char *value;
3148
3149 for (i = 0; i < list->keys_size; ++i) {
3150 /* get the key name */
3151 if ((value = strpbrk(keys_str, " \t\n"))) {
3152 len = value - keys_str;
3153 while (isspace(value[0])) {
3154 value++;
3155 }
3156 } else {
3157 len = strlen(keys_str);
3158 }
3159
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003160 rc = resolve_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
3161 if (rc) {
3162 if (rc == EXIT_FAILURE) {
3163 LOGVAL(LYE_INRESOLV, (line == UINT_MAX ? line : 0), "list keys", keys_str);
3164 }
3165 return rc;
3166 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003167
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003168 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003169 /* check_key logs */
3170 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003171 }
3172
3173 /* prepare for next iteration */
3174 while (value && isspace(value[0])) {
3175 value++;
3176 }
3177 keys_str = value;
3178 }
3179
Michal Vaskof02e3742015-08-05 16:27:02 +02003180 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003181}
3182
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003183/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003185resolve_unres_schema_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003186{
3187 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003188 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003189}
3190
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003191/* logs directly */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003192static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003193resolve_unres_schema_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), uint32_t UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003194{
3195 /* TODO */
Michal Vaskof02e3742015-08-05 16:27:02 +02003196 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197}
3198
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003199/**
Michal Vaskobb211122015-08-19 14:03:11 +02003200 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003201 *
3202 * @param[in] mod Main module.
3203 * @param[in] item Item to resolve. Type determined by \p type.
3204 * @param[in] type Type of the unresolved item.
3205 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003206 * @param[in] unres Unres schema structure to use.
3207 * @param[in] line Line in the input file. UINT_MAX turns logging off, 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 *
3209 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3210 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003211static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003212resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003213 struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003214{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003215 int rc = -1, has_str = 0;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003216 struct lys_node *snode;
3217 const char *base_name;
3218
3219 struct lys_ident *ident;
3220 struct lys_type *stype;
3221 struct lys_feature **feat_ptr;
3222 struct lys_node_choice *choic;
3223 struct lys_unique *uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003224
3225 switch (type) {
3226 case UNRES_RESOLVED:
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003227 LOGINT;
Michal Vasko45b42312015-08-05 09:30:11 +02003228 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003230 base_name = str_snode;
3231 ident = item;
3232
3233 rc = resolve_base_ident(mod, ident, base_name, "ident", line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234 has_str = 1;
3235 break;
3236 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003237 base_name = str_snode;
3238 stype = item;
3239
3240 rc = resolve_base_ident(mod, NULL, base_name, "type", line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 has_str = 1;
3242 break;
3243 case UNRES_TYPE_LEAFREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003244 snode = str_snode;
3245 stype = item;
3246
3247 rc = resolve_path_arg_schema(mod, stype->info.lref.path, snode, line,
3248 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249 has_str = 0;
3250 break;
3251 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003252 base_name = str_snode;
3253 stype = item;
3254
3255 /* HACK type->der is temporarily its parent */
3256 rc = resolve_superior_type(base_name, stype->prefix, mod, (struct lys_node *)stype->der, &stype->der);
3257 if (!rc) {
3258 stype->base = stype->der->type.base;
3259 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003260 has_str = 1;
3261 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003263 base_name = str_snode;
3264 feat_ptr = item;
3265
3266 rc = resolve_feature(base_name, mod, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 has_str = 1;
3268 break;
3269 case UNRES_USES:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003270 rc = resolve_unres_schema_uses(item, unres, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 has_str = 0;
3272 break;
3273 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003274 base_name = str_snode;
3275 stype = item;
3276
3277 rc = check_default(stype, base_name);
3278 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279 has_str = 0;
3280 break;
3281 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003282 base_name = str_snode;
3283 choic = item;
3284
3285 rc = resolve_sibling(mod, choic->child, NULL, 0, base_name, 0, LYS_ANYXML | LYS_CASE
3286 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST, &choic->dflt);
3287 /* there is no prefix, that is the only error */
3288 assert(rc != -1);
3289 if (rc == EXIT_FAILURE) {
3290 LOGVAL(LYE_INRESOLV, line, "choice default", base_name);
3291 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003292 has_str = 1;
3293 break;
3294 case UNRES_LIST_KEYS:
Michal Vasko9957e592015-08-17 15:04:09 +02003295 rc = resolve_list_keys(mod, item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003296 has_str = 1;
3297 break;
3298 case UNRES_LIST_UNIQ:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003299 /* actually the unique string */
3300 base_name = str_snode;
3301 uniq = item;
3302
3303 rc = resolve_unique((struct lys_node *)uniq->leafs, base_name, uniq, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003304 has_str = 1;
3305 break;
3306 case UNRES_WHEN:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003307 rc = resolve_unres_schema_when(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003308 has_str = 0;
3309 break;
3310 case UNRES_MUST:
Michal Vasko0bd29d12015-08-19 11:45:49 +02003311 rc = resolve_unres_schema_must(item, str_snode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003312 has_str = 0;
3313 break;
3314 }
3315
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003316 if (has_str && !rc) {
3317 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318 }
3319
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003320 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003321}
3322
Michal Vaskof02e3742015-08-05 16:27:02 +02003323/* logs directly */
3324static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003325print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003326{
Michal Vaskof02e3742015-08-05 16:27:02 +02003327 char line_str[18];
3328
3329 if (line) {
3330 sprintf(line_str, " (line %u)", line);
3331 } else {
3332 line_str[0] = '\0';
3333 }
3334
3335 switch (type) {
3336 case UNRES_RESOLVED:
3337 LOGINT;
3338 break;
3339 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003340 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003341 break;
3342 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003343 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003344 break;
3345 case UNRES_TYPE_LEAFREF:
3346 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3347 break;
3348 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003349 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 +02003350 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003351 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003352 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 +02003353 break;
3354 case UNRES_USES:
3355 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3356 break;
3357 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003358 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 +02003359 break;
3360 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003361 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 +02003362 break;
3363 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003364 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 +02003365 break;
3366 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003367 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 +02003368 break;
3369 case UNRES_WHEN:
3370 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "when", ((struct lys_when *)item)->cond, line_str);
3371 break;
3372 case UNRES_MUST:
3373 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "must", ((struct lys_restr *)item)->expr, line_str);
3374 break;
3375 }
3376}
3377
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003378/**
Michal Vaskobb211122015-08-19 14:03:11 +02003379 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003380 *
3381 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003382 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003383 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003384 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003385 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003386int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003387resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003388{
Michal Vasko1c4e0ef2015-08-19 11:19:28 +02003389 uint32_t i, resolved, unres_uses, res_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003390 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391
3392 assert(unres);
3393
Michal Vasko51054ca2015-08-12 12:20:00 +02003394 resolved = 0;
3395
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003397 do {
3398 unres_uses = 0;
3399 res_uses = 0;
3400
3401 for (i = 0; i < unres->count; ++i) {
3402 if (unres->type[i] != UNRES_USES) {
3403 continue;
3404 }
3405
3406 ++unres_uses;
Michal Vasko0bd29d12015-08-19 11:45:49 +02003407 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 +02003408 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003409 unres->type[i] = UNRES_RESOLVED;
3410 ++resolved;
3411 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003412 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003413 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003414 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003415 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003416 } while (res_uses && (res_uses < unres_uses));
3417
3418 if (res_uses < unres_uses) {
3419 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003420 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003421 }
3422
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 /* the rest */
3424 for (i = 0; i < unres->count; ++i) {
3425 if (unres->type[i] == UNRES_RESOLVED) {
3426 continue;
3427 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003428
Michal Vasko0bd29d12015-08-19 11:45:49 +02003429 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 +02003430 if (!rc) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003431 unres->type[i] = UNRES_RESOLVED;
3432 ++resolved;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003433 } else if (rc == -1) {
3434 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435 }
3436 }
3437
3438 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003439 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3440 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441 }
3442
3443 return EXIT_SUCCESS;
3444}
3445
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003446/**
Michal Vaskobb211122015-08-19 14:03:11 +02003447 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003448 *
3449 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003450 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003451 * @param[in] item Item to resolve. Type determined by \p type.
3452 * @param[in] type Type of the unresolved item.
3453 * @param[in] str String argument.
3454 * @param[in] line Line in the input file.
3455 *
3456 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3457 */
3458int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003459unres_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 +02003460 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003461{
3462 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003463 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464}
3465
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003466/**
Michal Vaskobb211122015-08-19 14:03:11 +02003467 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003468 *
3469 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003470 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003471 * @param[in] item Item to resolve. Type determined by \p type.
3472 * @param[in] type Type of the unresolved item.
3473 * @param[in] snode Schema node argument.
3474 * @param[in] line Line in the input file.
3475 *
3476 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3477 */
3478int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003479unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003480 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003482 int rc;
3483
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484 assert(unres && item);
3485
Michal Vasko0bd29d12015-08-19 11:45:49 +02003486 rc = resolve_unres_schema_item(mod, item, type, snode, unres, UINT_MAX);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003487 if (rc != EXIT_FAILURE) {
3488 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489 }
3490
Michal Vasko0bd29d12015-08-19 11:45:49 +02003491 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003492
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493 unres->count++;
3494 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3495 unres->item[unres->count-1] = item;
3496 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3497 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003498 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003499 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003500#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3502 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003503#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003504
3505 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506}
3507
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508/**
Michal Vaskobb211122015-08-19 14:03:11 +02003509 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003510 *
3511 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003512 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003513 * @param[in] item Old item to be resolved.
3514 * @param[in] type Type of the old unresolved item.
3515 * @param[in] new_item New item to use in the duplicate.
3516 *
3517 * @return EXIT_SUCCESS on success, -1 on error.
3518 */
Michal Vaskodad19402015-08-06 09:51:53 +02003519int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003520unres_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 +02003521{
3522 int i;
3523
3524 if (!item || !new_item) {
Michal Vaskodad19402015-08-06 09:51:53 +02003525 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003526 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 }
3528
Michal Vasko0bd29d12015-08-19 11:45:49 +02003529 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003530
3531 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003532 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003533 }
3534
Michal Vasko4adc10f2015-08-11 15:26:17 +02003535 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003537 if (unres_schema_add_node(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 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003542 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003543 LOGINT;
3544 return -1;
3545 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003546 }
Michal Vaskodad19402015-08-06 09:51:53 +02003547
3548 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549}
3550
Michal Vaskof02e3742015-08-05 16:27:02 +02003551/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003553unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554{
3555 uint32_t ret = -1, i;
3556
3557 for (i = 0; i < unres->count; ++i) {
3558 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3559 ret = i;
3560 break;
3561 }
3562 }
3563
3564 return ret;
3565}
Michal Vasko8bcdf292015-08-19 14:04:43 +02003566
3567/* logs directly */
3568static void
3569print_unres_data_item_fail(struct lyd_node *dnode, uint32_t line)
3570{
3571 struct lys_node_leaf *sleaf;
3572 char line_str[18];
3573
3574 if (line) {
3575 sprintf(line_str, " (line %u)", line);
3576 } else {
3577 line_str[0] = '\0';
3578 }
3579
3580 sleaf = (struct lys_node_leaf *)dnode->schema;
3581 assert(sleaf->nodetype == LYS_LEAF);
3582
3583 if (sleaf->type.base == LY_TYPE_LEAFREF) {
3584 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
3585 sleaf->type.info.lref.path, line_str);
3586 } else if (sleaf->type.base == LY_TYPE_INST) {
3587 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
3588 ((struct lyd_node_leaf *)dnode)->value_str, line_str);
3589 }
3590}
3591
3592/**
3593 * @brief Resolve a single unres data item. Logs directly.
3594 *
3595 * @param[in] dnode Data node to resolve.
3596 * @param[in] line Line in the input file. UINT_MAX turns logging off, 0 skips line print.
3597 *
3598 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3599 */
3600static int
3601resolve_unres_data_item(struct lyd_node *dnode, uint32_t line)
3602{
3603 uint32_t i;
3604 struct lyd_node_leaf *dleaf;
3605 struct lys_node_leaf *sleaf;
3606 struct unres_data matches;
3607
3608 memset(&matches, 0, sizeof matches);
3609 dleaf = (struct lyd_node_leaf *)dnode;
3610 sleaf = (struct lys_node_leaf *)dleaf->schema;
3611
3612 /* leafref */
3613 if (sleaf->type.base == LY_TYPE_LEAFREF) {
3614 if (resolve_path_arg_data((struct lyd_node *)dleaf, sleaf->type.info.lref.path, line, &matches)) {
3615 return -1;
3616 }
3617
3618 /* check that value matches */
3619 for (i = 0; i < matches.count; ++i) {
3620 if (dleaf->value_str == ((struct lyd_node_leaf *)matches.dnode[i])->value_str) {
3621 dleaf->value.leafref = matches.dnode[i];
3622 break;
3623 }
3624 }
3625
3626 free(matches.dnode);
3627 memset(&matches, 0, sizeof matches);
3628
3629 if (!dleaf->value.leafref) {
3630 /* reference not found */
3631 LOGVAL(LYE_SPEC, line, "Leafref \"%s\" value \"%s\" did not match any node value.",
3632 sleaf->type.info.lref.path, dleaf->value_str);
3633 return EXIT_FAILURE;
3634 }
3635
3636 /* instance-identifier */
3637 } else if (sleaf->type.base == LY_TYPE_INST) {
3638 ly_errno = 0;
3639 if (!resolve_instid_json((struct lyd_node *)dleaf, dleaf->value_str, line)) {
3640 if (ly_errno) {
3641 return -1;
3642 } else if (sleaf->type.info.inst.req > -1) {
3643 LOGVAL(LYE_SPEC, line, "There is no instance of \"%s\".", dleaf->value_str);
3644 return EXIT_FAILURE;
3645 } else {
3646 LOGVRB("There is no instance of \"%s\", but is not required.", dleaf->value_str);
3647 }
3648 }
3649 } else {
3650 LOGINT;
3651 return -1;
3652 }
3653
3654 return EXIT_SUCCESS;
3655}
3656
3657/**
3658 * @brief Try to resolve an unres data item. Logs indirectly.
3659 *
3660 * @param[in] unres Unres data structure to use.
3661 * @param[in] dnode Data node to use.
3662 * @param[in] line Line in the input file.
3663 *
3664 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3665 */
3666int
3667unres_data_add(struct unres_data *unres, struct lyd_node *dnode, uint32_t line)
3668{
3669 int rc;
3670
3671 assert(unres && dnode);
3672
3673 rc = resolve_unres_data_item(dnode, UINT_MAX);
3674 if (rc != EXIT_FAILURE) {
3675 return rc;
3676 }
3677
3678 print_unres_data_item_fail(dnode, line);
3679
3680 ++unres->count;
3681 unres->dnode = realloc(unres->dnode, unres->count*sizeof *unres->dnode);
3682 unres->dnode[unres->count-1] = dnode;
3683#ifndef NDEBUG
3684 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3685 unres->line[unres->count-1] = line;
3686#endif
3687
3688 return EXIT_SUCCESS;
3689}
3690
3691/**
3692 * @brief Resolve every unres data item in the structure. Logs directly.
3693 *
3694 * @param[in] unres Unres data structure to use.
3695 *
3696 * @return EXIT_SUCCESS on success, -1 on error.
3697 */
3698int
3699resolve_unres_data(struct unres_data *unres)
3700{
3701 uint32_t i;
3702 int rc;
3703
3704 for (i = 0; i < unres->count; ++i) {
3705 rc = resolve_unres_data_item(unres->dnode[i], LOGLINE_IDX(unres, i));
3706 if (rc) {
3707 LOGVAL(LYE_SPEC, 0, "There are unresolved data items left.");
3708 return -1;
3709 }
3710 }
3711
3712 return EXIT_SUCCESS;
3713}