blob: 9891b3e99a5938cf36bf154f31da3f62cef5e1a5 [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 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Michal Vasko88c29542015-11-27 14:57:53 +010028#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020029#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020030#include "tree_internal.h"
31
Michal Vasko730dfdf2015-08-11 14:48:05 +020032/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020033 * @brief Parse an identifier.
34 *
35 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
36 * identifier = (ALPHA / "_")
37 * *(ALPHA / DIGIT / "_" / "-" / ".")
38 *
Michal Vaskobb211122015-08-19 14:03:11 +020039 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020040 *
41 * @return Number of characters successfully parsed.
42 */
Michal Vasko249e6b52015-08-19 11:08:52 +020043int
Radek Krejci6dc53a22015-08-17 13:27:59 +020044parse_identifier(const char *id)
45{
46 int parsed = 0;
47
48 if (((id[0] == 'x') || (id[0] == 'X'))
49 && ((id[1] == 'm') || (id[0] == 'M'))
50 && ((id[2] == 'l') || (id[2] == 'L'))) {
51 return -parsed;
52 }
53
54 if (!isalpha(id[0]) && (id[0] != '_')) {
55 return -parsed;
56 }
57
58 ++parsed;
59 ++id;
60
61 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
62 ++parsed;
63 ++id;
64 }
65
66 return parsed;
67}
68
69/**
70 * @brief Parse a node-identifier.
71 *
Michal Vasko723e50c2015-10-20 15:20:29 +020072 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020073 *
Michal Vaskobb211122015-08-19 14:03:11 +020074 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020075 * @param[out] mod_name Points to the module name, NULL if there is not any.
76 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020077 * @param[out] name Points to the node name.
78 * @param[out] nam_len Length of the node name.
79 *
80 * @return Number of characters successfully parsed,
81 * positive on success, negative on failure.
82 */
83static int
Michal Vasko723e50c2015-10-20 15:20:29 +020084parse_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 +020085{
86 int parsed = 0, ret;
87
88 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020089 if (mod_name) {
90 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020091 }
Michal Vasko723e50c2015-10-20 15:20:29 +020092 if (mod_name_len) {
93 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020094 }
95 if (name) {
96 *name = NULL;
97 }
98 if (nam_len) {
99 *nam_len = 0;
100 }
101
102 if ((ret = parse_identifier(id)) < 1) {
103 return ret;
104 }
105
Michal Vasko723e50c2015-10-20 15:20:29 +0200106 if (mod_name) {
107 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200108 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200109 if (mod_name_len) {
110 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200111 }
112
113 parsed += ret;
114 id += ret;
115
116 /* there is prefix */
117 if (id[0] == ':') {
118 ++parsed;
119 ++id;
120
121 /* there isn't */
122 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200123 if (name && mod_name) {
124 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200125 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200126 if (mod_name) {
127 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200128 }
129
Michal Vasko723e50c2015-10-20 15:20:29 +0200130 if (nam_len && mod_name_len) {
131 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200132 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (mod_name_len) {
134 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
136
137 return parsed;
138 }
139
140 /* identifier (node name) */
141 if ((ret = parse_identifier(id)) < 1) {
142 return -parsed+ret;
143 }
144
145 if (name) {
146 *name = id;
147 }
148 if (nam_len) {
149 *nam_len = ret;
150 }
151
152 return parsed+ret;
153}
154
155/**
156 * @brief Parse a path-predicate (leafref).
157 *
158 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
159 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
160 *
Michal Vaskobb211122015-08-19 14:03:11 +0200161 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200162 * @param[out] prefix Points to the prefix, NULL if there is not any.
163 * @param[out] pref_len Length of the prefix, 0 if there is not any.
164 * @param[out] name Points to the node name.
165 * @param[out] nam_len Length of the node name.
166 * @param[out] path_key_expr Points to the path-key-expr.
167 * @param[out] pke_len Length of the path-key-expr.
168 * @param[out] has_predicate Flag to mark whether there is another predicate following.
169 *
170 * @return Number of characters successfully parsed,
171 * positive on success, negative on failure.
172 */
173static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200174parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
175 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200176{
177 const char *ptr;
178 int parsed = 0, ret;
179
180 assert(id);
181 if (prefix) {
182 *prefix = NULL;
183 }
184 if (pref_len) {
185 *pref_len = 0;
186 }
187 if (name) {
188 *name = NULL;
189 }
190 if (nam_len) {
191 *nam_len = 0;
192 }
193 if (path_key_expr) {
194 *path_key_expr = NULL;
195 }
196 if (pke_len) {
197 *pke_len = 0;
198 }
199 if (has_predicate) {
200 *has_predicate = 0;
201 }
202
203 if (id[0] != '[') {
204 return -parsed;
205 }
206
207 ++parsed;
208 ++id;
209
210 while (isspace(id[0])) {
211 ++parsed;
212 ++id;
213 }
214
215 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
216 return -parsed+ret;
217 }
218
219 parsed += ret;
220 id += ret;
221
222 while (isspace(id[0])) {
223 ++parsed;
224 ++id;
225 }
226
227 if (id[0] != '=') {
228 return -parsed;
229 }
230
231 ++parsed;
232 ++id;
233
234 while (isspace(id[0])) {
235 ++parsed;
236 ++id;
237 }
238
239 if ((ptr = strchr(id, ']')) == NULL) {
240 return -parsed;
241 }
242
243 --ptr;
244 while (isspace(ptr[0])) {
245 --ptr;
246 }
247 ++ptr;
248
249 ret = ptr-id;
250 if (path_key_expr) {
251 *path_key_expr = id;
252 }
253 if (pke_len) {
254 *pke_len = ret;
255 }
256
257 parsed += ret;
258 id += ret;
259
260 while (isspace(id[0])) {
261 ++parsed;
262 ++id;
263 }
264
265 assert(id[0] == ']');
266
267 if (id[1] == '[') {
268 *has_predicate = 1;
269 }
270
271 return parsed+1;
272}
273
274/**
275 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
276 * the ".." and the first node-identifier, other calls parse a single
277 * node-identifier each.
278 *
279 * path-key-expr = current-function-invocation *WSP "/" *WSP
280 * rel-path-keyexpr
281 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
282 * *(node-identifier *WSP "/" *WSP)
283 * node-identifier
284 *
Michal Vaskobb211122015-08-19 14:03:11 +0200285 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200286 * @param[out] prefix Points to the prefix, NULL if there is not any.
287 * @param[out] pref_len Length of the prefix, 0 if there is not any.
288 * @param[out] name Points to the node name.
289 * @param[out] nam_len Length of the node name.
290 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
291 * must not be changed between consecutive calls.
292 * @return Number of characters successfully parsed,
293 * positive on success, negative on failure.
294 */
295static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200296parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
297 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200298{
299 int parsed = 0, ret, par_times = 0;
300
301 assert(id);
302 assert(parent_times);
303 if (prefix) {
304 *prefix = NULL;
305 }
306 if (pref_len) {
307 *pref_len = 0;
308 }
309 if (name) {
310 *name = NULL;
311 }
312 if (nam_len) {
313 *nam_len = 0;
314 }
315
316 if (!*parent_times) {
317 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
318 if (strncmp(id, "current()", 9)) {
319 return -parsed;
320 }
321
322 parsed += 9;
323 id += 9;
324
325 while (isspace(id[0])) {
326 ++parsed;
327 ++id;
328 }
329
330 if (id[0] != '/') {
331 return -parsed;
332 }
333
334 ++parsed;
335 ++id;
336
337 while (isspace(id[0])) {
338 ++parsed;
339 ++id;
340 }
341
342 /* rel-path-keyexpr */
343 if (strncmp(id, "..", 2)) {
344 return -parsed;
345 }
346 ++par_times;
347
348 parsed += 2;
349 id += 2;
350
351 while (isspace(id[0])) {
352 ++parsed;
353 ++id;
354 }
355 }
356
357 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
358 *
359 * first parent reference with whitespaces already parsed
360 */
361 if (id[0] != '/') {
362 return -parsed;
363 }
364
365 ++parsed;
366 ++id;
367
368 while (isspace(id[0])) {
369 ++parsed;
370 ++id;
371 }
372
373 while (!strncmp(id, "..", 2) && !*parent_times) {
374 ++par_times;
375
376 parsed += 2;
377 id += 2;
378
379 while (isspace(id[0])) {
380 ++parsed;
381 ++id;
382 }
383
384 if (id[0] != '/') {
385 return -parsed;
386 }
387
388 ++parsed;
389 ++id;
390
391 while (isspace(id[0])) {
392 ++parsed;
393 ++id;
394 }
395 }
396
397 if (!*parent_times) {
398 *parent_times = par_times;
399 }
400
401 /* all parent references must be parsed at this point */
402 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
403 return -parsed+ret;
404 }
405
406 parsed += ret;
407 id += ret;
408
409 return parsed;
410}
411
412/**
413 * @brief Parse path-arg (leafref).
414 *
415 * path-arg = absolute-path / relative-path
416 * absolute-path = 1*("/" (node-identifier *path-predicate))
417 * relative-path = 1*(".." "/") descendant-path
418 *
Michal Vaskobb211122015-08-19 14:03:11 +0200419 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200420 * @param[out] prefix Points to the prefix, NULL if there is not any.
421 * @param[out] pref_len Length of the prefix, 0 if there is not any.
422 * @param[out] name Points to the node name.
423 * @param[out] nam_len Length of the node name.
424 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
425 * must not be changed between consecutive calls. -1 if the
426 * path is relative.
427 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
428 *
429 * @return Number of characters successfully parsed,
430 * positive on success, negative on failure.
431 */
432static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200433parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
434 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200435{
436 int parsed = 0, ret, par_times = 0;
437
438 assert(id);
439 assert(parent_times);
440 if (prefix) {
441 *prefix = NULL;
442 }
443 if (pref_len) {
444 *pref_len = 0;
445 }
446 if (name) {
447 *name = NULL;
448 }
449 if (nam_len) {
450 *nam_len = 0;
451 }
452 if (has_predicate) {
453 *has_predicate = 0;
454 }
455
456 if (!*parent_times && !strncmp(id, "..", 2)) {
457 ++par_times;
458
459 parsed += 2;
460 id += 2;
461
462 while (!strncmp(id, "/..", 3)) {
463 ++par_times;
464
465 parsed += 3;
466 id += 3;
467 }
468 }
469
470 if (!*parent_times) {
471 if (par_times) {
472 *parent_times = par_times;
473 } else {
474 *parent_times = -1;
475 }
476 }
477
478 if (id[0] != '/') {
479 return -parsed;
480 }
481
482 /* skip '/' */
483 ++parsed;
484 ++id;
485
486 /* node-identifier ([prefix:]identifier) */
487 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
488 return -parsed-ret;
489 }
490
491 parsed += ret;
492 id += ret;
493
494 /* there is no predicate */
495 if ((id[0] == '/') || !id[0]) {
496 return parsed;
497 } else if (id[0] != '[') {
498 return -parsed;
499 }
500
501 if (has_predicate) {
502 *has_predicate = 1;
503 }
504
505 return parsed;
506}
507
508/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200509 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200510 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200511 *
512 * instance-identifier = 1*("/" (node-identifier *predicate))
513 *
Michal Vaskobb211122015-08-19 14:03:11 +0200514 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200515 * @param[out] model Points to the model name.
516 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200517 * @param[out] name Points to the node name.
518 * @param[out] nam_len Length of the node name.
519 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
520 *
521 * @return Number of characters successfully parsed,
522 * positive on success, negative on failure.
523 */
524static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200525parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
526 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200527{
528 int parsed = 0, ret;
529
530 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200531 if (model) {
532 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200533 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200534 if (mod_len) {
535 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200536 }
537 if (name) {
538 *name = NULL;
539 }
540 if (nam_len) {
541 *nam_len = 0;
542 }
543 if (has_predicate) {
544 *has_predicate = 0;
545 }
546
547 if (id[0] != '/') {
548 return -parsed;
549 }
550
551 ++parsed;
552 ++id;
553
Michal Vasko1f2cc332015-08-19 11:18:32 +0200554 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200555 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200556 } else if (model && !*model) {
557 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200558 }
559
560 parsed += ret;
561 id += ret;
562
563 if ((id[0] == '[') && has_predicate) {
564 *has_predicate = 1;
565 }
566
567 return parsed;
568}
569
570/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200571 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200572 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200573 *
574 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
575 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
576 * ((DQUOTE string DQUOTE) /
577 * (SQUOTE string SQUOTE))
578 * pos = non-negative-integer-value
579 *
Michal Vaskobb211122015-08-19 14:03:11 +0200580 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200581 * @param[out] model Points to the model name.
582 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200583 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
584 * @param[out] nam_len Length of the node name.
585 * @param[out] value Value the node-identifier must have (string from the grammar),
586 * NULL if there is not any.
587 * @param[out] val_len Length of the value, 0 if there is not any.
588 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
589 *
590 * @return Number of characters successfully parsed,
591 * positive on success, negative on failure.
592 */
593static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200594parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
595 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596{
597 const char *ptr;
598 int parsed = 0, ret;
599 char quote;
600
601 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200602 if (model) {
603 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200604 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200605 if (mod_len) {
606 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200607 }
608 if (name) {
609 *name = NULL;
610 }
611 if (nam_len) {
612 *nam_len = 0;
613 }
614 if (value) {
615 *value = NULL;
616 }
617 if (val_len) {
618 *val_len = 0;
619 }
620 if (has_predicate) {
621 *has_predicate = 0;
622 }
623
624 if (id[0] != '[') {
625 return -parsed;
626 }
627
628 ++parsed;
629 ++id;
630
631 while (isspace(id[0])) {
632 ++parsed;
633 ++id;
634 }
635
636 /* pos */
637 if (isdigit(id[0])) {
638 if (name) {
639 *name = id;
640 }
641
642 if (id[0] == '0') {
643 ++parsed;
644 ++id;
645
646 if (isdigit(id[0])) {
647 return -parsed;
648 }
649 }
650
651 while (isdigit(id[0])) {
652 ++parsed;
653 ++id;
654 }
655
656 if (nam_len) {
657 *nam_len = id-(*name);
658 }
659
660 /* "." */
661 } else if (id[0] == '.') {
662 if (name) {
663 *name = id;
664 }
665 if (nam_len) {
666 *nam_len = 1;
667 }
668
669 ++parsed;
670 ++id;
671
672 /* node-identifier */
673 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200674 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200675 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200676 } else if (model && !*model) {
677 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200679
680 parsed += ret;
681 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200682 }
683
684 while (isspace(id[0])) {
685 ++parsed;
686 ++id;
687 }
688
689 if (id[0] != '=') {
690 return -parsed;
691 }
692
693 ++parsed;
694 ++id;
695
696 while (isspace(id[0])) {
697 ++parsed;
698 ++id;
699 }
700
701 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
702 if ((id[0] == '\"') || (id[0] == '\'')) {
703 quote = id[0];
704
705 ++parsed;
706 ++id;
707
708 if ((ptr = strchr(id, quote)) == NULL) {
709 return -parsed;
710 }
711 ret = ptr-id;
712
713 if (value) {
714 *value = id;
715 }
716 if (val_len) {
717 *val_len = ret;
718 }
719
720 parsed += ret+1;
721 id += ret+1;
722 } else {
723 return -parsed;
724 }
725
726 while (isspace(id[0])) {
727 ++parsed;
728 ++id;
729 }
730
731 if (id[0] != ']') {
732 return -parsed;
733 }
734
735 ++parsed;
736 ++id;
737
738 if ((id[0] == '[') && has_predicate) {
739 *has_predicate = 1;
740 }
741
742 return parsed;
743}
744
745/**
746 * @brief Parse schema-nodeid.
747 *
748 * schema-nodeid = absolute-schema-nodeid /
749 * descendant-schema-nodeid
750 * absolute-schema-nodeid = 1*("/" node-identifier)
751 * descendant-schema-nodeid =
752 * node-identifier
753 * absolute-schema-nodeid
754 *
Michal Vaskobb211122015-08-19 14:03:11 +0200755 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200756 * @param[out] mod_name Points to the module name, NULL if there is not any.
757 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200758 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
759 * @param[out] nam_len Length of the node name.
760 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
761 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100762 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
763 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200764 *
765 * @return Number of characters successfully parsed,
766 * positive on success, negative on failure.
767 */
768static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200769parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100770 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200771{
772 int parsed = 0, ret;
773
774 assert(id);
775 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200776 if (mod_name) {
777 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200778 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200779 if (mod_name_len) {
780 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200781 }
782 if (name) {
783 *name = NULL;
784 }
785 if (nam_len) {
786 *nam_len = 0;
787 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100788 if (has_predicate) {
789 *has_predicate = 0;
790 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200791
792 if (id[0] != '/') {
793 if (*is_relative != -1) {
794 return -parsed;
795 } else {
796 *is_relative = 1;
797 }
798 } else {
799 if (*is_relative == -1) {
800 *is_relative = 0;
801 }
802 ++parsed;
803 ++id;
804 }
805
Michal Vasko723e50c2015-10-20 15:20:29 +0200806 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200807 return -parsed+ret;
808 }
809
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100810 parsed += ret;
811 id += ret;
812
813 if ((id[0] == '[') && has_predicate) {
814 *has_predicate = 1;
815 }
816
817 return parsed;
818}
819
820/**
821 * @brief Parse schema predicate (special format internally used).
822 *
823 * predicate = "[" *WSP predicate-expr *WSP "]"
824 * predicate-expr = identifier / key-with-value
825 * key-with-value = identifier *WSP "=" *WSP
826 * ((DQUOTE string DQUOTE) /
827 * (SQUOTE string SQUOTE))
828 *
829 * @param[in] id Identifier to use.
830 * @param[out] name Points to the list key name.
831 * @param[out] nam_len Length of \p name.
832 * @param[out] value Points to the key value.
833 * @param[out] val_len Length of \p value.
834 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
835 */
836static int
Michal Vasko3547c532016-03-14 09:40:50 +0100837parse_schema_list_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
838 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100839{
840 const char *ptr;
841 int parsed = 0, ret;
842 char quote;
843
844 assert(id);
845 if (name) {
846 *name = NULL;
847 }
848 if (nam_len) {
849 *nam_len = 0;
850 }
851 if (value) {
852 *value = NULL;
853 }
854 if (val_len) {
855 *val_len = 0;
856 }
857 if (has_predicate) {
858 *has_predicate = 0;
859 }
860
861 if (id[0] != '[') {
862 return -parsed;
863 }
864
865 ++parsed;
866 ++id;
867
868 while (isspace(id[0])) {
869 ++parsed;
870 ++id;
871 }
872
873 /* node-identifier */
874 if ((ret = parse_identifier(id)) < 1) {
875 return -parsed + ret;
876 }
877 if (name) {
878 *name = id;
879 }
880 if (nam_len) {
881 *nam_len = ret;
882 }
883
884 parsed += ret;
885 id += ret;
886
887 while (isspace(id[0])) {
888 ++parsed;
889 ++id;
890 }
891
892 /* there is value as well */
893 if (id[0] == '=') {
894 ++parsed;
895 ++id;
896
897 while (isspace(id[0])) {
898 ++parsed;
899 ++id;
900 }
901
902 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
903 if ((id[0] == '\"') || (id[0] == '\'')) {
904 quote = id[0];
905
906 ++parsed;
907 ++id;
908
909 if ((ptr = strchr(id, quote)) == NULL) {
910 return -parsed;
911 }
912 ret = ptr - id;
913
914 if (value) {
915 *value = id;
916 }
917 if (val_len) {
918 *val_len = ret;
919 }
920
921 parsed += ret + 1;
922 id += ret + 1;
923 } else {
924 return -parsed;
925 }
926
927 while (isspace(id[0])) {
928 ++parsed;
929 ++id;
930 }
931 }
932
933 if (id[0] != ']') {
934 return -parsed;
935 }
936
937 ++parsed;
938 ++id;
939
940 if ((id[0] == '[') && has_predicate) {
941 *has_predicate = 1;
942 }
943
944 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200945}
946
947/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100948 * @brief Resolve (find) a data node based on a schema-nodeid.
949 *
950 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
951 * module).
952 *
953 */
954struct lyd_node *
955resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
956{
957 char *str, *token, *p;
958 struct lyd_node *result = start, *iter;
959 const struct lys_node *schema = NULL;
960
961 assert(nodeid && start);
962
963 if (nodeid[0] == '/') {
964 return NULL;
965 }
966
967 str = p = strdup(nodeid);
968 if (!str) {
969 LOGMEM;
970 return NULL;
971 }
972 while (p) {
973 token = p;
974 p = strchr(p, '/');
975 if (p) {
976 *p = '\0';
977 p++;
978 }
979
980 schema = NULL;
981 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
982 free(str);
983 return NULL;
984 }
985
986 LY_TREE_FOR(result, iter) {
987 if (iter->schema == schema) {
988 break;
989 }
990 }
991
992 if (!p) {
993 /* final result */
994 result = iter;
995 } else {
996 result = iter->child;
997 }
998 }
999 free(str);
1000
1001 return result;
1002}
1003
1004/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1005int
1006resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1007 const struct lys_node **ret)
1008{
1009 const char *name, *mod_name, *id;
1010 const struct lys_node *sibling;
1011 int r, nam_len, mod_name_len, is_relative = -1;
1012 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001013 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001014
1015 assert(nodeid && (start || module) && !(start && module) && ret);
1016
1017 id = nodeid;
1018
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001019 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001020 return ((id - nodeid) - r) + 1;
1021 }
1022 id += r;
1023
1024 if ((is_relative && !start) || (!is_relative && !module)) {
1025 return -1;
1026 }
1027
1028 /* descendant-schema-nodeid */
1029 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001030 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001031
1032 /* absolute-schema-nodeid */
1033 } else {
1034 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001035 if (!start_mod) {
1036 return -1;
1037 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001038 start = start_mod->data;
1039 }
1040
1041 while (1) {
1042 sibling = NULL;
1043 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1044 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1045 /* name match */
1046 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1047 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
1048 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
1049
1050 /* module check */
1051 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1052 if (!prefix_mod) {
1053 return -1;
1054 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001055 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001056 continue;
1057 }
1058
1059 /* the result node? */
1060 if (!id[0]) {
1061 *ret = sibling;
1062 return EXIT_SUCCESS;
1063 }
1064
1065 /* check for shorthand cases - then 'start' does not change */
1066 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1067 || (sibling->nodetype == LYS_CASE)) {
1068 start = sibling->child;
1069 }
1070 break;
1071 }
1072 }
1073
1074 /* no match */
1075 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001076 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001077 return EXIT_SUCCESS;
1078 }
1079
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001080 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001081 return ((id - nodeid) - r) + 1;
1082 }
1083 id += r;
1084 }
1085
1086 /* cannot get here */
1087 LOGINT;
1088 return -1;
1089}
1090
1091/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1092int
1093resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
1094 const struct lys_node **ret)
1095{
1096 const char *name, *mod_name, *id;
1097 const struct lys_node *sibling;
1098 int r, nam_len, mod_name_len, is_relative = -1;
1099 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001100 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001101
1102 assert(nodeid && start && ret);
1103 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1104
1105 id = nodeid;
1106 module = start->module;
1107
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001108 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001109 return ((id - nodeid) - r) + 1;
1110 }
1111 id += r;
1112
1113 if (!is_relative) {
1114 return -1;
1115 }
1116
1117 while (1) {
1118 sibling = NULL;
1119 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1120 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1121 /* name match */
1122 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1123
1124 /* module check */
1125 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1126 if (!prefix_mod) {
1127 return -1;
1128 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001129 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001130 continue;
1131 }
1132
1133 /* the result node? */
1134 if (!id[0]) {
1135 if (!(sibling->nodetype & ret_nodetype)) {
1136 /* wrong node type, too bad */
1137 continue;
1138 }
1139 *ret = sibling;
1140 return EXIT_SUCCESS;
1141 }
1142
1143 /* check for shorthand cases - then 'start' does not change */
1144 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1145 || (sibling->nodetype == LYS_CASE)) {
1146 start = sibling->child;
1147 }
1148 break;
1149 }
1150 }
1151
1152 /* no match */
1153 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001154 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001155 return EXIT_SUCCESS;
1156 }
1157
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001158 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001159 return ((id - nodeid) - r) + 1;
1160 }
1161 id += r;
1162 }
1163
1164 /* cannot get here */
1165 LOGINT;
1166 return -1;
1167}
1168
1169/* choice default */
1170int
1171resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1172{
1173 /* cannot actually be a path */
1174 if (strchr(nodeid, '/')) {
1175 return -1;
1176 }
1177
1178 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1179}
1180
1181/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1182static int
1183resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1184{
1185 const struct lys_module *module;
1186 const char *mod_prefix, *name;
1187 int i, mod_prefix_len, nam_len;
1188
1189 /* parse the identifier, it must be parsed on one call */
1190 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1191 return -i + 1;
1192 }
1193
1194 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1195 if (!module) {
1196 return -1;
1197 }
1198 if (module != start->module) {
1199 start = module->data;
1200 }
1201
1202 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1203
1204 return EXIT_SUCCESS;
1205}
1206
1207int
1208resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1209 const struct lys_node **ret)
1210{
1211 const char *name, *mod_name, *id;
1212 const struct lys_node *sibling, *start;
1213 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko4f0dad02016-02-15 14:08:23 +01001214 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001215
1216 assert(nodeid && module && ret);
1217 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1218
1219 id = nodeid;
1220 start = module->data;
1221
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001222 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001223 return ((id - nodeid) - r) + 1;
1224 }
1225 id += r;
1226
1227 if (is_relative) {
1228 return -1;
1229 }
1230
1231 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001232 if (!abs_start_mod) {
1233 return -1;
1234 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001235
1236 while (1) {
1237 sibling = NULL;
1238 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1239 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1240 /* name match */
1241 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1242
1243 /* module check */
1244 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1245 if (!prefix_mod) {
1246 return -1;
1247 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001248 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001249 continue;
1250 }
1251
1252 /* the result node? */
1253 if (!id[0]) {
1254 if (!(sibling->nodetype & ret_nodetype)) {
1255 /* wrong node type, too bad */
1256 continue;
1257 }
1258 *ret = sibling;
1259 return EXIT_SUCCESS;
1260 }
1261
1262 /* check for shorthand cases - then 'start' does not change */
1263 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1264 || (sibling->nodetype == LYS_CASE)) {
1265 start = sibling->child;
1266 }
1267 break;
1268 }
1269 }
1270
1271 /* no match */
1272 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001273 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001274 return EXIT_SUCCESS;
1275 }
1276
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001277 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001278 return ((id - nodeid) - r) + 1;
1279 }
1280 id += r;
1281 }
1282
1283 /* cannot get here */
1284 LOGINT;
1285 return -1;
1286}
1287
Michal Vaskoe733d682016-03-14 09:08:27 +01001288static int
Michal Vasko3547c532016-03-14 09:40:50 +01001289resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001290{
1291 const char *name;
1292 int nam_len, has_predicate, i;
1293
Michal Vasko3547c532016-03-14 09:40:50 +01001294 if ((i = parse_schema_list_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001295 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
1296 return -1;
1297 }
1298
1299 predicate += i;
1300 *parsed += i;
1301
1302 for (i = 0; i < list->keys_size; ++i) {
1303 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1304 break;
1305 }
1306 }
1307
1308 if (i == list->keys_size) {
1309 LOGVAL(LYE_PATH_INKEY, 0, LY_VLOG_NONE, NULL, name);
1310 return -1;
1311 }
1312
1313 /* more predicates? */
1314 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001315 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001316 }
1317
1318 return 0;
1319}
1320
1321/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
1322const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001323resolve_json_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001324{
1325 char *str;
1326 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001327 const struct lys_node *sibling;
Michal Vaskoe733d682016-03-14 09:08:27 +01001328 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001329 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001330 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001331
Michal Vasko3547c532016-03-14 09:40:50 +01001332 assert(nodeid && (ctx || start));
1333 if (!ctx) {
1334 ctx = start->module->ctx;
1335 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001336
1337 id = nodeid;
1338
Michal Vaskoe733d682016-03-14 09:08:27 +01001339 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
1340 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1341 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001342 }
1343 id += r;
1344
1345 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001346 assert(start);
1347 start = start->child;
1348 if (!start) {
1349 /* no descendants, fail for sure */
1350 LOGVAL(LYE_PATH_INNODE, 0, LY_VLOG_NONE, NULL, name);
1351 return NULL;
1352 }
1353 module = start->module;
1354 } else {
1355 if (!mod_name) {
1356 LOGVAL(LYE_PATH_MISSMOD, 0, LY_VLOG_NONE, NULL, name);
1357 return NULL;
1358 }
1359
1360 str = strndup(mod_name, mod_name_len);
1361 module = ly_ctx_get_module(ctx, str, NULL);
1362 free(str);
1363 if (!module) {
1364 LOGVAL(LYE_PATH_INMOD, 0, LY_VLOG_NONE, NULL, mod_name);
1365 return NULL;
1366 }
1367 start = module->data;
1368
1369 /* now it's as if there was no module name */
1370 mod_name = NULL;
1371 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001372 }
1373
Michal Vaskoe733d682016-03-14 09:08:27 +01001374 prev_mod = module;
1375
Michal Vasko3edeaf72016-02-11 13:17:43 +01001376 while (1) {
1377 sibling = NULL;
1378 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1379 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1380 /* name match */
1381 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1382
1383 /* module check */
1384 if (mod_name) {
1385 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1386 if (!prefix_mod) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001387 LOGVAL(LYE_PATH_INMOD, 0, LY_VLOG_NONE, NULL, mod_name);
1388 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001389 }
1390 } else {
1391 prefix_mod = prev_mod;
1392 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001393 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001394 continue;
1395 }
1396
Michal Vaskoe733d682016-03-14 09:08:27 +01001397 /* do we have some predicates on it? */
1398 if (has_predicate) {
1399 r = 0;
1400 if (sibling->nodetype != LYS_LIST) {
1401 LOGVAL(LYE_PATH_NLIST, 0, LY_VLOG_NONE, NULL, name);
1402 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001403 } else if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001404 return NULL;
1405 }
1406 id += r;
1407 }
1408
Michal Vasko3edeaf72016-02-11 13:17:43 +01001409 /* the result node? */
1410 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001411 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001412 }
1413
1414 /* check for shorthand cases - then 'start' does not change */
1415 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1416 || (sibling->nodetype == LYS_CASE)) {
1417 start = sibling->child;
1418 }
1419
1420 /* update prev mod */
1421 prev_mod = start->module;
1422 break;
1423 }
1424 }
1425
1426 /* no match */
1427 if (!sibling) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001428 LOGVAL(LYE_PATH_INNODE, 0, LY_VLOG_NONE, NULL, name);
1429 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001430 }
1431
Michal Vaskoe733d682016-03-14 09:08:27 +01001432 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
1433 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1434 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001435 }
1436 id += r;
1437 }
1438
1439 /* cannot get here */
1440 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001441 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001442}
1443
1444/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001445 * @brief Resolves length or range intervals. Does not log.
1446 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1447 *
1448 * @param[in] str_restr The restriction as a string.
1449 * @param[in] type The type of the restriction.
1450 * @param[in] superior_restr Flag whether to check superior
1451 * types.
1452 * @param[out] local_intv The final interval structure.
1453 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001454 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001455 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001456int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001457resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1458 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001459{
1460 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001461 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001462 int64_t local_smin, local_smax;
1463 uint64_t local_umin, local_umax;
1464 long double local_fmin, local_fmax;
1465 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001466 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001467
1468 switch (type->base) {
1469 case LY_TYPE_BINARY:
1470 kind = 0;
1471 local_umin = 0;
1472 local_umax = 18446744073709551615UL;
1473
1474 if (!str_restr && type->info.binary.length) {
1475 str_restr = type->info.binary.length->expr;
1476 }
1477 break;
1478 case LY_TYPE_DEC64:
1479 kind = 2;
1480 local_fmin = -9223372036854775808.0;
1481 local_fmin /= 1 << type->info.dec64.dig;
1482 local_fmax = 9223372036854775807.0;
1483 local_fmax /= 1 << type->info.dec64.dig;
1484
1485 if (!str_restr && type->info.dec64.range) {
1486 str_restr = type->info.dec64.range->expr;
1487 }
1488 break;
1489 case LY_TYPE_INT8:
1490 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001491 local_smin = __INT64_C(-128);
1492 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001493
1494 if (!str_restr && type->info.num.range) {
1495 str_restr = type->info.num.range->expr;
1496 }
1497 break;
1498 case LY_TYPE_INT16:
1499 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001500 local_smin = __INT64_C(-32768);
1501 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001502
1503 if (!str_restr && type->info.num.range) {
1504 str_restr = type->info.num.range->expr;
1505 }
1506 break;
1507 case LY_TYPE_INT32:
1508 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001509 local_smin = __INT64_C(-2147483648);
1510 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001511
1512 if (!str_restr && type->info.num.range) {
1513 str_restr = type->info.num.range->expr;
1514 }
1515 break;
1516 case LY_TYPE_INT64:
1517 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001518 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1519 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001520
1521 if (!str_restr && type->info.num.range) {
1522 str_restr = type->info.num.range->expr;
1523 }
1524 break;
1525 case LY_TYPE_UINT8:
1526 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001527 local_umin = __UINT64_C(0);
1528 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001529
1530 if (!str_restr && type->info.num.range) {
1531 str_restr = type->info.num.range->expr;
1532 }
1533 break;
1534 case LY_TYPE_UINT16:
1535 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001536 local_umin = __UINT64_C(0);
1537 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001538
1539 if (!str_restr && type->info.num.range) {
1540 str_restr = type->info.num.range->expr;
1541 }
1542 break;
1543 case LY_TYPE_UINT32:
1544 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001545 local_umin = __UINT64_C(0);
1546 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001547
1548 if (!str_restr && type->info.num.range) {
1549 str_restr = type->info.num.range->expr;
1550 }
1551 break;
1552 case LY_TYPE_UINT64:
1553 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001554 local_umin = __UINT64_C(0);
1555 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001556
1557 if (!str_restr && type->info.num.range) {
1558 str_restr = type->info.num.range->expr;
1559 }
1560 break;
1561 case LY_TYPE_STRING:
1562 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001563 local_umin = __UINT64_C(0);
1564 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001565
1566 if (!str_restr && type->info.str.length) {
1567 str_restr = type->info.str.length->expr;
1568 }
1569 break;
1570 default:
1571 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001572 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001573 }
1574
1575 /* process superior types */
1576 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001577 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1578 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001579 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001580 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001581 assert(!intv || (intv->kind == kind));
1582 }
1583
1584 if (!str_restr) {
1585 /* we are validating data and not have any restriction, but a superior type might have */
1586 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001587 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1588 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001589 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001590 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001591 assert(!intv || (intv->kind == kind));
1592 }
1593 *local_intv = intv;
1594 return EXIT_SUCCESS;
1595 }
1596
1597 /* adjust local min and max */
1598 if (intv) {
1599 tmp_intv = intv;
1600
1601 if (kind == 0) {
1602 local_umin = tmp_intv->value.uval.min;
1603 } else if (kind == 1) {
1604 local_smin = tmp_intv->value.sval.min;
1605 } else if (kind == 2) {
1606 local_fmin = tmp_intv->value.fval.min;
1607 }
1608
1609 while (tmp_intv->next) {
1610 tmp_intv = tmp_intv->next;
1611 }
1612
1613 if (kind == 0) {
1614 local_umax = tmp_intv->value.uval.max;
1615 } else if (kind == 1) {
1616 local_smax = tmp_intv->value.sval.max;
1617 } else if (kind == 2) {
1618 local_fmax = tmp_intv->value.fval.max;
1619 }
1620 }
1621
1622 /* finally parse our restriction */
1623 seg_ptr = str_restr;
1624 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001625 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001626 *local_intv = malloc(sizeof **local_intv);
1627 tmp_local_intv = *local_intv;
1628 } else {
1629 tmp_local_intv->next = malloc(sizeof **local_intv);
1630 tmp_local_intv = tmp_local_intv->next;
1631 }
Michal Vasko253035f2015-12-17 16:58:13 +01001632 if (!tmp_local_intv) {
1633 LOGMEM;
1634 return -1;
1635 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001636
1637 tmp_local_intv->kind = kind;
1638 tmp_local_intv->next = NULL;
1639
1640 /* min */
1641 ptr = seg_ptr;
1642 while (isspace(ptr[0])) {
1643 ++ptr;
1644 }
1645 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1646 if (kind == 0) {
1647 tmp_local_intv->value.uval.min = atoll(ptr);
1648 } else if (kind == 1) {
1649 tmp_local_intv->value.sval.min = atoll(ptr);
1650 } else if (kind == 2) {
1651 tmp_local_intv->value.fval.min = atoll(ptr);
1652 }
1653
1654 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1655 ++ptr;
1656 }
1657 while (isdigit(ptr[0])) {
1658 ++ptr;
1659 }
1660 } else if (!strncmp(ptr, "min", 3)) {
1661 if (kind == 0) {
1662 tmp_local_intv->value.uval.min = local_umin;
1663 } else if (kind == 1) {
1664 tmp_local_intv->value.sval.min = local_smin;
1665 } else if (kind == 2) {
1666 tmp_local_intv->value.fval.min = local_fmin;
1667 }
1668
1669 ptr += 3;
1670 } else if (!strncmp(ptr, "max", 3)) {
1671 if (kind == 0) {
1672 tmp_local_intv->value.uval.min = local_umax;
1673 } else if (kind == 1) {
1674 tmp_local_intv->value.sval.min = local_smax;
1675 } else if (kind == 2) {
1676 tmp_local_intv->value.fval.min = local_fmax;
1677 }
1678
1679 ptr += 3;
1680 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001681 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001682 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001683 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001684 }
1685
1686 while (isspace(ptr[0])) {
1687 ptr++;
1688 }
1689
1690 /* no interval or interval */
1691 if ((ptr[0] == '|') || !ptr[0]) {
1692 if (kind == 0) {
1693 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1694 } else if (kind == 1) {
1695 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1696 } else if (kind == 2) {
1697 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1698 }
1699 } else if (!strncmp(ptr, "..", 2)) {
1700 /* skip ".." */
1701 ptr += 2;
1702 while (isspace(ptr[0])) {
1703 ++ptr;
1704 }
1705
1706 /* max */
1707 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1708 if (kind == 0) {
1709 tmp_local_intv->value.uval.max = atoll(ptr);
1710 } else if (kind == 1) {
1711 tmp_local_intv->value.sval.max = atoll(ptr);
1712 } else if (kind == 2) {
1713 tmp_local_intv->value.fval.max = atoll(ptr);
1714 }
1715 } else if (!strncmp(ptr, "max", 3)) {
1716 if (kind == 0) {
1717 tmp_local_intv->value.uval.max = local_umax;
1718 } else if (kind == 1) {
1719 tmp_local_intv->value.sval.max = local_smax;
1720 } else if (kind == 2) {
1721 tmp_local_intv->value.fval.max = local_fmax;
1722 }
1723 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001724 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001725 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001726 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001727 }
1728 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001729 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001730 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001731 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001732 }
1733
1734 /* next segment (next OR) */
1735 seg_ptr = strchr(seg_ptr, '|');
1736 if (!seg_ptr) {
1737 break;
1738 }
1739 seg_ptr++;
1740 }
1741
1742 /* check local restrictions against superior ones */
1743 if (intv) {
1744 tmp_intv = intv;
1745 tmp_local_intv = *local_intv;
1746
1747 while (tmp_local_intv && tmp_intv) {
1748 /* reuse local variables */
1749 if (kind == 0) {
1750 local_umin = tmp_local_intv->value.uval.min;
1751 local_umax = tmp_local_intv->value.uval.max;
1752
1753 /* it must be in this interval */
1754 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1755 /* this interval is covered, next one */
1756 if (local_umax <= tmp_intv->value.uval.max) {
1757 tmp_local_intv = tmp_local_intv->next;
1758 continue;
1759 /* ascending order of restrictions -> fail */
1760 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001761 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001762 goto cleanup;
1763 }
1764 }
1765 } else if (kind == 1) {
1766 local_smin = tmp_local_intv->value.sval.min;
1767 local_smax = tmp_local_intv->value.sval.max;
1768
1769 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1770 if (local_smax <= tmp_intv->value.sval.max) {
1771 tmp_local_intv = tmp_local_intv->next;
1772 continue;
1773 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001774 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001775 goto cleanup;
1776 }
1777 }
1778 } else if (kind == 2) {
1779 local_fmin = tmp_local_intv->value.fval.min;
1780 local_fmax = tmp_local_intv->value.fval.max;
1781
1782 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1783 if (local_fmax <= tmp_intv->value.fval.max) {
1784 tmp_local_intv = tmp_local_intv->next;
1785 continue;
1786 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001787 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001788 goto cleanup;
1789 }
1790 }
1791 }
1792
1793 tmp_intv = tmp_intv->next;
1794 }
1795
1796 /* some interval left uncovered -> fail */
1797 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001798 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001799 }
1800
1801 }
1802
1803cleanup:
1804 while (intv) {
1805 tmp_intv = intv->next;
1806 free(intv);
1807 intv = tmp_intv;
1808 }
1809
1810 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001811 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001812 while (*local_intv) {
1813 tmp_local_intv = (*local_intv)->next;
1814 free(*local_intv);
1815 *local_intv = tmp_local_intv;
1816 }
1817 }
1818
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001819 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001820}
1821
Michal Vasko730dfdf2015-08-11 14:48:05 +02001822/**
Michal Vasko88c29542015-11-27 14:57:53 +01001823 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001824 *
1825 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001826 * @param[in] mod_name Typedef name module name.
1827 * @param[in] module Main module.
1828 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001829 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001830 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001831 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001832 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001833int
Michal Vasko1e62a092015-12-01 12:27:20 +01001834resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
1835 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001836{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001837 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001838 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001839 int tpdf_size;
1840
Michal Vasko1dca6882015-10-22 14:29:42 +02001841 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001842 /* no prefix, try built-in types */
1843 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1844 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001845 if (ret) {
1846 *ret = ly_types[i].def;
1847 }
1848 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001849 }
1850 }
1851 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001852 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001853 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001854 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001855 }
1856 }
1857
Michal Vasko1dca6882015-10-22 14:29:42 +02001858 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001859 /* search in local typedefs */
1860 while (parent) {
1861 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001862 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001863 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1864 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001865 break;
1866
Radek Krejci76512572015-08-04 09:47:08 +02001867 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001868 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1869 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001870 break;
1871
Radek Krejci76512572015-08-04 09:47:08 +02001872 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001873 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1874 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001875 break;
1876
Radek Krejci76512572015-08-04 09:47:08 +02001877 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001878 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1879 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001880 break;
1881
Radek Krejci76512572015-08-04 09:47:08 +02001882 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001883 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1884 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001885 break;
1886
Radek Krejci76512572015-08-04 09:47:08 +02001887 case LYS_INPUT:
1888 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001889 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1890 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001891 break;
1892
1893 default:
1894 parent = parent->parent;
1895 continue;
1896 }
1897
1898 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001899 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001900 if (ret) {
1901 *ret = &tpdf[i];
1902 }
1903 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001904 }
1905 }
1906
1907 parent = parent->parent;
1908 }
Radek Krejcic071c542016-01-27 14:57:51 +01001909 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001910 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001911 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001912 if (!module) {
1913 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001914 }
1915 }
1916
1917 /* search in top level typedefs */
1918 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001919 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001920 if (ret) {
1921 *ret = &module->tpdf[i];
1922 }
1923 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001924 }
1925 }
1926
1927 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01001928 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001929 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001930 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001931 if (ret) {
1932 *ret = &module->inc[i].submodule->tpdf[j];
1933 }
1934 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001935 }
1936 }
1937 }
1938
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001939 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001940}
1941
Michal Vasko1dca6882015-10-22 14:29:42 +02001942/**
1943 * @brief Check the default \p value of the \p type. Logs directly.
1944 *
1945 * @param[in] type Type definition to use.
1946 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01001947 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02001948 * @param[in] first Whether this is the first resolution try. Affects logging.
1949 * @param[in] line Line in the input file.
1950 *
1951 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1952 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001953static int
Michal Vasko56826402016-03-02 11:11:37 +01001954check_default(struct lys_type *type, const char *value, struct lys_module *module, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001955{
Michal Vasko1dca6882015-10-22 14:29:42 +02001956 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01001957 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02001958
1959 /* dummy leaf */
1960 node.value_str = value;
1961 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01001962 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01001963 if (!node.schema) {
1964 LOGMEM;
1965 return -1;
1966 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001967 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01001968 if (!node.schema->name) {
1969 LOGMEM;
1970 return -1;
1971 }
Michal Vasko56826402016-03-02 11:11:37 +01001972 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01001973 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02001974
Radek Krejci37b756f2016-01-18 10:15:03 +01001975 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02001976 if (!type->info.lref.target) {
1977 ret = EXIT_FAILURE;
1978 goto finish;
1979 }
Michal Vasko56826402016-03-02 11:11:37 +01001980 ret = check_default(&type->info.lref.target->type, value, module, first, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001981
1982 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1983 /* it was converted to JSON format before, nothing else sensible we can do */
1984
1985 } else {
Radek Krejci37b756f2016-01-18 10:15:03 +01001986 ret = lyp_parse_value(&node, NULL, 1, NULL, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001987 }
1988
1989finish:
1990 if (node.value_type == LY_TYPE_BITS) {
1991 free(node.value.bit);
1992 }
1993 free((char *)node.schema->name);
1994 free(node.schema);
1995
1996 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001997}
1998
Michal Vasko730dfdf2015-08-11 14:48:05 +02001999/**
2000 * @brief Check a key for mandatory attributes. Logs directly.
2001 *
2002 * @param[in] key The key to check.
2003 * @param[in] flags What flags to check.
2004 * @param[in] list The list of all the keys.
2005 * @param[in] index Index of the key in the key list.
2006 * @param[in] name The name of the keys.
2007 * @param[in] len The name length.
2008 * @param[in] line The line in the input file.
2009 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002010 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002011 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002012static int
Radek Krejciadb57612016-02-16 13:34:34 +01002013check_key(struct lys_node_list *list, int index, const char *name, int len, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002014{
Radek Krejciadb57612016-02-16 13:34:34 +01002015 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002016 char *dup = NULL;
2017 int j;
2018
2019 /* existence */
2020 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002021 if (name[len] != '\0') {
2022 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002023 if (!dup) {
2024 LOGMEM;
2025 return -1;
2026 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002027 dup[len] = '\0';
2028 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002029 }
Radek Krejciadb57612016-02-16 13:34:34 +01002030 LOGVAL(LYE_KEY_MISS, line, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002031 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002032 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002033 }
2034
2035 /* uniqueness */
2036 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002037 if (key == list->keys[j]) {
2038 LOGVAL(LYE_KEY_DUP, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002039 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002040 }
2041 }
2042
2043 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002044 if (key->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002045 LOGVAL(LYE_KEY_NLEAF, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002046 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002047 }
2048
2049 /* type of the leaf is not built-in empty */
2050 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejciadb57612016-02-16 13:34:34 +01002051 LOGVAL(LYE_KEY_TYPE, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002052 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002053 }
2054
2055 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002056 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
2057 LOGVAL(LYE_KEY_CONFIG, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002058 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002059 }
2060
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002061 /* key is not placed from augment */
2062 if (key->parent->nodetype == LYS_AUGMENT) {
2063 LOGVAL(LYE_KEY_MISS, line, 0, NULL, key->name);
2064 LOGVAL(LYE_SPEC, 0, LY_VLOG_LYS, key, "Key inserted from augment.");
2065 return -1;
2066 }
2067
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002068 return EXIT_SUCCESS;
2069}
2070
Michal Vasko730dfdf2015-08-11 14:48:05 +02002071/**
Radek Krejci581ce772015-11-10 17:22:40 +01002072 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002073 *
2074 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002075 * @param[in] uniq_str_path One path from the unique string.
Michal Vasko184521f2015-09-24 13:14:26 +02002076 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002077 * @param[in] line The line in the input file.
2078 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002079 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002080 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002081int
Michal Vasko0b85aa82016-03-07 14:37:43 +01002082resolve_unique(struct lys_node *parent, const char *uniq_str_path, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002083{
Radek Krejci581ce772015-11-10 17:22:40 +01002084 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002085 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002086
Michal Vasko0b85aa82016-03-07 14:37:43 +01002087 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002088 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002089 if (rc) {
2090 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2091 if (rc > 0) {
2092 LOGVAL(LYE_INCHAR, 0, 0, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejci581ce772015-11-10 17:22:40 +01002093 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002094 rc = -1;
2095 } else if (!first) {
2096 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2097 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target leaf not found.");
2098 rc = -1;
2099 } else {
2100 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101 }
Radek Krejci581ce772015-11-10 17:22:40 +01002102 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002103 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002104 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002105 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Radek Krejciadb57612016-02-16 13:34:34 +01002106 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002107 rc = -1;
2108 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002109 }
2110
Radek Krejcicf509982015-12-15 09:22:44 +01002111 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002112 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name,
2113 line, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002114 return -1;
2115 }
2116
Radek Krejcica7efb72016-01-18 13:06:01 +01002117 /* set leaf's unique flag */
2118 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2119
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002120 return EXIT_SUCCESS;
2121
2122error:
2123
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002124 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002125}
2126
Michal Vasko730dfdf2015-08-11 14:48:05 +02002127/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002128 * @brief Resolve (find) a feature definition. Logs directly.
2129 *
2130 * @param[in] name Feature name.
2131 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02002132 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002133 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002134 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002135 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002136 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002137 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002138static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002139resolve_feature(const char *id, const struct lys_module *module, int first, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002140{
Michal Vasko2d851a92015-10-20 16:16:36 +02002141 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002142 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002143 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002144
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002145 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002146 assert(module);
2147
2148 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002149 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002150 LOGVAL(LYE_INCHAR, line, 0, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002151 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002152 }
2153
Radek Krejcic071c542016-01-27 14:57:51 +01002154 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2155 if (!module) {
2156 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01002157 LOGVAL(LYE_INMOD_LEN, line, 0, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002158 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002159 }
2160
Radek Krejcic071c542016-01-27 14:57:51 +01002161 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002162 for (j = 0; j < module->features_size; j++) {
2163 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002164 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002165 /* check status */
2166 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002167 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejciadb57612016-02-16 13:34:34 +01002168 module->features[j].module, module->features[j].name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002169 return -1;
2170 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002171 *ret = &module->features[j];
2172 }
2173 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002174 }
2175 }
Radek Krejcic071c542016-01-27 14:57:51 +01002176 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002177 for (i = 0; i < module->inc_size; i++) {
2178 if (!module->inc[i].submodule) {
2179 /* not yet resolved */
2180 continue;
2181 }
Radek Krejcic071c542016-01-27 14:57:51 +01002182 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2183 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2184 if (ret) {
2185 /* check status */
2186 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002187 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002188 module->inc[i].submodule->features[j].flags,
2189 module->inc[i].submodule->features[j].module,
Radek Krejciadb57612016-02-16 13:34:34 +01002190 module->inc[i].submodule->features[j].name, line, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002191 return -1;
2192 }
2193 *ret = &(module->inc[i].submodule->features[j]);
2194 }
2195 return EXIT_SUCCESS;
2196 }
2197 }
2198 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002199
2200 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02002201 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002202 LOGVAL(LYE_INRESOLV, line, 0, NULL, "feature", id);
Michal Vasko184521f2015-09-24 13:14:26 +02002203 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002204 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002205}
2206
Michal Vasko23b61ec2015-08-19 11:19:50 +02002207/* ignores line */
2208static void
2209unres_data_del(struct unres_data *unres, uint32_t i)
2210{
2211 /* there are items after the one deleted */
2212 if (i+1 < unres->count) {
2213 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002214 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002215
2216 /* deleting the last item */
2217 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002218 free(unres->node);
2219 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002220 }
2221
2222 /* if there are no items after and it is not the last one, just move the counter */
2223 --unres->count;
2224}
2225
Michal Vasko0491ab32015-08-19 14:28:29 +02002226/**
2227 * @brief Resolve (find) a data node from a specific module. Does not log.
2228 *
2229 * @param[in] mod Module to search in.
2230 * @param[in] name Name of the data node.
2231 * @param[in] nam_len Length of the name.
2232 * @param[in] start Data node to start the search from.
2233 * @param[in,out] parents Resolved nodes. If there are some parents,
2234 * they are replaced (!!) with the resolvents.
2235 *
2236 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2237 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002238static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002239resolve_data(const 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 +02002240{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002241 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002242 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002243 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002244
Michal Vasko23b61ec2015-08-19 11:19:50 +02002245 if (!parents->count) {
2246 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002247 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002248 if (!parents->node) {
2249 LOGMEM;
2250 return EXIT_FAILURE;
2251 }
Michal Vaskocf024702015-10-08 15:01:42 +02002252 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002253 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002254 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002255 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002256 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002257 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002258 continue;
2259 }
2260 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002261 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002262 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2263 && node->schema->name[nam_len] == '\0') {
2264 /* matching target */
2265 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002266 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002267 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002268 flag = 1;
2269 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002270 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002271 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002272 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2273 if (!parents->node) {
2274 return EXIT_FAILURE;
2275 }
Michal Vaskocf024702015-10-08 15:01:42 +02002276 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002277 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002278 }
2279 }
2280 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002281
2282 if (!flag) {
2283 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002284 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002285 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002286 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002287 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002288 }
2289
Michal Vasko0491ab32015-08-19 14:28:29 +02002290 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002291}
2292
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002293/**
2294 * @brief Resolve (find) a data node. Does not log.
2295 *
Radek Krejci581ce772015-11-10 17:22:40 +01002296 * @param[in] mod_name Module name of the data node.
2297 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002298 * @param[in] name Name of the data node.
2299 * @param[in] nam_len Length of the name.
2300 * @param[in] start Data node to start the search from.
2301 * @param[in,out] parents Resolved nodes. If there are some parents,
2302 * they are replaced (!!) with the resolvents.
2303 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002304 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002305 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002306static int
Radek Krejci581ce772015-11-10 17:22:40 +01002307resolve_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 +02002308 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002309{
Michal Vasko1e62a092015-12-01 12:27:20 +01002310 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002311 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002312
Michal Vasko23b61ec2015-08-19 11:19:50 +02002313 assert(start);
2314
Michal Vasko31fc3672015-10-21 12:08:13 +02002315 if (mod_name) {
2316 /* we have mod_name, find appropriate module */
2317 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002318 if (!str) {
2319 LOGMEM;
2320 return -1;
2321 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002322 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2323 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002324 if (!mod) {
2325 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002326 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002327 }
2328 } else {
2329 /* no prefix, module is the same as of current node */
2330 mod = start->schema->module;
2331 }
2332
2333 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002334}
2335
Michal Vasko730dfdf2015-08-11 14:48:05 +02002336/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002337 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02002338 * only specific errors, general no-resolvent error is left to the caller,
2339 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002340 *
Michal Vaskobb211122015-08-19 14:03:11 +02002341 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02002342 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02002343 * @param[in] line Line in the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01002344 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002345 * @param[in,out] node_match Nodes satisfying the restriction
2346 * without the predicate. Nodes not
2347 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002348 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002349 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002350 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002351 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002352static int
Radek Krejciadb57612016-02-16 13:34:34 +01002353resolve_path_predicate_data(const char *pred, int first, uint32_t line,struct lyd_node *node,
2354 struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002355{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002356 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002357 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002358 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002359 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2360 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002361 uint32_t j;
2362
2363 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002364 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002365 if (!source_match.node) {
2366 LOGMEM;
2367 return -1;
2368 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002369 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002370 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002371 if (!dest_match.node) {
2372 LOGMEM;
2373 return -1;
2374 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002375
2376 do {
2377 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2378 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002379 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002380 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002381 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002382 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002383 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002384 pred += i;
2385
Michal Vasko23b61ec2015-08-19 11:19:50 +02002386 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002387 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002388 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002389
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002390 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002391 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002392 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002393 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002394 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002395 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002396 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002397 i = 0;
2398 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002399 }
2400
2401 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002402 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002403 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002404 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2405 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002406 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002407 rc = -1;
2408 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002409 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002410 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002411 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002412 dest_match.node[0] = dest_match.node[0]->parent;
2413 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002414 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002415 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002416 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002417 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002418 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002419 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002420 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002421 }
2422 }
2423 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002424 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002425 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002426 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002427 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002428 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002429 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002430 i = 0;
2431 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002432 }
2433
2434 if (pke_len == pke_parsed) {
2435 break;
2436 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002437 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 +02002438 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002439 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002440 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002441 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002442 }
2443 pke_parsed += i;
2444 }
2445
2446 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002447 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2448 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002449 goto remove_leafref;
2450 }
2451
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002452 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002453 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002454 goto remove_leafref;
2455 }
2456
2457 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002458 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002459 continue;
2460
2461remove_leafref:
2462 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002463 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002464 }
2465 } while (has_predicate);
2466
Michal Vaskocf024702015-10-08 15:01:42 +02002467 free(source_match.node);
2468 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002469 if (parsed) {
2470 *parsed = parsed_loc;
2471 }
2472 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002473
2474error:
2475
2476 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002477 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002478 }
2479 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002480 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002481 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002482 if (parsed) {
2483 *parsed = -parsed_loc+i;
2484 }
2485 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002486}
2487
Michal Vasko730dfdf2015-08-11 14:48:05 +02002488/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002489 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002490 *
Michal Vaskocf024702015-10-08 15:01:42 +02002491 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002492 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002493 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002494 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002495 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002496 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002497 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002498 */
Michal Vasko184521f2015-09-24 13:14:26 +02002499static int
Michal Vaskocf024702015-10-08 15:01:42 +02002500resolve_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 +02002501{
Radek Krejci71b795b2015-08-10 16:20:39 +02002502 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002503 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002504 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002505 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002506
Michal Vaskocf024702015-10-08 15:01:42 +02002507 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002508
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002509 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002510 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002511
2512 /* searching for nodeset */
2513 do {
2514 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002515 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002516 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002517 goto error;
2518 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002519 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002520 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002521
Michal Vasko23b61ec2015-08-19 11:19:50 +02002522 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002523 if (parent_times != -1) {
2524 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002525 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002526 if (!ret->node) {
2527 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002528 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002529 goto error;
2530 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002531 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002532 for (i = 0; i < parent_times; ++i) {
2533 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002534 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002535 /* error, too many .. */
Radek Krejciadb57612016-02-16 13:34:34 +01002536 LOGVAL(LYE_INVAL, line, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002537 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002538 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002539 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002540 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002541 data = ret->node[0] = node->parent;
2542 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002543 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002544 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002545 free(ret->node);
2546 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002547 } else {
2548 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002549 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002550 }
2551 }
2552
2553 /* absolute path */
2554 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002555 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002556 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002557 if (data->prev) {
2558 for (; data->prev->next; data = data->prev);
2559 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002560 }
2561 }
2562
2563 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002564 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002565 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002566 LOGVAL(LYE_INELEM_LEN, line, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002567 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002568 goto error;
2569 }
2570
2571 if (has_predicate) {
2572 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002573 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002574 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2575 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002576 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002577 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002578 continue;
2579 }
2580
2581 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002582 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002583 }
Radek Krejciadb57612016-02-16 13:34:34 +01002584 if ((rc = resolve_path_predicate_data(path, first, line, node, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002585 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002586 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002587 LOGVAL(LYE_NORESOLV, 0, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002588 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002589 goto error;
2590 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002591 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002592 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593
Michal Vasko23b61ec2015-08-19 11:19:50 +02002594 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002595 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002596 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, node, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002597 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002598 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002599 goto error;
2600 }
2601 }
2602 } while (path[0] != '\0');
2603
Michal Vaskof02e3742015-08-05 16:27:02 +02002604 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002605
2606error:
2607
Michal Vaskocf024702015-10-08 15:01:42 +02002608 free(ret->node);
2609 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002610 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002611
Michal Vasko0491ab32015-08-19 14:28:29 +02002612 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002613}
2614
Michal Vasko730dfdf2015-08-11 14:48:05 +02002615/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002616 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002617 *
Michal Vaskobb211122015-08-19 14:03:11 +02002618 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002619 * @param[in] context_node Predicate context node (where the predicate is placed).
2620 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko184521f2015-09-24 13:14:26 +02002621 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002622 * @param[in] line Line in the input file.
2623 *
Michal Vasko184521f2015-09-24 13:14:26 +02002624 * @return 0 on forward reference, otherwise the number
2625 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002626 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002627 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002628static int
Radek Krejciadb57612016-02-16 13:34:34 +01002629resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
2630 struct lys_node *parent, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002631{
Michal Vasko1e62a092015-12-01 12:27:20 +01002632 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002633 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2634 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 +02002635 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002636
2637 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002638 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002639 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002640 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002641 return -parsed+i;
2642 }
2643 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002644 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002645
Michal Vasko58090902015-08-13 14:04:15 +02002646 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002647 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002648 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002649 }
Radek Krejciadb57612016-02-16 13:34:34 +01002650 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002651 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002652 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002653 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002654 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002655 }
2656 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002657 }
2658
2659 /* destination */
2660 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2661 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002662 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002663 return -parsed;
2664 }
2665 pke_parsed += i;
2666
Radek Krejciadb57612016-02-16 13:34:34 +01002667 /* parent is actually the parent of this leaf, so skip the first ".." */
2668 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002669 if (!dst_node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002670 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002671 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002672 }
Radek Krejciadb57612016-02-16 13:34:34 +01002673 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002674 }
2675 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002676 if (!dest_pref) {
2677 dest_pref = dst_node->module->name;
2678 }
2679 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002680 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002681 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002682 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002683 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002684 }
2685 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002686 }
2687
2688 if (pke_len == pke_parsed) {
2689 break;
2690 }
2691
2692 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2693 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002694 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent,
2695 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002696 return -parsed;
2697 }
2698 pke_parsed += i;
2699 }
2700
2701 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002702 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002703 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
2704 LOGVAL(LYE_SPEC, 0, 0, NULL, "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02002705 return -parsed;
2706 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002707 } while (has_predicate);
2708
2709 return parsed;
2710}
2711
Michal Vasko730dfdf2015-08-11 14:48:05 +02002712/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002713 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002714 *
Michal Vaskobb211122015-08-19 14:03:11 +02002715 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002716 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002717 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2718 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002719 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002720 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002721 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002722 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002723 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002724 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002725static int
Radek Krejciadb57612016-02-16 13:34:34 +01002726resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf, int first, uint32_t line,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002727 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002728{
Michal Vasko1e62a092015-12-01 12:27:20 +01002729 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002730 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002731 const char *id, *prefix, *name;
2732 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002733 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002734
Michal Vasko184521f2015-09-24 13:14:26 +02002735 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002736 parent_times = 0;
2737 id = path;
2738
2739 do {
2740 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002741 LOGVAL(LYE_INCHAR, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002742 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002743 }
2744 id += i;
2745
Michal Vasko184521f2015-09-24 13:14:26 +02002746 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002747 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002748 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002749 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002750 /* get start node */
2751 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002752 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002753 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002754 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002755 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002756 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002757 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002758 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002759 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002760 if (parent_tpdf) {
2761 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejciadb57612016-02-16 13:34:34 +01002762 LOGVAL(LYE_NORESOLV, line, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002763 return -1;
2764 }
2765
Radek Krejciadb57612016-02-16 13:34:34 +01002766 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002767 i = 0;
2768 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002769 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002770 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002771 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002772 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002773 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002774 }
Michal Vasko58090902015-08-13 14:04:15 +02002775
2776 /* this node is a wrong node, we actually need the augment target */
2777 if (node->nodetype == LYS_AUGMENT) {
2778 node = ((struct lys_node_augment *)node)->target;
2779 if (!node) {
2780 continue;
2781 }
2782 }
2783
2784 ++i;
2785 if (i == parent_times) {
2786 break;
2787 }
2788 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002789 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002790
Michal Vasko1f76a282015-08-04 16:16:53 +02002791 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002792 } else {
2793 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002794 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002795 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002796
Michal Vasko184521f2015-09-24 13:14:26 +02002797 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002798 } else {
2799 node = node->child;
2800 }
2801
Michal Vasko4f0dad02016-02-15 14:08:23 +01002802 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002803 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01002804 }
2805
Michal Vasko36cbaa42015-12-14 13:15:48 +01002806 rc = lys_get_sibling(node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002807 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002808 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002809 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002810 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002811 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002812 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002813
2814 if (has_predicate) {
2815 /* we have predicate, so the current result must be list */
2816 if (node->nodetype != LYS_LIST) {
Radek Krejciadb57612016-02-16 13:34:34 +01002817 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002818 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002819 }
2820
Radek Krejciadb57612016-02-16 13:34:34 +01002821 i = resolve_path_predicate_schema(id, node, parent, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002822 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002823 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002824 } else if (i < 0) {
2825 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002826 }
2827 id += i;
2828 }
2829 } while (id[0]);
2830
Radek Krejcib1c12512015-08-11 11:22:04 +02002831 /* the target must be leaf or leaf-list */
2832 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejciadb57612016-02-16 13:34:34 +01002833 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002834 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002835 }
2836
Radek Krejcicf509982015-12-15 09:22:44 +01002837 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002838 if (lyp_check_status(parent->flags, parent->module, parent->name,
2839 node->flags, node->module, node->name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002840 return -1;
2841 }
2842
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002843 if (ret) {
2844 *ret = node;
2845 }
2846 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002847}
2848
Michal Vasko730dfdf2015-08-11 14:48:05 +02002849/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002850 * @brief Resolve instance-identifier predicate in JSON data format.
2851 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002852 *
Michal Vaskobb211122015-08-19 14:03:11 +02002853 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002854 * @param[in,out] node_match Nodes matching the restriction without
2855 * the predicate. Nodes not satisfying
2856 * the predicate are removed.
2857 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002858 * @return Number of characters successfully parsed,
2859 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002860 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002862resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002864 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002865 struct unres_data target_match;
2866 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002867 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002868 const char *model, *name, *value;
2869 char *str;
2870 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2871 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872
Michal Vasko1f2cc332015-08-19 11:18:32 +02002873 assert(pred && node_match->count);
2874
Michal Vaskocf024702015-10-08 15:01:42 +02002875 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002876 idx = -1;
2877 parsed = 0;
2878
2879 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002880 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 return -parsed+i;
2882 }
2883 parsed += i;
2884 pred += i;
2885
Michal Vasko1f2cc332015-08-19 11:18:32 +02002886 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 if (isdigit(name[0])) {
2888 idx = atoi(name);
2889 }
2890
Michal Vasko1f2cc332015-08-19 11:18:32 +02002891 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002892 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002893 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002894 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002895 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002896 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002897 if (!target_match.node) {
2898 LOGMEM;
2899 return -1;
2900 }
Michal Vaskocf024702015-10-08 15:01:42 +02002901 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002902 } else {
2903 str = strndup(model, mod_len);
2904 mod = ly_ctx_get_module(ctx, str, NULL);
2905 free(str);
2906
Radek Krejci804836a2016-02-03 10:39:55 +01002907 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002908 goto remove_instid;
2909 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002910 }
2911
2912 /* check that we have the correct type */
2913 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002914 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002915 goto remove_instid;
2916 }
2917 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002918 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002919 goto remove_instid;
2920 }
2921 }
2922
Michal Vasko83a6c462015-10-08 16:43:53 +02002923 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2924 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002925 || (!value && (idx != cur_idx))) {
2926 goto remove_instid;
2927 }
2928
Michal Vaskocf024702015-10-08 15:01:42 +02002929 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930
2931 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002932 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 continue;
2934
2935remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002936 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937
2938 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002939 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002940 }
2941 } while (has_predicate);
2942
2943 return parsed;
2944}
2945
Michal Vasko730dfdf2015-08-11 14:48:05 +02002946/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002947 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002948 *
Radek Krejciadb57612016-02-16 13:34:34 +01002949 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02002950 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002951 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002952 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002953 * @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 +02002954 */
Michal Vasko184521f2015-09-24 13:14:26 +02002955static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002956resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002957{
Radek Krejcic5090c32015-08-12 09:46:19 +02002958 int i = 0, j;
2959 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002960 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002961 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002962 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002963 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002964 int mod_len, name_len, has_predicate;
2965 struct unres_data node_match;
2966 uint32_t k;
2967
2968 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002969
Radek Krejcic5090c32015-08-12 09:46:19 +02002970 /* we need root to resolve absolute path */
2971 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002972 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002973 if (data->prev) {
2974 for (; data->prev->next; data = data->prev);
2975 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002976
Radek Krejcic5090c32015-08-12 09:46:19 +02002977 /* search for the instance node */
2978 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002979 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002980 if (j <= 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002981 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002982 goto error;
2983 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002984 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002985
Michal Vasko1f2cc332015-08-19 11:18:32 +02002986 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002987 if (!str) {
2988 LOGMEM;
2989 goto error;
2990 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002991 mod = ly_ctx_get_module(ctx, str, NULL);
2992 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002993
Radek Krejcic5090c32015-08-12 09:46:19 +02002994 if (!mod) {
2995 /* no instance exists */
2996 return NULL;
2997 }
2998
Michal Vasko1f2cc332015-08-19 11:18:32 +02002999 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003000 /* no instance exists */
3001 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003002 }
3003
3004 if (has_predicate) {
3005 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003006 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003007 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3008 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3009 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003010 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003011 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003012 continue;
3013 }
3014
3015 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003016 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003017 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003018
Michal Vaskof39142b2015-10-21 11:40:05 +02003019 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003020 if (j < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003021 LOGVAL(LYE_INPRED, line, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003022 goto error;
3023 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003024 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003025
Michal Vasko1f2cc332015-08-19 11:18:32 +02003026 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003027 /* no instance exists */
3028 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003029 }
3030 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003031 }
3032
Michal Vasko1f2cc332015-08-19 11:18:32 +02003033 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003034 /* no instance exists */
3035 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003036 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003037 /* instance identifier must resolve to a single node */
Radek Krejciadb57612016-02-16 13:34:34 +01003038 LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003039
3040 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003041 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003042
3043 return NULL;
3044 } else {
3045 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003046 result = node_match.node[0];
3047 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003048
3049 return result;
3050 }
3051
3052error:
3053
3054 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003055 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003056
3057 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003058}
3059
Michal Vasko730dfdf2015-08-11 14:48:05 +02003060/**
3061 * @brief Passes config flag down to children. Does not log.
3062 *
3063 * @param[in] node Parent node.
3064 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003065static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003066inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067{
Radek Krejci1d82ef62015-08-07 14:44:40 +02003068 LY_TREE_FOR(node, node) {
3069 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
3070 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003071 }
3072}
3073
Michal Vasko730dfdf2015-08-11 14:48:05 +02003074/**
Michal Vasko7178e692016-02-12 15:58:05 +01003075 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003076 *
Michal Vaskobb211122015-08-19 14:03:11 +02003077 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003078 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko7178e692016-02-12 15:58:05 +01003079 * @param[in] first Whether this is the first resolution try.
3080 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003081 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003082 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003083 */
Michal Vasko7178e692016-02-12 15:58:05 +01003084static int
3085resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003086{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003087 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003088 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003089
Michal Vasko1d87a922015-08-21 12:57:16 +02003090 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003091
3092 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003093 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), (const struct lys_node **)&aug->target);
Michal Vasko7178e692016-02-12 15:58:05 +01003094 if (rc == -1) {
3095 return -1;
3096 }
3097 if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003098 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003099 return -1;
3100 }
3101 if (!aug->target) {
Michal Vasko7178e692016-02-12 15:58:05 +01003102 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003103 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01003104 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003105 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003106 }
3107
3108 if (!aug->child) {
3109 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003110 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003111 return EXIT_SUCCESS;
3112 }
3113
Michal Vaskod58d5962016-03-02 14:29:41 +01003114 /* check for mandatory nodes - if the target node is in another module
3115 * the added nodes cannot be mandatory
3116 */
3117 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3118 && lyp_check_mandatory((struct lys_node *)aug)) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003119 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, "mandatory", "augment node");
3120 LOGVAL(LYE_SPEC, 0, 0, NULL, "When augmenting data in another module, mandatory nodes are not allowed.");
Michal Vaskod58d5962016-03-02 14:29:41 +01003121 return -1;
3122 }
3123
Michal Vasko07e89ef2016-03-03 13:28:57 +01003124 /* check augment target type and then augment nodes type */
3125 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3126 LY_TREE_FOR(aug->child, sub) {
3127 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003128 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3129 LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003130 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3131 return -1;
3132 }
3133 }
3134 } else if (aug->target->nodetype == LYS_CHOICE) {
3135 LY_TREE_FOR(aug->child, sub) {
3136 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003137 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3138 LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003139 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3140 return -1;
3141 }
3142 }
3143 } else {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003144 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3145 LOGVAL(LYE_SPEC, 0, 0, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003146 return -1;
3147 }
3148
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003149 /* inherit config information from parent, augment does not have
3150 * config property, but we need to keep the information for subelements
3151 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003152 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003153 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154 inherit_config_flag(sub);
3155 }
3156
Radek Krejcic071c542016-01-27 14:57:51 +01003157 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003158 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01003159 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003160 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003161 }
3162 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003163 /* reconnect augmenting data into the target - add them to the target child list */
3164 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003165 sub = aug->target->child->prev; /* remember current target's last node */
3166 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003167 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003168 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003169 } else {
3170 aug->target->child = aug->child;
3171 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172
3173 return EXIT_SUCCESS;
3174}
3175
Michal Vasko730dfdf2015-08-11 14:48:05 +02003176/**
3177 * @brief Resolve uses, apply augments, refines. Logs directly.
3178 *
Michal Vaskobb211122015-08-19 14:03:11 +02003179 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003180 * @param[in,out] unres List of unresolved items.
3181 * @param[in] line Line in the input file.
3182 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003183 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003184 */
Michal Vasko184521f2015-09-24 13:14:26 +02003185static int
Michal Vaskodef0db12015-10-07 13:22:48 +02003186resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187{
3188 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003189 struct lys_node *node = NULL;
3190 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003191 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003192 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003193 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003194 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003195
Michal Vasko71e1aa82015-08-12 12:17:51 +02003196 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003197 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003198 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003199
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003201 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01003202 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003203 if (!node) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003204 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3205 LOGVAL(LYE_SPEC, 0, 0, NULL, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003206 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003207 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208 }
3209 ctx = uses->module->ctx;
3210
Michal Vaskodef0db12015-10-07 13:22:48 +02003211 /* we managed to copy the grouping, the rest must be possible to resolve */
3212
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003213 /* apply refines */
3214 for (i = 0; i < uses->refine_size; i++) {
3215 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003216 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
3217 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003218 if (rc || !node) {
Radek Krejciadb57612016-02-16 13:34:34 +01003219 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003220 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221 }
3222
Radek Krejci1d82ef62015-08-07 14:44:40 +02003223 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003224 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3225 LOGVAL(LYE_SPEC, 0, 0, NULL, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003226 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003227 }
3228
3229 /* description on any nodetype */
3230 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003231 lydict_remove(ctx, node->dsc);
3232 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003233 }
3234
3235 /* reference on any nodetype */
3236 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003237 lydict_remove(ctx, node->ref);
3238 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 }
3240
3241 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003242 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003243 node->flags &= ~LYS_CONFIG_MASK;
3244 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003245 }
3246
3247 /* default value ... */
3248 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003249 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003251 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3252 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3253 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003254 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003255 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3256 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003257 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejciadb57612016-02-16 13:34:34 +01003258 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003259 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003260 }
3261 }
3262 }
3263
3264 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003265 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003266 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003268 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269
3270 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003271 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003272 }
3273 }
3274
3275 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003276 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3277 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3278 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279 }
3280
3281 /* min/max-elements on list or leaf-list */
3282 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003283 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003285 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286 }
3287 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003288 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003290 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003292 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 }
3294 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003295 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003296 }
3297 }
3298
3299 /* must in leaf, leaf-list, list, container or anyxml */
3300 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003301 switch (node->nodetype) {
3302 case LYS_LEAF:
3303 old_size = &((struct lys_node_leaf *)node)->must_size;
3304 old_must = &((struct lys_node_leaf *)node)->must;
3305 break;
3306 case LYS_LEAFLIST:
3307 old_size = &((struct lys_node_leaflist *)node)->must_size;
3308 old_must = &((struct lys_node_leaflist *)node)->must;
3309 break;
3310 case LYS_LIST:
3311 old_size = &((struct lys_node_list *)node)->must_size;
3312 old_must = &((struct lys_node_list *)node)->must;
3313 break;
3314 case LYS_CONTAINER:
3315 old_size = &((struct lys_node_container *)node)->must_size;
3316 old_must = &((struct lys_node_container *)node)->must;
3317 break;
3318 case LYS_ANYXML:
3319 old_size = &((struct lys_node_anyxml *)node)->must_size;
3320 old_must = &((struct lys_node_anyxml *)node)->must;
3321 break;
3322 default:
3323 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003324 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003325 }
3326
3327 size = *old_size + rfn->must_size;
3328 must = realloc(*old_must, size * sizeof *rfn->must);
3329 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003331 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003332 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003333 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3334 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3335 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3336 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3337 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3338 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 }
3340
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003341 *old_must = must;
3342 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003343 }
3344 }
3345
3346 /* apply augments */
3347 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko7178e692016-02-12 15:58:05 +01003348 rc = resolve_augment(&uses->augment[i], uses->child, 0, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003349 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003350 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351 }
3352 }
3353
3354 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003355}
3356
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357/**
3358 * @brief Resolve base identity recursively. Does not log.
3359 *
3360 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003361 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003362 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003363 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003364 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003365 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003366 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003367static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003368resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003369 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003370{
Michal Vaskof02e3742015-08-05 16:27:02 +02003371 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003372 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003373 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003374
Radek Krejcicf509982015-12-15 09:22:44 +01003375 assert(ret);
3376
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377 /* search module */
3378 for (i = 0; i < module->ident_size; i++) {
3379 if (!strcmp(basename, module->ident[i].name)) {
3380
3381 if (!ident) {
3382 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003383 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003384 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003385 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003386 }
3387
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003388 base = &module->ident[i];
3389 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003390 }
3391 }
3392
3393 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003394 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3395 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3396 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003397
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003398 if (!ident) {
3399 *ret = &module->inc[j].submodule->ident[i];
3400 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003401 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003402
3403 base = &module->inc[j].submodule->ident[i];
3404 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003405 }
3406 }
3407 }
3408
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003409matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003411 if (base) {
3412 /* check for circular reference */
3413 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3414 if (ident == base_iter) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003415 LOGVAL(LYE_INARG, 0, LY_VLOG_NONE, NULL, base_iter->name, "base");
3416 LOGVAL(LYE_SPEC, 0, 0, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003417 return EXIT_FAILURE;
3418 }
3419 }
3420 /* checks done, store the result */
3421 ident->base = base;
3422
3423 /* maintain backlinks to the derived identitise */
3424 while (base) {
3425 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 if (der) {
3427 der->next = malloc(sizeof *der);
3428 der = der->next;
3429 } else {
3430 ident->base->der = der = malloc(sizeof *der);
3431 }
Michal Vasko253035f2015-12-17 16:58:13 +01003432 if (!der) {
3433 LOGMEM;
3434 return EXIT_FAILURE;
3435 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003436 der->next = NULL;
3437 der->ident = ident;
3438
Radek Krejcibabbff82016-02-19 13:31:37 +01003439 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003440 }
Radek Krejcicf509982015-12-15 09:22:44 +01003441 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003442 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003443 }
3444
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003445 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003446}
3447
Michal Vasko730dfdf2015-08-11 14:48:05 +02003448/**
3449 * @brief Resolve base identity. Logs directly.
3450 *
3451 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003452 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003453 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003454 * @param[in] parent Either "type" or "identity".
Michal Vasko184521f2015-09-24 13:14:26 +02003455 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003456 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003457 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003459 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003460 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003461static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003462resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003463 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464{
3465 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003466 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003467 struct lys_ident *target, **ret;
3468 uint8_t flags;
3469 struct lys_module *mod;
3470
3471 assert((ident && !type) || (!ident && type));
3472
3473 if (!type) {
3474 /* have ident to resolve */
3475 ret = &target;
3476 flags = ident->flags;
3477 mod = ident->module;
3478 } else {
3479 /* have type to fill */
3480 ret = &type->info.ident.ref;
3481 flags = type->parent->flags;
3482 mod = type->parent->module;
3483 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484
3485 /* search for the base identity */
3486 name = strchr(basename, ':');
3487 if (name) {
3488 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003489 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003490 name++;
3491
Michal Vasko2d851a92015-10-20 16:16:36 +02003492 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003494 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495 }
3496 } else {
3497 name = basename;
3498 }
3499
Radek Krejcic071c542016-01-27 14:57:51 +01003500 /* get module where to search */
3501 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3502 if (!module) {
3503 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01003504 LOGVAL(LYE_INMOD, line, 0, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003505 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 }
3507
Radek Krejcic071c542016-01-27 14:57:51 +01003508 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003509 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003510 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003511 } else if (ly_errno) {
3512 LOGVAL(LYE_LINE, line, 0, NULL);
3513 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 }
Radek Krejcic071c542016-01-27 14:57:51 +01003515 /* and all its submodules */
3516 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3517 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3518 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003519 } else if (ly_errno) {
3520 LOGVAL(LYE_LINE, line, 0, NULL);
3521 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003522 }
3523 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524
Michal Vasko184521f2015-09-24 13:14:26 +02003525 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003526 LOGVAL(LYE_INARG, line, 0, NULL, basename, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003527 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003528 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003529
3530success:
3531 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003532 if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name,
3533 line, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003534 return -1;
3535 }
3536
3537 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538}
3539
Michal Vasko730dfdf2015-08-11 14:48:05 +02003540/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003541 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003542 *
3543 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003544 * @param[in] ident_name Identityref name.
3545 * @param[in] line Line from the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01003546 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003547 *
3548 * @return Pointer to the identity resolvent, NULL on error.
3549 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003550struct lys_ident *
Radek Krejciadb57612016-02-16 13:34:34 +01003551resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003553 const char *mod_name, *name;
3554 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003555 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003556
Michal Vaskofb0873c2015-08-21 09:00:07 +02003557 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 return NULL;
3559 }
3560
Michal Vaskoc633ca02015-08-21 14:03:51 +02003561 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003562 if (rc < (signed)strlen(ident_name)) {
Radek Krejciadb57612016-02-16 13:34:34 +01003563 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003564 return NULL;
3565 }
3566
Michal Vaskoc633ca02015-08-21 14:03:51 +02003567 if (!strcmp(base->name, name) && (!mod_name
3568 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003569 return base;
3570 }
3571
3572 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003573 if (!strcmp(der->ident->name, name) && (!mod_name
3574 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3575 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 /* we have match */
3577 return der->ident;
3578 }
3579 }
3580
Radek Krejciadb57612016-02-16 13:34:34 +01003581 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 return NULL;
3583}
3584
Michal Vasko730dfdf2015-08-11 14:48:05 +02003585/**
Michal Vasko7955b362015-09-04 14:18:15 +02003586 * @brief Resolve (find) choice default case. Does not log.
3587 *
3588 * @param[in] choic Choice to use.
3589 * @param[in] dflt Name of the default case.
3590 *
3591 * @return Pointer to the default node or NULL.
3592 */
3593static struct lys_node *
3594resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3595{
3596 struct lys_node *child, *ret;
3597
3598 LY_TREE_FOR(choic->child, child) {
3599 if (child->nodetype == LYS_USES) {
3600 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3601 if (ret) {
3602 return ret;
3603 }
3604 }
3605
Radek Krejci749190d2016-02-18 16:26:25 +01003606 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003607 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3608 return child;
3609 }
3610 }
3611
3612 return NULL;
3613}
3614
3615/**
Michal Vaskobb211122015-08-19 14:03:11 +02003616 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003617 *
Michal Vaskobb211122015-08-19 14:03:11 +02003618 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003619 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003620 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003621 * @param[in] line Line in the input file.
3622 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003623 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003624 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003626resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003628 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003629 struct lys_node *parent;
3630
3631 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3632 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3633
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003634 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003635 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3636 if (rc == -1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003637 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003638 return -1;
3639 } else if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003640 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003641 return -1;
3642 } else if (!uses->grp) {
3643 if (parent && first) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003644 ++parent->nacm;
3645 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003646 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003647 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003648 }
3649
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003650 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003651 if (parent && first) {
3652 ++parent->nacm;
3653 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 return EXIT_FAILURE;
3655 }
3656
Michal Vaskodef0db12015-10-07 13:22:48 +02003657 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003658 if (!rc) {
3659 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003660 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003661 if (!parent->nacm) {
3662 LOGINT;
3663 return -1;
3664 }
3665 --parent->nacm;
3666 }
Radek Krejcicf509982015-12-15 09:22:44 +01003667
3668 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003669 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003670 uses->grp->flags, uses->grp->module, uses->grp->name,
3671 line, (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003672 return -1;
3673 }
3674
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003675 return EXIT_SUCCESS;
3676 }
3677
Michal Vasko407f1bb2015-09-23 15:51:07 +02003678 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003679 ++parent->nacm;
3680 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003681 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682}
3683
Michal Vasko730dfdf2015-08-11 14:48:05 +02003684/**
Michal Vasko9957e592015-08-17 15:04:09 +02003685 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003686 *
Michal Vaskobb211122015-08-19 14:03:11 +02003687 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003688 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003689 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003690 * @param[in] line Line in the input file.
3691 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003692 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003693 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003694static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003695resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003696{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003697 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003698 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003699
3700 for (i = 0; i < list->keys_size; ++i) {
3701 /* get the key name */
3702 if ((value = strpbrk(keys_str, " \t\n"))) {
3703 len = value - keys_str;
3704 while (isspace(value[0])) {
3705 value++;
3706 }
3707 } else {
3708 len = strlen(keys_str);
3709 }
3710
Michal Vasko4f0dad02016-02-15 14:08:23 +01003711 rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003712 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003713 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003714 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003715 }
3716 return rc;
3717 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003718
Radek Krejciadb57612016-02-16 13:34:34 +01003719 if (check_key(list, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003720 /* check_key logs */
3721 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003722 }
3723
Radek Krejcicf509982015-12-15 09:22:44 +01003724 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003725 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejciadb57612016-02-16 13:34:34 +01003726 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3727 line, (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003728 return -1;
3729 }
3730
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003731 /* prepare for next iteration */
3732 while (value && isspace(value[0])) {
3733 value++;
3734 }
3735 keys_str = value;
3736 }
3737
Michal Vaskof02e3742015-08-05 16:27:02 +02003738 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003739}
3740
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003741/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003742 * @brief Resolve (check) all must conditions of \p node.
3743 * Logs directly.
3744 *
3745 * @param[in] node Data node with optional must statements.
3746 * @param[in] first Whether this is the first resolution to try.
3747 * @param[in] line Line in the input file.
3748 *
3749 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3750 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003751static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003752resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003753{
Michal Vaskobf19d252015-10-08 15:39:17 +02003754 uint8_t i, must_size;
3755 struct lys_restr *must;
3756 struct lyxp_set set;
3757
3758 assert(node);
3759 memset(&set, 0, sizeof set);
3760
3761 switch (node->schema->nodetype) {
3762 case LYS_CONTAINER:
3763 must_size = ((struct lys_node_container *)node->schema)->must_size;
3764 must = ((struct lys_node_container *)node->schema)->must;
3765 break;
3766 case LYS_LEAF:
3767 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3768 must = ((struct lys_node_leaf *)node->schema)->must;
3769 break;
3770 case LYS_LEAFLIST:
3771 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3772 must = ((struct lys_node_leaflist *)node->schema)->must;
3773 break;
3774 case LYS_LIST:
3775 must_size = ((struct lys_node_list *)node->schema)->must_size;
3776 must = ((struct lys_node_list *)node->schema)->must;
3777 break;
3778 case LYS_ANYXML:
3779 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3780 must = ((struct lys_node_anyxml *)node->schema)->must;
3781 break;
3782 default:
3783 must_size = 0;
3784 break;
3785 }
3786
3787 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003788 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003789 return -1;
3790 }
3791
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003792 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003793
3794 if (!set.value.bool) {
3795 if (!first) {
Michal Vasko7d3ec592016-02-17 12:06:44 +01003796 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003797 }
3798 return 1;
3799 }
3800 }
3801
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003802 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003803}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003804
Michal Vaskobf19d252015-10-08 15:39:17 +02003805/**
Michal Vaskocf024702015-10-08 15:01:42 +02003806 * @brief Resolve (find) when condition context node. Does not log.
3807 *
3808 * @param[in] node Data node, whose conditional definition is being decided.
3809 * @param[in] schema Schema node with a when condition.
3810 *
3811 * @return Context node.
3812 */
3813static struct lyd_node *
3814resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003815{
Michal Vaskocf024702015-10-08 15:01:42 +02003816 struct lyd_node *parent;
3817 struct lys_node *sparent;
3818 uint16_t i, data_depth, schema_depth;
3819
3820 /* find a not schema-only node */
3821 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3822 schema = lys_parent(schema);
3823 if (!schema) {
3824 return NULL;
3825 }
3826 }
3827
3828 /* get node depths */
3829 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3830 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3831 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3832 ++schema_depth;
3833 }
3834 }
3835 if (data_depth < schema_depth) {
3836 return NULL;
3837 }
3838
3839 /* find the corresponding data node */
3840 for (i = 0; i < data_depth - schema_depth; ++i) {
3841 node = node->parent;
3842 }
3843 if (node->schema != schema) {
3844 return NULL;
3845 }
3846
3847 return node;
3848}
3849
3850/**
3851 * @brief Resolve (check) all when conditions relevant for \p node.
3852 * Logs directly.
3853 *
3854 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3855 * @param[in] first Whether this is the first resolution to try.
3856 * @param[in] line Line in the input file.
3857 *
3858 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3859 */
3860static int
3861resolve_when(struct lyd_node *node, int first, uint32_t line)
3862{
3863 struct lyd_node *ctx_node = NULL;
3864 struct lys_node *parent;
3865 struct lyxp_set set;
3866
3867 assert(node);
3868 memset(&set, 0, sizeof set);
3869
3870 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003871 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003872 return -1;
3873 }
3874
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003875 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003876
3877 if (!set.value.bool) {
3878 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003879 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003880 }
3881 return 1;
3882 }
3883 }
3884
3885 parent = node->schema;
3886 goto check_augment;
3887
3888 /* check when in every schema node that affects node */
3889 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3890 if (((struct lys_node_uses *)parent)->when) {
3891 if (!ctx_node) {
3892 ctx_node = resolve_when_ctx_node(node, parent);
3893 if (!ctx_node) {
3894 LOGINT;
3895 return -1;
3896 }
3897 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003898 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003899 return -1;
3900 }
3901
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003902 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003903
3904 if (!set.value.bool) {
3905 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003906 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003907 }
3908 return 1;
3909 }
3910 }
3911
3912check_augment:
3913 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3914 if (!ctx_node) {
3915 ctx_node = resolve_when_ctx_node(node, parent->parent);
3916 if (!ctx_node) {
3917 LOGINT;
3918 return -1;
3919 }
3920 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003921 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003922 return -1;
3923 }
3924
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003925 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003926
3927 if (!set.value.bool) {
3928 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003929 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003930 }
3931 return 1;
3932 }
3933 }
3934
3935 parent = lys_parent(parent);
3936 }
3937
3938 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003939}
3940
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003941/**
Michal Vaskobb211122015-08-19 14:03:11 +02003942 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003943 *
3944 * @param[in] mod Main module.
3945 * @param[in] item Item to resolve. Type determined by \p type.
3946 * @param[in] type Type of the unresolved item.
3947 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003948 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003949 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003950 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003951 *
3952 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3953 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003954static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003955resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003956 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003957{
Radek Krejci4f78b532016-02-17 13:43:00 +01003958 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003959 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003960 const char *base_name;
3961
3962 struct lys_ident *ident;
3963 struct lys_type *stype;
3964 struct lys_feature **feat_ptr;
3965 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003966 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003967
3968 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003969 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003970 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003971 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003972 ident = item;
3973
Radek Krejcibabbff82016-02-19 13:31:37 +01003974 rc = resolve_base_ident(mod, ident, base_name, "identity", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003975 break;
3976 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003977 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003978 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003979 stype = item;
3980
Radek Krejcicf509982015-12-15 09:22:44 +01003981 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003982 break;
3983 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003984 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003985 stype = item;
3986
Radek Krejci2f12f852016-01-08 12:59:57 +01003987 /* HACK - when there is no parent, we are in top level typedef and in that
3988 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3989 * know it via tpdf_flag */
3990 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01003991 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01003992 node = (struct lys_node *)stype->parent;
3993 }
3994
3995 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003996 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01003997 if (stype->info.lref.target) {
3998 /* store the backlink from leafref target */
3999 if (!stype->info.lref.target->child) {
4000 stype->info.lref.target->child = (void*)ly_set_new();
4001 if (!stype->info.lref.target->child) {
4002 LOGMEM;
4003 return -1;
4004 }
4005 }
4006 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
4007 }
4008
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004009 break;
4010 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004011 /* parent */
4012 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004013 stype = item;
4014
Michal Vasko88c29542015-11-27 14:57:53 +01004015 /* HACK type->der is temporarily unparsed type statement */
4016 yin = (struct lyxml_elem *)stype->der;
4017 stype->der = NULL;
4018
4019 rc = fill_yin_type(mod, node, yin, stype, unres);
4020 if (!rc) {
4021 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01004022 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01004023 } else {
4024 /* may try again later, put all back how it was */
4025 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004026 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004027 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004028 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004029 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004030 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004031 feat_ptr = item;
4032
Michal Vasko184521f2015-09-24 13:14:26 +02004033 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004034 break;
4035 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02004036 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004037 break;
4038 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004039 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004040 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004041 stype = item;
4042
Michal Vasko56826402016-03-02 11:11:37 +01004043 rc = check_default(stype, base_name, mod, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004044 break;
4045 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004046 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004047 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004048 choic = item;
4049
Michal Vasko7955b362015-09-04 14:18:15 +02004050 choic->dflt = resolve_choice_dflt(choic, base_name);
4051 if (choic->dflt) {
4052 rc = EXIT_SUCCESS;
4053 } else {
4054 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004055 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004056 break;
4057 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004058 has_str = 1;
Michal Vasko36cbaa42015-12-14 13:15:48 +01004059 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004060 break;
4061 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004062 has_str = 1;
Radek Krejci581ce772015-11-10 17:22:40 +01004063 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004065 case UNRES_AUGMENT:
4066 rc = resolve_augment(item, NULL, first, line);
Michal Vasko7178e692016-02-12 15:58:05 +01004067 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004068 default:
4069 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004070 break;
4071 }
4072
Radek Krejci4f78b532016-02-17 13:43:00 +01004073 if (has_str && !rc) {
4074 lydict_remove(mod->ctx, str_snode);
4075 }
4076
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004077 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004078}
4079
Michal Vaskof02e3742015-08-05 16:27:02 +02004080/* logs directly */
4081static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02004082print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004083{
Michal Vaskof02e3742015-08-05 16:27:02 +02004084 char line_str[18];
4085
4086 if (line) {
4087 sprintf(line_str, " (line %u)", line);
4088 } else {
4089 line_str[0] = '\0';
4090 }
4091
4092 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004093 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004094 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004095 break;
4096 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004097 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004098 break;
4099 case UNRES_TYPE_LEAFREF:
4100 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
4101 break;
4102 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004103 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
4104 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004105 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004106 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004107 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 +02004108 break;
4109 case UNRES_USES:
4110 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
4111 break;
4112 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004113 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 +02004114 break;
4115 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004116 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 +02004117 break;
4118 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004119 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 +02004120 break;
4121 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004122 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 +02004123 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004124 case UNRES_AUGMENT:
Michal Vasko729d2912016-02-12 16:01:43 +01004125 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "augment target", ((struct lys_node_augment *)item)->target_name, line_str);
Michal Vasko7178e692016-02-12 15:58:05 +01004126 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004127 default:
4128 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004129 break;
4130 }
4131}
4132
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004133/**
Michal Vaskobb211122015-08-19 14:03:11 +02004134 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004135 *
4136 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004137 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004138 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004139 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004140 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004141int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004142resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004143{
Michal Vasko88c29542015-11-27 14:57:53 +01004144 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004145 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004146
4147 assert(unres);
4148
Michal Vasko51054ca2015-08-12 12:20:00 +02004149 resolved = 0;
4150
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004151 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004152 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004153 unres_count = 0;
4154 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004155
4156 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01004157 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
4158 * we need every type's base only */
4159 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004160 continue;
4161 }
4162
Michal Vasko88c29542015-11-27 14:57:53 +01004163 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004164 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
4165 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004166 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004167 unres->type[i] = UNRES_RESOLVED;
4168 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004169 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004170 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004171 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004172 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004173 }
Michal Vasko88c29542015-11-27 14:57:53 +01004174 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004175
Michal Vasko88c29542015-11-27 14:57:53 +01004176 if (res_count < unres_count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004177 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004178 }
4179
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004180 /* the rest */
4181 for (i = 0; i < unres->count; ++i) {
4182 if (unres->type[i] == UNRES_RESOLVED) {
4183 continue;
4184 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004185
Michal Vasko407f1bb2015-09-23 15:51:07 +02004186 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
4187 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02004188 if (rc) {
4189 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004190 }
Michal Vasko184521f2015-09-24 13:14:26 +02004191
4192 unres->type[i] = UNRES_RESOLVED;
4193 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004194 }
4195
4196 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004197 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004198 }
4199
Radek Krejcic071c542016-01-27 14:57:51 +01004200 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004201 return EXIT_SUCCESS;
4202}
4203
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004204/**
Michal Vaskobb211122015-08-19 14:03:11 +02004205 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004206 *
4207 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004208 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004209 * @param[in] item Item to resolve. Type determined by \p type.
4210 * @param[in] type Type of the unresolved item.
4211 * @param[in] str String argument.
4212 * @param[in] line Line in the input file.
4213 *
4214 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4215 */
4216int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004217unres_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 +02004218 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004219{
Radek Krejci4f78b532016-02-17 13:43:00 +01004220 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)lydict_insert(mod->ctx, str, 0), line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221}
4222
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004223/**
Michal Vaskobb211122015-08-19 14:03:11 +02004224 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004225 *
4226 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004227 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004228 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004229 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004230 * @param[in] snode Schema node argument.
4231 * @param[in] line Line in the input file.
4232 *
4233 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4234 */
4235int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004236unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02004237 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004238{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004239 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004240 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004241
Michal Vasko9bf425b2015-10-22 11:42:03 +02004242 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4243 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004244
Michal Vasko184521f2015-09-24 13:14:26 +02004245 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004246 if (rc != EXIT_FAILURE) {
4247 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004248 }
4249
Michal Vasko0bd29d12015-08-19 11:45:49 +02004250 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02004251
Michal Vasko88c29542015-11-27 14:57:53 +01004252 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4253 if (type == UNRES_TYPE_DER) {
4254 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
4255 lyxml_unlink_elem(mod->ctx, yin, 1);
4256 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4257 }
4258
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004259 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004260 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4261 if (!unres->item) {
4262 LOGMEM;
4263 return -1;
4264 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004265 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004266 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4267 if (!unres->type) {
4268 LOGMEM;
4269 return -1;
4270 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004271 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004272 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4273 if (!unres->str_snode) {
4274 LOGMEM;
4275 return -1;
4276 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004277 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004278 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4279 if (!unres->module) {
4280 LOGMEM;
4281 return -1;
4282 }
4283 unres->module[unres->count-1] = mod;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004284#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004285 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
4286 if (!unres->line) {
4287 LOGMEM;
4288 return -1;
4289 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004290 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004291#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004292
4293 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004294}
4295
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004296/**
Michal Vaskobb211122015-08-19 14:03:11 +02004297 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004298 *
4299 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004300 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004301 * @param[in] item Old item to be resolved.
4302 * @param[in] type Type of the old unresolved item.
4303 * @param[in] new_item New item to use in the duplicate.
4304 *
4305 * @return EXIT_SUCCESS on success, -1 on error.
4306 */
Michal Vaskodad19402015-08-06 09:51:53 +02004307int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004308unres_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 +02004309{
4310 int i;
4311
Michal Vaskocf024702015-10-08 15:01:42 +02004312 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004313
Michal Vasko0bd29d12015-08-19 11:45:49 +02004314 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004315
4316 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004317 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318 }
4319
Michal Vasko0d204592015-10-07 09:50:04 +02004320 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004321 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004322 LOGINT;
4323 return -1;
4324 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004325 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004326 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004327 LOGINT;
4328 return -1;
4329 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004330 }
Michal Vaskodad19402015-08-06 09:51:53 +02004331
4332 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004333}
4334
Michal Vaskof02e3742015-08-05 16:27:02 +02004335/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004336int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004337unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004338{
4339 uint32_t ret = -1, i;
4340
4341 for (i = 0; i < unres->count; ++i) {
4342 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4343 ret = i;
4344 break;
4345 }
4346 }
4347
4348 return ret;
4349}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004350
Michal Vasko88c29542015-11-27 14:57:53 +01004351void
Radek Krejcic071c542016-01-27 14:57:51 +01004352unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004353{
4354 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004355 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01004356
Radek Krejcic071c542016-01-27 14:57:51 +01004357 if (!unres || !(*unres)) {
4358 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004359 }
4360
Radek Krejcic071c542016-01-27 14:57:51 +01004361 assert(module || (*unres)->count == 0);
4362
4363 for (i = 0; i < (*unres)->count; ++i) {
4364 if ((*unres)->module[i] != module) {
4365 if ((*unres)->type[i] != UNRES_RESOLVED) {
4366 unresolved++;
4367 }
4368 continue;
4369 }
4370 if ((*unres)->type[i] == UNRES_TYPE_DER) {
4371 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
4372 }
4373 (*unres)->type[i] = UNRES_RESOLVED;
4374 }
4375
4376 if (!module || (!unresolved && !module->type)) {
4377 free((*unres)->item);
4378 free((*unres)->type);
4379 free((*unres)->str_snode);
4380 free((*unres)->module);
Michal Vasko88c29542015-11-27 14:57:53 +01004381#ifndef NDEBUG
Radek Krejcic071c542016-01-27 14:57:51 +01004382 free((*unres)->line);
Michal Vasko88c29542015-11-27 14:57:53 +01004383#endif
Radek Krejcic071c542016-01-27 14:57:51 +01004384 free((*unres));
4385 (*unres) = NULL;
4386 }
Michal Vasko88c29542015-11-27 14:57:53 +01004387}
4388
Michal Vasko8bcdf292015-08-19 14:04:43 +02004389/* logs directly */
4390static void
Michal Vaskocf024702015-10-08 15:01:42 +02004391print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004392{
4393 struct lys_node_leaf *sleaf;
4394 char line_str[18];
4395
4396 if (line) {
4397 sprintf(line_str, " (line %u)", line);
4398 } else {
4399 line_str[0] = '\0';
4400 }
4401
Michal Vaskocf024702015-10-08 15:01:42 +02004402 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004403
Michal Vaskocf024702015-10-08 15:01:42 +02004404 switch (type) {
4405 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004406 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
4407 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004408 break;
4409 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004410 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02004411 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004412 break;
4413 case UNRES_WHEN:
4414 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
4415 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02004416 case UNRES_MUST:
4417 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
4418 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004419 default:
4420 LOGINT;
4421 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004422 }
4423}
4424
4425/**
4426 * @brief Resolve a single unres data item. Logs directly.
4427 *
Michal Vaskocf024702015-10-08 15:01:42 +02004428 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02004429 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02004430 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02004431 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004432 *
4433 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4434 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004435int
Michal Vaskocf024702015-10-08 15:01:42 +02004436resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004437{
4438 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004439 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004440 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004441 struct lys_node_leaf *sleaf;
4442 struct unres_data matches;
4443
4444 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004445 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004446 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004447
Michal Vaskocf024702015-10-08 15:01:42 +02004448 switch (type) {
4449 case UNRES_LEAFREF:
4450 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02004451 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004452 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004453 }
4454
4455 /* check that value matches */
4456 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004457 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004458 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004459 break;
4460 }
4461 }
4462
Michal Vaskocf024702015-10-08 15:01:42 +02004463 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004464 memset(&matches, 0, sizeof matches);
4465
Michal Vaskocf024702015-10-08 15:01:42 +02004466 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004467 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02004468 if (!first) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01004469 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
4470 LOGVAL(LYE_SPEC, 0, 0, NULL, "Leafref value \"%s\" did not match any node value.", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004471 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004472 return EXIT_FAILURE;
4473 }
Michal Vaskocf024702015-10-08 15:01:42 +02004474 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004475
Michal Vaskocf024702015-10-08 15:01:42 +02004476 case UNRES_INSTID:
4477 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004478 ly_errno = 0;
Radek Krejci40f17b92016-02-03 14:30:43 +01004479 leaf->value.instance = resolve_instid(node, leaf->value_str, line);
4480 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004481 if (ly_errno) {
4482 return -1;
4483 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004484 if (!first) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01004485 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004486 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004487 return EXIT_FAILURE;
4488 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004489 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004490 }
4491 }
Michal Vaskocf024702015-10-08 15:01:42 +02004492 break;
4493
4494 case UNRES_WHEN:
4495 if ((rc = resolve_when(node, first, line))) {
4496 return rc;
4497 }
4498 break;
4499
Michal Vaskobf19d252015-10-08 15:39:17 +02004500 case UNRES_MUST:
4501 if ((rc = resolve_must(node, first, line))) {
4502 return rc;
4503 }
4504 break;
4505
Michal Vaskocf024702015-10-08 15:01:42 +02004506 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004507 LOGINT;
4508 return -1;
4509 }
4510
4511 return EXIT_SUCCESS;
4512}
4513
4514/**
4515 * @brief Try to resolve an unres data item. Logs indirectly.
4516 *
4517 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004518 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004519 * @param[in] line Line in the input file.
4520 *
4521 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4522 */
4523int
Michal Vaskocf024702015-10-08 15:01:42 +02004524unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004525{
4526 int rc;
4527
Michal Vaskobf19d252015-10-08 15:39:17 +02004528 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004529
Michal Vaskocf024702015-10-08 15:01:42 +02004530 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004531 if (rc != EXIT_FAILURE) {
4532 return rc;
4533 }
4534
Michal Vaskocf024702015-10-08 15:01:42 +02004535 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004536
4537 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004538 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4539 if (!unres->node) {
4540 LOGMEM;
4541 return -1;
4542 }
Michal Vaskocf024702015-10-08 15:01:42 +02004543 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004544 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4545 if (!unres->type) {
4546 LOGMEM;
4547 return -1;
4548 }
Michal Vaskocf024702015-10-08 15:01:42 +02004549 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004550#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004551 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4552 if (!unres->line) {
4553 LOGMEM;
4554 return -1;
4555 }
Michal Vaskocf024702015-10-08 15:01:42 +02004556 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004557#endif
4558
4559 return EXIT_SUCCESS;
4560}
4561
4562/**
4563 * @brief Resolve every unres data item in the structure. Logs directly.
4564 *
4565 * @param[in] unres Unres data structure to use.
4566 *
4567 * @return EXIT_SUCCESS on success, -1 on error.
4568 */
4569int
4570resolve_unres_data(struct unres_data *unres)
4571{
4572 uint32_t i;
4573 int rc;
4574
4575 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004576 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004577 if (rc) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004578 return -1;
4579 }
4580 }
4581
4582 return EXIT_SUCCESS;
4583}