blob: dd0c6b31336253635c160a6ff505193ae83812f9 [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 Vaskocf024702015-10-08 15:01:42 +020033#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020034#include "parser.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020035#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020036#include "tree_internal.h"
37
Michal Vasko730dfdf2015-08-11 14:48:05 +020038/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020039 * @brief Parse an identifier.
40 *
41 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
42 * identifier = (ALPHA / "_")
43 * *(ALPHA / DIGIT / "_" / "-" / ".")
44 *
Michal Vaskobb211122015-08-19 14:03:11 +020045 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020046 *
47 * @return Number of characters successfully parsed.
48 */
Michal Vasko249e6b52015-08-19 11:08:52 +020049int
Radek Krejci6dc53a22015-08-17 13:27:59 +020050parse_identifier(const char *id)
51{
52 int parsed = 0;
53
54 if (((id[0] == 'x') || (id[0] == 'X'))
55 && ((id[1] == 'm') || (id[0] == 'M'))
56 && ((id[2] == 'l') || (id[2] == 'L'))) {
57 return -parsed;
58 }
59
60 if (!isalpha(id[0]) && (id[0] != '_')) {
61 return -parsed;
62 }
63
64 ++parsed;
65 ++id;
66
67 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
68 ++parsed;
69 ++id;
70 }
71
72 return parsed;
73}
74
75/**
76 * @brief Parse a node-identifier.
77 *
Michal Vasko723e50c2015-10-20 15:20:29 +020078 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020079 *
Michal Vaskobb211122015-08-19 14:03:11 +020080 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020081 * @param[out] mod_name Points to the module name, NULL if there is not any.
82 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020083 * @param[out] name Points to the node name.
84 * @param[out] nam_len Length of the node name.
85 *
86 * @return Number of characters successfully parsed,
87 * positive on success, negative on failure.
88 */
89static int
Michal Vasko723e50c2015-10-20 15:20:29 +020090parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +020091{
92 int parsed = 0, ret;
93
94 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020095 if (mod_name) {
96 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020097 }
Michal Vasko723e50c2015-10-20 15:20:29 +020098 if (mod_name_len) {
99 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200100 }
101 if (name) {
102 *name = NULL;
103 }
104 if (nam_len) {
105 *nam_len = 0;
106 }
107
108 if ((ret = parse_identifier(id)) < 1) {
109 return ret;
110 }
111
Michal Vasko723e50c2015-10-20 15:20:29 +0200112 if (mod_name) {
113 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200115 if (mod_name_len) {
116 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200117 }
118
119 parsed += ret;
120 id += ret;
121
122 /* there is prefix */
123 if (id[0] == ':') {
124 ++parsed;
125 ++id;
126
127 /* there isn't */
128 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200129 if (name && mod_name) {
130 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200131 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200132 if (mod_name) {
133 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200134 }
135
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 if (nam_len && mod_name_len) {
137 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200138 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200139 if (mod_name_len) {
140 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200141 }
142
143 return parsed;
144 }
145
146 /* identifier (node name) */
147 if ((ret = parse_identifier(id)) < 1) {
148 return -parsed+ret;
149 }
150
151 if (name) {
152 *name = id;
153 }
154 if (nam_len) {
155 *nam_len = ret;
156 }
157
158 return parsed+ret;
159}
160
161/**
162 * @brief Parse a path-predicate (leafref).
163 *
164 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
165 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
166 *
Michal Vaskobb211122015-08-19 14:03:11 +0200167 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200168 * @param[out] prefix Points to the prefix, NULL if there is not any.
169 * @param[out] pref_len Length of the prefix, 0 if there is not any.
170 * @param[out] name Points to the node name.
171 * @param[out] nam_len Length of the node name.
172 * @param[out] path_key_expr Points to the path-key-expr.
173 * @param[out] pke_len Length of the path-key-expr.
174 * @param[out] has_predicate Flag to mark whether there is another predicate following.
175 *
176 * @return Number of characters successfully parsed,
177 * positive on success, negative on failure.
178 */
179static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200180parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
181 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200182{
183 const char *ptr;
184 int parsed = 0, ret;
185
186 assert(id);
187 if (prefix) {
188 *prefix = NULL;
189 }
190 if (pref_len) {
191 *pref_len = 0;
192 }
193 if (name) {
194 *name = NULL;
195 }
196 if (nam_len) {
197 *nam_len = 0;
198 }
199 if (path_key_expr) {
200 *path_key_expr = NULL;
201 }
202 if (pke_len) {
203 *pke_len = 0;
204 }
205 if (has_predicate) {
206 *has_predicate = 0;
207 }
208
209 if (id[0] != '[') {
210 return -parsed;
211 }
212
213 ++parsed;
214 ++id;
215
216 while (isspace(id[0])) {
217 ++parsed;
218 ++id;
219 }
220
221 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
222 return -parsed+ret;
223 }
224
225 parsed += ret;
226 id += ret;
227
228 while (isspace(id[0])) {
229 ++parsed;
230 ++id;
231 }
232
233 if (id[0] != '=') {
234 return -parsed;
235 }
236
237 ++parsed;
238 ++id;
239
240 while (isspace(id[0])) {
241 ++parsed;
242 ++id;
243 }
244
245 if ((ptr = strchr(id, ']')) == NULL) {
246 return -parsed;
247 }
248
249 --ptr;
250 while (isspace(ptr[0])) {
251 --ptr;
252 }
253 ++ptr;
254
255 ret = ptr-id;
256 if (path_key_expr) {
257 *path_key_expr = id;
258 }
259 if (pke_len) {
260 *pke_len = ret;
261 }
262
263 parsed += ret;
264 id += ret;
265
266 while (isspace(id[0])) {
267 ++parsed;
268 ++id;
269 }
270
271 assert(id[0] == ']');
272
273 if (id[1] == '[') {
274 *has_predicate = 1;
275 }
276
277 return parsed+1;
278}
279
280/**
281 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
282 * the ".." and the first node-identifier, other calls parse a single
283 * node-identifier each.
284 *
285 * path-key-expr = current-function-invocation *WSP "/" *WSP
286 * rel-path-keyexpr
287 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
288 * *(node-identifier *WSP "/" *WSP)
289 * node-identifier
290 *
Michal Vaskobb211122015-08-19 14:03:11 +0200291 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200292 * @param[out] prefix Points to the prefix, NULL if there is not any.
293 * @param[out] pref_len Length of the prefix, 0 if there is not any.
294 * @param[out] name Points to the node name.
295 * @param[out] nam_len Length of the node name.
296 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
297 * must not be changed between consecutive calls.
298 * @return Number of characters successfully parsed,
299 * positive on success, negative on failure.
300 */
301static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200302parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
303 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200304{
305 int parsed = 0, ret, par_times = 0;
306
307 assert(id);
308 assert(parent_times);
309 if (prefix) {
310 *prefix = NULL;
311 }
312 if (pref_len) {
313 *pref_len = 0;
314 }
315 if (name) {
316 *name = NULL;
317 }
318 if (nam_len) {
319 *nam_len = 0;
320 }
321
322 if (!*parent_times) {
323 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
324 if (strncmp(id, "current()", 9)) {
325 return -parsed;
326 }
327
328 parsed += 9;
329 id += 9;
330
331 while (isspace(id[0])) {
332 ++parsed;
333 ++id;
334 }
335
336 if (id[0] != '/') {
337 return -parsed;
338 }
339
340 ++parsed;
341 ++id;
342
343 while (isspace(id[0])) {
344 ++parsed;
345 ++id;
346 }
347
348 /* rel-path-keyexpr */
349 if (strncmp(id, "..", 2)) {
350 return -parsed;
351 }
352 ++par_times;
353
354 parsed += 2;
355 id += 2;
356
357 while (isspace(id[0])) {
358 ++parsed;
359 ++id;
360 }
361 }
362
363 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
364 *
365 * first parent reference with whitespaces already parsed
366 */
367 if (id[0] != '/') {
368 return -parsed;
369 }
370
371 ++parsed;
372 ++id;
373
374 while (isspace(id[0])) {
375 ++parsed;
376 ++id;
377 }
378
379 while (!strncmp(id, "..", 2) && !*parent_times) {
380 ++par_times;
381
382 parsed += 2;
383 id += 2;
384
385 while (isspace(id[0])) {
386 ++parsed;
387 ++id;
388 }
389
390 if (id[0] != '/') {
391 return -parsed;
392 }
393
394 ++parsed;
395 ++id;
396
397 while (isspace(id[0])) {
398 ++parsed;
399 ++id;
400 }
401 }
402
403 if (!*parent_times) {
404 *parent_times = par_times;
405 }
406
407 /* all parent references must be parsed at this point */
408 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
409 return -parsed+ret;
410 }
411
412 parsed += ret;
413 id += ret;
414
415 return parsed;
416}
417
418/**
419 * @brief Parse path-arg (leafref).
420 *
421 * path-arg = absolute-path / relative-path
422 * absolute-path = 1*("/" (node-identifier *path-predicate))
423 * relative-path = 1*(".." "/") descendant-path
424 *
Michal Vaskobb211122015-08-19 14:03:11 +0200425 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200426 * @param[out] prefix Points to the prefix, NULL if there is not any.
427 * @param[out] pref_len Length of the prefix, 0 if there is not any.
428 * @param[out] name Points to the node name.
429 * @param[out] nam_len Length of the node name.
430 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
431 * must not be changed between consecutive calls. -1 if the
432 * path is relative.
433 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
434 *
435 * @return Number of characters successfully parsed,
436 * positive on success, negative on failure.
437 */
438static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200439parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
440 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200441{
442 int parsed = 0, ret, par_times = 0;
443
444 assert(id);
445 assert(parent_times);
446 if (prefix) {
447 *prefix = NULL;
448 }
449 if (pref_len) {
450 *pref_len = 0;
451 }
452 if (name) {
453 *name = NULL;
454 }
455 if (nam_len) {
456 *nam_len = 0;
457 }
458 if (has_predicate) {
459 *has_predicate = 0;
460 }
461
462 if (!*parent_times && !strncmp(id, "..", 2)) {
463 ++par_times;
464
465 parsed += 2;
466 id += 2;
467
468 while (!strncmp(id, "/..", 3)) {
469 ++par_times;
470
471 parsed += 3;
472 id += 3;
473 }
474 }
475
476 if (!*parent_times) {
477 if (par_times) {
478 *parent_times = par_times;
479 } else {
480 *parent_times = -1;
481 }
482 }
483
484 if (id[0] != '/') {
485 return -parsed;
486 }
487
488 /* skip '/' */
489 ++parsed;
490 ++id;
491
492 /* node-identifier ([prefix:]identifier) */
493 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
494 return -parsed-ret;
495 }
496
497 parsed += ret;
498 id += ret;
499
500 /* there is no predicate */
501 if ((id[0] == '/') || !id[0]) {
502 return parsed;
503 } else if (id[0] != '[') {
504 return -parsed;
505 }
506
507 if (has_predicate) {
508 *has_predicate = 1;
509 }
510
511 return parsed;
512}
513
514/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200515 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200516 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200517 *
518 * instance-identifier = 1*("/" (node-identifier *predicate))
519 *
Michal Vaskobb211122015-08-19 14:03:11 +0200520 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200521 * @param[out] model Points to the model name.
522 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200523 * @param[out] name Points to the node name.
524 * @param[out] nam_len Length of the node name.
525 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
526 *
527 * @return Number of characters successfully parsed,
528 * positive on success, negative on failure.
529 */
530static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200531parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
532 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200533{
534 int parsed = 0, ret;
535
536 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200537 if (model) {
538 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200539 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200540 if (mod_len) {
541 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200542 }
543 if (name) {
544 *name = NULL;
545 }
546 if (nam_len) {
547 *nam_len = 0;
548 }
549 if (has_predicate) {
550 *has_predicate = 0;
551 }
552
553 if (id[0] != '/') {
554 return -parsed;
555 }
556
557 ++parsed;
558 ++id;
559
Michal Vasko1f2cc332015-08-19 11:18:32 +0200560 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200561 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200562 } else if (model && !*model) {
563 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200564 }
565
566 parsed += ret;
567 id += ret;
568
569 if ((id[0] == '[') && has_predicate) {
570 *has_predicate = 1;
571 }
572
573 return parsed;
574}
575
576/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200577 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200578 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200579 *
580 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
581 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
582 * ((DQUOTE string DQUOTE) /
583 * (SQUOTE string SQUOTE))
584 * pos = non-negative-integer-value
585 *
Michal Vaskobb211122015-08-19 14:03:11 +0200586 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200587 * @param[out] model Points to the model name.
588 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200589 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
590 * @param[out] nam_len Length of the node name.
591 * @param[out] value Value the node-identifier must have (string from the grammar),
592 * NULL if there is not any.
593 * @param[out] val_len Length of the value, 0 if there is not any.
594 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
595 *
596 * @return Number of characters successfully parsed,
597 * positive on success, negative on failure.
598 */
599static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200600parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
601 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602{
603 const char *ptr;
604 int parsed = 0, ret;
605 char quote;
606
607 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200608 if (model) {
609 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200610 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200611 if (mod_len) {
612 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200613 }
614 if (name) {
615 *name = NULL;
616 }
617 if (nam_len) {
618 *nam_len = 0;
619 }
620 if (value) {
621 *value = NULL;
622 }
623 if (val_len) {
624 *val_len = 0;
625 }
626 if (has_predicate) {
627 *has_predicate = 0;
628 }
629
630 if (id[0] != '[') {
631 return -parsed;
632 }
633
634 ++parsed;
635 ++id;
636
637 while (isspace(id[0])) {
638 ++parsed;
639 ++id;
640 }
641
642 /* pos */
643 if (isdigit(id[0])) {
644 if (name) {
645 *name = id;
646 }
647
648 if (id[0] == '0') {
649 ++parsed;
650 ++id;
651
652 if (isdigit(id[0])) {
653 return -parsed;
654 }
655 }
656
657 while (isdigit(id[0])) {
658 ++parsed;
659 ++id;
660 }
661
662 if (nam_len) {
663 *nam_len = id-(*name);
664 }
665
666 /* "." */
667 } else if (id[0] == '.') {
668 if (name) {
669 *name = id;
670 }
671 if (nam_len) {
672 *nam_len = 1;
673 }
674
675 ++parsed;
676 ++id;
677
678 /* node-identifier */
679 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200681 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682 } else if (model && !*model) {
683 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200685
686 parsed += ret;
687 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200688 }
689
690 while (isspace(id[0])) {
691 ++parsed;
692 ++id;
693 }
694
695 if (id[0] != '=') {
696 return -parsed;
697 }
698
699 ++parsed;
700 ++id;
701
702 while (isspace(id[0])) {
703 ++parsed;
704 ++id;
705 }
706
707 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
708 if ((id[0] == '\"') || (id[0] == '\'')) {
709 quote = id[0];
710
711 ++parsed;
712 ++id;
713
714 if ((ptr = strchr(id, quote)) == NULL) {
715 return -parsed;
716 }
717 ret = ptr-id;
718
719 if (value) {
720 *value = id;
721 }
722 if (val_len) {
723 *val_len = ret;
724 }
725
726 parsed += ret+1;
727 id += ret+1;
728 } else {
729 return -parsed;
730 }
731
732 while (isspace(id[0])) {
733 ++parsed;
734 ++id;
735 }
736
737 if (id[0] != ']') {
738 return -parsed;
739 }
740
741 ++parsed;
742 ++id;
743
744 if ((id[0] == '[') && has_predicate) {
745 *has_predicate = 1;
746 }
747
748 return parsed;
749}
750
751/**
752 * @brief Parse schema-nodeid.
753 *
754 * schema-nodeid = absolute-schema-nodeid /
755 * descendant-schema-nodeid
756 * absolute-schema-nodeid = 1*("/" node-identifier)
757 * descendant-schema-nodeid =
758 * node-identifier
759 * absolute-schema-nodeid
760 *
Michal Vaskobb211122015-08-19 14:03:11 +0200761 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200762 * @param[out] mod_name Points to the module name, NULL if there is not any.
763 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200764 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
765 * @param[out] nam_len Length of the node name.
766 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
767 * on the first call, must not be changed between consecutive calls.
768 *
769 * @return Number of characters successfully parsed,
770 * positive on success, negative on failure.
771 */
772static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200773parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200774 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200775{
776 int parsed = 0, ret;
777
778 assert(id);
779 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200780 if (mod_name) {
781 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200783 if (mod_name_len) {
784 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200785 }
786 if (name) {
787 *name = NULL;
788 }
789 if (nam_len) {
790 *nam_len = 0;
791 }
792
793 if (id[0] != '/') {
794 if (*is_relative != -1) {
795 return -parsed;
796 } else {
797 *is_relative = 1;
798 }
799 } else {
800 if (*is_relative == -1) {
801 *is_relative = 0;
802 }
803 ++parsed;
804 ++id;
805 }
806
Michal Vasko723e50c2015-10-20 15:20:29 +0200807 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200808 return -parsed+ret;
809 }
810
811 return parsed+ret;
812}
813
814/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200815 * @brief Resolves length or range intervals. Does not log.
816 * Syntax is assumed to be correct, *local_intv MUST be NULL.
817 *
818 * @param[in] str_restr The restriction as a string.
819 * @param[in] type The type of the restriction.
820 * @param[in] superior_restr Flag whether to check superior
821 * types.
822 * @param[out] local_intv The final interval structure.
823 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200824 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200825 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200826int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200827resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
828 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200829{
830 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200831 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200832 int64_t local_smin, local_smax;
833 uint64_t local_umin, local_umax;
834 long double local_fmin, local_fmax;
835 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200836 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200837
838 switch (type->base) {
839 case LY_TYPE_BINARY:
840 kind = 0;
841 local_umin = 0;
842 local_umax = 18446744073709551615UL;
843
844 if (!str_restr && type->info.binary.length) {
845 str_restr = type->info.binary.length->expr;
846 }
847 break;
848 case LY_TYPE_DEC64:
849 kind = 2;
850 local_fmin = -9223372036854775808.0;
851 local_fmin /= 1 << type->info.dec64.dig;
852 local_fmax = 9223372036854775807.0;
853 local_fmax /= 1 << type->info.dec64.dig;
854
855 if (!str_restr && type->info.dec64.range) {
856 str_restr = type->info.dec64.range->expr;
857 }
858 break;
859 case LY_TYPE_INT8:
860 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100861 local_smin = __INT64_C(-128);
862 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200863
864 if (!str_restr && type->info.num.range) {
865 str_restr = type->info.num.range->expr;
866 }
867 break;
868 case LY_TYPE_INT16:
869 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100870 local_smin = __INT64_C(-32768);
871 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200872
873 if (!str_restr && type->info.num.range) {
874 str_restr = type->info.num.range->expr;
875 }
876 break;
877 case LY_TYPE_INT32:
878 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100879 local_smin = __INT64_C(-2147483648);
880 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200881
882 if (!str_restr && type->info.num.range) {
883 str_restr = type->info.num.range->expr;
884 }
885 break;
886 case LY_TYPE_INT64:
887 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100888 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
889 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200890
891 if (!str_restr && type->info.num.range) {
892 str_restr = type->info.num.range->expr;
893 }
894 break;
895 case LY_TYPE_UINT8:
896 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100897 local_umin = __UINT64_C(0);
898 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200899
900 if (!str_restr && type->info.num.range) {
901 str_restr = type->info.num.range->expr;
902 }
903 break;
904 case LY_TYPE_UINT16:
905 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100906 local_umin = __UINT64_C(0);
907 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200908
909 if (!str_restr && type->info.num.range) {
910 str_restr = type->info.num.range->expr;
911 }
912 break;
913 case LY_TYPE_UINT32:
914 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100915 local_umin = __UINT64_C(0);
916 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200917
918 if (!str_restr && type->info.num.range) {
919 str_restr = type->info.num.range->expr;
920 }
921 break;
922 case LY_TYPE_UINT64:
923 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100924 local_umin = __UINT64_C(0);
925 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200926
927 if (!str_restr && type->info.num.range) {
928 str_restr = type->info.num.range->expr;
929 }
930 break;
931 case LY_TYPE_STRING:
932 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100933 local_umin = __UINT64_C(0);
934 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200935
936 if (!str_restr && type->info.str.length) {
937 str_restr = type->info.str.length->expr;
938 }
939 break;
940 default:
941 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200942 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200943 }
944
945 /* process superior types */
946 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200947 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
948 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200949 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200950 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200951 assert(!intv || (intv->kind == kind));
952 }
953
954 if (!str_restr) {
955 /* we are validating data and not have any restriction, but a superior type might have */
956 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200957 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
958 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200959 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200960 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200961 assert(!intv || (intv->kind == kind));
962 }
963 *local_intv = intv;
964 return EXIT_SUCCESS;
965 }
966
967 /* adjust local min and max */
968 if (intv) {
969 tmp_intv = intv;
970
971 if (kind == 0) {
972 local_umin = tmp_intv->value.uval.min;
973 } else if (kind == 1) {
974 local_smin = tmp_intv->value.sval.min;
975 } else if (kind == 2) {
976 local_fmin = tmp_intv->value.fval.min;
977 }
978
979 while (tmp_intv->next) {
980 tmp_intv = tmp_intv->next;
981 }
982
983 if (kind == 0) {
984 local_umax = tmp_intv->value.uval.max;
985 } else if (kind == 1) {
986 local_smax = tmp_intv->value.sval.max;
987 } else if (kind == 2) {
988 local_fmax = tmp_intv->value.fval.max;
989 }
990 }
991
992 /* finally parse our restriction */
993 seg_ptr = str_restr;
994 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +0200995 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200996 *local_intv = malloc(sizeof **local_intv);
997 tmp_local_intv = *local_intv;
998 } else {
999 tmp_local_intv->next = malloc(sizeof **local_intv);
1000 tmp_local_intv = tmp_local_intv->next;
1001 }
1002
1003 tmp_local_intv->kind = kind;
1004 tmp_local_intv->next = NULL;
1005
1006 /* min */
1007 ptr = seg_ptr;
1008 while (isspace(ptr[0])) {
1009 ++ptr;
1010 }
1011 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1012 if (kind == 0) {
1013 tmp_local_intv->value.uval.min = atoll(ptr);
1014 } else if (kind == 1) {
1015 tmp_local_intv->value.sval.min = atoll(ptr);
1016 } else if (kind == 2) {
1017 tmp_local_intv->value.fval.min = atoll(ptr);
1018 }
1019
1020 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1021 ++ptr;
1022 }
1023 while (isdigit(ptr[0])) {
1024 ++ptr;
1025 }
1026 } else if (!strncmp(ptr, "min", 3)) {
1027 if (kind == 0) {
1028 tmp_local_intv->value.uval.min = local_umin;
1029 } else if (kind == 1) {
1030 tmp_local_intv->value.sval.min = local_smin;
1031 } else if (kind == 2) {
1032 tmp_local_intv->value.fval.min = local_fmin;
1033 }
1034
1035 ptr += 3;
1036 } else if (!strncmp(ptr, "max", 3)) {
1037 if (kind == 0) {
1038 tmp_local_intv->value.uval.min = local_umax;
1039 } else if (kind == 1) {
1040 tmp_local_intv->value.sval.min = local_smax;
1041 } else if (kind == 2) {
1042 tmp_local_intv->value.fval.min = local_fmax;
1043 }
1044
1045 ptr += 3;
1046 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001047 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001048 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001049 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001050 }
1051
1052 while (isspace(ptr[0])) {
1053 ptr++;
1054 }
1055
1056 /* no interval or interval */
1057 if ((ptr[0] == '|') || !ptr[0]) {
1058 if (kind == 0) {
1059 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1060 } else if (kind == 1) {
1061 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1062 } else if (kind == 2) {
1063 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1064 }
1065 } else if (!strncmp(ptr, "..", 2)) {
1066 /* skip ".." */
1067 ptr += 2;
1068 while (isspace(ptr[0])) {
1069 ++ptr;
1070 }
1071
1072 /* max */
1073 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1074 if (kind == 0) {
1075 tmp_local_intv->value.uval.max = atoll(ptr);
1076 } else if (kind == 1) {
1077 tmp_local_intv->value.sval.max = atoll(ptr);
1078 } else if (kind == 2) {
1079 tmp_local_intv->value.fval.max = atoll(ptr);
1080 }
1081 } else if (!strncmp(ptr, "max", 3)) {
1082 if (kind == 0) {
1083 tmp_local_intv->value.uval.max = local_umax;
1084 } else if (kind == 1) {
1085 tmp_local_intv->value.sval.max = local_smax;
1086 } else if (kind == 2) {
1087 tmp_local_intv->value.fval.max = local_fmax;
1088 }
1089 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001090 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001091 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001092 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001093 }
1094 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001095 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001096 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001097 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001098 }
1099
1100 /* next segment (next OR) */
1101 seg_ptr = strchr(seg_ptr, '|');
1102 if (!seg_ptr) {
1103 break;
1104 }
1105 seg_ptr++;
1106 }
1107
1108 /* check local restrictions against superior ones */
1109 if (intv) {
1110 tmp_intv = intv;
1111 tmp_local_intv = *local_intv;
1112
1113 while (tmp_local_intv && tmp_intv) {
1114 /* reuse local variables */
1115 if (kind == 0) {
1116 local_umin = tmp_local_intv->value.uval.min;
1117 local_umax = tmp_local_intv->value.uval.max;
1118
1119 /* it must be in this interval */
1120 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1121 /* this interval is covered, next one */
1122 if (local_umax <= tmp_intv->value.uval.max) {
1123 tmp_local_intv = tmp_local_intv->next;
1124 continue;
1125 /* ascending order of restrictions -> fail */
1126 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001127 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001128 goto cleanup;
1129 }
1130 }
1131 } else if (kind == 1) {
1132 local_smin = tmp_local_intv->value.sval.min;
1133 local_smax = tmp_local_intv->value.sval.max;
1134
1135 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1136 if (local_smax <= tmp_intv->value.sval.max) {
1137 tmp_local_intv = tmp_local_intv->next;
1138 continue;
1139 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001140 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001141 goto cleanup;
1142 }
1143 }
1144 } else if (kind == 2) {
1145 local_fmin = tmp_local_intv->value.fval.min;
1146 local_fmax = tmp_local_intv->value.fval.max;
1147
1148 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1149 if (local_fmax <= tmp_intv->value.fval.max) {
1150 tmp_local_intv = tmp_local_intv->next;
1151 continue;
1152 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001153 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001154 goto cleanup;
1155 }
1156 }
1157 }
1158
1159 tmp_intv = tmp_intv->next;
1160 }
1161
1162 /* some interval left uncovered -> fail */
1163 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001164 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001165 }
1166
1167 }
1168
1169cleanup:
1170 while (intv) {
1171 tmp_intv = intv->next;
1172 free(intv);
1173 intv = tmp_intv;
1174 }
1175
1176 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001177 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001178 while (*local_intv) {
1179 tmp_local_intv = (*local_intv)->next;
1180 free(*local_intv);
1181 *local_intv = tmp_local_intv;
1182 }
1183 }
1184
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001185 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001186}
1187
Michal Vasko730dfdf2015-08-11 14:48:05 +02001188/**
1189 * @brief Resolve a typedef. Does not log.
1190 *
1191 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001192 * @param[in] mod_name Typedef name module name.
1193 * @param[in] module Main module.
1194 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001195 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001196 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001197 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001198 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001199int
Michal Vasko1dca6882015-10-22 14:29:42 +02001200resolve_superior_type(const char *name, const char *mod_name, struct lys_module *module, struct lys_node *parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001201 struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001202{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001203 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001204 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001205 int tpdf_size;
1206
Michal Vasko1dca6882015-10-22 14:29:42 +02001207 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001208 /* no prefix, try built-in types */
1209 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1210 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001211 if (ret) {
1212 *ret = ly_types[i].def;
1213 }
1214 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001215 }
1216 }
1217 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001218 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001219 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001220 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001221 }
1222 }
1223
Michal Vasko1dca6882015-10-22 14:29:42 +02001224 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001225 /* search in local typedefs */
1226 while (parent) {
1227 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001228 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001229 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1230 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001231 break;
1232
Radek Krejci76512572015-08-04 09:47:08 +02001233 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001234 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1235 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001236 break;
1237
Radek Krejci76512572015-08-04 09:47:08 +02001238 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001239 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1240 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001241 break;
1242
Radek Krejci76512572015-08-04 09:47:08 +02001243 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001244 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1245 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001246 break;
1247
Radek Krejci76512572015-08-04 09:47:08 +02001248 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001249 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1250 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001251 break;
1252
Radek Krejci76512572015-08-04 09:47:08 +02001253 case LYS_INPUT:
1254 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001255 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1256 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001257 break;
1258
1259 default:
1260 parent = parent->parent;
1261 continue;
1262 }
1263
1264 for (i = 0; i < tpdf_size; i++) {
1265 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001266 if (ret) {
1267 *ret = &tpdf[i];
1268 }
1269 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001270 }
1271 }
1272
1273 parent = parent->parent;
1274 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001275 } else if (mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001276 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001277 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001278 if (!module) {
1279 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001280 }
1281 }
1282
1283 /* search in top level typedefs */
1284 for (i = 0; i < module->tpdf_size; i++) {
1285 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001286 if (ret) {
1287 *ret = &module->tpdf[i];
1288 }
1289 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001290 }
1291 }
1292
1293 /* search in submodules */
1294 for (i = 0; i < module->inc_size; i++) {
1295 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1296 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001297 if (ret) {
1298 *ret = &module->inc[i].submodule->tpdf[j];
1299 }
1300 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001301 }
1302 }
1303 }
1304
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001305 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001306}
1307
Michal Vasko1dca6882015-10-22 14:29:42 +02001308/**
1309 * @brief Check the default \p value of the \p type. Logs directly.
1310 *
1311 * @param[in] type Type definition to use.
1312 * @param[in] value Default value to check.
1313 * @param[in] first Whether this is the first resolution try. Affects logging.
1314 * @param[in] line Line in the input file.
1315 *
1316 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1317 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001318static int
Michal Vasko1dca6882015-10-22 14:29:42 +02001319check_default(struct lys_type *type, const char *value, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001320{
Michal Vasko1dca6882015-10-22 14:29:42 +02001321 struct lyd_node_leaf_list node;
1322 struct lys_type *iter;
1323 int ret = EXIT_SUCCESS, found;
1324
1325 /* dummy leaf */
1326 node.value_str = value;
1327 node.value_type = type->base;
1328 node.schema = calloc(1, sizeof *node.schema);
1329 node.schema->name = strdup("default");
1330
1331 if (type->base == LY_TYPE_UNION) {
1332 found = 0;
1333 iter = lyp_get_next_union_type(type, NULL, &found);
1334 while (iter) {
1335 node.value_type = iter->base;
1336
1337 /* special case with too much effort required and almost no added value */
1338 if ((iter->base == LY_TYPE_IDENT) || (iter->base == LY_TYPE_INST)) {
1339 LOGVAL(LYE_SPEC, line,
1340 "Union with \"instance-identifier\" or \"identityref\" and a default value is not supported!");
1341 ret = -1;
1342 goto finish;
1343 }
1344
1345 if (!lyp_parse_value(&node, iter, 1, NULL, UINT_MAX)) {
1346 break;
1347 }
1348
1349 found = 0;
1350 iter = lyp_get_next_union_type(type, iter, &found);
1351 }
1352
1353 if (!iter) {
1354 if (!first) {
1355 LOGVAL(LYE_INVAL, line, node.value_str, "default");
1356 }
1357 ret = EXIT_FAILURE;
1358 goto finish;
1359 }
1360
1361 } else if (type->base == LY_TYPE_LEAFREF) {
1362 if (!type->info.lref.target) {
1363 ret = EXIT_FAILURE;
1364 goto finish;
1365 }
1366 ret = check_default(&type->info.lref.target->type, value, first, line);
1367
1368 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1369 /* it was converted to JSON format before, nothing else sensible we can do */
1370
1371 } else {
1372 ret = lyp_parse_value(&node, type, 1, NULL, (first ? UINT_MAX : line));
1373 }
1374
1375finish:
1376 if (node.value_type == LY_TYPE_BITS) {
1377 free(node.value.bit);
1378 }
1379 free((char *)node.schema->name);
1380 free(node.schema);
1381
1382 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001383}
1384
Michal Vasko730dfdf2015-08-11 14:48:05 +02001385/**
1386 * @brief Check a key for mandatory attributes. Logs directly.
1387 *
1388 * @param[in] key The key to check.
1389 * @param[in] flags What flags to check.
1390 * @param[in] list The list of all the keys.
1391 * @param[in] index Index of the key in the key list.
1392 * @param[in] name The name of the keys.
1393 * @param[in] len The name length.
1394 * @param[in] line The line in the input file.
1395 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001396 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001397 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001398static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001399check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1400 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001401{
1402 char *dup = NULL;
1403 int j;
1404
1405 /* existence */
1406 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001407 if (name[len] != '\0') {
1408 dup = strdup(name);
1409 dup[len] = '\0';
1410 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001411 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001412 LOGVAL(LYE_KEY_MISS, line, name);
1413 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001414 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001415 }
1416
1417 /* uniqueness */
1418 for (j = index - 1; j >= 0; j--) {
1419 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001420 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001421 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001422 }
1423 }
1424
1425 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001426 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001427 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001428 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001429 }
1430
1431 /* type of the leaf is not built-in empty */
1432 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001433 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001434 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001435 }
1436
1437 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001438 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001439 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001440 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001441 }
1442
1443 return EXIT_SUCCESS;
1444}
1445
Michal Vasko730dfdf2015-08-11 14:48:05 +02001446/**
Radek Krejci581ce772015-11-10 17:22:40 +01001447 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001448 *
1449 * @param[in] parent The parent node of the unique structure.
1450 * @param[in] uniq_str The value of the unique node.
Michal Vasko184521f2015-09-24 13:14:26 +02001451 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001452 * @param[in] line The line in the input file.
1453 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001454 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001455 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001456int
Radek Krejci581ce772015-11-10 17:22:40 +01001457resolve_unique(struct lys_node *parent, const char *uniq_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001458{
Radek Krejci581ce772015-11-10 17:22:40 +01001459 int rc;
1460 struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001461
Radek Krejci581ce772015-11-10 17:22:40 +01001462 rc = resolve_schema_nodeid(uniq_str, parent->child, parent->module, LYS_LEAF, &leaf);
1463 if (rc) {
1464 if ((rc == -1) || !first) {
1465 LOGVAL(LYE_INARG, line, uniq_str, "unique");
1466 if (rc == EXIT_FAILURE) {
1467 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
1468 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001469 }
Radek Krejci581ce772015-11-10 17:22:40 +01001470 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001471 }
Radek Krejci581ce772015-11-10 17:22:40 +01001472 if (!leaf || leaf->nodetype != LYS_LEAF) {
1473 LOGVAL(LYE_INARG, line, uniq_str, "unique");
1474 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1475 rc = -1;
1476 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001477 }
1478
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001479 return EXIT_SUCCESS;
1480
1481error:
1482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001483 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001484}
1485
Michal Vasko730dfdf2015-08-11 14:48:05 +02001486/**
1487 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1488 *
Michal Vaskobb211122015-08-19 14:03:11 +02001489 * @param[in] uses The uses to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001490 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001491 * @param[in] line The line in the input file.
1492 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001493 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001494 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001495static int
Michal Vasko184521f2015-09-24 13:14:26 +02001496resolve_grouping(struct lys_node_uses *uses, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001497{
Michal Vasko563ef092015-09-04 13:17:23 +02001498 struct lys_module *module;
Radek Krejci2d5692b2015-10-31 23:12:16 +01001499 const char *mod_prefix, *name;
1500 int i, mod_prefix_len, nam_len;
Radek Krejci10c760e2015-08-14 14:45:43 +02001501 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001502
Michal Vasko58090902015-08-13 14:04:15 +02001503 /* parse the identifier, it must be parsed on one call */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001504 if ((i = parse_node_identifier(uses->name, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02001505 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001506 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001507 } else if (uses->name[i]) {
1508 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001509 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001510 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001511
Radek Krejci2d5692b2015-10-31 23:12:16 +01001512 if (mod_prefix) {
1513 module = lys_get_import_module(uses->module, mod_prefix, mod_prefix_len, NULL, 0);
Michal Vasko563ef092015-09-04 13:17:23 +02001514 if (!module) {
Radek Krejci2d5692b2015-10-31 23:12:16 +01001515 LOGVAL(LYE_INMOD_LEN, line, mod_prefix_len, mod_prefix);
Michal Vasko563ef092015-09-04 13:17:23 +02001516 return -1;
1517 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001518 start = module->data;
1519 } else {
Michal Vasko563ef092015-09-04 13:17:23 +02001520 start = (struct lys_node *)uses;
Michal Vasko2bdcca92015-08-17 16:00:45 +02001521 }
1522
Michal Vasko563ef092015-09-04 13:17:23 +02001523 uses->grp = lys_find_grouping_up(name, start, 1);
1524 if (uses->grp) {
1525 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001526 }
1527
Radek Krejci2d5692b2015-10-31 23:12:16 +01001528 if (mod_prefix || !first) {
Michal Vasko184521f2015-09-24 13:14:26 +02001529 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
1530 }
Michal Vasko563ef092015-09-04 13:17:23 +02001531 /* import must now be fully resolved */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001532 if (mod_prefix) {
Michal Vasko563ef092015-09-04 13:17:23 +02001533 return -1;
1534 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001535 return EXIT_FAILURE;
1536}
1537
Michal Vasko730dfdf2015-08-11 14:48:05 +02001538/**
1539 * @brief Resolve (find) a feature definition. Logs directly.
1540 *
1541 * @param[in] name Feature name.
1542 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001543 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001544 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001545 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001546 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001547 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001548 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001549static int
Michal Vasko184521f2015-09-24 13:14:26 +02001550resolve_feature(const char *id, struct lys_module *module, int first, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001551{
Michal Vasko2d851a92015-10-20 16:16:36 +02001552 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001553 int mod_name_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001554
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001555 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001556 assert(module);
1557
1558 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001559 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001560 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1561 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001562 }
1563
Michal Vasko2d851a92015-10-20 16:16:36 +02001564 if (mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001565 /* search in imported modules */
Michal Vaskob6729c62015-10-21 12:09:47 +02001566 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001567 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001568 /* identity refers unknown data model */
Michal Vasko2d851a92015-10-20 16:16:36 +02001569 LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001570 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001571 }
1572 } else {
1573 /* search in submodules */
1574 for (i = 0; i < module->inc_size; i++) {
1575 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1576 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001577 if (ret) {
1578 *ret = &(module->inc[i].submodule->features[j]);
1579 }
1580 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001581 }
1582 }
1583 }
1584 }
1585
1586 /* search in the identified module */
1587 for (j = 0; j < module->features_size; j++) {
1588 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001589 if (ret) {
1590 *ret = &module->features[j];
1591 }
1592 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001593 }
1594 }
1595
1596 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001597 if (!first) {
1598 LOGVAL(LYE_INRESOLV, line, "feature", id);
1599 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001600 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001601}
1602
Michal Vasko730dfdf2015-08-11 14:48:05 +02001603/**
Radek Krejci581ce772015-11-10 17:22:40 +01001604 * @brief Resolve (find) a data node based on a schema-nodeid.
1605 *
1606 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1607 * module).
1608 *
1609 */
1610struct lyd_node *
1611resolve_data_nodeid(const char *id, struct lyd_node *start)
1612{
1613 char *str, *token, *p;
1614 struct lyd_node *result = start, *iter;
1615 struct lys_node *schema = NULL;
1616
1617 assert(start);
1618 assert(id);
1619
1620 if (id[0] == '/') {
1621 return NULL;
1622 }
1623
1624 str = p = strdup(id);
1625 while(p) {
1626 token = p;
1627 p = strchr(p, '/');
1628 if (p) {
1629 *p = '\0';
1630 p++;
1631 }
1632
1633 if (resolve_schema_nodeid(token, result->schema, result->schema->module, LYS_LEAF, &schema)) {
1634 free(str);
1635 return NULL;
1636 }
1637
1638 LY_TREE_FOR(result, iter) {
1639 if (iter->schema == schema) {
1640 break;
1641 }
1642 }
1643
1644 if (!p) {
1645 /* final result */
1646 result = iter;
1647 } else {
1648 result = iter->child;
1649 }
1650 }
1651 free(str);
1652
1653 return result;
1654}
1655
1656/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001657 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001658 *
Michal Vasko1be88302015-10-22 16:07:47 +02001659 * node_type - LYS_AUGMENT (searches also RPCs and notifications, augmented nodes are fine, too)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001660 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001661 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001662 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1663 *
Michal Vasko1be88302015-10-22 16:07:47 +02001664 * If \p id is absolute, \p start is ignored. If \p id is relative, \p start must be the first child to be searched
1665 * continuing with its siblings. Normally skips augments except \p node_type LYS_AUGMENT (augmenting an augment node).
Michal Vasko730dfdf2015-08-11 14:48:05 +02001666 *
1667 * @param[in] id Schema-nodeid string.
1668 * @param[in] start Start of the relative search.
Michal Vaskobb211122015-08-19 14:03:11 +02001669 * @param[in] mod Module to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001670 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001671 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001672 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001673 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001674 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001675int
1676resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1677 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001678{
Michal Vasko723e50c2015-10-20 15:20:29 +02001679 const char *name, *mod_name;
Radek Krejci76512572015-08-04 09:47:08 +02001680 struct lys_node *sibling;
Michal Vasko1be88302015-10-22 16:07:47 +02001681 int i, opts, nam_len, mod_name_len, is_relative = -1;
1682 struct lys_module *prev_mod, *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001683 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1684 uint8_t in_submod = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001685
1686 assert(mod);
1687 assert(id);
1688
Michal Vasko723e50c2015-10-20 15:20:29 +02001689 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001690 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001691 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001692 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001693
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001694 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001695 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001696 }
1697
Michal Vasko1be88302015-10-22 16:07:47 +02001698 /* set options for lys_getnext() */
1699 opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT;
1700 if (node_type == LYS_USES) {
1701 opts |= LYS_GETNEXT_WITHGROUPING;
1702 }
1703
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001704 /* absolute-schema-nodeid */
1705 if (!is_relative) {
Michal Vasko723e50c2015-10-20 15:20:29 +02001706 if (mod_name) {
Michal Vaskob6729c62015-10-21 12:09:47 +02001707 start_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001708 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001709 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001710 }
1711 start = start_mod->data;
1712 } else {
1713 start = mod->data;
1714 start_mod = mod;
1715 }
1716 /* descendant-schema-nodeid */
1717 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001718 if (start) {
1719 start_mod = start->module;
1720 } else {
Michal Vasko0ff32e12015-10-23 10:13:23 +02001721 start = mod->data;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001722 start_mod = mod;
1723 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001724 }
1725
Michal Vasko1be88302015-10-22 16:07:47 +02001726 prev_mod = start_mod;
1727
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001728 while (1) {
Radek Krejcib14b3c52015-11-04 10:15:12 +01001729 if (start) {
1730 sibling = lys_getnext(NULL, start->parent, start_mod, opts);
1731 } else {
1732 sibling = NULL;
1733 }
1734
Michal Vasko1be88302015-10-22 16:07:47 +02001735 while (sibling) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001736 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001737 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
Michal Vaskoa4b5d322015-10-09 12:12:37 +02001738 && (!(sibling->nodetype & (LYS_RPC | LYS_NOTIF)) || (node_type == LYS_AUGMENT))
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001739 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001740 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001741 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001742
Michal Vasko1be88302015-10-22 16:07:47 +02001743 /* module name match check */
Michal Vasko723e50c2015-10-20 15:20:29 +02001744 if (mod_name) {
Michal Vasko1be88302015-10-22 16:07:47 +02001745 prefix_mod = lys_get_import_module(prev_mod, NULL, 0, mod_name, mod_name_len);
1746 if (!prefix_mod && (node_type == LYS_AUGMENT)) {
1747 /* we want augment nodes in this case */
1748 prefix_mod = sibling->module;
1749 if (prefix_mod->type) {
1750 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1751 }
1752 if (strncmp(prefix_mod->name, mod_name, mod_name_len) || prefix_mod->name[mod_name_len]) {
1753 prefix_mod = NULL;
1754 }
1755 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001756 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001757 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001758 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001759 } else {
Michal Vasko1be88302015-10-22 16:07:47 +02001760 prefix_mod = prev_mod;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001761 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001762
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001763 /* modules need to always be checked, we want to skip augments */
1764 if (!sibling->module->type) {
1765 if (prefix_mod != sibling->module) {
Michal Vasko1be88302015-10-22 16:07:47 +02001766 goto next;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001767 }
1768 } else {
1769 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
Michal Vasko1be88302015-10-22 16:07:47 +02001770 goto next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001771 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001772 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001773
Michal Vasko1e989c02015-08-04 12:33:00 +02001774 /* the result node? */
1775 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001776 /* we're looking only for groupings, this is a data node */
1777 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
Michal Vasko1be88302015-10-22 16:07:47 +02001778 goto next;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001779 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001780 if (ret) {
1781 *ret = sibling;
1782 }
1783 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001784 }
1785
Michal Vaskodcc7a802015-08-06 11:59:47 +02001786 /* we're looking for a grouping (node_type == LYS_USES),
1787 * but this isn't it, we cannot search inside
1788 */
1789 if (sibling->nodetype == LYS_GROUPING) {
Michal Vasko1be88302015-10-22 16:07:47 +02001790 goto next;
Michal Vaskodcc7a802015-08-06 11:59:47 +02001791 }
1792
Michal Vasko1be88302015-10-22 16:07:47 +02001793 /* remember the module */
1794 prev_mod = prefix_mod;
1795
Michal Vasko1e989c02015-08-04 12:33:00 +02001796 /* check for shorthand cases - then 'start' does not change */
1797 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1798 || (sibling->nodetype == LYS_CASE)) {
1799 start = sibling->child;
1800 }
1801 break;
1802 }
Michal Vasko1be88302015-10-22 16:07:47 +02001803
1804next:
1805 sibling = lys_getnext(sibling, start->parent, NULL, opts);
Michal Vasko1e989c02015-08-04 12:33:00 +02001806 }
1807
1808 /* we did not find the case in direct siblings */
1809 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001810 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001811 }
1812
1813 /* no match */
1814 if (!sibling) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001815 /* are we done with the included submodules as well? */
1816 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001817 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001818 }
1819
Michal Vasko1e989c02015-08-04 12:33:00 +02001820 /* we aren't, check the next one */
1821 ++in_submod;
Michal Vasko1e989c02015-08-04 12:33:00 +02001822 start = start_mod->inc[in_submod-1].submodule->data;
1823 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001824 }
1825
1826 /* we found our submodule */
1827 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001828 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001829 in_submod = 0;
1830 }
1831
Michal Vasko723e50c2015-10-20 15:20:29 +02001832 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001833 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001834 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001835 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001836 }
1837
1838 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001839 LOGINT;
1840 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841}
1842
Michal Vasko23b61ec2015-08-19 11:19:50 +02001843/* ignores line */
1844static void
1845unres_data_del(struct unres_data *unres, uint32_t i)
1846{
1847 /* there are items after the one deleted */
1848 if (i+1 < unres->count) {
1849 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001850 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001851
1852 /* deleting the last item */
1853 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001854 free(unres->node);
1855 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001856 }
1857
1858 /* if there are no items after and it is not the last one, just move the counter */
1859 --unres->count;
1860}
1861
Michal Vasko0491ab32015-08-19 14:28:29 +02001862/**
1863 * @brief Resolve (find) a data node from a specific module. Does not log.
1864 *
1865 * @param[in] mod Module to search in.
1866 * @param[in] name Name of the data node.
1867 * @param[in] nam_len Length of the name.
1868 * @param[in] start Data node to start the search from.
1869 * @param[in,out] parents Resolved nodes. If there are some parents,
1870 * they are replaced (!!) with the resolvents.
1871 *
1872 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
1873 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001874static int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001875resolve_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 +02001876{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001877 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001878 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001879 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001880
Michal Vasko23b61ec2015-08-19 11:19:50 +02001881 if (!parents->count) {
1882 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001883 parents->node = malloc(sizeof *parents->node);
1884 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001885 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001886 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02001887 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001888 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001889 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001890 continue;
1891 }
1892 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02001893 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001894 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1895 && node->schema->name[nam_len] == '\0') {
1896 /* matching target */
1897 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02001898 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02001899 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001900 flag = 1;
1901 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02001902 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001903 ++parents->count;
Michal Vaskocf024702015-10-08 15:01:42 +02001904 parents->node = realloc(parents->node, parents->count * sizeof *parents->node);
1905 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001906 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001907 }
1908 }
1909 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001910
1911 if (!flag) {
1912 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001913 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02001914 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001915 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02001916 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001917 }
1918
Michal Vasko0491ab32015-08-19 14:28:29 +02001919 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02001920}
1921
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001922/**
1923 * @brief Resolve (find) a data node. Does not log.
1924 *
Radek Krejci581ce772015-11-10 17:22:40 +01001925 * @param[in] mod_name Module name of the data node.
1926 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001927 * @param[in] name Name of the data node.
1928 * @param[in] nam_len Length of the name.
1929 * @param[in] start Data node to start the search from.
1930 * @param[in,out] parents Resolved nodes. If there are some parents,
1931 * they are replaced (!!) with the resolvents.
1932 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001933 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001934 */
Radek Krejcic5090c32015-08-12 09:46:19 +02001935static int
Radek Krejci581ce772015-11-10 17:22:40 +01001936resolve_data_node(const char *mod_name, int mod_name_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02001937 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02001938{
1939 struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02001940 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02001941
Michal Vasko23b61ec2015-08-19 11:19:50 +02001942 assert(start);
1943
Michal Vasko31fc3672015-10-21 12:08:13 +02001944 if (mod_name) {
1945 /* we have mod_name, find appropriate module */
1946 str = strndup(mod_name, mod_name_len);
1947 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
1948 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02001949 if (!mod) {
1950 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001951 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001952 }
1953 } else {
1954 /* no prefix, module is the same as of current node */
1955 mod = start->schema->module;
1956 }
1957
1958 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001959}
1960
Michal Vasko730dfdf2015-08-11 14:48:05 +02001961/**
Michal Vaskof39142b2015-10-21 11:40:05 +02001962 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02001963 * only specific errors, general no-resolvent error is left to the caller,
1964 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001965 *
Michal Vaskobb211122015-08-19 14:03:11 +02001966 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001967 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02001968 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001969 * @param[in,out] node_match Nodes satisfying the restriction
1970 * without the predicate. Nodes not
1971 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02001972 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001973 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001974 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001975 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001976static int
Michal Vasko184521f2015-09-24 13:14:26 +02001977resolve_path_predicate_data(const char *pred, int first, uint32_t line, struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001978{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001979 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001980 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001981 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02001982 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
1983 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001984 uint32_t j;
1985
1986 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001987 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001988 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001989 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001990
1991 do {
1992 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
1993 &pke_len, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001994 LOGVAL(LYE_INCHAR, line, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02001995 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001996 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001997 }
Michal Vasko0491ab32015-08-19 14:28:29 +02001998 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001999 pred += i;
2000
Michal Vasko23b61ec2015-08-19 11:19:50 +02002001 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002002 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002003 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002004
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002005 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002006 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002007 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002008 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002009 if ((rc == -1) || !first) {
2010 LOGVAL(LYE_LINE, line);
2011 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002012 i = 0;
2013 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002014 }
2015
2016 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002017 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002018 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002019 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2020 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002021 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002022 rc = -1;
2023 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002024 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002025 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002026 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002027 dest_match.node[0] = dest_match.node[0]->parent;
2028 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002029 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002030 if (!first) {
2031 LOGVAL(LYE_LINE, line);
2032 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002033 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002034 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002035 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002036 }
2037 }
2038 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002039 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002040 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002041 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002042 if ((rc == -1) || !first) {
2043 LOGVAL(LYE_LINE, line);
2044 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002045 i = 0;
2046 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002047 }
2048
2049 if (pke_len == pke_parsed) {
2050 break;
2051 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002052 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 +02002053 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002054 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002055 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002056 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002057 }
2058 pke_parsed += i;
2059 }
2060
2061 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002062 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2063 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002064 goto remove_leafref;
2065 }
2066
Michal Vasko83a6c462015-10-08 16:43:53 +02002067 if (((struct lyd_node_leaf_list *)source_match.node[0])->value_str
2068 != ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002069 goto remove_leafref;
2070 }
2071
2072 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002073 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002074 continue;
2075
2076remove_leafref:
2077 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002078 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002079 }
2080 } while (has_predicate);
2081
Michal Vaskocf024702015-10-08 15:01:42 +02002082 free(source_match.node);
2083 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002084 if (parsed) {
2085 *parsed = parsed_loc;
2086 }
2087 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002088
2089error:
2090
2091 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002092 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002093 }
2094 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002095 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002096 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002097 if (parsed) {
2098 *parsed = -parsed_loc+i;
2099 }
2100 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101}
2102
Michal Vasko730dfdf2015-08-11 14:48:05 +02002103/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002104 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002105 *
Michal Vaskocf024702015-10-08 15:01:42 +02002106 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002107 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002108 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002109 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002110 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002111 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002112 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002113 */
Michal Vasko184521f2015-09-24 13:14:26 +02002114static int
Michal Vaskocf024702015-10-08 15:01:42 +02002115resolve_path_arg_data(struct lyd_node *node, const char *path, int first, uint32_t line, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002116{
Radek Krejci71b795b2015-08-10 16:20:39 +02002117 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002118 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002119 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002120 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002121
Michal Vaskocf024702015-10-08 15:01:42 +02002122 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002123
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002124 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002125 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002126
2127 /* searching for nodeset */
2128 do {
2129 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002130 LOGVAL(LYE_INCHAR, line, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002131 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002132 goto error;
2133 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002135 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002136
Michal Vasko23b61ec2015-08-19 11:19:50 +02002137 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002138 if (parent_times != -1) {
2139 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002140 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02002141 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002142 for (i = 0; i < parent_times; ++i) {
2143 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002144 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002145 /* error, too many .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002146 LOGVAL(LYE_INVAL, line, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002147 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002148 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002149 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002150 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002151 data = ret->node[0] = node->parent;
2152 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002153 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002154 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002155 free(ret->node);
2156 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002157 } else {
2158 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002159 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002160 }
2161 }
2162
2163 /* absolute path */
2164 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002165 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002166 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002167 if (data->prev) {
2168 for (; data->prev->next; data = data->prev);
2169 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002170 }
2171 }
2172
2173 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002174 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002175 if ((rc == -1) || !first) {
2176 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
2177 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002178 goto error;
2179 }
2180
2181 if (has_predicate) {
2182 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002183 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002184 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2185 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002186 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002187 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002188 continue;
2189 }
2190
2191 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002192 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002193 }
Michal Vasko184521f2015-09-24 13:14:26 +02002194 if ((rc = resolve_path_predicate_data(path, first, line, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002195 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002196 if ((rc == -1) || !first) {
2197 LOGVAL(LYE_NORESOLV, 0, path);
2198 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002199 goto error;
2200 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002202 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002203
Michal Vasko23b61ec2015-08-19 11:19:50 +02002204 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002205 if (!first) {
2206 LOGVAL(LYE_NORESOLV, line, path-parsed);
2207 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002208 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002209 goto error;
2210 }
2211 }
2212 } while (path[0] != '\0');
2213
Michal Vaskof02e3742015-08-05 16:27:02 +02002214 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002215
2216error:
2217
Michal Vaskocf024702015-10-08 15:01:42 +02002218 free(ret->node);
2219 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002220 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002221
Michal Vasko0491ab32015-08-19 14:28:29 +02002222 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002223}
2224
Michal Vasko730dfdf2015-08-11 14:48:05 +02002225/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002226 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002227 *
Michal Vaskobb211122015-08-19 14:03:11 +02002228 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002229 * @param[in] mod Schema module.
2230 * @param[in] source_node Left operand node.
2231 * @param[in] dest_node Right ooperand node.
Michal Vasko184521f2015-09-24 13:14:26 +02002232 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002233 * @param[in] line Line in the input file.
2234 *
Michal Vasko184521f2015-09-24 13:14:26 +02002235 * @return 0 on forward reference, otherwise the number
2236 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002237 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002238 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002239static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002240resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vasko184521f2015-09-24 13:14:26 +02002241 struct lys_node *dest_node, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002242{
2243 struct lys_node *src_node, *dst_node;
2244 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2245 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 +02002246 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002247
2248 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002249 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002250 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002251 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002252 return -parsed+i;
2253 }
2254 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002255 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002256
Michal Vasko58090902015-08-13 14:04:15 +02002257 /* source (must be leaf) */
Michal Vasko165dc4a2015-10-23 09:44:27 +02002258 rc = lys_get_sibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len,
2259 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002260 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002261 if ((rc == -1) || !first) {
2262 LOGVAL(LYE_NORESOLV, line, path-parsed);
2263 }
2264 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002265 }
2266
2267 /* destination */
2268 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2269 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002270 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002271 return -parsed;
2272 }
2273 pke_parsed += i;
2274
2275 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2276 dst_node = dest_node;
2277 for (i = 1; i < dest_parent_times; ++i) {
2278 dst_node = dst_node->parent;
2279 if (!dst_node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002280 if (!first) {
2281 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2282 }
2283 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002284 }
2285 }
2286 while (1) {
Michal Vasko165dc4a2015-10-23 09:44:27 +02002287 rc = lys_get_sibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
2288 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002289 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002290 if ((rc == -1) || !first) {
2291 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2292 }
2293 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002294 }
2295
2296 if (pke_len == pke_parsed) {
2297 break;
2298 }
2299
2300 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2301 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002302 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002303 return -parsed;
2304 }
2305 pke_parsed += i;
2306 }
2307
2308 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002309 if (dst_node->nodetype != LYS_LEAF) {
Michal Vaskod9173342015-08-17 14:35:36 +02002310 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002311 LOGVAL(LYE_SPEC, 0, "Destination node not a leaf, but %s.", strnodetype(dst_node->nodetype));
2312 return -parsed;
2313 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002314 } while (has_predicate);
2315
2316 return parsed;
2317}
2318
Michal Vasko730dfdf2015-08-11 14:48:05 +02002319/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002320 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002321 *
Michal Vaskobb211122015-08-19 14:03:11 +02002322 * @param[in] mod Module to use.
2323 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002324 * @param[in] parent_node Parent of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002325 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002326 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002327 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002328 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002329 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002330 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002331static int
Michal Vasko184521f2015-09-24 13:14:26 +02002332resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, int first,
2333 uint32_t line, struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002334{
Michal Vasko58090902015-08-13 14:04:15 +02002335 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002336 const char *id, *prefix, *name;
2337 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002338 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002339
Michal Vasko184521f2015-09-24 13:14:26 +02002340 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002341 parent_times = 0;
2342 id = path;
2343
2344 do {
2345 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002346 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002347 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002348 }
2349 id += i;
2350
Michal Vasko184521f2015-09-24 13:14:26 +02002351 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002352 if (parent_times == -1) {
2353 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002354 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002355 if (!first) {
2356 LOGVAL(LYE_NORESOLV, line, path);
2357 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002358 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002359 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002360 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002361 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002362 node = parent_node;
2363 i = 0;
2364 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002365 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002366 if (!first) {
2367 LOGVAL(LYE_NORESOLV, line, path);
2368 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002369 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002370 }
Michal Vasko58090902015-08-13 14:04:15 +02002371
2372 /* this node is a wrong node, we actually need the augment target */
2373 if (node->nodetype == LYS_AUGMENT) {
2374 node = ((struct lys_node_augment *)node)->target;
2375 if (!node) {
2376 continue;
2377 }
2378 }
2379
2380 ++i;
2381 if (i == parent_times) {
2382 break;
2383 }
2384 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002385 }
2386 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002387 } else {
2388 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002389 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002390 }
Michal Vasko184521f2015-09-24 13:14:26 +02002391 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002392 } else {
2393 node = node->child;
2394 }
2395
Michal Vasko165dc4a2015-10-23 09:44:27 +02002396 rc = lys_get_sibling(mod, node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002397 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002398 if ((rc == -1) || !first) {
2399 LOGVAL(LYE_NORESOLV, line, path);
2400 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002401 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002402 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002403
2404 if (has_predicate) {
2405 /* we have predicate, so the current result must be list */
2406 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002407 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002408 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002409 }
2410
Michal Vasko184521f2015-09-24 13:14:26 +02002411 i = resolve_path_predicate_schema(id, mod, node, parent_node, first, line);
2412 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002413 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002414 } else if (i < 0) {
2415 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002416 }
2417 id += i;
2418 }
2419 } while (id[0]);
2420
Radek Krejcib1c12512015-08-11 11:22:04 +02002421 /* the target must be leaf or leaf-list */
2422 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002423 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002424 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002425 }
2426
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002427 if (ret) {
2428 *ret = node;
2429 }
2430 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002431}
2432
Michal Vasko730dfdf2015-08-11 14:48:05 +02002433/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002434 * @brief Resolve instance-identifier predicate in JSON data format.
2435 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002436 *
Michal Vaskobb211122015-08-19 14:03:11 +02002437 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002438 * @param[in,out] node_match Nodes matching the restriction without
2439 * the predicate. Nodes not satisfying
2440 * the predicate are removed.
2441 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002442 * @return Number of characters successfully parsed,
2443 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002444 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002445static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002446resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002447{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002448 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002449 struct unres_data target_match;
2450 struct ly_ctx *ctx;
2451 struct lys_module *mod;
2452 const char *model, *name, *value;
2453 char *str;
2454 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2455 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456
Michal Vasko1f2cc332015-08-19 11:18:32 +02002457 assert(pred && node_match->count);
2458
Michal Vaskocf024702015-10-08 15:01:42 +02002459 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002460 idx = -1;
2461 parsed = 0;
2462
2463 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002464 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002465 return -parsed+i;
2466 }
2467 parsed += i;
2468 pred += i;
2469
Michal Vasko1f2cc332015-08-19 11:18:32 +02002470 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002471 if (isdigit(name[0])) {
2472 idx = atoi(name);
2473 }
2474
Michal Vasko1f2cc332015-08-19 11:18:32 +02002475 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002476 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002477 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002478 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002479 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002480 target_match.node = malloc(sizeof *target_match.node);
2481 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002482 } else {
2483 str = strndup(model, mod_len);
2484 mod = ly_ctx_get_module(ctx, str, NULL);
2485 free(str);
2486
Michal Vaskocf024702015-10-08 15:01:42 +02002487 if (resolve_data(mod, name, nam_len, node_match->node[j], &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002488 goto remove_instid;
2489 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002490 }
2491
2492 /* check that we have the correct type */
2493 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002494 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002495 goto remove_instid;
2496 }
2497 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002498 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002499 goto remove_instid;
2500 }
2501 }
2502
Michal Vasko83a6c462015-10-08 16:43:53 +02002503 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2504 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002505 || (!value && (idx != cur_idx))) {
2506 goto remove_instid;
2507 }
2508
Michal Vaskocf024702015-10-08 15:01:42 +02002509 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002510
2511 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002512 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002513 continue;
2514
2515remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002516 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002517
2518 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002519 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002520 }
2521 } while (has_predicate);
2522
2523 return parsed;
2524}
2525
Michal Vasko730dfdf2015-08-11 14:48:05 +02002526/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002527 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002528 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002529 * @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 +02002530 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002531 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002532 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002533 * @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 +02002534 */
Michal Vasko184521f2015-09-24 13:14:26 +02002535static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002536resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002537{
Radek Krejcic5090c32015-08-12 09:46:19 +02002538 int i = 0, j;
2539 struct lyd_node *result = NULL;
2540 struct lys_module *mod = NULL;
2541 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002542 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002543 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002544 int mod_len, name_len, has_predicate;
2545 struct unres_data node_match;
2546 uint32_t k;
2547
2548 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002549
Radek Krejcic5090c32015-08-12 09:46:19 +02002550 /* we need root to resolve absolute path */
2551 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002552 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002553 if (data->prev) {
2554 for (; data->prev->next; data = data->prev);
2555 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002556
Radek Krejcic5090c32015-08-12 09:46:19 +02002557 /* search for the instance node */
2558 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002559 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002560 if (j <= 0) {
2561 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002562 goto error;
2563 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002564 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002565
Michal Vasko1f2cc332015-08-19 11:18:32 +02002566 str = strndup(model, mod_len);
2567 mod = ly_ctx_get_module(ctx, str, NULL);
2568 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002569
Radek Krejcic5090c32015-08-12 09:46:19 +02002570 if (!mod) {
2571 /* no instance exists */
2572 return NULL;
2573 }
2574
Michal Vasko1f2cc332015-08-19 11:18:32 +02002575 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002576 /* no instance exists */
2577 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002578 }
2579
2580 if (has_predicate) {
2581 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002582 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002583 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2584 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2585 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002586 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002587 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002588 continue;
2589 }
2590
2591 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002592 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002594
Michal Vaskof39142b2015-10-21 11:40:05 +02002595 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002596 if (j < 1) {
2597 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002598 goto error;
2599 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002600 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002601
Michal Vasko1f2cc332015-08-19 11:18:32 +02002602 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002603 /* no instance exists */
2604 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002605 }
2606 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002607 }
2608
Michal Vasko1f2cc332015-08-19 11:18:32 +02002609 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002610 /* no instance exists */
2611 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002612 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002613 /* instance identifier must resolve to a single node */
2614 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2615
2616 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002617 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002618
2619 return NULL;
2620 } else {
2621 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002622 result = node_match.node[0];
2623 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002624
2625 return result;
2626 }
2627
2628error:
2629
2630 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002631 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002632
2633 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002634}
2635
Michal Vasko730dfdf2015-08-11 14:48:05 +02002636/**
2637 * @brief Passes config flag down to children. Does not log.
2638 *
2639 * @param[in] node Parent node.
2640 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002642inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002644 LY_TREE_FOR(node, node) {
2645 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2646 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002647 }
2648}
2649
Michal Vasko730dfdf2015-08-11 14:48:05 +02002650/**
Michal Vaskod9173342015-08-17 14:35:36 +02002651 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002652 *
Michal Vaskobb211122015-08-19 14:03:11 +02002653 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002654 * @param[in] siblings Nodes where to start the search in.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002655 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002656 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002657 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002658int
Michal Vasko1d87a922015-08-21 12:57:16 +02002659resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002660{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002661 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002662 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002663
Michal Vasko1d87a922015-08-21 12:57:16 +02002664 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002665
2666 /* resolve target node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002667 rc = resolve_schema_nodeid(aug->target_name, siblings, aug->module, LYS_AUGMENT, &aug->target);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002668 if (rc) {
2669 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002670 }
2671
2672 if (!aug->child) {
2673 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002674 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002675 return EXIT_SUCCESS;
2676 }
2677
2678 /* inherit config information from parent, augment does not have
2679 * config property, but we need to keep the information for subelements
2680 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002681 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002682 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002683 inherit_config_flag(sub);
2684 }
2685
Radek Krejci07911992015-08-14 15:13:31 +02002686 /* check identifier uniquness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02002687 LY_TREE_FOR(aug->child, sub) {
2688 if (lys_check_id(sub, aug->parent, aug->module)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002689 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002690 }
2691 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002692 /* reconnect augmenting data into the target - add them to the target child list */
2693 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002694 sub = aug->target->child->prev; /* remember current target's last node */
2695 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002696 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002697 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002698 } else {
2699 aug->target->child = aug->child;
2700 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002701
2702 return EXIT_SUCCESS;
2703}
2704
Michal Vasko730dfdf2015-08-11 14:48:05 +02002705/**
2706 * @brief Resolve uses, apply augments, refines. Logs directly.
2707 *
Michal Vaskobb211122015-08-19 14:03:11 +02002708 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002709 * @param[in,out] unres List of unresolved items.
2710 * @param[in] line Line in the input file.
2711 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002712 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002713 */
Michal Vasko184521f2015-09-24 13:14:26 +02002714static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002715resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002716{
2717 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002718 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002719 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002720 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002721 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002722 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002723
Michal Vasko71e1aa82015-08-12 12:17:51 +02002724 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002725 /* HACK just check that the grouing is resolved */
2726 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002727
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002728 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002729 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002730 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002731 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002732 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002733 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002734 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002735 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002736 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002737 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002738 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002739 }
2740 }
2741 ctx = uses->module->ctx;
2742
Michal Vaskodef0db12015-10-07 13:22:48 +02002743 /* we managed to copy the grouping, the rest must be possible to resolve */
2744
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002745 /* apply refines */
2746 for (i = 0; i < uses->refine_size; i++) {
2747 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002748 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2749 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002750 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2751 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002752 }
2753
Radek Krejci1d82ef62015-08-07 14:44:40 +02002754 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002755 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002756 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002757 }
2758
2759 /* description on any nodetype */
2760 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002761 lydict_remove(ctx, node->dsc);
2762 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002763 }
2764
2765 /* reference on any nodetype */
2766 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002767 lydict_remove(ctx, node->ref);
2768 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002769 }
2770
2771 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002772 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002773 node->flags &= ~LYS_CONFIG_MASK;
2774 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002775 }
2776
2777 /* default value ... */
2778 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002779 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002781 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2782 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2783 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002785 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2786 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002787 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2788 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002789 }
2790 }
2791 }
2792
2793 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002794 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002795 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002797 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002798
2799 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002800 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002801 }
2802 }
2803
2804 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002805 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2806 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2807 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 }
2809
2810 /* min/max-elements on list or leaf-list */
2811 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002812 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002813 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002814 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002815 }
2816 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002817 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002818 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002819 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002820 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002821 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002822 }
2823 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002824 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002825 }
2826 }
2827
2828 /* must in leaf, leaf-list, list, container or anyxml */
2829 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002830 switch (node->nodetype) {
2831 case LYS_LEAF:
2832 old_size = &((struct lys_node_leaf *)node)->must_size;
2833 old_must = &((struct lys_node_leaf *)node)->must;
2834 break;
2835 case LYS_LEAFLIST:
2836 old_size = &((struct lys_node_leaflist *)node)->must_size;
2837 old_must = &((struct lys_node_leaflist *)node)->must;
2838 break;
2839 case LYS_LIST:
2840 old_size = &((struct lys_node_list *)node)->must_size;
2841 old_must = &((struct lys_node_list *)node)->must;
2842 break;
2843 case LYS_CONTAINER:
2844 old_size = &((struct lys_node_container *)node)->must_size;
2845 old_must = &((struct lys_node_container *)node)->must;
2846 break;
2847 case LYS_ANYXML:
2848 old_size = &((struct lys_node_anyxml *)node)->must_size;
2849 old_must = &((struct lys_node_anyxml *)node)->must;
2850 break;
2851 default:
2852 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02002853 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002854 }
2855
2856 size = *old_size + rfn->must_size;
2857 must = realloc(*old_must, size * sizeof *rfn->must);
2858 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002859 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002860 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002862 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
2863 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2864 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2865 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2866 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2867 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002868 }
2869
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002870 *old_must = must;
2871 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872 }
2873 }
2874
2875 /* apply augments */
2876 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002877 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002878 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002879 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
2880 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 }
2882 }
2883
2884 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002885}
2886
Michal Vasko730dfdf2015-08-11 14:48:05 +02002887/**
2888 * @brief Resolve base identity recursively. Does not log.
2889 *
2890 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002891 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002892 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002893 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002894 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002895 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002896 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002897static int
2898resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2899 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900{
Michal Vaskof02e3742015-08-05 16:27:02 +02002901 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002902 struct lys_ident *base_iter = NULL;
2903 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002904
2905 /* search module */
2906 for (i = 0; i < module->ident_size; i++) {
2907 if (!strcmp(basename, module->ident[i].name)) {
2908
2909 if (!ident) {
2910 /* just search for type, so do not modify anything, just return
2911 * the base identity pointer
2912 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002913 if (ret) {
2914 *ret = &module->ident[i];
2915 }
2916 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 }
2918
2919 /* we are resolving identity definition, so now update structures */
2920 ident->base = base_iter = &module->ident[i];
2921
2922 break;
2923 }
2924 }
2925
2926 /* search submodules */
2927 if (!base_iter) {
2928 for (j = 0; j < module->inc_size; j++) {
2929 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2930 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2931
2932 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002933 if (ret) {
2934 *ret = &module->inc[j].submodule->ident[i];
2935 }
2936 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937 }
2938
2939 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2940 break;
2941 }
2942 }
2943 }
2944 }
2945
2946 /* we found it somewhere */
2947 if (base_iter) {
2948 while (base_iter) {
2949 for (der = base_iter->der; der && der->next; der = der->next);
2950 if (der) {
2951 der->next = malloc(sizeof *der);
2952 der = der->next;
2953 } else {
2954 ident->base->der = der = malloc(sizeof *der);
2955 }
2956 der->next = NULL;
2957 der->ident = ident;
2958
2959 base_iter = base_iter->base;
2960 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002961 if (ret) {
2962 *ret = ident->base;
2963 }
2964 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002965 }
2966
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002967 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002968}
2969
Michal Vasko730dfdf2015-08-11 14:48:05 +02002970/**
2971 * @brief Resolve base identity. Logs directly.
2972 *
2973 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002974 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002975 * @param[in] basename Base name of the identity.
2976 * @param[in] parent Either "type" or "ident".
Michal Vasko184521f2015-09-24 13:14:26 +02002977 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002978 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002979 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002980 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002981 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002982 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002983static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002984resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko184521f2015-09-24 13:14:26 +02002985 int first, uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986{
2987 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002988 int i, mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002989
2990 /* search for the base identity */
2991 name = strchr(basename, ':');
2992 if (name) {
2993 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02002994 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002995 name++;
2996
Michal Vasko2d851a92015-10-20 16:16:36 +02002997 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002998 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02002999 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003000 }
3001 } else {
3002 name = basename;
3003 }
3004
Michal Vasko2d851a92015-10-20 16:16:36 +02003005 if (mod_name_len) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003006 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02003007 module = lys_get_import_module(module, NULL, 0, basename, mod_name_len);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003008 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003009 /* identity refers unknown data model */
Michal Vasko1dca6882015-10-22 14:29:42 +02003010 LOGVAL(LYE_INMOD, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003011 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003012 }
3013 } else {
3014 /* search in submodules */
3015 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003016 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3017 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003018 }
3019 }
3020 }
3021
3022 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003023 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3024 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003025 }
3026
Michal Vasko184521f2015-09-24 13:14:26 +02003027 if (!first) {
3028 LOGVAL(LYE_INARG, line, basename, parent);
3029 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003030 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003031}
3032
Michal Vasko730dfdf2015-08-11 14:48:05 +02003033/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003034 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003035 *
3036 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003037 * @param[in] ident_name Identityref name.
3038 * @param[in] line Line from the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003039 *
3040 * @return Pointer to the identity resolvent, NULL on error.
3041 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003042struct lys_ident *
Michal Vaskof39142b2015-10-21 11:40:05 +02003043resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003044{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003045 const char *mod_name, *name;
3046 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003047 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048
Michal Vaskofb0873c2015-08-21 09:00:07 +02003049 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050 return NULL;
3051 }
3052
Michal Vaskoc633ca02015-08-21 14:03:51 +02003053 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003054 if (rc < (signed)strlen(ident_name)) {
3055 LOGVAL(LYE_INCHAR, line, ident_name[-rc], &ident_name[-rc]);
3056 return NULL;
3057 }
3058
Michal Vaskoc633ca02015-08-21 14:03:51 +02003059 if (!strcmp(base->name, name) && (!mod_name
3060 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003061 return base;
3062 }
3063
3064 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003065 if (!strcmp(der->ident->name, name) && (!mod_name
3066 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3067 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003068 /* we have match */
3069 return der->ident;
3070 }
3071 }
3072
Michal Vaskofb0873c2015-08-21 09:00:07 +02003073 LOGVAL(LYE_INRESOLV, line, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003074 return NULL;
3075}
3076
Michal Vasko730dfdf2015-08-11 14:48:05 +02003077/**
Michal Vasko7955b362015-09-04 14:18:15 +02003078 * @brief Resolve (find) choice default case. Does not log.
3079 *
3080 * @param[in] choic Choice to use.
3081 * @param[in] dflt Name of the default case.
3082 *
3083 * @return Pointer to the default node or NULL.
3084 */
3085static struct lys_node *
3086resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3087{
3088 struct lys_node *child, *ret;
3089
3090 LY_TREE_FOR(choic->child, child) {
3091 if (child->nodetype == LYS_USES) {
3092 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3093 if (ret) {
3094 return ret;
3095 }
3096 }
3097
3098 if ((child->name == dflt) && (child->nodetype & (LYS_ANYXML | LYS_CASE
3099 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3100 return child;
3101 }
3102 }
3103
3104 return NULL;
3105}
3106
3107/**
Michal Vaskobb211122015-08-19 14:03:11 +02003108 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003109 *
Michal Vaskobb211122015-08-19 14:03:11 +02003110 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003111 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003112 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003113 * @param[in] line Line in the input file.
3114 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003115 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003116 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003118resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003120 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003121 struct lys_node *parent;
3122
3123 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3124 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3125
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003126 if (!uses->grp) {
Michal Vasko184521f2015-09-24 13:14:26 +02003127 rc = resolve_grouping(uses, first, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003128 if (rc) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003129 if (parent && first && (rc == EXIT_FAILURE)) {
3130 ++parent->nacm;
3131 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003132 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003133 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003134 }
3135
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003136 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003137 if (parent && first) {
3138 ++parent->nacm;
3139 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003140 return EXIT_FAILURE;
3141 }
3142
Michal Vaskodef0db12015-10-07 13:22:48 +02003143 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003144 if (!rc) {
3145 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003146 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003147 if (!parent->nacm) {
3148 LOGINT;
3149 return -1;
3150 }
3151 --parent->nacm;
3152 }
3153 return EXIT_SUCCESS;
3154 }
3155
Michal Vasko407f1bb2015-09-23 15:51:07 +02003156 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003157 ++parent->nacm;
3158 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003159 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003160}
3161
Michal Vasko730dfdf2015-08-11 14:48:05 +02003162/**
Michal Vasko9957e592015-08-17 15:04:09 +02003163 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003164 *
Michal Vaskobb211122015-08-19 14:03:11 +02003165 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003166 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003167 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003168 * @param[in] line Line in the input file.
3169 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003170 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003171 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172static int
Michal Vasko184521f2015-09-24 13:14:26 +02003173resolve_list_keys(struct lys_module *mod, struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003175 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003176 const char *value;
3177
3178 for (i = 0; i < list->keys_size; ++i) {
3179 /* get the key name */
3180 if ((value = strpbrk(keys_str, " \t\n"))) {
3181 len = value - keys_str;
3182 while (isspace(value[0])) {
3183 value++;
3184 }
3185 } else {
3186 len = strlen(keys_str);
3187 }
3188
Michal Vasko165dc4a2015-10-23 09:44:27 +02003189 rc = lys_get_sibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003190 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003191 if ((rc == -1) || !first) {
3192 LOGVAL(LYE_INRESOLV, line, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003193 }
3194 return rc;
3195 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003196
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003197 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 /* check_key logs */
3199 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200 }
3201
3202 /* prepare for next iteration */
3203 while (value && isspace(value[0])) {
3204 value++;
3205 }
3206 keys_str = value;
3207 }
3208
Michal Vaskof02e3742015-08-05 16:27:02 +02003209 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210}
3211
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003212/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003213 * @brief Resolve (check) all must conditions of \p node.
3214 * Logs directly.
3215 *
3216 * @param[in] node Data node with optional must statements.
3217 * @param[in] first Whether this is the first resolution to try.
3218 * @param[in] line Line in the input file.
3219 *
3220 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3221 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003222static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003223resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003224{
Michal Vaskobf19d252015-10-08 15:39:17 +02003225 uint8_t i, must_size;
3226 struct lys_restr *must;
3227 struct lyxp_set set;
3228
3229 assert(node);
3230 memset(&set, 0, sizeof set);
3231
3232 switch (node->schema->nodetype) {
3233 case LYS_CONTAINER:
3234 must_size = ((struct lys_node_container *)node->schema)->must_size;
3235 must = ((struct lys_node_container *)node->schema)->must;
3236 break;
3237 case LYS_LEAF:
3238 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3239 must = ((struct lys_node_leaf *)node->schema)->must;
3240 break;
3241 case LYS_LEAFLIST:
3242 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3243 must = ((struct lys_node_leaflist *)node->schema)->must;
3244 break;
3245 case LYS_LIST:
3246 must_size = ((struct lys_node_list *)node->schema)->must_size;
3247 must = ((struct lys_node_list *)node->schema)->must;
3248 break;
3249 case LYS_ANYXML:
3250 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3251 must = ((struct lys_node_anyxml *)node->schema)->must;
3252 break;
3253 default:
3254 must_size = 0;
3255 break;
3256 }
3257
3258 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003259 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003260 return -1;
3261 }
3262
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003263 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003264
3265 if (!set.value.bool) {
3266 if (!first) {
3267 LOGVAL(LYE_NOCOND, line, "Must", must[i].expr);
3268 }
3269 return 1;
3270 }
3271 }
3272
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003274}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275
Michal Vaskobf19d252015-10-08 15:39:17 +02003276/**
Michal Vaskocf024702015-10-08 15:01:42 +02003277 * @brief Resolve (find) when condition context node. Does not log.
3278 *
3279 * @param[in] node Data node, whose conditional definition is being decided.
3280 * @param[in] schema Schema node with a when condition.
3281 *
3282 * @return Context node.
3283 */
3284static struct lyd_node *
3285resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286{
Michal Vaskocf024702015-10-08 15:01:42 +02003287 struct lyd_node *parent;
3288 struct lys_node *sparent;
3289 uint16_t i, data_depth, schema_depth;
3290
3291 /* find a not schema-only node */
3292 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3293 schema = lys_parent(schema);
3294 if (!schema) {
3295 return NULL;
3296 }
3297 }
3298
3299 /* get node depths */
3300 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3301 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3302 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3303 ++schema_depth;
3304 }
3305 }
3306 if (data_depth < schema_depth) {
3307 return NULL;
3308 }
3309
3310 /* find the corresponding data node */
3311 for (i = 0; i < data_depth - schema_depth; ++i) {
3312 node = node->parent;
3313 }
3314 if (node->schema != schema) {
3315 return NULL;
3316 }
3317
3318 return node;
3319}
3320
3321/**
3322 * @brief Resolve (check) all when conditions relevant for \p node.
3323 * Logs directly.
3324 *
3325 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3326 * @param[in] first Whether this is the first resolution to try.
3327 * @param[in] line Line in the input file.
3328 *
3329 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3330 */
3331static int
3332resolve_when(struct lyd_node *node, int first, uint32_t line)
3333{
3334 struct lyd_node *ctx_node = NULL;
3335 struct lys_node *parent;
3336 struct lyxp_set set;
3337
3338 assert(node);
3339 memset(&set, 0, sizeof set);
3340
3341 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003342 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003343 return -1;
3344 }
3345
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003346 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003347
3348 if (!set.value.bool) {
3349 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003350 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003351 }
3352 return 1;
3353 }
3354 }
3355
3356 parent = node->schema;
3357 goto check_augment;
3358
3359 /* check when in every schema node that affects node */
3360 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3361 if (((struct lys_node_uses *)parent)->when) {
3362 if (!ctx_node) {
3363 ctx_node = resolve_when_ctx_node(node, parent);
3364 if (!ctx_node) {
3365 LOGINT;
3366 return -1;
3367 }
3368 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003369 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003370 return -1;
3371 }
3372
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003373 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003374
3375 if (!set.value.bool) {
3376 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003377 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003378 }
3379 return 1;
3380 }
3381 }
3382
3383check_augment:
3384 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3385 if (!ctx_node) {
3386 ctx_node = resolve_when_ctx_node(node, parent->parent);
3387 if (!ctx_node) {
3388 LOGINT;
3389 return -1;
3390 }
3391 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003392 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003393 return -1;
3394 }
3395
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003396 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003397
3398 if (!set.value.bool) {
3399 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003400 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003401 }
3402 return 1;
3403 }
3404 }
3405
3406 parent = lys_parent(parent);
3407 }
3408
3409 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410}
3411
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003412/**
Michal Vaskobb211122015-08-19 14:03:11 +02003413 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003414 *
3415 * @param[in] mod Main module.
3416 * @param[in] item Item to resolve. Type determined by \p type.
3417 * @param[in] type Type of the unresolved item.
3418 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003419 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003420 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003421 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003422 *
3423 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3424 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003425static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003426resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003427 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003428{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003429 int rc = -1, has_str = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003430 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003431 const char *base_name;
3432
3433 struct lys_ident *ident;
3434 struct lys_type *stype;
3435 struct lys_feature **feat_ptr;
3436 struct lys_node_choice *choic;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003437
3438 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003439 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003440 base_name = str_snode;
3441 ident = item;
3442
Michal Vasko184521f2015-09-24 13:14:26 +02003443 rc = resolve_base_ident(mod, ident, base_name, "ident", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003444 has_str = 1;
3445 break;
3446 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003447 base_name = str_snode;
3448 stype = item;
3449
Michal Vasko184521f2015-09-24 13:14:26 +02003450 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003451 has_str = 1;
3452 break;
3453 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003454 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003455 stype = item;
3456
Michal Vasko184521f2015-09-24 13:14:26 +02003457 rc = resolve_path_arg_schema(mod, stype->info.lref.path, node, first, line,
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003458 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003459 has_str = 0;
3460 break;
3461 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003462 base_name = str_snode;
3463 stype = item;
3464
3465 /* HACK type->der is temporarily its parent */
Michal Vasko1dca6882015-10-22 14:29:42 +02003466 rc = resolve_superior_type(base_name, stype->module_name, mod, (struct lys_node *)stype->der, &stype->der);
Michal Vasko0d343d12015-08-24 14:57:36 +02003467 if (rc == -1) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003468 LOGVAL(LYE_INMOD, line, stype->module_name);
Michal Vasko0d343d12015-08-24 14:57:36 +02003469 } else if (!rc) {
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003470 stype->base = stype->der->type.base;
3471 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472 has_str = 1;
3473 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003474 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003475 base_name = str_snode;
3476 feat_ptr = item;
3477
Michal Vasko184521f2015-09-24 13:14:26 +02003478 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479 has_str = 1;
3480 break;
3481 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003482 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483 has_str = 0;
3484 break;
3485 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003486 base_name = str_snode;
3487 stype = item;
3488
Michal Vasko1dca6882015-10-22 14:29:42 +02003489 rc = check_default(stype, base_name, first, line);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003490 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 has_str = 0;
3492 break;
3493 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003494 base_name = str_snode;
3495 choic = item;
3496
Michal Vasko7955b362015-09-04 14:18:15 +02003497 choic->dflt = resolve_choice_dflt(choic, base_name);
3498 if (choic->dflt) {
3499 rc = EXIT_SUCCESS;
3500 } else {
3501 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003502 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503 has_str = 1;
3504 break;
3505 case UNRES_LIST_KEYS:
Michal Vasko184521f2015-09-24 13:14:26 +02003506 rc = resolve_list_keys(mod, item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507 has_str = 1;
3508 break;
3509 case UNRES_LIST_UNIQ:
Radek Krejci581ce772015-11-10 17:22:40 +01003510 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511 has_str = 1;
3512 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003513 default:
3514 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003515 break;
3516 }
3517
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003518 if (has_str && !rc) {
3519 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 }
3521
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003522 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003523}
3524
Michal Vaskof02e3742015-08-05 16:27:02 +02003525/* logs directly */
3526static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003527print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528{
Michal Vaskof02e3742015-08-05 16:27:02 +02003529 char line_str[18];
3530
3531 if (line) {
3532 sprintf(line_str, " (line %u)", line);
3533 } else {
3534 line_str[0] = '\0';
3535 }
3536
3537 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003538 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003539 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003540 break;
3541 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003542 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003543 break;
3544 case UNRES_TYPE_LEAFREF:
3545 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3546 break;
3547 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003548 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 +02003549 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003550 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003551 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 +02003552 break;
3553 case UNRES_USES:
3554 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3555 break;
3556 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003557 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 +02003558 break;
3559 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003560 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 +02003561 break;
3562 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003563 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 +02003564 break;
3565 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003566 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 +02003567 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003568 default:
3569 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003570 break;
3571 }
3572}
3573
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003574/**
Michal Vaskobb211122015-08-19 14:03:11 +02003575 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003576 *
3577 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003578 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003579 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003580 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003581 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003582int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003583resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003584{
Michal Vasko1c4e0ef2015-08-19 11:19:28 +02003585 uint32_t i, resolved, unres_uses, res_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003586 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587
3588 assert(unres);
3589
Michal Vasko51054ca2015-08-12 12:20:00 +02003590 resolved = 0;
3591
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003592 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003593 do {
3594 unres_uses = 0;
3595 res_uses = 0;
3596
3597 for (i = 0; i < unres->count; ++i) {
3598 if (unres->type[i] != UNRES_USES) {
3599 continue;
3600 }
3601
3602 ++unres_uses;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003603 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3604 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003605 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003606 unres->type[i] = UNRES_RESOLVED;
3607 ++resolved;
3608 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003609 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003610 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003611 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003612 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003613 } while (res_uses && (res_uses < unres_uses));
3614
3615 if (res_uses < unres_uses) {
3616 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003617 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003618 }
3619
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003620 /* the rest */
3621 for (i = 0; i < unres->count; ++i) {
3622 if (unres->type[i] == UNRES_RESOLVED) {
3623 continue;
3624 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003625
Michal Vasko407f1bb2015-09-23 15:51:07 +02003626 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3627 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003628 if (rc) {
3629 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630 }
Michal Vasko184521f2015-09-24 13:14:26 +02003631
3632 unres->type[i] = UNRES_RESOLVED;
3633 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003634 }
3635
3636 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003637 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3638 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639 }
3640
3641 return EXIT_SUCCESS;
3642}
3643
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003644/**
Michal Vaskobb211122015-08-19 14:03:11 +02003645 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003646 *
3647 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003648 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003649 * @param[in] item Item to resolve. Type determined by \p type.
3650 * @param[in] type Type of the unresolved item.
3651 * @param[in] str String argument.
3652 * @param[in] line Line in the input file.
3653 *
3654 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3655 */
3656int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003657unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, const char *str,
Michal Vasko7955b362015-09-04 14:18:15 +02003658 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003659{
3660 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003661 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662}
3663
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003664/**
Michal Vaskobb211122015-08-19 14:03:11 +02003665 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003666 *
3667 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003668 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003669 * @param[in] item Item to resolve. Type determined by \p type.
3670 * @param[in] type Type of the unresolved item.
3671 * @param[in] snode Schema node argument.
3672 * @param[in] line Line in the input file.
3673 *
3674 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3675 */
3676int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003677unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003678 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003680 int rc;
3681
Michal Vasko9bf425b2015-10-22 11:42:03 +02003682 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
3683 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684
Michal Vasko184521f2015-09-24 13:14:26 +02003685 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003686 if (rc != EXIT_FAILURE) {
3687 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003688 }
3689
Michal Vasko0bd29d12015-08-19 11:45:49 +02003690 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003691
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003692 unres->count++;
3693 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3694 unres->item[unres->count-1] = item;
3695 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3696 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003697 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003698 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003699#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003700 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3701 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003702#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003703
3704 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705}
3706
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003707/**
Michal Vaskobb211122015-08-19 14:03:11 +02003708 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003709 *
3710 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003711 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003712 * @param[in] item Old item to be resolved.
3713 * @param[in] type Type of the old unresolved item.
3714 * @param[in] new_item New item to use in the duplicate.
3715 *
3716 * @return EXIT_SUCCESS on success, -1 on error.
3717 */
Michal Vaskodad19402015-08-06 09:51:53 +02003718int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003719unres_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 +02003720{
3721 int i;
3722
Michal Vaskocf024702015-10-08 15:01:42 +02003723 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003724
Michal Vasko0bd29d12015-08-19 11:45:49 +02003725 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726
3727 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003728 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003729 }
3730
Michal Vasko0d204592015-10-07 09:50:04 +02003731 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003732 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003733 LOGINT;
3734 return -1;
3735 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003736 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003737 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003738 LOGINT;
3739 return -1;
3740 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003741 }
Michal Vaskodad19402015-08-06 09:51:53 +02003742
3743 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003744}
3745
Michal Vaskof02e3742015-08-05 16:27:02 +02003746/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003747int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003748unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003749{
3750 uint32_t ret = -1, i;
3751
3752 for (i = 0; i < unres->count; ++i) {
3753 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3754 ret = i;
3755 break;
3756 }
3757 }
3758
3759 return ret;
3760}
Michal Vasko8bcdf292015-08-19 14:04:43 +02003761
3762/* logs directly */
3763static void
Michal Vaskocf024702015-10-08 15:01:42 +02003764print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003765{
3766 struct lys_node_leaf *sleaf;
3767 char line_str[18];
3768
3769 if (line) {
3770 sprintf(line_str, " (line %u)", line);
3771 } else {
3772 line_str[0] = '\0';
3773 }
3774
Michal Vaskocf024702015-10-08 15:01:42 +02003775 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003776
Michal Vaskocf024702015-10-08 15:01:42 +02003777 switch (type) {
3778 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003779 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
3780 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003781 break;
3782 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003783 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02003784 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003785 break;
3786 case UNRES_WHEN:
3787 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
3788 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02003789 case UNRES_MUST:
3790 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
3791 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003792 default:
3793 LOGINT;
3794 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003795 }
3796}
3797
3798/**
3799 * @brief Resolve a single unres data item. Logs directly.
3800 *
Michal Vaskocf024702015-10-08 15:01:42 +02003801 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02003802 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02003803 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02003804 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003805 *
3806 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3807 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02003808int
Michal Vaskocf024702015-10-08 15:01:42 +02003809resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003810{
3811 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02003812 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02003813 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003814 struct lys_node_leaf *sleaf;
3815 struct unres_data matches;
3816
3817 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02003818 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02003819 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003820
Michal Vaskocf024702015-10-08 15:01:42 +02003821 switch (type) {
3822 case UNRES_LEAFREF:
3823 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02003824 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003825 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003826 }
3827
3828 /* check that value matches */
3829 for (i = 0; i < matches.count; ++i) {
Michal Vasko83a6c462015-10-08 16:43:53 +02003830 if (leaf->value_str == ((struct lyd_node_leaf_list *)matches.node[i])->value_str) {
Michal Vaskocf024702015-10-08 15:01:42 +02003831 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02003832 break;
3833 }
3834 }
3835
Michal Vaskocf024702015-10-08 15:01:42 +02003836 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003837 memset(&matches, 0, sizeof matches);
3838
Michal Vaskocf024702015-10-08 15:01:42 +02003839 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003840 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02003841 if (!first) {
3842 LOGVAL(LYE_SPEC, line, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02003843 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02003844 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02003845 return EXIT_FAILURE;
3846 }
Michal Vaskocf024702015-10-08 15:01:42 +02003847 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003848
Michal Vaskocf024702015-10-08 15:01:42 +02003849 case UNRES_INSTID:
3850 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003851 ly_errno = 0;
Michal Vaskof39142b2015-10-21 11:40:05 +02003852 if (!resolve_instid(node, leaf->value_str, line)) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003853 if (ly_errno) {
3854 return -1;
3855 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02003856 if (!first) {
Michal Vaskocf024702015-10-08 15:01:42 +02003857 LOGVAL(LYE_SPEC, line, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02003858 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02003859 return EXIT_FAILURE;
3860 } else {
Michal Vaskocf024702015-10-08 15:01:42 +02003861 LOGVRB("There is no instance of \"%s\", but is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003862 }
3863 }
Michal Vaskocf024702015-10-08 15:01:42 +02003864 break;
3865
3866 case UNRES_WHEN:
3867 if ((rc = resolve_when(node, first, line))) {
3868 return rc;
3869 }
3870 break;
3871
Michal Vaskobf19d252015-10-08 15:39:17 +02003872 case UNRES_MUST:
3873 if ((rc = resolve_must(node, first, line))) {
3874 return rc;
3875 }
3876 break;
3877
Michal Vaskocf024702015-10-08 15:01:42 +02003878 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003879 LOGINT;
3880 return -1;
3881 }
3882
3883 return EXIT_SUCCESS;
3884}
3885
3886/**
3887 * @brief Try to resolve an unres data item. Logs indirectly.
3888 *
3889 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02003890 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003891 * @param[in] line Line in the input file.
3892 *
3893 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3894 */
3895int
Michal Vaskocf024702015-10-08 15:01:42 +02003896unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003897{
3898 int rc;
3899
Michal Vaskobf19d252015-10-08 15:39:17 +02003900 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02003901
Michal Vaskocf024702015-10-08 15:01:42 +02003902 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003903 if (rc != EXIT_FAILURE) {
3904 return rc;
3905 }
3906
Michal Vaskocf024702015-10-08 15:01:42 +02003907 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003908
3909 ++unres->count;
Michal Vaskocf024702015-10-08 15:01:42 +02003910 unres->node = realloc(unres->node, unres->count * sizeof *unres->node);
3911 unres->node[unres->count - 1] = node;
3912 unres->type = realloc(unres->type, unres->count * sizeof *unres->type);
3913 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003914#ifndef NDEBUG
Michal Vaskocf024702015-10-08 15:01:42 +02003915 unres->line = realloc(unres->line, unres->count * sizeof *unres->line);
3916 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003917#endif
3918
3919 return EXIT_SUCCESS;
3920}
3921
3922/**
3923 * @brief Resolve every unres data item in the structure. Logs directly.
3924 *
3925 * @param[in] unres Unres data structure to use.
3926 *
3927 * @return EXIT_SUCCESS on success, -1 on error.
3928 */
3929int
3930resolve_unres_data(struct unres_data *unres)
3931{
3932 uint32_t i;
3933 int rc;
3934
3935 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003936 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02003937 if (rc) {
3938 LOGVAL(LYE_SPEC, 0, "There are unresolved data items left.");
3939 return -1;
3940 }
3941 }
3942
3943 return EXIT_SUCCESS;
3944}