blob: b2d0f240892e15e81b3f34d71f2260d996ed1c9a [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022#define _GNU_SOURCE
23
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020028#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020029
30#include "libyang.h"
31#include "resolve.h"
32#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020033#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020034#include "parser.h"
Michal Vasko88c29542015-11-27 14:57:53 +010035#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020036#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020037#include "tree_internal.h"
38
Michal Vasko730dfdf2015-08-11 14:48:05 +020039/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020040 * @brief Parse an identifier.
41 *
42 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
43 * identifier = (ALPHA / "_")
44 * *(ALPHA / DIGIT / "_" / "-" / ".")
45 *
Michal Vaskobb211122015-08-19 14:03:11 +020046 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020047 *
48 * @return Number of characters successfully parsed.
49 */
Michal Vasko249e6b52015-08-19 11:08:52 +020050int
Radek Krejci6dc53a22015-08-17 13:27:59 +020051parse_identifier(const char *id)
52{
53 int parsed = 0;
54
55 if (((id[0] == 'x') || (id[0] == 'X'))
56 && ((id[1] == 'm') || (id[0] == 'M'))
57 && ((id[2] == 'l') || (id[2] == 'L'))) {
58 return -parsed;
59 }
60
61 if (!isalpha(id[0]) && (id[0] != '_')) {
62 return -parsed;
63 }
64
65 ++parsed;
66 ++id;
67
68 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
69 ++parsed;
70 ++id;
71 }
72
73 return parsed;
74}
75
76/**
77 * @brief Parse a node-identifier.
78 *
Michal Vasko723e50c2015-10-20 15:20:29 +020079 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020080 *
Michal Vaskobb211122015-08-19 14:03:11 +020081 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020082 * @param[out] mod_name Points to the module name, NULL if there is not any.
83 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020084 * @param[out] name Points to the node name.
85 * @param[out] nam_len Length of the node name.
86 *
87 * @return Number of characters successfully parsed,
88 * positive on success, negative on failure.
89 */
90static int
Michal Vasko723e50c2015-10-20 15:20:29 +020091parse_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 +020092{
93 int parsed = 0, ret;
94
95 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020096 if (mod_name) {
97 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020098 }
Michal Vasko723e50c2015-10-20 15:20:29 +020099 if (mod_name_len) {
100 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200101 }
102 if (name) {
103 *name = NULL;
104 }
105 if (nam_len) {
106 *nam_len = 0;
107 }
108
109 if ((ret = parse_identifier(id)) < 1) {
110 return ret;
111 }
112
Michal Vasko723e50c2015-10-20 15:20:29 +0200113 if (mod_name) {
114 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200115 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200116 if (mod_name_len) {
117 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200118 }
119
120 parsed += ret;
121 id += ret;
122
123 /* there is prefix */
124 if (id[0] == ':') {
125 ++parsed;
126 ++id;
127
128 /* there isn't */
129 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200130 if (name && mod_name) {
131 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200132 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (mod_name) {
134 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
136
Michal Vasko723e50c2015-10-20 15:20:29 +0200137 if (nam_len && mod_name_len) {
138 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200139 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200140 if (mod_name_len) {
141 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200142 }
143
144 return parsed;
145 }
146
147 /* identifier (node name) */
148 if ((ret = parse_identifier(id)) < 1) {
149 return -parsed+ret;
150 }
151
152 if (name) {
153 *name = id;
154 }
155 if (nam_len) {
156 *nam_len = ret;
157 }
158
159 return parsed+ret;
160}
161
162/**
163 * @brief Parse a path-predicate (leafref).
164 *
165 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
166 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
167 *
Michal Vaskobb211122015-08-19 14:03:11 +0200168 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 * @param[out] prefix Points to the prefix, NULL if there is not any.
170 * @param[out] pref_len Length of the prefix, 0 if there is not any.
171 * @param[out] name Points to the node name.
172 * @param[out] nam_len Length of the node name.
173 * @param[out] path_key_expr Points to the path-key-expr.
174 * @param[out] pke_len Length of the path-key-expr.
175 * @param[out] has_predicate Flag to mark whether there is another predicate following.
176 *
177 * @return Number of characters successfully parsed,
178 * positive on success, negative on failure.
179 */
180static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200181parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
182 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200183{
184 const char *ptr;
185 int parsed = 0, ret;
186
187 assert(id);
188 if (prefix) {
189 *prefix = NULL;
190 }
191 if (pref_len) {
192 *pref_len = 0;
193 }
194 if (name) {
195 *name = NULL;
196 }
197 if (nam_len) {
198 *nam_len = 0;
199 }
200 if (path_key_expr) {
201 *path_key_expr = NULL;
202 }
203 if (pke_len) {
204 *pke_len = 0;
205 }
206 if (has_predicate) {
207 *has_predicate = 0;
208 }
209
210 if (id[0] != '[') {
211 return -parsed;
212 }
213
214 ++parsed;
215 ++id;
216
217 while (isspace(id[0])) {
218 ++parsed;
219 ++id;
220 }
221
222 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
223 return -parsed+ret;
224 }
225
226 parsed += ret;
227 id += ret;
228
229 while (isspace(id[0])) {
230 ++parsed;
231 ++id;
232 }
233
234 if (id[0] != '=') {
235 return -parsed;
236 }
237
238 ++parsed;
239 ++id;
240
241 while (isspace(id[0])) {
242 ++parsed;
243 ++id;
244 }
245
246 if ((ptr = strchr(id, ']')) == NULL) {
247 return -parsed;
248 }
249
250 --ptr;
251 while (isspace(ptr[0])) {
252 --ptr;
253 }
254 ++ptr;
255
256 ret = ptr-id;
257 if (path_key_expr) {
258 *path_key_expr = id;
259 }
260 if (pke_len) {
261 *pke_len = ret;
262 }
263
264 parsed += ret;
265 id += ret;
266
267 while (isspace(id[0])) {
268 ++parsed;
269 ++id;
270 }
271
272 assert(id[0] == ']');
273
274 if (id[1] == '[') {
275 *has_predicate = 1;
276 }
277
278 return parsed+1;
279}
280
281/**
282 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
283 * the ".." and the first node-identifier, other calls parse a single
284 * node-identifier each.
285 *
286 * path-key-expr = current-function-invocation *WSP "/" *WSP
287 * rel-path-keyexpr
288 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
289 * *(node-identifier *WSP "/" *WSP)
290 * node-identifier
291 *
Michal Vaskobb211122015-08-19 14:03:11 +0200292 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200293 * @param[out] prefix Points to the prefix, NULL if there is not any.
294 * @param[out] pref_len Length of the prefix, 0 if there is not any.
295 * @param[out] name Points to the node name.
296 * @param[out] nam_len Length of the node name.
297 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
298 * must not be changed between consecutive calls.
299 * @return Number of characters successfully parsed,
300 * positive on success, negative on failure.
301 */
302static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200303parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
304 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200305{
306 int parsed = 0, ret, par_times = 0;
307
308 assert(id);
309 assert(parent_times);
310 if (prefix) {
311 *prefix = NULL;
312 }
313 if (pref_len) {
314 *pref_len = 0;
315 }
316 if (name) {
317 *name = NULL;
318 }
319 if (nam_len) {
320 *nam_len = 0;
321 }
322
323 if (!*parent_times) {
324 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
325 if (strncmp(id, "current()", 9)) {
326 return -parsed;
327 }
328
329 parsed += 9;
330 id += 9;
331
332 while (isspace(id[0])) {
333 ++parsed;
334 ++id;
335 }
336
337 if (id[0] != '/') {
338 return -parsed;
339 }
340
341 ++parsed;
342 ++id;
343
344 while (isspace(id[0])) {
345 ++parsed;
346 ++id;
347 }
348
349 /* rel-path-keyexpr */
350 if (strncmp(id, "..", 2)) {
351 return -parsed;
352 }
353 ++par_times;
354
355 parsed += 2;
356 id += 2;
357
358 while (isspace(id[0])) {
359 ++parsed;
360 ++id;
361 }
362 }
363
364 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
365 *
366 * first parent reference with whitespaces already parsed
367 */
368 if (id[0] != '/') {
369 return -parsed;
370 }
371
372 ++parsed;
373 ++id;
374
375 while (isspace(id[0])) {
376 ++parsed;
377 ++id;
378 }
379
380 while (!strncmp(id, "..", 2) && !*parent_times) {
381 ++par_times;
382
383 parsed += 2;
384 id += 2;
385
386 while (isspace(id[0])) {
387 ++parsed;
388 ++id;
389 }
390
391 if (id[0] != '/') {
392 return -parsed;
393 }
394
395 ++parsed;
396 ++id;
397
398 while (isspace(id[0])) {
399 ++parsed;
400 ++id;
401 }
402 }
403
404 if (!*parent_times) {
405 *parent_times = par_times;
406 }
407
408 /* all parent references must be parsed at this point */
409 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
410 return -parsed+ret;
411 }
412
413 parsed += ret;
414 id += ret;
415
416 return parsed;
417}
418
419/**
420 * @brief Parse path-arg (leafref).
421 *
422 * path-arg = absolute-path / relative-path
423 * absolute-path = 1*("/" (node-identifier *path-predicate))
424 * relative-path = 1*(".." "/") descendant-path
425 *
Michal Vaskobb211122015-08-19 14:03:11 +0200426 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200427 * @param[out] prefix Points to the prefix, NULL if there is not any.
428 * @param[out] pref_len Length of the prefix, 0 if there is not any.
429 * @param[out] name Points to the node name.
430 * @param[out] nam_len Length of the node name.
431 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
432 * must not be changed between consecutive calls. -1 if the
433 * path is relative.
434 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
435 *
436 * @return Number of characters successfully parsed,
437 * positive on success, negative on failure.
438 */
439static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200440parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
441 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200442{
443 int parsed = 0, ret, par_times = 0;
444
445 assert(id);
446 assert(parent_times);
447 if (prefix) {
448 *prefix = NULL;
449 }
450 if (pref_len) {
451 *pref_len = 0;
452 }
453 if (name) {
454 *name = NULL;
455 }
456 if (nam_len) {
457 *nam_len = 0;
458 }
459 if (has_predicate) {
460 *has_predicate = 0;
461 }
462
463 if (!*parent_times && !strncmp(id, "..", 2)) {
464 ++par_times;
465
466 parsed += 2;
467 id += 2;
468
469 while (!strncmp(id, "/..", 3)) {
470 ++par_times;
471
472 parsed += 3;
473 id += 3;
474 }
475 }
476
477 if (!*parent_times) {
478 if (par_times) {
479 *parent_times = par_times;
480 } else {
481 *parent_times = -1;
482 }
483 }
484
485 if (id[0] != '/') {
486 return -parsed;
487 }
488
489 /* skip '/' */
490 ++parsed;
491 ++id;
492
493 /* node-identifier ([prefix:]identifier) */
494 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
495 return -parsed-ret;
496 }
497
498 parsed += ret;
499 id += ret;
500
501 /* there is no predicate */
502 if ((id[0] == '/') || !id[0]) {
503 return parsed;
504 } else if (id[0] != '[') {
505 return -parsed;
506 }
507
508 if (has_predicate) {
509 *has_predicate = 1;
510 }
511
512 return parsed;
513}
514
515/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200516 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200517 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200518 *
519 * instance-identifier = 1*("/" (node-identifier *predicate))
520 *
Michal Vaskobb211122015-08-19 14:03:11 +0200521 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200522 * @param[out] model Points to the model name.
523 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200524 * @param[out] name Points to the node name.
525 * @param[out] nam_len Length of the node name.
526 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
527 *
528 * @return Number of characters successfully parsed,
529 * positive on success, negative on failure.
530 */
531static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200532parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
533 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200534{
535 int parsed = 0, ret;
536
537 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200538 if (model) {
539 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200540 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200541 if (mod_len) {
542 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200543 }
544 if (name) {
545 *name = NULL;
546 }
547 if (nam_len) {
548 *nam_len = 0;
549 }
550 if (has_predicate) {
551 *has_predicate = 0;
552 }
553
554 if (id[0] != '/') {
555 return -parsed;
556 }
557
558 ++parsed;
559 ++id;
560
Michal Vasko1f2cc332015-08-19 11:18:32 +0200561 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200562 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200563 } else if (model && !*model) {
564 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200565 }
566
567 parsed += ret;
568 id += ret;
569
570 if ((id[0] == '[') && has_predicate) {
571 *has_predicate = 1;
572 }
573
574 return parsed;
575}
576
577/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200578 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200579 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200580 *
581 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
582 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
583 * ((DQUOTE string DQUOTE) /
584 * (SQUOTE string SQUOTE))
585 * pos = non-negative-integer-value
586 *
Michal Vaskobb211122015-08-19 14:03:11 +0200587 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200588 * @param[out] model Points to the model name.
589 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200590 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
591 * @param[out] nam_len Length of the node name.
592 * @param[out] value Value the node-identifier must have (string from the grammar),
593 * NULL if there is not any.
594 * @param[out] val_len Length of the value, 0 if there is not any.
595 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
596 *
597 * @return Number of characters successfully parsed,
598 * positive on success, negative on failure.
599 */
600static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200601parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
602 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200603{
604 const char *ptr;
605 int parsed = 0, ret;
606 char quote;
607
608 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200609 if (model) {
610 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200612 if (mod_len) {
613 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 }
615 if (name) {
616 *name = NULL;
617 }
618 if (nam_len) {
619 *nam_len = 0;
620 }
621 if (value) {
622 *value = NULL;
623 }
624 if (val_len) {
625 *val_len = 0;
626 }
627 if (has_predicate) {
628 *has_predicate = 0;
629 }
630
631 if (id[0] != '[') {
632 return -parsed;
633 }
634
635 ++parsed;
636 ++id;
637
638 while (isspace(id[0])) {
639 ++parsed;
640 ++id;
641 }
642
643 /* pos */
644 if (isdigit(id[0])) {
645 if (name) {
646 *name = id;
647 }
648
649 if (id[0] == '0') {
650 ++parsed;
651 ++id;
652
653 if (isdigit(id[0])) {
654 return -parsed;
655 }
656 }
657
658 while (isdigit(id[0])) {
659 ++parsed;
660 ++id;
661 }
662
663 if (nam_len) {
664 *nam_len = id-(*name);
665 }
666
667 /* "." */
668 } else if (id[0] == '.') {
669 if (name) {
670 *name = id;
671 }
672 if (nam_len) {
673 *nam_len = 1;
674 }
675
676 ++parsed;
677 ++id;
678
679 /* node-identifier */
680 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200681 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200682 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200683 } else if (model && !*model) {
684 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200685 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200686
687 parsed += ret;
688 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200689 }
690
691 while (isspace(id[0])) {
692 ++parsed;
693 ++id;
694 }
695
696 if (id[0] != '=') {
697 return -parsed;
698 }
699
700 ++parsed;
701 ++id;
702
703 while (isspace(id[0])) {
704 ++parsed;
705 ++id;
706 }
707
708 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
709 if ((id[0] == '\"') || (id[0] == '\'')) {
710 quote = id[0];
711
712 ++parsed;
713 ++id;
714
715 if ((ptr = strchr(id, quote)) == NULL) {
716 return -parsed;
717 }
718 ret = ptr-id;
719
720 if (value) {
721 *value = id;
722 }
723 if (val_len) {
724 *val_len = ret;
725 }
726
727 parsed += ret+1;
728 id += ret+1;
729 } else {
730 return -parsed;
731 }
732
733 while (isspace(id[0])) {
734 ++parsed;
735 ++id;
736 }
737
738 if (id[0] != ']') {
739 return -parsed;
740 }
741
742 ++parsed;
743 ++id;
744
745 if ((id[0] == '[') && has_predicate) {
746 *has_predicate = 1;
747 }
748
749 return parsed;
750}
751
752/**
753 * @brief Parse schema-nodeid.
754 *
755 * schema-nodeid = absolute-schema-nodeid /
756 * descendant-schema-nodeid
757 * absolute-schema-nodeid = 1*("/" node-identifier)
758 * descendant-schema-nodeid =
759 * node-identifier
760 * absolute-schema-nodeid
761 *
Michal Vaskobb211122015-08-19 14:03:11 +0200762 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200763 * @param[out] mod_name Points to the module name, NULL if there is not any.
764 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
766 * @param[out] nam_len Length of the node name.
767 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
768 * on the first call, must not be changed between consecutive calls.
769 *
770 * @return Number of characters successfully parsed,
771 * positive on success, negative on failure.
772 */
773static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200774parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200775 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200776{
777 int parsed = 0, ret;
778
779 assert(id);
780 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200781 if (mod_name) {
782 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200783 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200784 if (mod_name_len) {
785 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200786 }
787 if (name) {
788 *name = NULL;
789 }
790 if (nam_len) {
791 *nam_len = 0;
792 }
793
794 if (id[0] != '/') {
795 if (*is_relative != -1) {
796 return -parsed;
797 } else {
798 *is_relative = 1;
799 }
800 } else {
801 if (*is_relative == -1) {
802 *is_relative = 0;
803 }
804 ++parsed;
805 ++id;
806 }
807
Michal Vasko723e50c2015-10-20 15:20:29 +0200808 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 return -parsed+ret;
810 }
811
812 return parsed+ret;
813}
814
815/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200816 * @brief Resolves length or range intervals. Does not log.
817 * Syntax is assumed to be correct, *local_intv MUST be NULL.
818 *
819 * @param[in] str_restr The restriction as a string.
820 * @param[in] type The type of the restriction.
821 * @param[in] superior_restr Flag whether to check superior
822 * types.
823 * @param[out] local_intv The final interval structure.
824 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200825 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200826 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200827int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200828resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
829 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200830{
831 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200832 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200833 int64_t local_smin, local_smax;
834 uint64_t local_umin, local_umax;
835 long double local_fmin, local_fmax;
836 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200837 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200838
839 switch (type->base) {
840 case LY_TYPE_BINARY:
841 kind = 0;
842 local_umin = 0;
843 local_umax = 18446744073709551615UL;
844
845 if (!str_restr && type->info.binary.length) {
846 str_restr = type->info.binary.length->expr;
847 }
848 break;
849 case LY_TYPE_DEC64:
850 kind = 2;
851 local_fmin = -9223372036854775808.0;
852 local_fmin /= 1 << type->info.dec64.dig;
853 local_fmax = 9223372036854775807.0;
854 local_fmax /= 1 << type->info.dec64.dig;
855
856 if (!str_restr && type->info.dec64.range) {
857 str_restr = type->info.dec64.range->expr;
858 }
859 break;
860 case LY_TYPE_INT8:
861 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100862 local_smin = __INT64_C(-128);
863 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200864
865 if (!str_restr && type->info.num.range) {
866 str_restr = type->info.num.range->expr;
867 }
868 break;
869 case LY_TYPE_INT16:
870 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100871 local_smin = __INT64_C(-32768);
872 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200873
874 if (!str_restr && type->info.num.range) {
875 str_restr = type->info.num.range->expr;
876 }
877 break;
878 case LY_TYPE_INT32:
879 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100880 local_smin = __INT64_C(-2147483648);
881 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200882
883 if (!str_restr && type->info.num.range) {
884 str_restr = type->info.num.range->expr;
885 }
886 break;
887 case LY_TYPE_INT64:
888 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +0100889 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
890 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200891
892 if (!str_restr && type->info.num.range) {
893 str_restr = type->info.num.range->expr;
894 }
895 break;
896 case LY_TYPE_UINT8:
897 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100898 local_umin = __UINT64_C(0);
899 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200900
901 if (!str_restr && type->info.num.range) {
902 str_restr = type->info.num.range->expr;
903 }
904 break;
905 case LY_TYPE_UINT16:
906 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100907 local_umin = __UINT64_C(0);
908 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200909
910 if (!str_restr && type->info.num.range) {
911 str_restr = type->info.num.range->expr;
912 }
913 break;
914 case LY_TYPE_UINT32:
915 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100916 local_umin = __UINT64_C(0);
917 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200918
919 if (!str_restr && type->info.num.range) {
920 str_restr = type->info.num.range->expr;
921 }
922 break;
923 case LY_TYPE_UINT64:
924 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100925 local_umin = __UINT64_C(0);
926 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200927
928 if (!str_restr && type->info.num.range) {
929 str_restr = type->info.num.range->expr;
930 }
931 break;
932 case LY_TYPE_STRING:
933 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +0100934 local_umin = __UINT64_C(0);
935 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200936
937 if (!str_restr && type->info.str.length) {
938 str_restr = type->info.str.length->expr;
939 }
940 break;
941 default:
942 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200943 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200944 }
945
946 /* process superior types */
947 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200948 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
949 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200950 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200951 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200952 assert(!intv || (intv->kind == kind));
953 }
954
955 if (!str_restr) {
956 /* we are validating data and not have any restriction, but a superior type might have */
957 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200958 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
959 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200960 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200961 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200962 assert(!intv || (intv->kind == kind));
963 }
964 *local_intv = intv;
965 return EXIT_SUCCESS;
966 }
967
968 /* adjust local min and max */
969 if (intv) {
970 tmp_intv = intv;
971
972 if (kind == 0) {
973 local_umin = tmp_intv->value.uval.min;
974 } else if (kind == 1) {
975 local_smin = tmp_intv->value.sval.min;
976 } else if (kind == 2) {
977 local_fmin = tmp_intv->value.fval.min;
978 }
979
980 while (tmp_intv->next) {
981 tmp_intv = tmp_intv->next;
982 }
983
984 if (kind == 0) {
985 local_umax = tmp_intv->value.uval.max;
986 } else if (kind == 1) {
987 local_smax = tmp_intv->value.sval.max;
988 } else if (kind == 2) {
989 local_fmax = tmp_intv->value.fval.max;
990 }
991 }
992
993 /* finally parse our restriction */
994 seg_ptr = str_restr;
995 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +0200996 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200997 *local_intv = malloc(sizeof **local_intv);
998 tmp_local_intv = *local_intv;
999 } else {
1000 tmp_local_intv->next = malloc(sizeof **local_intv);
1001 tmp_local_intv = tmp_local_intv->next;
1002 }
Michal Vasko253035f2015-12-17 16:58:13 +01001003 if (!tmp_local_intv) {
1004 LOGMEM;
1005 return -1;
1006 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001007
1008 tmp_local_intv->kind = kind;
1009 tmp_local_intv->next = NULL;
1010
1011 /* min */
1012 ptr = seg_ptr;
1013 while (isspace(ptr[0])) {
1014 ++ptr;
1015 }
1016 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1017 if (kind == 0) {
1018 tmp_local_intv->value.uval.min = atoll(ptr);
1019 } else if (kind == 1) {
1020 tmp_local_intv->value.sval.min = atoll(ptr);
1021 } else if (kind == 2) {
1022 tmp_local_intv->value.fval.min = atoll(ptr);
1023 }
1024
1025 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1026 ++ptr;
1027 }
1028 while (isdigit(ptr[0])) {
1029 ++ptr;
1030 }
1031 } else if (!strncmp(ptr, "min", 3)) {
1032 if (kind == 0) {
1033 tmp_local_intv->value.uval.min = local_umin;
1034 } else if (kind == 1) {
1035 tmp_local_intv->value.sval.min = local_smin;
1036 } else if (kind == 2) {
1037 tmp_local_intv->value.fval.min = local_fmin;
1038 }
1039
1040 ptr += 3;
1041 } else if (!strncmp(ptr, "max", 3)) {
1042 if (kind == 0) {
1043 tmp_local_intv->value.uval.min = local_umax;
1044 } else if (kind == 1) {
1045 tmp_local_intv->value.sval.min = local_smax;
1046 } else if (kind == 2) {
1047 tmp_local_intv->value.fval.min = local_fmax;
1048 }
1049
1050 ptr += 3;
1051 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001052 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001053 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001054 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001055 }
1056
1057 while (isspace(ptr[0])) {
1058 ptr++;
1059 }
1060
1061 /* no interval or interval */
1062 if ((ptr[0] == '|') || !ptr[0]) {
1063 if (kind == 0) {
1064 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1065 } else if (kind == 1) {
1066 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1067 } else if (kind == 2) {
1068 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1069 }
1070 } else if (!strncmp(ptr, "..", 2)) {
1071 /* skip ".." */
1072 ptr += 2;
1073 while (isspace(ptr[0])) {
1074 ++ptr;
1075 }
1076
1077 /* max */
1078 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1079 if (kind == 0) {
1080 tmp_local_intv->value.uval.max = atoll(ptr);
1081 } else if (kind == 1) {
1082 tmp_local_intv->value.sval.max = atoll(ptr);
1083 } else if (kind == 2) {
1084 tmp_local_intv->value.fval.max = atoll(ptr);
1085 }
1086 } else if (!strncmp(ptr, "max", 3)) {
1087 if (kind == 0) {
1088 tmp_local_intv->value.uval.max = local_umax;
1089 } else if (kind == 1) {
1090 tmp_local_intv->value.sval.max = local_smax;
1091 } else if (kind == 2) {
1092 tmp_local_intv->value.fval.max = local_fmax;
1093 }
1094 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001095 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001096 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001097 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001098 }
1099 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001100 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001101 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001102 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001103 }
1104
1105 /* next segment (next OR) */
1106 seg_ptr = strchr(seg_ptr, '|');
1107 if (!seg_ptr) {
1108 break;
1109 }
1110 seg_ptr++;
1111 }
1112
1113 /* check local restrictions against superior ones */
1114 if (intv) {
1115 tmp_intv = intv;
1116 tmp_local_intv = *local_intv;
1117
1118 while (tmp_local_intv && tmp_intv) {
1119 /* reuse local variables */
1120 if (kind == 0) {
1121 local_umin = tmp_local_intv->value.uval.min;
1122 local_umax = tmp_local_intv->value.uval.max;
1123
1124 /* it must be in this interval */
1125 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1126 /* this interval is covered, next one */
1127 if (local_umax <= tmp_intv->value.uval.max) {
1128 tmp_local_intv = tmp_local_intv->next;
1129 continue;
1130 /* ascending order of restrictions -> fail */
1131 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001132 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001133 goto cleanup;
1134 }
1135 }
1136 } else if (kind == 1) {
1137 local_smin = tmp_local_intv->value.sval.min;
1138 local_smax = tmp_local_intv->value.sval.max;
1139
1140 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1141 if (local_smax <= tmp_intv->value.sval.max) {
1142 tmp_local_intv = tmp_local_intv->next;
1143 continue;
1144 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001145 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001146 goto cleanup;
1147 }
1148 }
1149 } else if (kind == 2) {
1150 local_fmin = tmp_local_intv->value.fval.min;
1151 local_fmax = tmp_local_intv->value.fval.max;
1152
1153 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1154 if (local_fmax <= tmp_intv->value.fval.max) {
1155 tmp_local_intv = tmp_local_intv->next;
1156 continue;
1157 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001158 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001159 goto cleanup;
1160 }
1161 }
1162 }
1163
1164 tmp_intv = tmp_intv->next;
1165 }
1166
1167 /* some interval left uncovered -> fail */
1168 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001169 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001170 }
1171
1172 }
1173
1174cleanup:
1175 while (intv) {
1176 tmp_intv = intv->next;
1177 free(intv);
1178 intv = tmp_intv;
1179 }
1180
1181 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001182 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001183 while (*local_intv) {
1184 tmp_local_intv = (*local_intv)->next;
1185 free(*local_intv);
1186 *local_intv = tmp_local_intv;
1187 }
1188 }
1189
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001190 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001191}
1192
Michal Vasko730dfdf2015-08-11 14:48:05 +02001193/**
Michal Vasko88c29542015-11-27 14:57:53 +01001194 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001195 *
1196 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001197 * @param[in] mod_name Typedef name module name.
1198 * @param[in] module Main module.
1199 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001200 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001201 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001202 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001203 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001204int
Michal Vasko1e62a092015-12-01 12:27:20 +01001205resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
1206 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001207{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001208 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001209 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001210 int tpdf_size;
1211
Michal Vasko1dca6882015-10-22 14:29:42 +02001212 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001213 /* no prefix, try built-in types */
1214 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1215 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001216 if (ret) {
1217 *ret = ly_types[i].def;
1218 }
1219 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001220 }
1221 }
1222 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001223 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001224 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001225 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001226 }
1227 }
1228
Michal Vasko1dca6882015-10-22 14:29:42 +02001229 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001230 /* search in local typedefs */
1231 while (parent) {
1232 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001233 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001234 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1235 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001236 break;
1237
Radek Krejci76512572015-08-04 09:47:08 +02001238 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001239 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1240 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001241 break;
1242
Radek Krejci76512572015-08-04 09:47:08 +02001243 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001244 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1245 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001246 break;
1247
Radek Krejci76512572015-08-04 09:47:08 +02001248 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001249 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1250 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001251 break;
1252
Radek Krejci76512572015-08-04 09:47:08 +02001253 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001254 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1255 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001256 break;
1257
Radek Krejci76512572015-08-04 09:47:08 +02001258 case LYS_INPUT:
1259 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001260 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1261 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001262 break;
1263
1264 default:
1265 parent = parent->parent;
1266 continue;
1267 }
1268
1269 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001270 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001271 if (ret) {
1272 *ret = &tpdf[i];
1273 }
1274 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001275 }
1276 }
1277
1278 parent = parent->parent;
1279 }
Radek Krejcic071c542016-01-27 14:57:51 +01001280 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001281 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001282 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001283 if (!module) {
1284 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001285 }
1286 }
1287
1288 /* search in top level typedefs */
1289 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001290 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001291 if (ret) {
1292 *ret = &module->tpdf[i];
1293 }
1294 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001295 }
1296 }
1297
1298 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01001299 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001300 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001301 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 +02001302 if (ret) {
1303 *ret = &module->inc[i].submodule->tpdf[j];
1304 }
1305 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001306 }
1307 }
1308 }
1309
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001310 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001311}
1312
Michal Vasko1dca6882015-10-22 14:29:42 +02001313/**
1314 * @brief Check the default \p value of the \p type. Logs directly.
1315 *
1316 * @param[in] type Type definition to use.
1317 * @param[in] value Default value to check.
1318 * @param[in] first Whether this is the first resolution try. Affects logging.
1319 * @param[in] line Line in the input file.
1320 *
1321 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1322 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001323static int
Michal Vasko1dca6882015-10-22 14:29:42 +02001324check_default(struct lys_type *type, const char *value, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001325{
Michal Vasko1dca6882015-10-22 14:29:42 +02001326 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01001327 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02001328
1329 /* dummy leaf */
1330 node.value_str = value;
1331 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01001332 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01001333 if (!node.schema) {
1334 LOGMEM;
1335 return -1;
1336 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001337 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01001338 if (!node.schema->name) {
1339 LOGMEM;
1340 return -1;
1341 }
Radek Krejci37b756f2016-01-18 10:15:03 +01001342 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02001343
Radek Krejci37b756f2016-01-18 10:15:03 +01001344 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02001345 if (!type->info.lref.target) {
1346 ret = EXIT_FAILURE;
1347 goto finish;
1348 }
1349 ret = check_default(&type->info.lref.target->type, value, first, line);
1350
1351 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1352 /* it was converted to JSON format before, nothing else sensible we can do */
1353
1354 } else {
Radek Krejci37b756f2016-01-18 10:15:03 +01001355 ret = lyp_parse_value(&node, NULL, 1, NULL, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001356 }
1357
1358finish:
1359 if (node.value_type == LY_TYPE_BITS) {
1360 free(node.value.bit);
1361 }
1362 free((char *)node.schema->name);
1363 free(node.schema);
1364
1365 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001366}
1367
Michal Vasko730dfdf2015-08-11 14:48:05 +02001368/**
1369 * @brief Check a key for mandatory attributes. Logs directly.
1370 *
1371 * @param[in] key The key to check.
1372 * @param[in] flags What flags to check.
1373 * @param[in] list The list of all the keys.
1374 * @param[in] index Index of the key in the key list.
1375 * @param[in] name The name of the keys.
1376 * @param[in] len The name length.
1377 * @param[in] line The line in the input file.
1378 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001379 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001380 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001381static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001382check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1383 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001384{
1385 char *dup = NULL;
1386 int j;
1387
1388 /* existence */
1389 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001390 if (name[len] != '\0') {
1391 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01001392 if (!dup) {
1393 LOGMEM;
1394 return -1;
1395 }
Michal Vaskof02e3742015-08-05 16:27:02 +02001396 dup[len] = '\0';
1397 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001398 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001399 LOGVAL(LYE_KEY_MISS, line, name);
1400 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001401 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001402 }
1403
1404 /* uniqueness */
1405 for (j = index - 1; j >= 0; j--) {
1406 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001407 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001408 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001409 }
1410 }
1411
1412 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001413 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001414 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001415 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001416 }
1417
1418 /* type of the leaf is not built-in empty */
1419 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001420 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001421 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001422 }
1423
1424 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001425 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001426 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001427 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001428 }
1429
1430 return EXIT_SUCCESS;
1431}
1432
Michal Vasko730dfdf2015-08-11 14:48:05 +02001433/**
Radek Krejci581ce772015-11-10 17:22:40 +01001434 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001435 *
1436 * @param[in] parent The parent node of the unique structure.
1437 * @param[in] uniq_str The value of the unique node.
Michal Vasko184521f2015-09-24 13:14:26 +02001438 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001439 * @param[in] line The line in the input file.
1440 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001441 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001442 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001443int
Radek Krejci581ce772015-11-10 17:22:40 +01001444resolve_unique(struct lys_node *parent, const char *uniq_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001445{
Radek Krejci581ce772015-11-10 17:22:40 +01001446 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01001447 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001448
Radek Krejci581ce772015-11-10 17:22:40 +01001449 rc = resolve_schema_nodeid(uniq_str, parent->child, parent->module, LYS_LEAF, &leaf);
1450 if (rc) {
1451 if ((rc == -1) || !first) {
1452 LOGVAL(LYE_INARG, line, uniq_str, "unique");
1453 if (rc == EXIT_FAILURE) {
1454 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
1455 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001456 }
Radek Krejci581ce772015-11-10 17:22:40 +01001457 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001458 }
Radek Krejci581ce772015-11-10 17:22:40 +01001459 if (!leaf || leaf->nodetype != LYS_LEAF) {
1460 LOGVAL(LYE_INARG, line, uniq_str, "unique");
1461 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1462 rc = -1;
1463 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001464 }
1465
Radek Krejcicf509982015-12-15 09:22:44 +01001466 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01001467 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, line)) {
Radek Krejcicf509982015-12-15 09:22:44 +01001468 return -1;
1469 }
1470
Radek Krejcica7efb72016-01-18 13:06:01 +01001471 /* set leaf's unique flag */
1472 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
1473
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001474 return EXIT_SUCCESS;
1475
1476error:
1477
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001478 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001479}
1480
Michal Vasko730dfdf2015-08-11 14:48:05 +02001481/**
1482 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1483 *
Michal Vaskobb211122015-08-19 14:03:11 +02001484 * @param[in] uses The uses to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001485 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001486 * @param[in] line The line in the input file.
1487 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001488 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001489 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001490static int
Michal Vasko184521f2015-09-24 13:14:26 +02001491resolve_grouping(struct lys_node_uses *uses, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001492{
Michal Vasko1e62a092015-12-01 12:27:20 +01001493 const struct lys_module *module;
Radek Krejci2d5692b2015-10-31 23:12:16 +01001494 const char *mod_prefix, *name;
1495 int i, mod_prefix_len, nam_len;
Radek Krejci10c760e2015-08-14 14:45:43 +02001496 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001497
Michal Vasko58090902015-08-13 14:04:15 +02001498 /* parse the identifier, it must be parsed on one call */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001499 if ((i = parse_node_identifier(uses->name, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02001500 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001501 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001502 } else if (uses->name[i]) {
1503 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001504 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001505 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001506
Radek Krejcic071c542016-01-27 14:57:51 +01001507 module = lys_get_import_module(uses->module, mod_prefix, mod_prefix_len, NULL, 0);
1508 if (!module) {
1509 LOGVAL(LYE_INMOD_LEN, line, mod_prefix_len, mod_prefix);
1510 return -1;
1511 } else if (module != uses->module) {
Michal Vasko2bdcca92015-08-17 16:00:45 +02001512 start = module->data;
1513 } else {
Michal Vasko563ef092015-09-04 13:17:23 +02001514 start = (struct lys_node *)uses;
Michal Vasko2bdcca92015-08-17 16:00:45 +02001515 }
1516
Radek Krejcic071c542016-01-27 14:57:51 +01001517 uses->grp = lys_find_grouping_up(name, start);
Michal Vasko563ef092015-09-04 13:17:23 +02001518 if (uses->grp) {
1519 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001520 }
1521
Radek Krejci2d5692b2015-10-31 23:12:16 +01001522 if (mod_prefix || !first) {
Michal Vasko184521f2015-09-24 13:14:26 +02001523 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
1524 }
Michal Vasko563ef092015-09-04 13:17:23 +02001525 /* import must now be fully resolved */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001526 if (mod_prefix) {
Michal Vasko563ef092015-09-04 13:17:23 +02001527 return -1;
1528 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001529 return EXIT_FAILURE;
1530}
1531
Michal Vasko730dfdf2015-08-11 14:48:05 +02001532/**
1533 * @brief Resolve (find) a feature definition. Logs directly.
1534 *
1535 * @param[in] name Feature name.
1536 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001537 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001538 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001539 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001540 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001541 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001542 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001543static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001544resolve_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 +02001545{
Michal Vasko2d851a92015-10-20 16:16:36 +02001546 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001547 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01001548 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001549
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001550 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001551 assert(module);
1552
1553 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001554 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001555 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1556 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001557 }
1558
Radek Krejcic071c542016-01-27 14:57:51 +01001559 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1560 if (!module) {
1561 /* identity refers unknown data model */
1562 LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
1563 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001564 }
1565
Radek Krejcic071c542016-01-27 14:57:51 +01001566 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001567 for (j = 0; j < module->features_size; j++) {
1568 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001569 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01001570 /* check status */
1571 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001572 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejcicf509982015-12-15 09:22:44 +01001573 module->features[j].module, module->features[j].name, line)) {
1574 return -1;
1575 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001576 *ret = &module->features[j];
1577 }
1578 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001579 }
1580 }
Radek Krejcic071c542016-01-27 14:57:51 +01001581 /* ... and all its submodules */
1582 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
1583 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1584 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1585 if (ret) {
1586 /* check status */
1587 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001588 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01001589 module->inc[i].submodule->features[j].flags,
1590 module->inc[i].submodule->features[j].module,
1591 module->inc[i].submodule->features[j].name, line)) {
1592 return -1;
1593 }
1594 *ret = &(module->inc[i].submodule->features[j]);
1595 }
1596 return EXIT_SUCCESS;
1597 }
1598 }
1599 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001600
1601 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001602 if (!first) {
1603 LOGVAL(LYE_INRESOLV, line, "feature", id);
1604 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001605 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001606}
1607
Michal Vasko730dfdf2015-08-11 14:48:05 +02001608/**
Radek Krejci581ce772015-11-10 17:22:40 +01001609 * @brief Resolve (find) a data node based on a schema-nodeid.
1610 *
1611 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1612 * module).
1613 *
1614 */
1615struct lyd_node *
1616resolve_data_nodeid(const char *id, struct lyd_node *start)
1617{
1618 char *str, *token, *p;
1619 struct lyd_node *result = start, *iter;
Michal Vasko1e62a092015-12-01 12:27:20 +01001620 const struct lys_node *schema = NULL;
Radek Krejci581ce772015-11-10 17:22:40 +01001621
1622 assert(start);
1623 assert(id);
1624
1625 if (id[0] == '/') {
1626 return NULL;
1627 }
1628
1629 str = p = strdup(id);
Michal Vasko253035f2015-12-17 16:58:13 +01001630 if (!str) {
1631 LOGMEM;
1632 return NULL;
1633 }
Radek Krejci581ce772015-11-10 17:22:40 +01001634 while(p) {
1635 token = p;
1636 p = strchr(p, '/');
1637 if (p) {
1638 *p = '\0';
1639 p++;
1640 }
1641
1642 if (resolve_schema_nodeid(token, result->schema, result->schema->module, LYS_LEAF, &schema)) {
1643 free(str);
1644 return NULL;
1645 }
1646
1647 LY_TREE_FOR(result, iter) {
1648 if (iter->schema == schema) {
1649 break;
1650 }
1651 }
1652
1653 if (!p) {
1654 /* final result */
1655 result = iter;
1656 } else {
1657 result = iter->child;
1658 }
1659 }
1660 free(str);
1661
1662 return result;
1663}
1664
1665/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001666 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001667 *
Michal Vasko1be88302015-10-22 16:07:47 +02001668 * node_type - LYS_AUGMENT (searches also RPCs and notifications, augmented nodes are fine, too)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001669 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001670 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001671 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1672 *
Michal Vasko1be88302015-10-22 16:07:47 +02001673 * If \p id is absolute, \p start is ignored. If \p id is relative, \p start must be the first child to be searched
1674 * continuing with its siblings. Normally skips augments except \p node_type LYS_AUGMENT (augmenting an augment node).
Michal Vasko730dfdf2015-08-11 14:48:05 +02001675 *
Michal Vasko8afe75e2015-12-11 12:02:20 +01001676 * ASSUMPTION 1: Module to resolve prefixes (JSON module names) from never changes.
1677 * ASSUMPTION 2: Submodule belongs-to does not act as an import (main module definitions or anything else is not
1678 * available to the submodule).
1679 * ASSUMPTION 3: Module prefix (name) must be resolved only in absolute-schema-nodeid and only on the first
1680 * node. The prefix cannot further change except for nodes from an augment.
1681 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001682 * @param[in] id Schema-nodeid string.
1683 * @param[in] start Start of the relative search.
Michal Vaskobb211122015-08-19 14:03:11 +02001684 * @param[in] mod Module to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001685 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001686 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001687 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001688 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001689 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001690int
Michal Vasko1e62a092015-12-01 12:27:20 +01001691resolve_schema_nodeid(const char *id, const struct lys_node *start, const struct lys_module *mod, LYS_NODE node_type,
1692 const struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001693{
Radek Krejcic071c542016-01-27 14:57:51 +01001694 const char *name, *mod_name;
Michal Vasko1e62a092015-12-01 12:27:20 +01001695 const struct lys_node *sibling;
Michal Vasko1be88302015-10-22 16:07:47 +02001696 int i, opts, nam_len, mod_name_len, is_relative = -1;
Michal Vasko8afe75e2015-12-11 12:02:20 +01001697 /* resolved import module from the start module, it must match the next node-name-match sibling */
1698 const struct lys_module *prefix_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001699
1700 assert(mod);
1701 assert(id);
1702
Michal Vasko723e50c2015-10-20 15:20:29 +02001703 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001704 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001705 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001706 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001707
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001708 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001709 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001710 }
1711
Michal Vasko1be88302015-10-22 16:07:47 +02001712 /* set options for lys_getnext() */
1713 opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT;
1714 if (node_type == LYS_USES) {
1715 opts |= LYS_GETNEXT_WITHGROUPING;
1716 }
1717
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001718 /* absolute-schema-nodeid */
1719 if (!is_relative) {
Radek Krejcic071c542016-01-27 14:57:51 +01001720 prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
1721 if (!prefix_mod) {
1722 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001723 }
Radek Krejcic071c542016-01-27 14:57:51 +01001724 start = prefix_mod->data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001725 /* descendant-schema-nodeid */
Michal Vasko8afe75e2015-12-11 12:02:20 +01001726 } else if (!start) {
1727 /* start must be set in this case */
1728 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001729 }
1730
1731 while (1) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001732 for (sibling = start; sibling; sibling = lys_getnext(sibling, start->parent, NULL, opts)) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001733 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001734 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
Michal Vaskoa4b5d322015-10-09 12:12:37 +02001735 && (!(sibling->nodetype & (LYS_RPC | LYS_NOTIF)) || (node_type == LYS_AUGMENT))
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001736 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001737 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001738 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001739
Michal Vasko8afe75e2015-12-11 12:02:20 +01001740 /* get module for module name match check */
Radek Krejcic071c542016-01-27 14:57:51 +01001741 prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
1742 if (!prefix_mod && (node_type == LYS_AUGMENT)) {
1743 /* we want augment nodes in this case */
1744 prefix_mod = sibling->module;
1745 if (strncmp(prefix_mod->name, mod_name, mod_name_len) || prefix_mod->name[mod_name_len]) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001746 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001747 }
Radek Krejcic071c542016-01-27 14:57:51 +01001748 } else if (!prefix_mod) {
1749 return -1;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001750 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001751
Michal Vasko8afe75e2015-12-11 12:02:20 +01001752 /* modules need to always be checked, we want to skip augments (no other reason to check them) */
Radek Krejcic071c542016-01-27 14:57:51 +01001753 if ((!sibling->module->type && prefix_mod != sibling->module) ||
1754 (sibling->module->type && prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto)) {
1755 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001756 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001757
Michal Vasko1e989c02015-08-04 12:33:00 +02001758 /* the result node? */
1759 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001760 /* we're looking only for groupings, this is a data node */
1761 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001762 continue;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001763 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001764 if (ret) {
1765 *ret = sibling;
1766 }
1767 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001768 }
1769
Michal Vaskodcc7a802015-08-06 11:59:47 +02001770 /* we're looking for a grouping (node_type == LYS_USES),
1771 * but this isn't it, we cannot search inside
1772 */
1773 if (sibling->nodetype == LYS_GROUPING) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001774 continue;
Michal Vaskodcc7a802015-08-06 11:59:47 +02001775 }
1776
Michal Vasko1e989c02015-08-04 12:33:00 +02001777 /* check for shorthand cases - then 'start' does not change */
1778 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1779 || (sibling->nodetype == LYS_CASE)) {
1780 start = sibling->child;
1781 }
1782 break;
1783 }
1784 }
1785
1786 /* we did not find the case in direct siblings */
1787 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001788 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001789 }
1790
1791 /* no match */
1792 if (!sibling) {
Radek Krejcic071c542016-01-27 14:57:51 +01001793 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001794 }
1795
Michal Vasko723e50c2015-10-20 15:20:29 +02001796 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001797 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001798 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001799 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001800 }
1801
1802 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001803 LOGINT;
1804 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001805}
1806
Michal Vasko23b61ec2015-08-19 11:19:50 +02001807/* ignores line */
1808static void
1809unres_data_del(struct unres_data *unres, uint32_t i)
1810{
1811 /* there are items after the one deleted */
1812 if (i+1 < unres->count) {
1813 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001814 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001815
1816 /* deleting the last item */
1817 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001818 free(unres->node);
1819 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001820 }
1821
1822 /* if there are no items after and it is not the last one, just move the counter */
1823 --unres->count;
1824}
1825
Michal Vasko0491ab32015-08-19 14:28:29 +02001826/**
1827 * @brief Resolve (find) a data node from a specific module. Does not log.
1828 *
1829 * @param[in] mod Module to search in.
1830 * @param[in] name Name of the data node.
1831 * @param[in] nam_len Length of the name.
1832 * @param[in] start Data node to start the search from.
1833 * @param[in,out] parents Resolved nodes. If there are some parents,
1834 * they are replaced (!!) with the resolvents.
1835 *
1836 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
1837 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001838static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001839resolve_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 +02001840{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001842 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001843 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001844
Michal Vasko23b61ec2015-08-19 11:19:50 +02001845 if (!parents->count) {
1846 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001847 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01001848 if (!parents->node) {
1849 LOGMEM;
1850 return EXIT_FAILURE;
1851 }
Michal Vaskocf024702015-10-08 15:01:42 +02001852 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001853 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001854 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02001855 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001856 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001857 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001858 continue;
1859 }
1860 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02001861 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001862 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1863 && node->schema->name[nam_len] == '\0') {
1864 /* matching target */
1865 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02001866 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02001867 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001868 flag = 1;
1869 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02001870 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001871 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01001872 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
1873 if (!parents->node) {
1874 return EXIT_FAILURE;
1875 }
Michal Vaskocf024702015-10-08 15:01:42 +02001876 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001877 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001878 }
1879 }
1880 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001881
1882 if (!flag) {
1883 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001884 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02001885 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001886 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02001887 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001888 }
1889
Michal Vasko0491ab32015-08-19 14:28:29 +02001890 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02001891}
1892
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001893/**
1894 * @brief Resolve (find) a data node. Does not log.
1895 *
Radek Krejci581ce772015-11-10 17:22:40 +01001896 * @param[in] mod_name Module name of the data node.
1897 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001898 * @param[in] name Name of the data node.
1899 * @param[in] nam_len Length of the name.
1900 * @param[in] start Data node to start the search from.
1901 * @param[in,out] parents Resolved nodes. If there are some parents,
1902 * they are replaced (!!) with the resolvents.
1903 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001904 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001905 */
Radek Krejcic5090c32015-08-12 09:46:19 +02001906static int
Radek Krejci581ce772015-11-10 17:22:40 +01001907resolve_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 +02001908 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02001909{
Michal Vasko1e62a092015-12-01 12:27:20 +01001910 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02001911 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02001912
Michal Vasko23b61ec2015-08-19 11:19:50 +02001913 assert(start);
1914
Michal Vasko31fc3672015-10-21 12:08:13 +02001915 if (mod_name) {
1916 /* we have mod_name, find appropriate module */
1917 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01001918 if (!str) {
1919 LOGMEM;
1920 return -1;
1921 }
Michal Vasko31fc3672015-10-21 12:08:13 +02001922 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
1923 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02001924 if (!mod) {
1925 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001926 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001927 }
1928 } else {
1929 /* no prefix, module is the same as of current node */
1930 mod = start->schema->module;
1931 }
1932
1933 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001934}
1935
Michal Vasko730dfdf2015-08-11 14:48:05 +02001936/**
Michal Vaskof39142b2015-10-21 11:40:05 +02001937 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02001938 * only specific errors, general no-resolvent error is left to the caller,
1939 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001940 *
Michal Vaskobb211122015-08-19 14:03:11 +02001941 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001942 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02001943 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001944 * @param[in,out] node_match Nodes satisfying the restriction
1945 * without the predicate. Nodes not
1946 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02001947 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001948 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001949 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001950 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001951static int
Michal Vasko184521f2015-09-24 13:14:26 +02001952resolve_path_predicate_data(const char *pred, int first, uint32_t line, struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001953{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001954 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001955 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001956 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02001957 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
1958 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001959 uint32_t j;
1960
1961 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001962 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01001963 if (!source_match.node) {
1964 LOGMEM;
1965 return -1;
1966 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001967 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001968 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01001969 if (!dest_match.node) {
1970 LOGMEM;
1971 return -1;
1972 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001973
1974 do {
1975 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
1976 &pke_len, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001977 LOGVAL(LYE_INCHAR, line, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02001978 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001979 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001980 }
Michal Vasko0491ab32015-08-19 14:28:29 +02001981 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001982 pred += i;
1983
Michal Vasko23b61ec2015-08-19 11:19:50 +02001984 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001985 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02001986 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02001987
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001988 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01001989 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02001990 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001991 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02001992 if ((rc == -1) || !first) {
1993 LOGVAL(LYE_LINE, line);
1994 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001995 i = 0;
1996 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001997 }
1998
1999 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002000 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002001 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002002 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2003 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002004 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002005 rc = -1;
2006 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002007 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002008 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002009 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002010 dest_match.node[0] = dest_match.node[0]->parent;
2011 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002012 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002013 if (!first) {
2014 LOGVAL(LYE_LINE, line);
2015 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002016 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002017 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002018 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002019 }
2020 }
2021 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002022 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002023 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002024 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002025 if ((rc == -1) || !first) {
2026 LOGVAL(LYE_LINE, line);
2027 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002028 i = 0;
2029 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002030 }
2031
2032 if (pke_len == pke_parsed) {
2033 break;
2034 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002035 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 +02002036 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002037 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002038 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002039 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002040 }
2041 pke_parsed += i;
2042 }
2043
2044 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002045 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2046 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002047 goto remove_leafref;
2048 }
2049
Michal Vasko83a6c462015-10-08 16:43:53 +02002050 if (((struct lyd_node_leaf_list *)source_match.node[0])->value_str
2051 != ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002052 goto remove_leafref;
2053 }
2054
2055 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002056 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002057 continue;
2058
2059remove_leafref:
2060 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002061 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002062 }
2063 } while (has_predicate);
2064
Michal Vaskocf024702015-10-08 15:01:42 +02002065 free(source_match.node);
2066 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002067 if (parsed) {
2068 *parsed = parsed_loc;
2069 }
2070 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002071
2072error:
2073
2074 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002075 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002076 }
2077 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002078 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002079 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002080 if (parsed) {
2081 *parsed = -parsed_loc+i;
2082 }
2083 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002084}
2085
Michal Vasko730dfdf2015-08-11 14:48:05 +02002086/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002087 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002088 *
Michal Vaskocf024702015-10-08 15:01:42 +02002089 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002090 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002091 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002092 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002093 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002094 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002095 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002096 */
Michal Vasko184521f2015-09-24 13:14:26 +02002097static int
Michal Vaskocf024702015-10-08 15:01:42 +02002098resolve_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 +02002099{
Radek Krejci71b795b2015-08-10 16:20:39 +02002100 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002102 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002103 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002104
Michal Vaskocf024702015-10-08 15:01:42 +02002105 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002106
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002107 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002108 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002109
2110 /* searching for nodeset */
2111 do {
2112 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002113 LOGVAL(LYE_INCHAR, line, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002114 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002115 goto error;
2116 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002117 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002118 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002119
Michal Vasko23b61ec2015-08-19 11:19:50 +02002120 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002121 if (parent_times != -1) {
2122 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002123 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002124 if (!ret->node) {
2125 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002126 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002127 goto error;
2128 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002129 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002130 for (i = 0; i < parent_times; ++i) {
2131 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002132 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002133 /* error, too many .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002134 LOGVAL(LYE_INVAL, line, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002135 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002136 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002137 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002138 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002139 data = ret->node[0] = node->parent;
2140 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002141 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002142 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002143 free(ret->node);
2144 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002145 } else {
2146 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002147 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002148 }
2149 }
2150
2151 /* absolute path */
2152 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002153 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002154 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002155 if (data->prev) {
2156 for (; data->prev->next; data = data->prev);
2157 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002158 }
2159 }
2160
2161 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002162 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002163 if ((rc == -1) || !first) {
2164 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
2165 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166 goto error;
2167 }
2168
2169 if (has_predicate) {
2170 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002171 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002172 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2173 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002174 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002175 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002176 continue;
2177 }
2178
2179 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002180 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002181 }
Michal Vasko184521f2015-09-24 13:14:26 +02002182 if ((rc = resolve_path_predicate_data(path, first, line, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002183 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002184 if ((rc == -1) || !first) {
2185 LOGVAL(LYE_NORESOLV, 0, path);
2186 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002187 goto error;
2188 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002189 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002190 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002191
Michal Vasko23b61ec2015-08-19 11:19:50 +02002192 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002193 if (!first) {
2194 LOGVAL(LYE_NORESOLV, line, path-parsed);
2195 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002196 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002197 goto error;
2198 }
2199 }
2200 } while (path[0] != '\0');
2201
Michal Vaskof02e3742015-08-05 16:27:02 +02002202 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002203
2204error:
2205
Michal Vaskocf024702015-10-08 15:01:42 +02002206 free(ret->node);
2207 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002208 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002209
Michal Vasko0491ab32015-08-19 14:28:29 +02002210 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002211}
2212
Michal Vasko730dfdf2015-08-11 14:48:05 +02002213/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002214 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002215 *
Michal Vaskobb211122015-08-19 14:03:11 +02002216 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002217 * @param[in] source_node Left operand node.
2218 * @param[in] dest_node Right ooperand node.
Michal Vasko184521f2015-09-24 13:14:26 +02002219 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002220 * @param[in] line Line in the input file.
2221 *
Michal Vasko184521f2015-09-24 13:14:26 +02002222 * @return 0 on forward reference, otherwise the number
2223 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002224 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002225 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002226static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01002227resolve_path_predicate_schema(const char *path, const struct lys_node *source_node,
Michal Vasko184521f2015-09-24 13:14:26 +02002228 struct lys_node *dest_node, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002229{
Michal Vasko1e62a092015-12-01 12:27:20 +01002230 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002231 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2232 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 +02002233 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002234
2235 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002236 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002237 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002238 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002239 return -parsed+i;
2240 }
2241 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002242 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002243
Michal Vasko58090902015-08-13 14:04:15 +02002244 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002245 if (!sour_pref) {
2246 sour_pref = source_node->module->name;
2247 }
2248 rc = lys_get_sibling(source_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002249 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002250 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002251 if ((rc == -1) || !first) {
2252 LOGVAL(LYE_NORESOLV, line, path-parsed);
2253 }
2254 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002255 }
2256
2257 /* destination */
2258 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2259 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002260 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002261 return -parsed;
2262 }
2263 pke_parsed += i;
2264
2265 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2266 dst_node = dest_node;
2267 for (i = 1; i < dest_parent_times; ++i) {
2268 dst_node = dst_node->parent;
2269 if (!dst_node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002270 if (!first) {
2271 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2272 }
2273 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002274 }
2275 }
2276 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002277 if (!dest_pref) {
2278 dest_pref = dst_node->module->name;
2279 }
2280 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002281 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002282 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002283 if ((rc == -1) || !first) {
2284 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2285 }
2286 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002287 }
2288
2289 if (pke_len == pke_parsed) {
2290 break;
2291 }
2292
2293 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2294 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002295 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002296 return -parsed;
2297 }
2298 pke_parsed += i;
2299 }
2300
2301 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002302 if (dst_node->nodetype != LYS_LEAF) {
Michal Vaskod9173342015-08-17 14:35:36 +02002303 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002304 LOGVAL(LYE_SPEC, 0, "Destination node not a leaf, but %s.", strnodetype(dst_node->nodetype));
2305 return -parsed;
2306 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002307 } while (has_predicate);
2308
2309 return parsed;
2310}
2311
Michal Vasko730dfdf2015-08-11 14:48:05 +02002312/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002313 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002314 *
Michal Vaskobb211122015-08-19 14:03:11 +02002315 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002316 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002317 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2318 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002319 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002320 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002321 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002322 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002323 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002324 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002325static int
Radek Krejci2f12f852016-01-08 12:59:57 +01002326resolve_path_arg_schema(const char *path, struct lys_node *parent_node, int parent_tpdf, int first, uint32_t line,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002327 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002328{
Michal Vasko1e62a092015-12-01 12:27:20 +01002329 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002330 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002331 const char *id, *prefix, *name;
2332 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002333 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002334
Michal Vasko184521f2015-09-24 13:14:26 +02002335 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002336 parent_times = 0;
2337 id = path;
2338
2339 do {
2340 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002341 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002342 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002343 }
2344 id += i;
2345
Michal Vasko184521f2015-09-24 13:14:26 +02002346 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002347 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002348 /* resolve prefix of the module */
2349 mod = lys_get_import_module(parent_node->module, NULL, 0, prefix, pref_len);
2350 /* get start node */
2351 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002352 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002353 if (!first) {
2354 LOGVAL(LYE_NORESOLV, line, path);
2355 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002356 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002357 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002358 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002359 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002360 if (parent_tpdf) {
2361 /* the path is not allowed to contain relative path since we are in top level typedef */
2362 LOGVAL(LYE_NORESOLV, line, path);
2363 return -1;
2364 }
2365
Michal Vasko58090902015-08-13 14:04:15 +02002366 node = parent_node;
2367 i = 0;
2368 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002369 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002370 if (!first) {
2371 LOGVAL(LYE_NORESOLV, line, path);
2372 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002373 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002374 }
Michal Vasko58090902015-08-13 14:04:15 +02002375
2376 /* this node is a wrong node, we actually need the augment target */
2377 if (node->nodetype == LYS_AUGMENT) {
2378 node = ((struct lys_node_augment *)node)->target;
2379 if (!node) {
2380 continue;
2381 }
2382 }
2383
2384 ++i;
2385 if (i == parent_times) {
2386 break;
2387 }
2388 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002389 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002390
Michal Vasko1f76a282015-08-04 16:16:53 +02002391 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002392 } else {
2393 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002394 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002395 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002396
2397 if (!prefix) {
Radek Krejcic071c542016-01-27 14:57:51 +01002398 mod = parent_node->module;
2399 prefix = mod->type ? ((struct lys_submodule *)mod)->belongsto->name : mod->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002400 }
Michal Vasko184521f2015-09-24 13:14:26 +02002401 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002402 } else {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002403 if (!prefix) {
Radek Krejcic071c542016-01-27 14:57:51 +01002404 mod = parent_node->module;
2405 prefix = mod->type ? ((struct lys_submodule *)mod)->belongsto->name : mod->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002406 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002407 node = node->child;
2408 }
2409
Michal Vasko36cbaa42015-12-14 13:15:48 +01002410 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 +02002411 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002412 if ((rc == -1) || !first) {
2413 LOGVAL(LYE_NORESOLV, line, path);
2414 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002415 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002416 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002417
2418 if (has_predicate) {
2419 /* we have predicate, so the current result must be list */
2420 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002421 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002422 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002423 }
2424
Michal Vasko36cbaa42015-12-14 13:15:48 +01002425 i = resolve_path_predicate_schema(id, node, parent_node, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002426 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002427 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002428 } else if (i < 0) {
2429 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002430 }
2431 id += i;
2432 }
2433 } while (id[0]);
2434
Radek Krejcib1c12512015-08-11 11:22:04 +02002435 /* the target must be leaf or leaf-list */
2436 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002437 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002438 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002439 }
2440
Radek Krejcicf509982015-12-15 09:22:44 +01002441 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01002442 if (lyp_check_status(parent_node->flags, parent_node->module, parent_node->name,
Radek Krejcicf509982015-12-15 09:22:44 +01002443 node->flags, node->module, node->name, line)) {
2444 return -1;
2445 }
2446
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002447 if (ret) {
2448 *ret = node;
2449 }
2450 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002451}
2452
Michal Vasko730dfdf2015-08-11 14:48:05 +02002453/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002454 * @brief Resolve instance-identifier predicate in JSON data format.
2455 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002456 *
Michal Vaskobb211122015-08-19 14:03:11 +02002457 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002458 * @param[in,out] node_match Nodes matching the restriction without
2459 * the predicate. Nodes not satisfying
2460 * the predicate are removed.
2461 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002462 * @return Number of characters successfully parsed,
2463 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002464 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002465static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002466resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002467{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002468 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002469 struct unres_data target_match;
2470 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002471 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002472 const char *model, *name, *value;
2473 char *str;
2474 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2475 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002476
Michal Vasko1f2cc332015-08-19 11:18:32 +02002477 assert(pred && node_match->count);
2478
Michal Vaskocf024702015-10-08 15:01:42 +02002479 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002480 idx = -1;
2481 parsed = 0;
2482
2483 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002484 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002485 return -parsed+i;
2486 }
2487 parsed += i;
2488 pred += i;
2489
Michal Vasko1f2cc332015-08-19 11:18:32 +02002490 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002491 if (isdigit(name[0])) {
2492 idx = atoi(name);
2493 }
2494
Michal Vasko1f2cc332015-08-19 11:18:32 +02002495 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002496 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002497 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002498 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002499 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002500 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002501 if (!target_match.node) {
2502 LOGMEM;
2503 return -1;
2504 }
Michal Vaskocf024702015-10-08 15:01:42 +02002505 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002506 } else {
2507 str = strndup(model, mod_len);
2508 mod = ly_ctx_get_module(ctx, str, NULL);
2509 free(str);
2510
Radek Krejci804836a2016-02-03 10:39:55 +01002511 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002512 goto remove_instid;
2513 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002514 }
2515
2516 /* check that we have the correct type */
2517 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002518 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002519 goto remove_instid;
2520 }
2521 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002522 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523 goto remove_instid;
2524 }
2525 }
2526
Michal Vasko83a6c462015-10-08 16:43:53 +02002527 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2528 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002529 || (!value && (idx != cur_idx))) {
2530 goto remove_instid;
2531 }
2532
Michal Vaskocf024702015-10-08 15:01:42 +02002533 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002534
2535 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002536 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002537 continue;
2538
2539remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002540 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002541
2542 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002543 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002544 }
2545 } while (has_predicate);
2546
2547 return parsed;
2548}
2549
Michal Vasko730dfdf2015-08-11 14:48:05 +02002550/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002551 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002552 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002553 * @param[in] data Any node in the data tree, used to get a data tree root and context
Michal Vasko730dfdf2015-08-11 14:48:05 +02002554 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002555 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002556 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002557 * @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 +02002558 */
Michal Vasko184521f2015-09-24 13:14:26 +02002559static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002560resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561{
Radek Krejcic5090c32015-08-12 09:46:19 +02002562 int i = 0, j;
2563 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002564 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002565 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002566 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002567 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002568 int mod_len, name_len, has_predicate;
2569 struct unres_data node_match;
2570 uint32_t k;
2571
2572 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002573
Radek Krejcic5090c32015-08-12 09:46:19 +02002574 /* we need root to resolve absolute path */
2575 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002576 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002577 if (data->prev) {
2578 for (; data->prev->next; data = data->prev);
2579 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002580
Radek Krejcic5090c32015-08-12 09:46:19 +02002581 /* search for the instance node */
2582 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002583 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002584 if (j <= 0) {
2585 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002586 goto error;
2587 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002588 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002589
Michal Vasko1f2cc332015-08-19 11:18:32 +02002590 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002591 if (!str) {
2592 LOGMEM;
2593 goto error;
2594 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002595 mod = ly_ctx_get_module(ctx, str, NULL);
2596 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002597
Radek Krejcic5090c32015-08-12 09:46:19 +02002598 if (!mod) {
2599 /* no instance exists */
2600 return NULL;
2601 }
2602
Michal Vasko1f2cc332015-08-19 11:18:32 +02002603 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002604 /* no instance exists */
2605 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002606 }
2607
2608 if (has_predicate) {
2609 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002610 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002611 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2612 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2613 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002614 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002615 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002616 continue;
2617 }
2618
2619 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002620 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002622
Michal Vaskof39142b2015-10-21 11:40:05 +02002623 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002624 if (j < 1) {
2625 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002626 goto error;
2627 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002628 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002629
Michal Vasko1f2cc332015-08-19 11:18:32 +02002630 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002631 /* no instance exists */
2632 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002633 }
2634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002635 }
2636
Michal Vasko1f2cc332015-08-19 11:18:32 +02002637 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002638 /* no instance exists */
2639 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002640 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002641 /* instance identifier must resolve to a single node */
2642 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2643
2644 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002645 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002646
2647 return NULL;
2648 } else {
2649 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002650 result = node_match.node[0];
2651 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002652
2653 return result;
2654 }
2655
2656error:
2657
2658 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002659 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002660
2661 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002662}
2663
Michal Vasko730dfdf2015-08-11 14:48:05 +02002664/**
2665 * @brief Passes config flag down to children. Does not log.
2666 *
2667 * @param[in] node Parent node.
2668 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002669static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002670inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002671{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002672 LY_TREE_FOR(node, node) {
2673 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2674 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002675 }
2676}
2677
Michal Vasko730dfdf2015-08-11 14:48:05 +02002678/**
Michal Vaskod9173342015-08-17 14:35:36 +02002679 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002680 *
Michal Vaskobb211122015-08-19 14:03:11 +02002681 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002682 * @param[in] siblings Nodes where to start the search in.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002683 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002684 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002685 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002686int
Michal Vasko1d87a922015-08-21 12:57:16 +02002687resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002688{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002689 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002690 struct lys_node *sub;
Radek Krejcic071c542016-01-27 14:57:51 +01002691 struct lys_module *mm;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002692
Michal Vasko1d87a922015-08-21 12:57:16 +02002693 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002694
2695 /* resolve target node */
Michal Vasko1e62a092015-12-01 12:27:20 +01002696 rc = resolve_schema_nodeid(aug->target_name, siblings, aug->module, LYS_AUGMENT, (const struct lys_node **)&aug->target);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002697 if (rc) {
2698 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002699 }
2700
2701 if (!aug->child) {
2702 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002703 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002704 return EXIT_SUCCESS;
2705 }
2706
2707 /* inherit config information from parent, augment does not have
2708 * config property, but we need to keep the information for subelements
2709 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002710 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002711 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002712 inherit_config_flag(sub);
2713 }
2714
Radek Krejcic071c542016-01-27 14:57:51 +01002715 /* check identifier uniqueness as in lys_node_addchild() */
2716 mm = aug->module->type ? ((struct lys_submodule *)aug->module)->belongsto : aug->module;
Michal Vasko1d87a922015-08-21 12:57:16 +02002717 LY_TREE_FOR(aug->child, sub) {
Radek Krejcic071c542016-01-27 14:57:51 +01002718 if (lys_check_id(sub, aug->parent, mm)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002719 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002720 }
2721 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002722 /* reconnect augmenting data into the target - add them to the target child list */
2723 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002724 sub = aug->target->child->prev; /* remember current target's last node */
2725 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002726 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002727 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002728 } else {
2729 aug->target->child = aug->child;
2730 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002731
2732 return EXIT_SUCCESS;
2733}
2734
Michal Vasko730dfdf2015-08-11 14:48:05 +02002735/**
2736 * @brief Resolve uses, apply augments, refines. Logs directly.
2737 *
Michal Vaskobb211122015-08-19 14:03:11 +02002738 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002739 * @param[in,out] unres List of unresolved items.
2740 * @param[in] line Line in the input file.
2741 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002742 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002743 */
Michal Vasko184521f2015-09-24 13:14:26 +02002744static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002745resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002746{
2747 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002748 struct lys_node *node = NULL;
2749 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002750 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002751 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002752 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002753 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002754
Michal Vasko71e1aa82015-08-12 12:17:51 +02002755 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002756 /* HACK just check that the grouing is resolved */
2757 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002758
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002759 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01002760 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcic071c542016-01-27 14:57:51 +01002761 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres);
Michal Vasko1e62a092015-12-01 12:27:20 +01002762 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002763 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002764 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002765 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002766 }
2767 ctx = uses->module->ctx;
2768
Michal Vaskodef0db12015-10-07 13:22:48 +02002769 /* we managed to copy the grouping, the rest must be possible to resolve */
2770
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771 /* apply refines */
2772 for (i = 0; i < uses->refine_size; i++) {
2773 rfn = &uses->refine[i];
Michal Vasko1e62a092015-12-01 12:27:20 +01002774 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF,
2775 (const struct lys_node **)&node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002776 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002777 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2778 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002779 }
2780
Radek Krejci1d82ef62015-08-07 14:44:40 +02002781 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002782 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002783 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 }
2785
2786 /* description on any nodetype */
2787 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002788 lydict_remove(ctx, node->dsc);
2789 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790 }
2791
2792 /* reference on any nodetype */
2793 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002794 lydict_remove(ctx, node->ref);
2795 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 }
2797
2798 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002799 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002800 node->flags &= ~LYS_CONFIG_MASK;
2801 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802 }
2803
2804 /* default value ... */
2805 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002806 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002807 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002808 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2809 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2810 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002811 /* choice */
Michal Vasko1e62a092015-12-01 12:27:20 +01002812 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE,
2813 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002814 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002815 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2816 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 }
2818 }
2819 }
2820
2821 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002822 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002823 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002824 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002825 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002826
2827 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002828 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002829 }
2830 }
2831
2832 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002833 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2834 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2835 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002836 }
2837
2838 /* min/max-elements on list or leaf-list */
2839 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002840 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002842 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002843 }
2844 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002845 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002846 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002847 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002849 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002850 }
2851 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002852 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002853 }
2854 }
2855
2856 /* must in leaf, leaf-list, list, container or anyxml */
2857 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002858 switch (node->nodetype) {
2859 case LYS_LEAF:
2860 old_size = &((struct lys_node_leaf *)node)->must_size;
2861 old_must = &((struct lys_node_leaf *)node)->must;
2862 break;
2863 case LYS_LEAFLIST:
2864 old_size = &((struct lys_node_leaflist *)node)->must_size;
2865 old_must = &((struct lys_node_leaflist *)node)->must;
2866 break;
2867 case LYS_LIST:
2868 old_size = &((struct lys_node_list *)node)->must_size;
2869 old_must = &((struct lys_node_list *)node)->must;
2870 break;
2871 case LYS_CONTAINER:
2872 old_size = &((struct lys_node_container *)node)->must_size;
2873 old_must = &((struct lys_node_container *)node)->must;
2874 break;
2875 case LYS_ANYXML:
2876 old_size = &((struct lys_node_anyxml *)node)->must_size;
2877 old_must = &((struct lys_node_anyxml *)node)->must;
2878 break;
2879 default:
2880 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02002881 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002882 }
2883
2884 size = *old_size + rfn->must_size;
2885 must = realloc(*old_must, size * sizeof *rfn->must);
2886 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002888 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002890 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
2891 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2892 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2893 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2894 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2895 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 }
2897
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002898 *old_must = must;
2899 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 }
2901 }
2902
2903 /* apply augments */
2904 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002905 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002906 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002907 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
2908 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002909 }
2910 }
2911
2912 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913}
2914
Michal Vasko730dfdf2015-08-11 14:48:05 +02002915/**
2916 * @brief Resolve base identity recursively. Does not log.
2917 *
2918 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002919 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002920 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002921 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002922 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002923 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002924 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002925static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002926resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002927 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928{
Michal Vaskof02e3742015-08-05 16:27:02 +02002929 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002930 struct lys_ident *base_iter = NULL;
2931 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932
Radek Krejcicf509982015-12-15 09:22:44 +01002933 assert(ret);
2934
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 /* search module */
2936 for (i = 0; i < module->ident_size; i++) {
2937 if (!strcmp(basename, module->ident[i].name)) {
2938
2939 if (!ident) {
2940 /* just search for type, so do not modify anything, just return
2941 * the base identity pointer
2942 */
Radek Krejcicf509982015-12-15 09:22:44 +01002943 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002944 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 }
2946
2947 /* we are resolving identity definition, so now update structures */
2948 ident->base = base_iter = &module->ident[i];
2949
2950 break;
2951 }
2952 }
2953
2954 /* search submodules */
2955 if (!base_iter) {
Radek Krejcic071c542016-01-27 14:57:51 +01002956 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002957 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2958 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2959
2960 if (!ident) {
Radek Krejcicf509982015-12-15 09:22:44 +01002961 *ret = &module->inc[j].submodule->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002962 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963 }
2964
2965 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2966 break;
2967 }
2968 }
2969 }
2970 }
2971
2972 /* we found it somewhere */
2973 if (base_iter) {
2974 while (base_iter) {
2975 for (der = base_iter->der; der && der->next; der = der->next);
2976 if (der) {
2977 der->next = malloc(sizeof *der);
2978 der = der->next;
2979 } else {
2980 ident->base->der = der = malloc(sizeof *der);
2981 }
Michal Vasko253035f2015-12-17 16:58:13 +01002982 if (!der) {
2983 LOGMEM;
2984 return EXIT_FAILURE;
2985 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986 der->next = NULL;
2987 der->ident = ident;
2988
2989 base_iter = base_iter->base;
2990 }
Radek Krejcicf509982015-12-15 09:22:44 +01002991 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002992 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002993 }
2994
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002995 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002996}
2997
Michal Vasko730dfdf2015-08-11 14:48:05 +02002998/**
2999 * @brief Resolve base identity. Logs directly.
3000 *
3001 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003002 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003003 * @param[in] basename Base name of the identity.
3004 * @param[in] parent Either "type" or "ident".
Michal Vasko184521f2015-09-24 13:14:26 +02003005 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003006 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003007 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003008 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003009 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003010 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003011static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003012resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003013 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014{
3015 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003016 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003017 struct lys_ident *target, **ret;
3018 uint8_t flags;
3019 struct lys_module *mod;
3020
3021 assert((ident && !type) || (!ident && type));
3022
3023 if (!type) {
3024 /* have ident to resolve */
3025 ret = &target;
3026 flags = ident->flags;
3027 mod = ident->module;
3028 } else {
3029 /* have type to fill */
3030 ret = &type->info.ident.ref;
3031 flags = type->parent->flags;
3032 mod = type->parent->module;
3033 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003034
3035 /* search for the base identity */
3036 name = strchr(basename, ':');
3037 if (name) {
3038 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003039 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003040 name++;
3041
Michal Vasko2d851a92015-10-20 16:16:36 +02003042 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003043 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003044 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003045 }
3046 } else {
3047 name = basename;
3048 }
3049
Radek Krejcic071c542016-01-27 14:57:51 +01003050 /* get module where to search */
3051 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3052 if (!module) {
3053 /* identity refers unknown data model */
3054 LOGVAL(LYE_INMOD, line, basename);
3055 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003056 }
3057
Radek Krejcic071c542016-01-27 14:57:51 +01003058 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003059 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003060 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003061 }
Radek Krejcic071c542016-01-27 14:57:51 +01003062 /* and all its submodules */
3063 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3064 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3065 goto success;
3066 }
3067 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003068
Michal Vasko184521f2015-09-24 13:14:26 +02003069 if (!first) {
3070 LOGVAL(LYE_INARG, line, basename, parent);
3071 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003072 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003073
3074success:
3075 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003076 if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name, line)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003077 return -1;
3078 }
3079
3080 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081}
3082
Michal Vasko730dfdf2015-08-11 14:48:05 +02003083/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003084 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003085 *
3086 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003087 * @param[in] ident_name Identityref name.
3088 * @param[in] line Line from the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003089 *
3090 * @return Pointer to the identity resolvent, NULL on error.
3091 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003092struct lys_ident *
Michal Vaskof39142b2015-10-21 11:40:05 +02003093resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003095 const char *mod_name, *name;
3096 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003097 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098
Michal Vaskofb0873c2015-08-21 09:00:07 +02003099 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003100 return NULL;
3101 }
3102
Michal Vaskoc633ca02015-08-21 14:03:51 +02003103 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003104 if (rc < (signed)strlen(ident_name)) {
3105 LOGVAL(LYE_INCHAR, line, ident_name[-rc], &ident_name[-rc]);
3106 return NULL;
3107 }
3108
Michal Vaskoc633ca02015-08-21 14:03:51 +02003109 if (!strcmp(base->name, name) && (!mod_name
3110 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003111 return base;
3112 }
3113
3114 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003115 if (!strcmp(der->ident->name, name) && (!mod_name
3116 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3117 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003118 /* we have match */
3119 return der->ident;
3120 }
3121 }
3122
Michal Vaskofb0873c2015-08-21 09:00:07 +02003123 LOGVAL(LYE_INRESOLV, line, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003124 return NULL;
3125}
3126
Michal Vasko730dfdf2015-08-11 14:48:05 +02003127/**
Michal Vasko7955b362015-09-04 14:18:15 +02003128 * @brief Resolve (find) choice default case. Does not log.
3129 *
3130 * @param[in] choic Choice to use.
3131 * @param[in] dflt Name of the default case.
3132 *
3133 * @return Pointer to the default node or NULL.
3134 */
3135static struct lys_node *
3136resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3137{
3138 struct lys_node *child, *ret;
3139
3140 LY_TREE_FOR(choic->child, child) {
3141 if (child->nodetype == LYS_USES) {
3142 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3143 if (ret) {
3144 return ret;
3145 }
3146 }
3147
3148 if ((child->name == dflt) && (child->nodetype & (LYS_ANYXML | LYS_CASE
3149 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3150 return child;
3151 }
3152 }
3153
3154 return NULL;
3155}
3156
3157/**
Michal Vaskobb211122015-08-19 14:03:11 +02003158 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003159 *
Michal Vaskobb211122015-08-19 14:03:11 +02003160 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003161 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003162 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003163 * @param[in] line Line in the input file.
3164 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003165 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003166 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003167static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003168resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003169{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003170 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003171 struct lys_node *parent;
3172
3173 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3174 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3175
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003176 if (!uses->grp) {
Michal Vasko184521f2015-09-24 13:14:26 +02003177 rc = resolve_grouping(uses, first, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003178 if (rc) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003179 if (parent && first && (rc == EXIT_FAILURE)) {
3180 ++parent->nacm;
3181 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003182 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003183 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184 }
3185
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003186 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003187 if (parent && first) {
3188 ++parent->nacm;
3189 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003190 return EXIT_FAILURE;
3191 }
3192
Michal Vaskodef0db12015-10-07 13:22:48 +02003193 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003194 if (!rc) {
3195 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003196 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003197 if (!parent->nacm) {
3198 LOGINT;
3199 return -1;
3200 }
3201 --parent->nacm;
3202 }
Radek Krejcicf509982015-12-15 09:22:44 +01003203
3204 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003205 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejcicf509982015-12-15 09:22:44 +01003206 uses->grp->flags, uses->grp->module, uses->grp->name, line)) {
3207 return -1;
3208 }
3209
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003210 return EXIT_SUCCESS;
3211 }
3212
Michal Vasko407f1bb2015-09-23 15:51:07 +02003213 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003214 ++parent->nacm;
3215 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003216 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217}
3218
Michal Vasko730dfdf2015-08-11 14:48:05 +02003219/**
Michal Vasko9957e592015-08-17 15:04:09 +02003220 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003221 *
Michal Vaskobb211122015-08-19 14:03:11 +02003222 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003223 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003224 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003225 * @param[in] line Line in the input file.
3226 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003227 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003228 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003230resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003231{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003232 int i, len, rc;
Radek Krejcic071c542016-01-27 14:57:51 +01003233 const char *value, *modname;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234
3235 for (i = 0; i < list->keys_size; ++i) {
3236 /* get the key name */
3237 if ((value = strpbrk(keys_str, " \t\n"))) {
3238 len = value - keys_str;
3239 while (isspace(value[0])) {
3240 value++;
3241 }
3242 } else {
3243 len = strlen(keys_str);
3244 }
3245
Radek Krejcic071c542016-01-27 14:57:51 +01003246 modname = list->module->type ? ((struct lys_submodule *)list->module)->belongsto->name : list->module->name;
3247 rc = lys_get_sibling(list->child, modname, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003248 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003249 if ((rc == -1) || !first) {
3250 LOGVAL(LYE_INRESOLV, line, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003251 }
3252 return rc;
3253 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003254
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003255 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003256 /* check_key logs */
3257 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003258 }
3259
Radek Krejcicf509982015-12-15 09:22:44 +01003260 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003261 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejcicf509982015-12-15 09:22:44 +01003262 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name, line)) {
3263 return -1;
3264 }
3265
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 /* prepare for next iteration */
3267 while (value && isspace(value[0])) {
3268 value++;
3269 }
3270 keys_str = value;
3271 }
3272
Michal Vaskof02e3742015-08-05 16:27:02 +02003273 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003274}
3275
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003276/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003277 * @brief Resolve (check) all must conditions of \p node.
3278 * Logs directly.
3279 *
3280 * @param[in] node Data node with optional must statements.
3281 * @param[in] first Whether this is the first resolution to try.
3282 * @param[in] line Line in the input file.
3283 *
3284 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3285 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003287resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003288{
Michal Vaskobf19d252015-10-08 15:39:17 +02003289 uint8_t i, must_size;
3290 struct lys_restr *must;
3291 struct lyxp_set set;
3292
3293 assert(node);
3294 memset(&set, 0, sizeof set);
3295
3296 switch (node->schema->nodetype) {
3297 case LYS_CONTAINER:
3298 must_size = ((struct lys_node_container *)node->schema)->must_size;
3299 must = ((struct lys_node_container *)node->schema)->must;
3300 break;
3301 case LYS_LEAF:
3302 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3303 must = ((struct lys_node_leaf *)node->schema)->must;
3304 break;
3305 case LYS_LEAFLIST:
3306 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3307 must = ((struct lys_node_leaflist *)node->schema)->must;
3308 break;
3309 case LYS_LIST:
3310 must_size = ((struct lys_node_list *)node->schema)->must_size;
3311 must = ((struct lys_node_list *)node->schema)->must;
3312 break;
3313 case LYS_ANYXML:
3314 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3315 must = ((struct lys_node_anyxml *)node->schema)->must;
3316 break;
3317 default:
3318 must_size = 0;
3319 break;
3320 }
3321
3322 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003323 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003324 return -1;
3325 }
3326
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003327 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003328
3329 if (!set.value.bool) {
3330 if (!first) {
3331 LOGVAL(LYE_NOCOND, line, "Must", must[i].expr);
3332 }
3333 return 1;
3334 }
3335 }
3336
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003337 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003338}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339
Michal Vaskobf19d252015-10-08 15:39:17 +02003340/**
Michal Vaskocf024702015-10-08 15:01:42 +02003341 * @brief Resolve (find) when condition context node. Does not log.
3342 *
3343 * @param[in] node Data node, whose conditional definition is being decided.
3344 * @param[in] schema Schema node with a when condition.
3345 *
3346 * @return Context node.
3347 */
3348static struct lyd_node *
3349resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003350{
Michal Vaskocf024702015-10-08 15:01:42 +02003351 struct lyd_node *parent;
3352 struct lys_node *sparent;
3353 uint16_t i, data_depth, schema_depth;
3354
3355 /* find a not schema-only node */
3356 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3357 schema = lys_parent(schema);
3358 if (!schema) {
3359 return NULL;
3360 }
3361 }
3362
3363 /* get node depths */
3364 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3365 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3366 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3367 ++schema_depth;
3368 }
3369 }
3370 if (data_depth < schema_depth) {
3371 return NULL;
3372 }
3373
3374 /* find the corresponding data node */
3375 for (i = 0; i < data_depth - schema_depth; ++i) {
3376 node = node->parent;
3377 }
3378 if (node->schema != schema) {
3379 return NULL;
3380 }
3381
3382 return node;
3383}
3384
3385/**
3386 * @brief Resolve (check) all when conditions relevant for \p node.
3387 * Logs directly.
3388 *
3389 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3390 * @param[in] first Whether this is the first resolution to try.
3391 * @param[in] line Line in the input file.
3392 *
3393 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3394 */
3395static int
3396resolve_when(struct lyd_node *node, int first, uint32_t line)
3397{
3398 struct lyd_node *ctx_node = NULL;
3399 struct lys_node *parent;
3400 struct lyxp_set set;
3401
3402 assert(node);
3403 memset(&set, 0, sizeof set);
3404
3405 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003406 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003407 return -1;
3408 }
3409
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003410 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003411
3412 if (!set.value.bool) {
3413 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003414 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003415 }
3416 return 1;
3417 }
3418 }
3419
3420 parent = node->schema;
3421 goto check_augment;
3422
3423 /* check when in every schema node that affects node */
3424 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3425 if (((struct lys_node_uses *)parent)->when) {
3426 if (!ctx_node) {
3427 ctx_node = resolve_when_ctx_node(node, parent);
3428 if (!ctx_node) {
3429 LOGINT;
3430 return -1;
3431 }
3432 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003433 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003434 return -1;
3435 }
3436
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003437 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003438
3439 if (!set.value.bool) {
3440 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003441 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003442 }
3443 return 1;
3444 }
3445 }
3446
3447check_augment:
3448 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3449 if (!ctx_node) {
3450 ctx_node = resolve_when_ctx_node(node, parent->parent);
3451 if (!ctx_node) {
3452 LOGINT;
3453 return -1;
3454 }
3455 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003456 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003457 return -1;
3458 }
3459
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003460 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003461
3462 if (!set.value.bool) {
3463 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003464 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003465 }
3466 return 1;
3467 }
3468 }
3469
3470 parent = lys_parent(parent);
3471 }
3472
3473 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003474}
3475
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003476/**
Michal Vaskobb211122015-08-19 14:03:11 +02003477 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003478 *
3479 * @param[in] mod Main module.
3480 * @param[in] item Item to resolve. Type determined by \p type.
3481 * @param[in] type Type of the unresolved item.
3482 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003483 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003484 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003485 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003486 *
3487 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3488 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003490resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003491 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003492{
Radek Krejci2f12f852016-01-08 12:59:57 +01003493 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003494 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003495 const char *base_name;
3496
3497 struct lys_ident *ident;
3498 struct lys_type *stype;
3499 struct lys_feature **feat_ptr;
3500 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003501 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502
3503 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003505 base_name = str_snode;
3506 ident = item;
3507
Michal Vasko184521f2015-09-24 13:14:26 +02003508 rc = resolve_base_ident(mod, ident, base_name, "ident", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 has_str = 1;
3510 break;
3511 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003512 base_name = str_snode;
3513 stype = item;
3514
Radek Krejcicf509982015-12-15 09:22:44 +01003515 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 has_str = 1;
3517 break;
3518 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003519 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003520 stype = item;
3521
Radek Krejci2f12f852016-01-08 12:59:57 +01003522 /* HACK - when there is no parent, we are in top level typedef and in that
3523 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3524 * know it via tpdf_flag */
3525 if (!node) {
3526 tpdf_flag = 1;
3527 node = (struct lys_node *)stype->parent;
3528 }
3529
3530 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003531 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01003532 if (stype->info.lref.target) {
3533 /* store the backlink from leafref target */
3534 if (!stype->info.lref.target->child) {
3535 stype->info.lref.target->child = (void*)ly_set_new();
3536 if (!stype->info.lref.target->child) {
3537 LOGMEM;
3538 return -1;
3539 }
3540 }
3541 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
3542 }
3543
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544 has_str = 0;
3545 break;
3546 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003547 /* parent */
3548 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003549 stype = item;
3550
Michal Vasko88c29542015-11-27 14:57:53 +01003551 /* HACK type->der is temporarily unparsed type statement */
3552 yin = (struct lyxml_elem *)stype->der;
3553 stype->der = NULL;
3554
3555 rc = fill_yin_type(mod, node, yin, stype, unres);
3556 if (!rc) {
3557 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01003558 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01003559 } else {
3560 /* may try again later, put all back how it was */
3561 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003562 }
Michal Vasko88c29542015-11-27 14:57:53 +01003563 has_str = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003566 base_name = str_snode;
3567 feat_ptr = item;
3568
Michal Vasko184521f2015-09-24 13:14:26 +02003569 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570 has_str = 1;
3571 break;
3572 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003573 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003574 has_str = 0;
3575 break;
3576 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003577 base_name = str_snode;
3578 stype = item;
3579
Michal Vasko1dca6882015-10-22 14:29:42 +02003580 rc = check_default(stype, base_name, first, line);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003581 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 has_str = 0;
3583 break;
3584 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003585 base_name = str_snode;
3586 choic = item;
3587
Michal Vasko7955b362015-09-04 14:18:15 +02003588 choic->dflt = resolve_choice_dflt(choic, base_name);
3589 if (choic->dflt) {
3590 rc = EXIT_SUCCESS;
3591 } else {
3592 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003593 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594 has_str = 1;
3595 break;
3596 case UNRES_LIST_KEYS:
Michal Vasko36cbaa42015-12-14 13:15:48 +01003597 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003598 has_str = 1;
3599 break;
3600 case UNRES_LIST_UNIQ:
Radek Krejci581ce772015-11-10 17:22:40 +01003601 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003602 has_str = 1;
3603 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003604 default:
3605 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003606 break;
3607 }
3608
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003609 if (has_str && !rc) {
3610 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003611 }
3612
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003613 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003614}
3615
Michal Vaskof02e3742015-08-05 16:27:02 +02003616/* logs directly */
3617static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003618print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003619{
Michal Vaskof02e3742015-08-05 16:27:02 +02003620 char line_str[18];
3621
3622 if (line) {
3623 sprintf(line_str, " (line %u)", line);
3624 } else {
3625 line_str[0] = '\0';
3626 }
3627
3628 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003629 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003630 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003631 break;
3632 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003633 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003634 break;
3635 case UNRES_TYPE_LEAFREF:
3636 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3637 break;
3638 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003639 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
3640 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003641 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003642 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003643 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 +02003644 break;
3645 case UNRES_USES:
3646 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3647 break;
3648 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003649 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 +02003650 break;
3651 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003652 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 +02003653 break;
3654 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003655 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 +02003656 break;
3657 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003658 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 +02003659 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003660 default:
3661 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003662 break;
3663 }
3664}
3665
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003666/**
Michal Vaskobb211122015-08-19 14:03:11 +02003667 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003668 *
3669 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003670 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003671 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003672 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003673 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003674int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003675resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003676{
Michal Vasko88c29542015-11-27 14:57:53 +01003677 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003678 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679
3680 assert(unres);
3681
Michal Vasko51054ca2015-08-12 12:20:00 +02003682 resolved = 0;
3683
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003685 do {
Michal Vasko88c29542015-11-27 14:57:53 +01003686 unres_count = 0;
3687 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003688
3689 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01003690 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
3691 * we need every type's base only */
3692 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003693 continue;
3694 }
3695
Michal Vasko88c29542015-11-27 14:57:53 +01003696 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003697 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3698 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003699 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003700 unres->type[i] = UNRES_RESOLVED;
3701 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01003702 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02003703 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003704 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003705 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003706 }
Michal Vasko88c29542015-11-27 14:57:53 +01003707 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02003708
Michal Vasko88c29542015-11-27 14:57:53 +01003709 if (res_count < unres_count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003710 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003711 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003712 }
3713
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003714 /* the rest */
3715 for (i = 0; i < unres->count; ++i) {
3716 if (unres->type[i] == UNRES_RESOLVED) {
3717 continue;
3718 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003719
Michal Vasko407f1bb2015-09-23 15:51:07 +02003720 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3721 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003722 if (rc) {
3723 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003724 }
Michal Vasko184521f2015-09-24 13:14:26 +02003725
3726 unres->type[i] = UNRES_RESOLVED;
3727 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003728 }
3729
3730 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003731 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3732 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003733 }
3734
Radek Krejcic071c542016-01-27 14:57:51 +01003735 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003736 return EXIT_SUCCESS;
3737}
3738
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003739/**
Michal Vaskobb211122015-08-19 14:03:11 +02003740 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003741 *
3742 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003743 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003744 * @param[in] item Item to resolve. Type determined by \p type.
3745 * @param[in] type Type of the unresolved item.
3746 * @param[in] str String argument.
3747 * @param[in] line Line in the input file.
3748 *
3749 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3750 */
3751int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003752unres_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 +02003753 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003754{
3755 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003756 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003757}
3758
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003759/**
Michal Vaskobb211122015-08-19 14:03:11 +02003760 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003761 *
3762 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003763 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003764 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01003765 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003766 * @param[in] snode Schema node argument.
3767 * @param[in] line Line in the input file.
3768 *
3769 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3770 */
3771int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003772unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003773 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003774{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003775 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01003776 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003777
Michal Vasko9bf425b2015-10-22 11:42:03 +02003778 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
3779 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003780
Michal Vasko184521f2015-09-24 13:14:26 +02003781 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003782 if (rc != EXIT_FAILURE) {
3783 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003784 }
3785
Michal Vasko0bd29d12015-08-19 11:45:49 +02003786 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003787
Michal Vasko88c29542015-11-27 14:57:53 +01003788 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
3789 if (type == UNRES_TYPE_DER) {
3790 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
3791 lyxml_unlink_elem(mod->ctx, yin, 1);
3792 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
3793 }
3794
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003795 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01003796 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
3797 if (!unres->item) {
3798 LOGMEM;
3799 return -1;
3800 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003801 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01003802 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
3803 if (!unres->type) {
3804 LOGMEM;
3805 return -1;
3806 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003807 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01003808 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
3809 if (!unres->str_snode) {
3810 LOGMEM;
3811 return -1;
3812 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01003814 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
3815 if (!unres->module) {
3816 LOGMEM;
3817 return -1;
3818 }
3819 unres->module[unres->count-1] = mod;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003820#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01003821 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
3822 if (!unres->line) {
3823 LOGMEM;
3824 return -1;
3825 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003826 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003827#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003828
3829 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003830}
3831
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003832/**
Michal Vaskobb211122015-08-19 14:03:11 +02003833 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003834 *
3835 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003836 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003837 * @param[in] item Old item to be resolved.
3838 * @param[in] type Type of the old unresolved item.
3839 * @param[in] new_item New item to use in the duplicate.
3840 *
3841 * @return EXIT_SUCCESS on success, -1 on error.
3842 */
Michal Vaskodad19402015-08-06 09:51:53 +02003843int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003844unres_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 +02003845{
3846 int i;
3847
Michal Vaskocf024702015-10-08 15:01:42 +02003848 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003849
Michal Vasko0bd29d12015-08-19 11:45:49 +02003850 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003851
3852 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003853 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003854 }
3855
Michal Vasko0d204592015-10-07 09:50:04 +02003856 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003857 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003858 LOGINT;
3859 return -1;
3860 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003861 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003862 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003863 LOGINT;
3864 return -1;
3865 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003866 }
Michal Vaskodad19402015-08-06 09:51:53 +02003867
3868 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003869}
3870
Michal Vaskof02e3742015-08-05 16:27:02 +02003871/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003872int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003873unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003874{
3875 uint32_t ret = -1, i;
3876
3877 for (i = 0; i < unres->count; ++i) {
3878 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3879 ret = i;
3880 break;
3881 }
3882 }
3883
3884 return ret;
3885}
Michal Vasko8bcdf292015-08-19 14:04:43 +02003886
Michal Vasko88c29542015-11-27 14:57:53 +01003887void
Radek Krejcic071c542016-01-27 14:57:51 +01003888unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01003889{
3890 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01003891 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01003892
Radek Krejcic071c542016-01-27 14:57:51 +01003893 if (!unres || !(*unres)) {
3894 return;
Michal Vasko88c29542015-11-27 14:57:53 +01003895 }
3896
Radek Krejcic071c542016-01-27 14:57:51 +01003897 assert(module || (*unres)->count == 0);
3898
3899 for (i = 0; i < (*unres)->count; ++i) {
3900 if ((*unres)->module[i] != module) {
3901 if ((*unres)->type[i] != UNRES_RESOLVED) {
3902 unresolved++;
3903 }
3904 continue;
3905 }
3906 if ((*unres)->type[i] == UNRES_TYPE_DER) {
3907 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
3908 }
3909 (*unres)->type[i] = UNRES_RESOLVED;
3910 }
3911
3912 if (!module || (!unresolved && !module->type)) {
3913 free((*unres)->item);
3914 free((*unres)->type);
3915 free((*unres)->str_snode);
3916 free((*unres)->module);
Michal Vasko88c29542015-11-27 14:57:53 +01003917#ifndef NDEBUG
Radek Krejcic071c542016-01-27 14:57:51 +01003918 free((*unres)->line);
Michal Vasko88c29542015-11-27 14:57:53 +01003919#endif
Radek Krejcic071c542016-01-27 14:57:51 +01003920 free((*unres));
3921 (*unres) = NULL;
3922 }
Michal Vasko88c29542015-11-27 14:57:53 +01003923}
3924
Michal Vasko8bcdf292015-08-19 14:04:43 +02003925/* logs directly */
3926static void
Michal Vaskocf024702015-10-08 15:01:42 +02003927print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003928{
3929 struct lys_node_leaf *sleaf;
3930 char line_str[18];
3931
3932 if (line) {
3933 sprintf(line_str, " (line %u)", line);
3934 } else {
3935 line_str[0] = '\0';
3936 }
3937
Michal Vaskocf024702015-10-08 15:01:42 +02003938 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003939
Michal Vaskocf024702015-10-08 15:01:42 +02003940 switch (type) {
3941 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003942 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
3943 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003944 break;
3945 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003946 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02003947 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003948 break;
3949 case UNRES_WHEN:
3950 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
3951 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02003952 case UNRES_MUST:
3953 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
3954 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003955 default:
3956 LOGINT;
3957 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003958 }
3959}
3960
3961/**
3962 * @brief Resolve a single unres data item. Logs directly.
3963 *
Michal Vaskocf024702015-10-08 15:01:42 +02003964 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02003965 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02003966 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02003967 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003968 *
3969 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3970 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02003971int
Michal Vaskocf024702015-10-08 15:01:42 +02003972resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003973{
3974 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02003975 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02003976 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003977 struct lys_node_leaf *sleaf;
3978 struct unres_data matches;
3979
3980 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02003981 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02003982 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003983
Michal Vaskocf024702015-10-08 15:01:42 +02003984 switch (type) {
3985 case UNRES_LEAFREF:
3986 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02003987 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003988 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003989 }
3990
3991 /* check that value matches */
3992 for (i = 0; i < matches.count; ++i) {
Michal Vasko83a6c462015-10-08 16:43:53 +02003993 if (leaf->value_str == ((struct lyd_node_leaf_list *)matches.node[i])->value_str) {
Michal Vaskocf024702015-10-08 15:01:42 +02003994 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02003995 break;
3996 }
3997 }
3998
Michal Vaskocf024702015-10-08 15:01:42 +02003999 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004000 memset(&matches, 0, sizeof matches);
4001
Michal Vaskocf024702015-10-08 15:01:42 +02004002 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004003 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02004004 if (!first) {
4005 LOGVAL(LYE_SPEC, line, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02004006 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004007 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004008 return EXIT_FAILURE;
4009 }
Michal Vaskocf024702015-10-08 15:01:42 +02004010 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004011
Michal Vaskocf024702015-10-08 15:01:42 +02004012 case UNRES_INSTID:
4013 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004014 ly_errno = 0;
Michal Vaskof39142b2015-10-21 11:40:05 +02004015 if (!resolve_instid(node, leaf->value_str, line)) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004016 if (ly_errno) {
4017 return -1;
4018 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004019 if (!first) {
Michal Vaskocf024702015-10-08 15:01:42 +02004020 LOGVAL(LYE_SPEC, line, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004021 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004022 return EXIT_FAILURE;
4023 } else {
Michal Vaskocf024702015-10-08 15:01:42 +02004024 LOGVRB("There is no instance of \"%s\", but is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004025 }
4026 }
Michal Vaskocf024702015-10-08 15:01:42 +02004027 break;
4028
4029 case UNRES_WHEN:
4030 if ((rc = resolve_when(node, first, line))) {
4031 return rc;
4032 }
4033 break;
4034
Michal Vaskobf19d252015-10-08 15:39:17 +02004035 case UNRES_MUST:
4036 if ((rc = resolve_must(node, first, line))) {
4037 return rc;
4038 }
4039 break;
4040
Michal Vaskocf024702015-10-08 15:01:42 +02004041 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004042 LOGINT;
4043 return -1;
4044 }
4045
4046 return EXIT_SUCCESS;
4047}
4048
4049/**
4050 * @brief Try to resolve an unres data item. Logs indirectly.
4051 *
4052 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004053 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004054 * @param[in] line Line in the input file.
4055 *
4056 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4057 */
4058int
Michal Vaskocf024702015-10-08 15:01:42 +02004059unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004060{
4061 int rc;
4062
Michal Vaskobf19d252015-10-08 15:39:17 +02004063 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004064
Michal Vaskocf024702015-10-08 15:01:42 +02004065 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004066 if (rc != EXIT_FAILURE) {
4067 return rc;
4068 }
4069
Michal Vaskocf024702015-10-08 15:01:42 +02004070 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004071
4072 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004073 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4074 if (!unres->node) {
4075 LOGMEM;
4076 return -1;
4077 }
Michal Vaskocf024702015-10-08 15:01:42 +02004078 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004079 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4080 if (!unres->type) {
4081 LOGMEM;
4082 return -1;
4083 }
Michal Vaskocf024702015-10-08 15:01:42 +02004084 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004085#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004086 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4087 if (!unres->line) {
4088 LOGMEM;
4089 return -1;
4090 }
Michal Vaskocf024702015-10-08 15:01:42 +02004091 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004092#endif
4093
4094 return EXIT_SUCCESS;
4095}
4096
4097/**
4098 * @brief Resolve every unres data item in the structure. Logs directly.
4099 *
4100 * @param[in] unres Unres data structure to use.
4101 *
4102 * @return EXIT_SUCCESS on success, -1 on error.
4103 */
4104int
4105resolve_unres_data(struct unres_data *unres)
4106{
4107 uint32_t i;
4108 int rc;
4109
4110 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004111 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004112 if (rc) {
4113 LOGVAL(LYE_SPEC, 0, "There are unresolved data items left.");
4114 return -1;
4115 }
4116 }
4117
4118 return EXIT_SUCCESS;
4119}