blob: c99d2d918a7b20f4bd277b3bcead3b2476a11b64 [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 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001280 } else if (mod_name) {
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 */
1299 for (i = 0; i < module->inc_size; i++) {
1300 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 */
1467 if (check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, line)) {
1468 return -1;
1469 }
1470
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001471 return EXIT_SUCCESS;
1472
1473error:
1474
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001475 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001476}
1477
Michal Vasko730dfdf2015-08-11 14:48:05 +02001478/**
1479 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1480 *
Michal Vaskobb211122015-08-19 14:03:11 +02001481 * @param[in] uses The uses to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001482 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001483 * @param[in] line The line in the input file.
1484 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001485 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001486 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001487static int
Michal Vasko184521f2015-09-24 13:14:26 +02001488resolve_grouping(struct lys_node_uses *uses, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001489{
Michal Vasko1e62a092015-12-01 12:27:20 +01001490 const struct lys_module *module;
Radek Krejci2d5692b2015-10-31 23:12:16 +01001491 const char *mod_prefix, *name;
1492 int i, mod_prefix_len, nam_len;
Radek Krejci10c760e2015-08-14 14:45:43 +02001493 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001494
Michal Vasko58090902015-08-13 14:04:15 +02001495 /* parse the identifier, it must be parsed on one call */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001496 if ((i = parse_node_identifier(uses->name, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02001497 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001498 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001499 } else if (uses->name[i]) {
1500 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 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001503
Radek Krejci2d5692b2015-10-31 23:12:16 +01001504 if (mod_prefix) {
1505 module = lys_get_import_module(uses->module, mod_prefix, mod_prefix_len, NULL, 0);
Michal Vasko563ef092015-09-04 13:17:23 +02001506 if (!module) {
Radek Krejci2d5692b2015-10-31 23:12:16 +01001507 LOGVAL(LYE_INMOD_LEN, line, mod_prefix_len, mod_prefix);
Michal Vasko563ef092015-09-04 13:17:23 +02001508 return -1;
1509 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001510 start = module->data;
1511 } else {
Michal Vasko563ef092015-09-04 13:17:23 +02001512 start = (struct lys_node *)uses;
Michal Vasko2bdcca92015-08-17 16:00:45 +02001513 }
1514
Michal Vasko563ef092015-09-04 13:17:23 +02001515 uses->grp = lys_find_grouping_up(name, start, 1);
1516 if (uses->grp) {
1517 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001518 }
1519
Radek Krejci2d5692b2015-10-31 23:12:16 +01001520 if (mod_prefix || !first) {
Michal Vasko184521f2015-09-24 13:14:26 +02001521 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
1522 }
Michal Vasko563ef092015-09-04 13:17:23 +02001523 /* import must now be fully resolved */
Radek Krejci2d5692b2015-10-31 23:12:16 +01001524 if (mod_prefix) {
Michal Vasko563ef092015-09-04 13:17:23 +02001525 return -1;
1526 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001527 return EXIT_FAILURE;
1528}
1529
Michal Vasko730dfdf2015-08-11 14:48:05 +02001530/**
1531 * @brief Resolve (find) a feature definition. Logs directly.
1532 *
1533 * @param[in] name Feature name.
1534 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001535 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001536 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001537 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001538 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001539 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001540 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001541static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001542resolve_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 +02001543{
Michal Vasko2d851a92015-10-20 16:16:36 +02001544 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001545 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01001546 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001547
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001548 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001549 assert(module);
1550
1551 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001552 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001553 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1554 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001555 }
1556
Michal Vasko2d851a92015-10-20 16:16:36 +02001557 if (mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001558 /* search in imported modules */
Michal Vaskob6729c62015-10-21 12:09:47 +02001559 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001560 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001561 /* identity refers unknown data model */
Michal Vasko2d851a92015-10-20 16:16:36 +02001562 LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001563 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001564 }
1565 } else {
1566 /* search in submodules */
1567 for (i = 0; i < module->inc_size; i++) {
1568 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1569 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001570 if (ret) {
1571 *ret = &(module->inc[i].submodule->features[j]);
1572 }
1573 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001574 }
1575 }
1576 }
1577 }
1578
1579 /* search in the identified module */
1580 for (j = 0; j < module->features_size; j++) {
1581 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001582 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01001583 /* check status */
1584 node = (struct lys_node *)*ret;
1585 if (check_status(node->flags, node->module, node->name, module->features[j].flags,
1586 module->features[j].module, module->features[j].name, line)) {
1587 return -1;
1588 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001589 *ret = &module->features[j];
1590 }
1591 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001592 }
1593 }
1594
1595 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001596 if (!first) {
1597 LOGVAL(LYE_INRESOLV, line, "feature", id);
1598 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001599 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001600}
1601
Michal Vasko730dfdf2015-08-11 14:48:05 +02001602/**
Radek Krejci581ce772015-11-10 17:22:40 +01001603 * @brief Resolve (find) a data node based on a schema-nodeid.
1604 *
1605 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1606 * module).
1607 *
1608 */
1609struct lyd_node *
1610resolve_data_nodeid(const char *id, struct lyd_node *start)
1611{
1612 char *str, *token, *p;
1613 struct lyd_node *result = start, *iter;
Michal Vasko1e62a092015-12-01 12:27:20 +01001614 const struct lys_node *schema = NULL;
Radek Krejci581ce772015-11-10 17:22:40 +01001615
1616 assert(start);
1617 assert(id);
1618
1619 if (id[0] == '/') {
1620 return NULL;
1621 }
1622
1623 str = p = strdup(id);
Michal Vasko253035f2015-12-17 16:58:13 +01001624 if (!str) {
1625 LOGMEM;
1626 return NULL;
1627 }
Radek Krejci581ce772015-11-10 17:22:40 +01001628 while(p) {
1629 token = p;
1630 p = strchr(p, '/');
1631 if (p) {
1632 *p = '\0';
1633 p++;
1634 }
1635
1636 if (resolve_schema_nodeid(token, result->schema, result->schema->module, LYS_LEAF, &schema)) {
1637 free(str);
1638 return NULL;
1639 }
1640
1641 LY_TREE_FOR(result, iter) {
1642 if (iter->schema == schema) {
1643 break;
1644 }
1645 }
1646
1647 if (!p) {
1648 /* final result */
1649 result = iter;
1650 } else {
1651 result = iter->child;
1652 }
1653 }
1654 free(str);
1655
1656 return result;
1657}
1658
1659/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001660 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001661 *
Michal Vasko1be88302015-10-22 16:07:47 +02001662 * node_type - LYS_AUGMENT (searches also RPCs and notifications, augmented nodes are fine, too)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001663 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001664 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001665 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1666 *
Michal Vasko1be88302015-10-22 16:07:47 +02001667 * If \p id is absolute, \p start is ignored. If \p id is relative, \p start must be the first child to be searched
1668 * continuing with its siblings. Normally skips augments except \p node_type LYS_AUGMENT (augmenting an augment node).
Michal Vasko730dfdf2015-08-11 14:48:05 +02001669 *
Michal Vasko8afe75e2015-12-11 12:02:20 +01001670 * ASSUMPTION 1: Module to resolve prefixes (JSON module names) from never changes.
1671 * ASSUMPTION 2: Submodule belongs-to does not act as an import (main module definitions or anything else is not
1672 * available to the submodule).
1673 * ASSUMPTION 3: Module prefix (name) must be resolved only in absolute-schema-nodeid and only on the first
1674 * node. The prefix cannot further change except for nodes from an augment.
1675 *
Michal Vasko730dfdf2015-08-11 14:48:05 +02001676 * @param[in] id Schema-nodeid string.
1677 * @param[in] start Start of the relative search.
Michal Vaskobb211122015-08-19 14:03:11 +02001678 * @param[in] mod Module to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001679 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001680 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001681 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001682 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001683 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001684int
Michal Vasko1e62a092015-12-01 12:27:20 +01001685resolve_schema_nodeid(const char *id, const struct lys_node *start, const struct lys_module *mod, LYS_NODE node_type,
1686 const struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001687{
Michal Vasko8afe75e2015-12-11 12:02:20 +01001688 const char *name, *mod_name, *pref_mod_name;
Michal Vasko1e62a092015-12-01 12:27:20 +01001689 const struct lys_node *sibling;
Michal Vasko1be88302015-10-22 16:07:47 +02001690 int i, opts, nam_len, mod_name_len, is_relative = -1;
Michal Vasko8afe75e2015-12-11 12:02:20 +01001691 /* resolved import module from the start module, it must match the next node-name-match sibling */
1692 const struct lys_module *prefix_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001693 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1694 uint8_t in_submod = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001695
1696 assert(mod);
1697 assert(id);
1698
Michal Vasko723e50c2015-10-20 15:20:29 +02001699 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001700 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001701 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001702 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001703
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001704 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001705 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001706 }
1707
Michal Vasko1be88302015-10-22 16:07:47 +02001708 /* set options for lys_getnext() */
1709 opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT;
1710 if (node_type == LYS_USES) {
1711 opts |= LYS_GETNEXT_WITHGROUPING;
1712 }
1713
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001714 /* absolute-schema-nodeid */
1715 if (!is_relative) {
Michal Vasko723e50c2015-10-20 15:20:29 +02001716 if (mod_name) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001717 prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
1718 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001719 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001720 }
Michal Vasko8afe75e2015-12-11 12:02:20 +01001721 start = prefix_mod->data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001722 } else {
1723 start = mod->data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001724 }
1725 /* 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 */
Michal Vasko723e50c2015-10-20 15:20:29 +02001741 if (mod_name) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001742 prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
1743
Michal Vasko1be88302015-10-22 16:07:47 +02001744 if (!prefix_mod && (node_type == LYS_AUGMENT)) {
1745 /* we want augment nodes in this case */
1746 prefix_mod = sibling->module;
1747 if (prefix_mod->type) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001748 pref_mod_name = ((struct lys_submodule *)prefix_mod)->belongsto->name;
1749 } else {
1750 pref_mod_name = prefix_mod->name;
Michal Vasko1be88302015-10-22 16:07:47 +02001751 }
Michal Vasko8afe75e2015-12-11 12:02:20 +01001752 if (strncmp(pref_mod_name, mod_name, mod_name_len) || pref_mod_name[mod_name_len]) {
Michal Vasko1be88302015-10-22 16:07:47 +02001753 prefix_mod = NULL;
1754 }
1755 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001756 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001757 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001758 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001759 } else {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001760 prefix_mod = mod;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001761 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001762
Michal Vasko8afe75e2015-12-11 12:02:20 +01001763 /* modules need to always be checked, we want to skip augments (no other reason to check them) */
1764 if (prefix_mod != sibling->module) {
1765 if (in_submod) {
1766 if (prefix_mod->type) {
1767 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1768 }
1769 if (sibling->module->type) {
1770 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
1771 continue;
1772 }
1773 } else {
1774 if (prefix_mod != sibling->module) {
1775 continue;
1776 }
1777 }
1778 } else {
1779 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001780 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001781 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001782
Michal Vasko1e989c02015-08-04 12:33:00 +02001783 /* the result node? */
1784 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001785 /* we're looking only for groupings, this is a data node */
1786 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001787 continue;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001788 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001789 if (ret) {
1790 *ret = sibling;
1791 }
1792 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001793 }
1794
Michal Vaskodcc7a802015-08-06 11:59:47 +02001795 /* we're looking for a grouping (node_type == LYS_USES),
1796 * but this isn't it, we cannot search inside
1797 */
1798 if (sibling->nodetype == LYS_GROUPING) {
Michal Vasko8afe75e2015-12-11 12:02:20 +01001799 continue;
Michal Vaskodcc7a802015-08-06 11:59:47 +02001800 }
1801
Michal Vasko1e989c02015-08-04 12:33:00 +02001802 /* check for shorthand cases - then 'start' does not change */
1803 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1804 || (sibling->nodetype == LYS_CASE)) {
1805 start = sibling->child;
1806 }
1807 break;
1808 }
1809 }
1810
1811 /* we did not find the case in direct siblings */
1812 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001813 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001814 }
1815
1816 /* no match */
1817 if (!sibling) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001818 /* are we done with the included submodules as well? */
Michal Vasko8afe75e2015-12-11 12:02:20 +01001819 if (start->parent || (in_submod == mod->inc_size)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001820 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001821 }
1822
Michal Vasko1e989c02015-08-04 12:33:00 +02001823 /* we aren't, check the next one */
1824 ++in_submod;
Michal Vasko8afe75e2015-12-11 12:02:20 +01001825 start = mod->inc[in_submod-1].submodule->data;
Michal Vasko1e989c02015-08-04 12:33:00 +02001826 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001827 }
1828
Michal Vasko723e50c2015-10-20 15:20:29 +02001829 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001830 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001831 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001832 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001833 }
1834
1835 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001836 LOGINT;
1837 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001838}
1839
Michal Vasko23b61ec2015-08-19 11:19:50 +02001840/* ignores line */
1841static void
1842unres_data_del(struct unres_data *unres, uint32_t i)
1843{
1844 /* there are items after the one deleted */
1845 if (i+1 < unres->count) {
1846 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001847 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001848
1849 /* deleting the last item */
1850 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001851 free(unres->node);
1852 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001853 }
1854
1855 /* if there are no items after and it is not the last one, just move the counter */
1856 --unres->count;
1857}
1858
Michal Vasko0491ab32015-08-19 14:28:29 +02001859/**
1860 * @brief Resolve (find) a data node from a specific module. Does not log.
1861 *
1862 * @param[in] mod Module to search in.
1863 * @param[in] name Name of the data node.
1864 * @param[in] nam_len Length of the name.
1865 * @param[in] start Data node to start the search from.
1866 * @param[in,out] parents Resolved nodes. If there are some parents,
1867 * they are replaced (!!) with the resolvents.
1868 *
1869 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
1870 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001871static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001872resolve_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 +02001873{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001874 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001875 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001876 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001877
Michal Vasko23b61ec2015-08-19 11:19:50 +02001878 if (!parents->count) {
1879 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001880 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01001881 if (!parents->node) {
1882 LOGMEM;
1883 return EXIT_FAILURE;
1884 }
Michal Vaskocf024702015-10-08 15:01:42 +02001885 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001886 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001887 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02001888 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001889 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001890 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001891 continue;
1892 }
1893 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02001894 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001895 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1896 && node->schema->name[nam_len] == '\0') {
1897 /* matching target */
1898 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02001899 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02001900 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001901 flag = 1;
1902 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02001903 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001904 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01001905 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
1906 if (!parents->node) {
1907 return EXIT_FAILURE;
1908 }
Michal Vaskocf024702015-10-08 15:01:42 +02001909 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001910 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001911 }
1912 }
1913 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001914
1915 if (!flag) {
1916 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001917 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02001918 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001919 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02001920 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001921 }
1922
Michal Vasko0491ab32015-08-19 14:28:29 +02001923 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02001924}
1925
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001926/**
1927 * @brief Resolve (find) a data node. Does not log.
1928 *
Radek Krejci581ce772015-11-10 17:22:40 +01001929 * @param[in] mod_name Module name of the data node.
1930 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001931 * @param[in] name Name of the data node.
1932 * @param[in] nam_len Length of the name.
1933 * @param[in] start Data node to start the search from.
1934 * @param[in,out] parents Resolved nodes. If there are some parents,
1935 * they are replaced (!!) with the resolvents.
1936 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001937 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001938 */
Radek Krejcic5090c32015-08-12 09:46:19 +02001939static int
Radek Krejci581ce772015-11-10 17:22:40 +01001940resolve_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 +02001941 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02001942{
Michal Vasko1e62a092015-12-01 12:27:20 +01001943 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02001944 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02001945
Michal Vasko23b61ec2015-08-19 11:19:50 +02001946 assert(start);
1947
Michal Vasko31fc3672015-10-21 12:08:13 +02001948 if (mod_name) {
1949 /* we have mod_name, find appropriate module */
1950 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01001951 if (!str) {
1952 LOGMEM;
1953 return -1;
1954 }
Michal Vasko31fc3672015-10-21 12:08:13 +02001955 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
1956 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02001957 if (!mod) {
1958 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001959 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001960 }
1961 } else {
1962 /* no prefix, module is the same as of current node */
1963 mod = start->schema->module;
1964 }
1965
1966 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001967}
1968
Michal Vasko730dfdf2015-08-11 14:48:05 +02001969/**
Michal Vaskof39142b2015-10-21 11:40:05 +02001970 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02001971 * only specific errors, general no-resolvent error is left to the caller,
1972 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001973 *
Michal Vaskobb211122015-08-19 14:03:11 +02001974 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001975 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02001976 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001977 * @param[in,out] node_match Nodes satisfying the restriction
1978 * without the predicate. Nodes not
1979 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02001980 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001981 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001982 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001983 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001984static int
Michal Vasko184521f2015-09-24 13:14:26 +02001985resolve_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 +02001986{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001987 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001988 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001989 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02001990 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
1991 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001992 uint32_t j;
1993
1994 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001995 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01001996 if (!source_match.node) {
1997 LOGMEM;
1998 return -1;
1999 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002000 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002001 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002002 if (!dest_match.node) {
2003 LOGMEM;
2004 return -1;
2005 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002006
2007 do {
2008 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2009 &pke_len, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002010 LOGVAL(LYE_INCHAR, line, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002011 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002012 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002013 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002014 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002015 pred += i;
2016
Michal Vasko23b61ec2015-08-19 11:19:50 +02002017 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002018 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002019 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002020
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002021 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002022 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002023 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
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 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002033 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002034 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002035 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2036 &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;
2039 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002040 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002041 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002042 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002043 dest_match.node[0] = dest_match.node[0]->parent;
2044 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002045 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002046 if (!first) {
2047 LOGVAL(LYE_LINE, line);
2048 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002049 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002050 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002051 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002052 }
2053 }
2054 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002055 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002056 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002057 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002058 if ((rc == -1) || !first) {
2059 LOGVAL(LYE_LINE, line);
2060 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002061 i = 0;
2062 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002063 }
2064
2065 if (pke_len == pke_parsed) {
2066 break;
2067 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002068 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 +02002069 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002070 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002071 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002072 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002073 }
2074 pke_parsed += i;
2075 }
2076
2077 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002078 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2079 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002080 goto remove_leafref;
2081 }
2082
Michal Vasko83a6c462015-10-08 16:43:53 +02002083 if (((struct lyd_node_leaf_list *)source_match.node[0])->value_str
2084 != ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002085 goto remove_leafref;
2086 }
2087
2088 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002089 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002090 continue;
2091
2092remove_leafref:
2093 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002094 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002095 }
2096 } while (has_predicate);
2097
Michal Vaskocf024702015-10-08 15:01:42 +02002098 free(source_match.node);
2099 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002100 if (parsed) {
2101 *parsed = parsed_loc;
2102 }
2103 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002104
2105error:
2106
2107 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002108 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002109 }
2110 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002111 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002112 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002113 if (parsed) {
2114 *parsed = -parsed_loc+i;
2115 }
2116 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002117}
2118
Michal Vasko730dfdf2015-08-11 14:48:05 +02002119/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002120 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002121 *
Michal Vaskocf024702015-10-08 15:01:42 +02002122 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002123 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002124 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002125 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002126 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002127 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002128 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002129 */
Michal Vasko184521f2015-09-24 13:14:26 +02002130static int
Michal Vaskocf024702015-10-08 15:01:42 +02002131resolve_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 +02002132{
Radek Krejci71b795b2015-08-10 16:20:39 +02002133 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002135 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002136 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002137
Michal Vaskocf024702015-10-08 15:01:42 +02002138 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002139
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002140 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002141 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002142
2143 /* searching for nodeset */
2144 do {
2145 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002146 LOGVAL(LYE_INCHAR, line, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002147 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002148 goto error;
2149 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002150 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002151 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002152
Michal Vasko23b61ec2015-08-19 11:19:50 +02002153 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002154 if (parent_times != -1) {
2155 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002156 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002157 if (!ret->node) {
2158 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002159 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002160 goto error;
2161 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002162 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002163 for (i = 0; i < parent_times; ++i) {
2164 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002165 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166 /* error, too many .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002167 LOGVAL(LYE_INVAL, line, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002168 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002169 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002170 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002171 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002172 data = ret->node[0] = node->parent;
2173 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002174 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002175 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002176 free(ret->node);
2177 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002178 } else {
2179 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002180 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002181 }
2182 }
2183
2184 /* absolute path */
2185 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002186 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002187 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002188 if (data->prev) {
2189 for (; data->prev->next; data = data->prev);
2190 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002191 }
2192 }
2193
2194 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002195 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002196 if ((rc == -1) || !first) {
2197 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
2198 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002199 goto error;
2200 }
2201
2202 if (has_predicate) {
2203 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002204 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002205 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2206 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002207 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002208 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002209 continue;
2210 }
2211
2212 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002213 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002214 }
Michal Vasko184521f2015-09-24 13:14:26 +02002215 if ((rc = resolve_path_predicate_data(path, first, line, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002216 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002217 if ((rc == -1) || !first) {
2218 LOGVAL(LYE_NORESOLV, 0, path);
2219 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002220 goto error;
2221 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002222 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002223 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224
Michal Vasko23b61ec2015-08-19 11:19:50 +02002225 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002226 if (!first) {
2227 LOGVAL(LYE_NORESOLV, line, path-parsed);
2228 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002229 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002230 goto error;
2231 }
2232 }
2233 } while (path[0] != '\0');
2234
Michal Vaskof02e3742015-08-05 16:27:02 +02002235 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002236
2237error:
2238
Michal Vaskocf024702015-10-08 15:01:42 +02002239 free(ret->node);
2240 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002241 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002242
Michal Vasko0491ab32015-08-19 14:28:29 +02002243 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002244}
2245
Michal Vasko730dfdf2015-08-11 14:48:05 +02002246/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002247 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002248 *
Michal Vaskobb211122015-08-19 14:03:11 +02002249 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002250 * @param[in] source_node Left operand node.
2251 * @param[in] dest_node Right ooperand node.
Michal Vasko184521f2015-09-24 13:14:26 +02002252 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002253 * @param[in] line Line in the input file.
2254 *
Michal Vasko184521f2015-09-24 13:14:26 +02002255 * @return 0 on forward reference, otherwise the number
2256 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002257 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002258 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002259static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01002260resolve_path_predicate_schema(const char *path, const struct lys_node *source_node,
Michal Vasko184521f2015-09-24 13:14:26 +02002261 struct lys_node *dest_node, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002262{
Michal Vasko1e62a092015-12-01 12:27:20 +01002263 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002264 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2265 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 +02002266 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002267
2268 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002269 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002270 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002271 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002272 return -parsed+i;
2273 }
2274 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002275 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002276
Michal Vasko58090902015-08-13 14:04:15 +02002277 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002278 if (!sour_pref) {
2279 sour_pref = source_node->module->name;
2280 }
2281 rc = lys_get_sibling(source_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002282 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002283 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002284 if ((rc == -1) || !first) {
2285 LOGVAL(LYE_NORESOLV, line, path-parsed);
2286 }
2287 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002288 }
2289
2290 /* destination */
2291 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2292 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002293 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002294 return -parsed;
2295 }
2296 pke_parsed += i;
2297
2298 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2299 dst_node = dest_node;
2300 for (i = 1; i < dest_parent_times; ++i) {
2301 dst_node = dst_node->parent;
2302 if (!dst_node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002303 if (!first) {
2304 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2305 }
2306 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002307 }
2308 }
2309 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002310 if (!dest_pref) {
2311 dest_pref = dst_node->module->name;
2312 }
2313 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002314 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002315 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002316 if ((rc == -1) || !first) {
2317 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2318 }
2319 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002320 }
2321
2322 if (pke_len == pke_parsed) {
2323 break;
2324 }
2325
2326 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2327 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002328 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002329 return -parsed;
2330 }
2331 pke_parsed += i;
2332 }
2333
2334 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002335 if (dst_node->nodetype != LYS_LEAF) {
Michal Vaskod9173342015-08-17 14:35:36 +02002336 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002337 LOGVAL(LYE_SPEC, 0, "Destination node not a leaf, but %s.", strnodetype(dst_node->nodetype));
2338 return -parsed;
2339 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002340 } while (has_predicate);
2341
2342 return parsed;
2343}
2344
Michal Vasko730dfdf2015-08-11 14:48:05 +02002345/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002346 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002347 *
Michal Vaskobb211122015-08-19 14:03:11 +02002348 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002349 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002350 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2351 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002352 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002353 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002354 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002355 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002356 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002357 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002358static int
Radek Krejci2f12f852016-01-08 12:59:57 +01002359resolve_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 +01002360 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002361{
Michal Vasko1e62a092015-12-01 12:27:20 +01002362 const struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002363 const char *id, *prefix, *name;
2364 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002365 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002366
Michal Vasko184521f2015-09-24 13:14:26 +02002367 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002368 parent_times = 0;
2369 id = path;
2370
2371 do {
2372 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002373 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002374 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002375 }
2376 id += i;
2377
Michal Vasko184521f2015-09-24 13:14:26 +02002378 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002379 if (parent_times == -1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002380 node = parent_node->module->data;
Michal Vasko58090902015-08-13 14:04:15 +02002381 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002382 if (!first) {
2383 LOGVAL(LYE_NORESOLV, line, path);
2384 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002385 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002386 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002387 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002388 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002389 if (parent_tpdf) {
2390 /* the path is not allowed to contain relative path since we are in top level typedef */
2391 LOGVAL(LYE_NORESOLV, line, path);
2392 return -1;
2393 }
2394
Michal Vasko58090902015-08-13 14:04:15 +02002395 node = parent_node;
2396 i = 0;
2397 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002398 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002399 if (!first) {
2400 LOGVAL(LYE_NORESOLV, line, path);
2401 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002402 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002403 }
Michal Vasko58090902015-08-13 14:04:15 +02002404
2405 /* this node is a wrong node, we actually need the augment target */
2406 if (node->nodetype == LYS_AUGMENT) {
2407 node = ((struct lys_node_augment *)node)->target;
2408 if (!node) {
2409 continue;
2410 }
2411 }
2412
2413 ++i;
2414 if (i == parent_times) {
2415 break;
2416 }
2417 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002418 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002419
Michal Vasko1f76a282015-08-04 16:16:53 +02002420 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002421 } else {
2422 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002423 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002424 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002425
2426 if (!prefix) {
2427 prefix = parent_node->module->name;
2428 }
Michal Vasko184521f2015-09-24 13:14:26 +02002429 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002430 } else {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002431 if (!prefix) {
2432 prefix = node->module->name;
2433 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002434 node = node->child;
2435 }
2436
Michal Vasko36cbaa42015-12-14 13:15:48 +01002437 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 +02002438 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002439 if ((rc == -1) || !first) {
2440 LOGVAL(LYE_NORESOLV, line, path);
2441 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002442 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002443 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002444
2445 if (has_predicate) {
2446 /* we have predicate, so the current result must be list */
2447 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002448 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002449 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002450 }
2451
Michal Vasko36cbaa42015-12-14 13:15:48 +01002452 i = resolve_path_predicate_schema(id, node, parent_node, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002453 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002454 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002455 } else if (i < 0) {
2456 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002457 }
2458 id += i;
2459 }
2460 } while (id[0]);
2461
Radek Krejcib1c12512015-08-11 11:22:04 +02002462 /* the target must be leaf or leaf-list */
2463 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002464 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002465 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002466 }
2467
Radek Krejcicf509982015-12-15 09:22:44 +01002468 /* check status */
2469 if (check_status(parent_node->flags, parent_node->module, parent_node->name,
2470 node->flags, node->module, node->name, line)) {
2471 return -1;
2472 }
2473
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002474 if (ret) {
2475 *ret = node;
2476 }
2477 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002478}
2479
Michal Vasko730dfdf2015-08-11 14:48:05 +02002480/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002481 * @brief Resolve instance-identifier predicate in JSON data format.
2482 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002483 *
Michal Vaskobb211122015-08-19 14:03:11 +02002484 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002485 * @param[in,out] node_match Nodes matching the restriction without
2486 * the predicate. Nodes not satisfying
2487 * the predicate are removed.
2488 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002489 * @return Number of characters successfully parsed,
2490 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002491 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002492static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002493resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002494{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002495 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002496 struct unres_data target_match;
2497 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002498 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002499 const char *model, *name, *value;
2500 char *str;
2501 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2502 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002503
Michal Vasko1f2cc332015-08-19 11:18:32 +02002504 assert(pred && node_match->count);
2505
Michal Vaskocf024702015-10-08 15:01:42 +02002506 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002507 idx = -1;
2508 parsed = 0;
2509
2510 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002511 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002512 return -parsed+i;
2513 }
2514 parsed += i;
2515 pred += i;
2516
Michal Vasko1f2cc332015-08-19 11:18:32 +02002517 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002518 if (isdigit(name[0])) {
2519 idx = atoi(name);
2520 }
2521
Michal Vasko1f2cc332015-08-19 11:18:32 +02002522 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002524 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002525 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002526 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002527 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002528 if (!target_match.node) {
2529 LOGMEM;
2530 return -1;
2531 }
Michal Vaskocf024702015-10-08 15:01:42 +02002532 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002533 } else {
2534 str = strndup(model, mod_len);
2535 mod = ly_ctx_get_module(ctx, str, NULL);
2536 free(str);
2537
Michal Vaskocf024702015-10-08 15:01:42 +02002538 if (resolve_data(mod, name, nam_len, node_match->node[j], &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002539 goto remove_instid;
2540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002541 }
2542
2543 /* check that we have the correct type */
2544 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002545 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002546 goto remove_instid;
2547 }
2548 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002549 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002550 goto remove_instid;
2551 }
2552 }
2553
Michal Vasko83a6c462015-10-08 16:43:53 +02002554 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2555 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002556 || (!value && (idx != cur_idx))) {
2557 goto remove_instid;
2558 }
2559
Michal Vaskocf024702015-10-08 15:01:42 +02002560 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561
2562 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002563 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002564 continue;
2565
2566remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002567 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002568
2569 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002570 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002571 }
2572 } while (has_predicate);
2573
2574 return parsed;
2575}
2576
Michal Vasko730dfdf2015-08-11 14:48:05 +02002577/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002578 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002579 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002580 * @param[in] data Any node in the data tree, used to get a data tree root and context
Michal Vasko730dfdf2015-08-11 14:48:05 +02002581 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002582 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002583 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002584 * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002585 */
Michal Vasko184521f2015-09-24 13:14:26 +02002586static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002587resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002588{
Radek Krejcic5090c32015-08-12 09:46:19 +02002589 int i = 0, j;
2590 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002591 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002592 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002593 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002594 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002595 int mod_len, name_len, has_predicate;
2596 struct unres_data node_match;
2597 uint32_t k;
2598
2599 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002600
Radek Krejcic5090c32015-08-12 09:46:19 +02002601 /* we need root to resolve absolute path */
2602 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002603 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002604 if (data->prev) {
2605 for (; data->prev->next; data = data->prev);
2606 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002607
Radek Krejcic5090c32015-08-12 09:46:19 +02002608 /* search for the instance node */
2609 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002610 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002611 if (j <= 0) {
2612 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002613 goto error;
2614 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002615 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002616
Michal Vasko1f2cc332015-08-19 11:18:32 +02002617 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002618 if (!str) {
2619 LOGMEM;
2620 goto error;
2621 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002622 mod = ly_ctx_get_module(ctx, str, NULL);
2623 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002624
Radek Krejcic5090c32015-08-12 09:46:19 +02002625 if (!mod) {
2626 /* no instance exists */
2627 return NULL;
2628 }
2629
Michal Vasko1f2cc332015-08-19 11:18:32 +02002630 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002631 /* no instance exists */
2632 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002633 }
2634
2635 if (has_predicate) {
2636 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002637 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002638 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2639 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2640 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002642 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643 continue;
2644 }
2645
2646 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002647 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002648 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002649
Michal Vaskof39142b2015-10-21 11:40:05 +02002650 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002651 if (j < 1) {
2652 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002653 goto error;
2654 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002655 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002656
Michal Vasko1f2cc332015-08-19 11:18:32 +02002657 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002658 /* no instance exists */
2659 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002660 }
2661 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002662 }
2663
Michal Vasko1f2cc332015-08-19 11:18:32 +02002664 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002665 /* no instance exists */
2666 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002667 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002668 /* instance identifier must resolve to a single node */
2669 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2670
2671 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002672 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002673
2674 return NULL;
2675 } else {
2676 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002677 result = node_match.node[0];
2678 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002679
2680 return result;
2681 }
2682
2683error:
2684
2685 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002686 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002687
2688 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002689}
2690
Michal Vasko730dfdf2015-08-11 14:48:05 +02002691/**
2692 * @brief Passes config flag down to children. Does not log.
2693 *
2694 * @param[in] node Parent node.
2695 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002696static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002697inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002698{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002699 LY_TREE_FOR(node, node) {
2700 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2701 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002702 }
2703}
2704
Michal Vasko730dfdf2015-08-11 14:48:05 +02002705/**
Michal Vaskod9173342015-08-17 14:35:36 +02002706 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002707 *
Michal Vaskobb211122015-08-19 14:03:11 +02002708 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002709 * @param[in] siblings Nodes where to start the search in.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002710 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002711 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002712 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002713int
Michal Vasko1d87a922015-08-21 12:57:16 +02002714resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002715{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002716 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002717 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002718
Michal Vasko1d87a922015-08-21 12:57:16 +02002719 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002720
2721 /* resolve target node */
Michal Vasko1e62a092015-12-01 12:27:20 +01002722 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 +02002723 if (rc) {
2724 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002725 }
2726
2727 if (!aug->child) {
2728 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002729 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002730 return EXIT_SUCCESS;
2731 }
2732
2733 /* inherit config information from parent, augment does not have
2734 * config property, but we need to keep the information for subelements
2735 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002736 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002737 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002738 inherit_config_flag(sub);
2739 }
2740
Radek Krejci07911992015-08-14 15:13:31 +02002741 /* check identifier uniquness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02002742 LY_TREE_FOR(aug->child, sub) {
2743 if (lys_check_id(sub, aug->parent, aug->module)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002744 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002745 }
2746 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002747 /* reconnect augmenting data into the target - add them to the target child list */
2748 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002749 sub = aug->target->child->prev; /* remember current target's last node */
2750 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002751 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002752 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002753 } else {
2754 aug->target->child = aug->child;
2755 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002756
2757 return EXIT_SUCCESS;
2758}
2759
Michal Vasko730dfdf2015-08-11 14:48:05 +02002760/**
2761 * @brief Resolve uses, apply augments, refines. Logs directly.
2762 *
Michal Vaskobb211122015-08-19 14:03:11 +02002763 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002764 * @param[in,out] unres List of unresolved items.
2765 * @param[in] line Line in the input file.
2766 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002767 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002768 */
Michal Vasko184521f2015-09-24 13:14:26 +02002769static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002770resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771{
2772 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002773 struct lys_node *node = NULL;
2774 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002775 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002776 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002777 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002778 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002779
Michal Vasko71e1aa82015-08-12 12:17:51 +02002780 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002781 /* HACK just check that the grouing is resolved */
2782 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002783
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01002785 LY_TREE_FOR(uses->grp->child, node_aux) {
2786 node = lys_node_dup(uses->module, node_aux, uses->flags, uses->nacm, 1, unres);
2787 if (!node) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002788 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002789 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790 }
Michal Vasko1e62a092015-12-01 12:27:20 +01002791 if (lys_node_addchild((struct lys_node *)uses, NULL, node)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002792 /* error logged */
Michal Vasko1e62a092015-12-01 12:27:20 +01002793 lys_node_free(node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002794 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002795 }
2796 }
2797 ctx = uses->module->ctx;
2798
Michal Vaskodef0db12015-10-07 13:22:48 +02002799 /* we managed to copy the grouping, the rest must be possible to resolve */
2800
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002801 /* apply refines */
2802 for (i = 0; i < uses->refine_size; i++) {
2803 rfn = &uses->refine[i];
Michal Vasko1e62a092015-12-01 12:27:20 +01002804 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF,
2805 (const struct lys_node **)&node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002806 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002807 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2808 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002809 }
2810
Radek Krejci1d82ef62015-08-07 14:44:40 +02002811 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002812 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002813 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002814 }
2815
2816 /* description on any nodetype */
2817 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002818 lydict_remove(ctx, node->dsc);
2819 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002820 }
2821
2822 /* reference on any nodetype */
2823 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002824 lydict_remove(ctx, node->ref);
2825 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002826 }
2827
2828 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002829 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002830 node->flags &= ~LYS_CONFIG_MASK;
2831 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002832 }
2833
2834 /* default value ... */
2835 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002836 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002837 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002838 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2839 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2840 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 /* choice */
Michal Vasko1e62a092015-12-01 12:27:20 +01002842 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE,
2843 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002844 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002845 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2846 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847 }
2848 }
2849 }
2850
2851 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002852 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002853 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002854 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002855 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002856
2857 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002858 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002859 }
2860 }
2861
2862 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002863 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2864 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2865 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 }
2867
2868 /* min/max-elements on list or leaf-list */
2869 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002870 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002871 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002872 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 }
2874 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002875 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002876 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002877 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002879 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 }
2881 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002882 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 }
2884 }
2885
2886 /* must in leaf, leaf-list, list, container or anyxml */
2887 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002888 switch (node->nodetype) {
2889 case LYS_LEAF:
2890 old_size = &((struct lys_node_leaf *)node)->must_size;
2891 old_must = &((struct lys_node_leaf *)node)->must;
2892 break;
2893 case LYS_LEAFLIST:
2894 old_size = &((struct lys_node_leaflist *)node)->must_size;
2895 old_must = &((struct lys_node_leaflist *)node)->must;
2896 break;
2897 case LYS_LIST:
2898 old_size = &((struct lys_node_list *)node)->must_size;
2899 old_must = &((struct lys_node_list *)node)->must;
2900 break;
2901 case LYS_CONTAINER:
2902 old_size = &((struct lys_node_container *)node)->must_size;
2903 old_must = &((struct lys_node_container *)node)->must;
2904 break;
2905 case LYS_ANYXML:
2906 old_size = &((struct lys_node_anyxml *)node)->must_size;
2907 old_must = &((struct lys_node_anyxml *)node)->must;
2908 break;
2909 default:
2910 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02002911 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002912 }
2913
2914 size = *old_size + rfn->must_size;
2915 must = realloc(*old_must, size * sizeof *rfn->must);
2916 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002918 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002919 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002920 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
2921 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2922 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2923 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2924 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2925 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926 }
2927
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002928 *old_must = must;
2929 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930 }
2931 }
2932
2933 /* apply augments */
2934 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002935 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002936 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002937 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
2938 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939 }
2940 }
2941
2942 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002943}
2944
Michal Vasko730dfdf2015-08-11 14:48:05 +02002945/**
2946 * @brief Resolve base identity recursively. Does not log.
2947 *
2948 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002949 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002950 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002951 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002952 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002953 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002954 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002955static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002956resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002957 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002958{
Michal Vaskof02e3742015-08-05 16:27:02 +02002959 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002960 struct lys_ident *base_iter = NULL;
2961 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002962
Radek Krejcicf509982015-12-15 09:22:44 +01002963 assert(ret);
2964
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002965 /* search module */
2966 for (i = 0; i < module->ident_size; i++) {
2967 if (!strcmp(basename, module->ident[i].name)) {
2968
2969 if (!ident) {
2970 /* just search for type, so do not modify anything, just return
2971 * the base identity pointer
2972 */
Radek Krejcicf509982015-12-15 09:22:44 +01002973 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002974 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002975 }
2976
2977 /* we are resolving identity definition, so now update structures */
2978 ident->base = base_iter = &module->ident[i];
2979
2980 break;
2981 }
2982 }
2983
2984 /* search submodules */
2985 if (!base_iter) {
2986 for (j = 0; j < module->inc_size; j++) {
2987 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2988 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2989
2990 if (!ident) {
Radek Krejcicf509982015-12-15 09:22:44 +01002991 *ret = &module->inc[j].submodule->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002992 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002993 }
2994
2995 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2996 break;
2997 }
2998 }
2999 }
3000 }
3001
3002 /* we found it somewhere */
3003 if (base_iter) {
3004 while (base_iter) {
3005 for (der = base_iter->der; der && der->next; der = der->next);
3006 if (der) {
3007 der->next = malloc(sizeof *der);
3008 der = der->next;
3009 } else {
3010 ident->base->der = der = malloc(sizeof *der);
3011 }
Michal Vasko253035f2015-12-17 16:58:13 +01003012 if (!der) {
3013 LOGMEM;
3014 return EXIT_FAILURE;
3015 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003016 der->next = NULL;
3017 der->ident = ident;
3018
3019 base_iter = base_iter->base;
3020 }
Radek Krejcicf509982015-12-15 09:22:44 +01003021 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003022 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003023 }
3024
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003025 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003026}
3027
Michal Vasko730dfdf2015-08-11 14:48:05 +02003028/**
3029 * @brief Resolve base identity. Logs directly.
3030 *
3031 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003032 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003033 * @param[in] basename Base name of the identity.
3034 * @param[in] parent Either "type" or "ident".
Michal Vasko184521f2015-09-24 13:14:26 +02003035 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003036 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003037 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003038 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003039 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003040 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003041static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003042resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003043 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003044{
3045 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003046 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003047 struct lys_ident *target, **ret;
3048 uint8_t flags;
3049 struct lys_module *mod;
3050
3051 assert((ident && !type) || (!ident && type));
3052
3053 if (!type) {
3054 /* have ident to resolve */
3055 ret = &target;
3056 flags = ident->flags;
3057 mod = ident->module;
3058 } else {
3059 /* have type to fill */
3060 ret = &type->info.ident.ref;
3061 flags = type->parent->flags;
3062 mod = type->parent->module;
3063 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003064
3065 /* search for the base identity */
3066 name = strchr(basename, ':');
3067 if (name) {
3068 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003069 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003070 name++;
3071
Michal Vasko2d851a92015-10-20 16:16:36 +02003072 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003074 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003075 }
3076 } else {
3077 name = basename;
3078 }
3079
Michal Vasko2d851a92015-10-20 16:16:36 +02003080 if (mod_name_len) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02003082 module = lys_get_import_module(module, NULL, 0, basename, mod_name_len);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003083 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003084 /* identity refers unknown data model */
Michal Vasko1dca6882015-10-22 14:29:42 +02003085 LOGVAL(LYE_INMOD, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003086 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087 }
3088 } else {
3089 /* search in submodules */
3090 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003091 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003092 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003093 }
3094 }
3095 }
3096
3097 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003098 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003099 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003100 }
3101
Michal Vasko184521f2015-09-24 13:14:26 +02003102 if (!first) {
3103 LOGVAL(LYE_INARG, line, basename, parent);
3104 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003105 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003106
3107success:
3108 /* check status */
3109 if (check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name, line)) {
3110 return -1;
3111 }
3112
3113 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003114}
3115
Michal Vasko730dfdf2015-08-11 14:48:05 +02003116/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003117 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003118 *
3119 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003120 * @param[in] ident_name Identityref name.
3121 * @param[in] line Line from the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003122 *
3123 * @return Pointer to the identity resolvent, NULL on error.
3124 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003125struct lys_ident *
Michal Vaskof39142b2015-10-21 11:40:05 +02003126resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003128 const char *mod_name, *name;
3129 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003130 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003131
Michal Vaskofb0873c2015-08-21 09:00:07 +02003132 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003133 return NULL;
3134 }
3135
Michal Vaskoc633ca02015-08-21 14:03:51 +02003136 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003137 if (rc < (signed)strlen(ident_name)) {
3138 LOGVAL(LYE_INCHAR, line, ident_name[-rc], &ident_name[-rc]);
3139 return NULL;
3140 }
3141
Michal Vaskoc633ca02015-08-21 14:03:51 +02003142 if (!strcmp(base->name, name) && (!mod_name
3143 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003144 return base;
3145 }
3146
3147 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003148 if (!strcmp(der->ident->name, name) && (!mod_name
3149 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3150 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151 /* we have match */
3152 return der->ident;
3153 }
3154 }
3155
Michal Vaskofb0873c2015-08-21 09:00:07 +02003156 LOGVAL(LYE_INRESOLV, line, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003157 return NULL;
3158}
3159
Michal Vasko730dfdf2015-08-11 14:48:05 +02003160/**
Michal Vasko7955b362015-09-04 14:18:15 +02003161 * @brief Resolve (find) choice default case. Does not log.
3162 *
3163 * @param[in] choic Choice to use.
3164 * @param[in] dflt Name of the default case.
3165 *
3166 * @return Pointer to the default node or NULL.
3167 */
3168static struct lys_node *
3169resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3170{
3171 struct lys_node *child, *ret;
3172
3173 LY_TREE_FOR(choic->child, child) {
3174 if (child->nodetype == LYS_USES) {
3175 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3176 if (ret) {
3177 return ret;
3178 }
3179 }
3180
3181 if ((child->name == dflt) && (child->nodetype & (LYS_ANYXML | LYS_CASE
3182 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3183 return child;
3184 }
3185 }
3186
3187 return NULL;
3188}
3189
3190/**
Michal Vaskobb211122015-08-19 14:03:11 +02003191 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003192 *
Michal Vaskobb211122015-08-19 14:03:11 +02003193 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003194 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003195 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003196 * @param[in] line Line in the input file.
3197 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003199 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003201resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003203 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003204 struct lys_node *parent;
3205
3206 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3207 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3208
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003209 if (!uses->grp) {
Michal Vasko184521f2015-09-24 13:14:26 +02003210 rc = resolve_grouping(uses, first, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003211 if (rc) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003212 if (parent && first && (rc == EXIT_FAILURE)) {
3213 ++parent->nacm;
3214 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003215 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003216 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 }
3218
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003219 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003220 if (parent && first) {
3221 ++parent->nacm;
3222 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003223 return EXIT_FAILURE;
3224 }
3225
Michal Vaskodef0db12015-10-07 13:22:48 +02003226 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003227 if (!rc) {
3228 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003229 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003230 if (!parent->nacm) {
3231 LOGINT;
3232 return -1;
3233 }
3234 --parent->nacm;
3235 }
Radek Krejcicf509982015-12-15 09:22:44 +01003236
3237 /* check status */
3238 if (check_status(uses->flags, uses->module, "of uses",
3239 uses->grp->flags, uses->grp->module, uses->grp->name, line)) {
3240 return -1;
3241 }
3242
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003243 return EXIT_SUCCESS;
3244 }
3245
Michal Vasko407f1bb2015-09-23 15:51:07 +02003246 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003247 ++parent->nacm;
3248 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003249 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250}
3251
Michal Vasko730dfdf2015-08-11 14:48:05 +02003252/**
Michal Vasko9957e592015-08-17 15:04:09 +02003253 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003254 *
Michal Vaskobb211122015-08-19 14:03:11 +02003255 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003256 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003257 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003258 * @param[in] line Line in the input file.
3259 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003260 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003261 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003263resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003265 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 const char *value;
3267
3268 for (i = 0; i < list->keys_size; ++i) {
3269 /* get the key name */
3270 if ((value = strpbrk(keys_str, " \t\n"))) {
3271 len = value - keys_str;
3272 while (isspace(value[0])) {
3273 value++;
3274 }
3275 } else {
3276 len = strlen(keys_str);
3277 }
3278
Michal Vasko36cbaa42015-12-14 13:15:48 +01003279 rc = lys_get_sibling(list->child, list->module->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003280 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003281 if ((rc == -1) || !first) {
3282 LOGVAL(LYE_INRESOLV, line, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003283 }
3284 return rc;
3285 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003287 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003288 /* check_key logs */
3289 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003290 }
3291
Radek Krejcicf509982015-12-15 09:22:44 +01003292 /* check status */
3293 if (check_status(list->flags, list->module, list->name,
3294 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name, line)) {
3295 return -1;
3296 }
3297
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298 /* prepare for next iteration */
3299 while (value && isspace(value[0])) {
3300 value++;
3301 }
3302 keys_str = value;
3303 }
3304
Michal Vaskof02e3742015-08-05 16:27:02 +02003305 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003306}
3307
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003308/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003309 * @brief Resolve (check) all must conditions of \p node.
3310 * Logs directly.
3311 *
3312 * @param[in] node Data node with optional must statements.
3313 * @param[in] first Whether this is the first resolution to try.
3314 * @param[in] line Line in the input file.
3315 *
3316 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3317 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003319resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003320{
Michal Vaskobf19d252015-10-08 15:39:17 +02003321 uint8_t i, must_size;
3322 struct lys_restr *must;
3323 struct lyxp_set set;
3324
3325 assert(node);
3326 memset(&set, 0, sizeof set);
3327
3328 switch (node->schema->nodetype) {
3329 case LYS_CONTAINER:
3330 must_size = ((struct lys_node_container *)node->schema)->must_size;
3331 must = ((struct lys_node_container *)node->schema)->must;
3332 break;
3333 case LYS_LEAF:
3334 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3335 must = ((struct lys_node_leaf *)node->schema)->must;
3336 break;
3337 case LYS_LEAFLIST:
3338 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3339 must = ((struct lys_node_leaflist *)node->schema)->must;
3340 break;
3341 case LYS_LIST:
3342 must_size = ((struct lys_node_list *)node->schema)->must_size;
3343 must = ((struct lys_node_list *)node->schema)->must;
3344 break;
3345 case LYS_ANYXML:
3346 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3347 must = ((struct lys_node_anyxml *)node->schema)->must;
3348 break;
3349 default:
3350 must_size = 0;
3351 break;
3352 }
3353
3354 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003355 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003356 return -1;
3357 }
3358
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003359 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003360
3361 if (!set.value.bool) {
3362 if (!first) {
3363 LOGVAL(LYE_NOCOND, line, "Must", must[i].expr);
3364 }
3365 return 1;
3366 }
3367 }
3368
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003370}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371
Michal Vaskobf19d252015-10-08 15:39:17 +02003372/**
Michal Vaskocf024702015-10-08 15:01:42 +02003373 * @brief Resolve (find) when condition context node. Does not log.
3374 *
3375 * @param[in] node Data node, whose conditional definition is being decided.
3376 * @param[in] schema Schema node with a when condition.
3377 *
3378 * @return Context node.
3379 */
3380static struct lyd_node *
3381resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382{
Michal Vaskocf024702015-10-08 15:01:42 +02003383 struct lyd_node *parent;
3384 struct lys_node *sparent;
3385 uint16_t i, data_depth, schema_depth;
3386
3387 /* find a not schema-only node */
3388 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3389 schema = lys_parent(schema);
3390 if (!schema) {
3391 return NULL;
3392 }
3393 }
3394
3395 /* get node depths */
3396 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3397 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3398 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3399 ++schema_depth;
3400 }
3401 }
3402 if (data_depth < schema_depth) {
3403 return NULL;
3404 }
3405
3406 /* find the corresponding data node */
3407 for (i = 0; i < data_depth - schema_depth; ++i) {
3408 node = node->parent;
3409 }
3410 if (node->schema != schema) {
3411 return NULL;
3412 }
3413
3414 return node;
3415}
3416
3417/**
3418 * @brief Resolve (check) all when conditions relevant for \p node.
3419 * Logs directly.
3420 *
3421 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3422 * @param[in] first Whether this is the first resolution to try.
3423 * @param[in] line Line in the input file.
3424 *
3425 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3426 */
3427static int
3428resolve_when(struct lyd_node *node, int first, uint32_t line)
3429{
3430 struct lyd_node *ctx_node = NULL;
3431 struct lys_node *parent;
3432 struct lyxp_set set;
3433
3434 assert(node);
3435 memset(&set, 0, sizeof set);
3436
3437 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003438 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003439 return -1;
3440 }
3441
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003442 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003443
3444 if (!set.value.bool) {
3445 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003446 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003447 }
3448 return 1;
3449 }
3450 }
3451
3452 parent = node->schema;
3453 goto check_augment;
3454
3455 /* check when in every schema node that affects node */
3456 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3457 if (((struct lys_node_uses *)parent)->when) {
3458 if (!ctx_node) {
3459 ctx_node = resolve_when_ctx_node(node, parent);
3460 if (!ctx_node) {
3461 LOGINT;
3462 return -1;
3463 }
3464 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003465 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003466 return -1;
3467 }
3468
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003469 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003470
3471 if (!set.value.bool) {
3472 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003473 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003474 }
3475 return 1;
3476 }
3477 }
3478
3479check_augment:
3480 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3481 if (!ctx_node) {
3482 ctx_node = resolve_when_ctx_node(node, parent->parent);
3483 if (!ctx_node) {
3484 LOGINT;
3485 return -1;
3486 }
3487 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003488 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003489 return -1;
3490 }
3491
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003492 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003493
3494 if (!set.value.bool) {
3495 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003496 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003497 }
3498 return 1;
3499 }
3500 }
3501
3502 parent = lys_parent(parent);
3503 }
3504
3505 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506}
3507
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508/**
Michal Vaskobb211122015-08-19 14:03:11 +02003509 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003510 *
3511 * @param[in] mod Main module.
3512 * @param[in] item Item to resolve. Type determined by \p type.
3513 * @param[in] type Type of the unresolved item.
3514 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003515 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003516 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003517 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003518 *
3519 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3520 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003521static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003522resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003523 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524{
Radek Krejci2f12f852016-01-08 12:59:57 +01003525 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003526 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003527 const char *base_name;
3528
3529 struct lys_ident *ident;
3530 struct lys_type *stype;
3531 struct lys_feature **feat_ptr;
3532 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003533 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534
3535 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003537 base_name = str_snode;
3538 ident = item;
3539
Michal Vasko184521f2015-09-24 13:14:26 +02003540 rc = resolve_base_ident(mod, ident, base_name, "ident", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 has_str = 1;
3542 break;
3543 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003544 base_name = str_snode;
3545 stype = item;
3546
Radek Krejcicf509982015-12-15 09:22:44 +01003547 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003548 has_str = 1;
3549 break;
3550 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003551 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003552 stype = item;
3553
Radek Krejci2f12f852016-01-08 12:59:57 +01003554 /* HACK - when there is no parent, we are in top level typedef and in that
3555 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3556 * know it via tpdf_flag */
3557 if (!node) {
3558 tpdf_flag = 1;
3559 node = (struct lys_node *)stype->parent;
3560 }
3561
3562 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003563 (const struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564 has_str = 0;
3565 break;
3566 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003567 /* parent */
3568 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003569 stype = item;
3570
Michal Vasko88c29542015-11-27 14:57:53 +01003571 /* HACK type->der is temporarily unparsed type statement */
3572 yin = (struct lyxml_elem *)stype->der;
3573 stype->der = NULL;
3574
3575 rc = fill_yin_type(mod, node, yin, stype, unres);
3576 if (!rc) {
3577 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01003578 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01003579 } else {
3580 /* may try again later, put all back how it was */
3581 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003582 }
Michal Vasko88c29542015-11-27 14:57:53 +01003583 has_str = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003584 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003585 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003586 base_name = str_snode;
3587 feat_ptr = item;
3588
Michal Vasko184521f2015-09-24 13:14:26 +02003589 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003590 has_str = 1;
3591 break;
3592 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003593 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594 has_str = 0;
3595 break;
3596 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003597 base_name = str_snode;
3598 stype = item;
3599
Michal Vasko1dca6882015-10-22 14:29:42 +02003600 rc = check_default(stype, base_name, first, line);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003601 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003602 has_str = 0;
3603 break;
3604 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003605 base_name = str_snode;
3606 choic = item;
3607
Michal Vasko7955b362015-09-04 14:18:15 +02003608 choic->dflt = resolve_choice_dflt(choic, base_name);
3609 if (choic->dflt) {
3610 rc = EXIT_SUCCESS;
3611 } else {
3612 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003613 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003614 has_str = 1;
3615 break;
3616 case UNRES_LIST_KEYS:
Michal Vasko36cbaa42015-12-14 13:15:48 +01003617 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003618 has_str = 1;
3619 break;
3620 case UNRES_LIST_UNIQ:
Radek Krejci581ce772015-11-10 17:22:40 +01003621 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003622 has_str = 1;
3623 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003624 default:
3625 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003626 break;
3627 }
3628
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003629 if (has_str && !rc) {
3630 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003631 }
3632
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003633 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003634}
3635
Michal Vaskof02e3742015-08-05 16:27:02 +02003636/* logs directly */
3637static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003638print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639{
Michal Vaskof02e3742015-08-05 16:27:02 +02003640 char line_str[18];
3641
3642 if (line) {
3643 sprintf(line_str, " (line %u)", line);
3644 } else {
3645 line_str[0] = '\0';
3646 }
3647
3648 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003649 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003650 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003651 break;
3652 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003653 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003654 break;
3655 case UNRES_TYPE_LEAFREF:
3656 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3657 break;
3658 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003659 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
3660 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003661 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003662 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003663 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 +02003664 break;
3665 case UNRES_USES:
3666 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3667 break;
3668 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003669 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 +02003670 break;
3671 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003672 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 +02003673 break;
3674 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003675 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 +02003676 break;
3677 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003678 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 +02003679 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003680 default:
3681 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003682 break;
3683 }
3684}
3685
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003686/**
Michal Vaskobb211122015-08-19 14:03:11 +02003687 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003688 *
3689 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003690 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003691 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003692 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003693 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003694int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003695resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003696{
Michal Vasko88c29542015-11-27 14:57:53 +01003697 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003698 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003699
3700 assert(unres);
3701
Michal Vasko51054ca2015-08-12 12:20:00 +02003702 resolved = 0;
3703
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003704 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003705 do {
Michal Vasko88c29542015-11-27 14:57:53 +01003706 unres_count = 0;
3707 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003708
3709 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01003710 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
3711 * we need every type's base only */
3712 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003713 continue;
3714 }
3715
Michal Vasko88c29542015-11-27 14:57:53 +01003716 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003717 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3718 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003719 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003720 unres->type[i] = UNRES_RESOLVED;
3721 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01003722 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02003723 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003724 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003725 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726 }
Michal Vasko88c29542015-11-27 14:57:53 +01003727 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02003728
Michal Vasko88c29542015-11-27 14:57:53 +01003729 if (res_count < unres_count) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003730 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003731 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003732 }
3733
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003734 /* the rest */
3735 for (i = 0; i < unres->count; ++i) {
3736 if (unres->type[i] == UNRES_RESOLVED) {
3737 continue;
3738 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003739
Michal Vasko407f1bb2015-09-23 15:51:07 +02003740 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3741 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003742 if (rc) {
3743 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003744 }
Michal Vasko184521f2015-09-24 13:14:26 +02003745
3746 unres->type[i] = UNRES_RESOLVED;
3747 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003748 }
3749
3750 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003751 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3752 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003753 }
3754
3755 return EXIT_SUCCESS;
3756}
3757
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003758/**
Michal Vaskobb211122015-08-19 14:03:11 +02003759 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003760 *
3761 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003762 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003763 * @param[in] item Item to resolve. Type determined by \p type.
3764 * @param[in] type Type of the unresolved item.
3765 * @param[in] str String argument.
3766 * @param[in] line Line in the input file.
3767 *
3768 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3769 */
3770int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003771unres_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 +02003772 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003773{
3774 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003775 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003776}
3777
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003778/**
Michal Vaskobb211122015-08-19 14:03:11 +02003779 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003780 *
3781 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003782 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003783 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01003784 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003785 * @param[in] snode Schema node argument.
3786 * @param[in] line Line in the input file.
3787 *
3788 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3789 */
3790int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003791unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003792 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003793{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003794 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01003795 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003796
Michal Vasko9bf425b2015-10-22 11:42:03 +02003797 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
3798 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003799
Michal Vasko184521f2015-09-24 13:14:26 +02003800 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003801 if (rc != EXIT_FAILURE) {
3802 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803 }
3804
Michal Vasko0bd29d12015-08-19 11:45:49 +02003805 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003806
Michal Vasko88c29542015-11-27 14:57:53 +01003807 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
3808 if (type == UNRES_TYPE_DER) {
3809 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
3810 lyxml_unlink_elem(mod->ctx, yin, 1);
3811 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
3812 }
3813
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003814 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01003815 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
3816 if (!unres->item) {
3817 LOGMEM;
3818 return -1;
3819 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003820 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01003821 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
3822 if (!unres->type) {
3823 LOGMEM;
3824 return -1;
3825 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003826 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01003827 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
3828 if (!unres->str_snode) {
3829 LOGMEM;
3830 return -1;
3831 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003832 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003833#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01003834 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
3835 if (!unres->line) {
3836 LOGMEM;
3837 return -1;
3838 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003839 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003840#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003841
3842 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003843}
3844
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003845/**
Michal Vaskobb211122015-08-19 14:03:11 +02003846 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003847 *
3848 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003849 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003850 * @param[in] item Old item to be resolved.
3851 * @param[in] type Type of the old unresolved item.
3852 * @param[in] new_item New item to use in the duplicate.
3853 *
3854 * @return EXIT_SUCCESS on success, -1 on error.
3855 */
Michal Vaskodad19402015-08-06 09:51:53 +02003856int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003857unres_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 +02003858{
3859 int i;
3860
Michal Vaskocf024702015-10-08 15:01:42 +02003861 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003862
Michal Vasko0bd29d12015-08-19 11:45:49 +02003863 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003864
3865 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003866 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003867 }
3868
Michal Vasko0d204592015-10-07 09:50:04 +02003869 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003870 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003871 LOGINT;
3872 return -1;
3873 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003874 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003875 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003876 LOGINT;
3877 return -1;
3878 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003879 }
Michal Vaskodad19402015-08-06 09:51:53 +02003880
3881 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003882}
3883
Michal Vaskof02e3742015-08-05 16:27:02 +02003884/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003885int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003886unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003887{
3888 uint32_t ret = -1, i;
3889
3890 for (i = 0; i < unres->count; ++i) {
3891 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3892 ret = i;
3893 break;
3894 }
3895 }
3896
3897 return ret;
3898}
Michal Vasko8bcdf292015-08-19 14:04:43 +02003899
Michal Vasko88c29542015-11-27 14:57:53 +01003900void
3901unres_schema_free(struct ly_ctx *ctx, struct unres_schema *unres)
3902{
3903 uint32_t i;
3904
3905 for (i = 0; i < unres->count; ++i) {
3906 if (unres->type[i] == UNRES_TYPE_DER) {
Michal Vasko345da0a2015-12-02 10:35:55 +01003907 lyxml_free(ctx, (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der);
Michal Vasko88c29542015-11-27 14:57:53 +01003908 }
3909 }
3910
3911 free(unres->item);
3912 free(unres->type);
3913 free(unres->str_snode);
3914#ifndef NDEBUG
3915 free(unres->line);
3916#endif
3917 free(unres);
3918}
3919
Michal Vasko8bcdf292015-08-19 14:04:43 +02003920/* logs directly */
3921static void
Michal Vaskocf024702015-10-08 15:01:42 +02003922print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003923{
3924 struct lys_node_leaf *sleaf;
3925 char line_str[18];
3926
3927 if (line) {
3928 sprintf(line_str, " (line %u)", line);
3929 } else {
3930 line_str[0] = '\0';
3931 }
3932
Michal Vaskocf024702015-10-08 15:01:42 +02003933 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003934
Michal Vaskocf024702015-10-08 15:01:42 +02003935 switch (type) {
3936 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003937 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
3938 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003939 break;
3940 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003941 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02003942 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003943 break;
3944 case UNRES_WHEN:
3945 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
3946 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02003947 case UNRES_MUST:
3948 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
3949 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003950 default:
3951 LOGINT;
3952 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003953 }
3954}
3955
3956/**
3957 * @brief Resolve a single unres data item. Logs directly.
3958 *
Michal Vaskocf024702015-10-08 15:01:42 +02003959 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02003960 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02003961 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02003962 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003963 *
3964 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3965 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02003966int
Michal Vaskocf024702015-10-08 15:01:42 +02003967resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003968{
3969 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02003970 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02003971 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003972 struct lys_node_leaf *sleaf;
3973 struct unres_data matches;
3974
3975 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02003976 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02003977 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003978
Michal Vaskocf024702015-10-08 15:01:42 +02003979 switch (type) {
3980 case UNRES_LEAFREF:
3981 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02003982 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003983 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003984 }
3985
3986 /* check that value matches */
3987 for (i = 0; i < matches.count; ++i) {
Michal Vasko83a6c462015-10-08 16:43:53 +02003988 if (leaf->value_str == ((struct lyd_node_leaf_list *)matches.node[i])->value_str) {
Michal Vaskocf024702015-10-08 15:01:42 +02003989 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02003990 break;
3991 }
3992 }
3993
Michal Vaskocf024702015-10-08 15:01:42 +02003994 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003995 memset(&matches, 0, sizeof matches);
3996
Michal Vaskocf024702015-10-08 15:01:42 +02003997 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003998 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02003999 if (!first) {
4000 LOGVAL(LYE_SPEC, line, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02004001 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004002 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004003 return EXIT_FAILURE;
4004 }
Michal Vaskocf024702015-10-08 15:01:42 +02004005 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004006
Michal Vaskocf024702015-10-08 15:01:42 +02004007 case UNRES_INSTID:
4008 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004009 ly_errno = 0;
Michal Vaskof39142b2015-10-21 11:40:05 +02004010 if (!resolve_instid(node, leaf->value_str, line)) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004011 if (ly_errno) {
4012 return -1;
4013 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004014 if (!first) {
Michal Vaskocf024702015-10-08 15:01:42 +02004015 LOGVAL(LYE_SPEC, line, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004016 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004017 return EXIT_FAILURE;
4018 } else {
Michal Vaskocf024702015-10-08 15:01:42 +02004019 LOGVRB("There is no instance of \"%s\", but is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004020 }
4021 }
Michal Vaskocf024702015-10-08 15:01:42 +02004022 break;
4023
4024 case UNRES_WHEN:
4025 if ((rc = resolve_when(node, first, line))) {
4026 return rc;
4027 }
4028 break;
4029
Michal Vaskobf19d252015-10-08 15:39:17 +02004030 case UNRES_MUST:
4031 if ((rc = resolve_must(node, first, line))) {
4032 return rc;
4033 }
4034 break;
4035
Michal Vaskocf024702015-10-08 15:01:42 +02004036 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004037 LOGINT;
4038 return -1;
4039 }
4040
4041 return EXIT_SUCCESS;
4042}
4043
4044/**
4045 * @brief Try to resolve an unres data item. Logs indirectly.
4046 *
4047 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004048 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004049 * @param[in] line Line in the input file.
4050 *
4051 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4052 */
4053int
Michal Vaskocf024702015-10-08 15:01:42 +02004054unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004055{
4056 int rc;
4057
Michal Vaskobf19d252015-10-08 15:39:17 +02004058 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004059
Michal Vaskocf024702015-10-08 15:01:42 +02004060 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004061 if (rc != EXIT_FAILURE) {
4062 return rc;
4063 }
4064
Michal Vaskocf024702015-10-08 15:01:42 +02004065 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004066
4067 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004068 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4069 if (!unres->node) {
4070 LOGMEM;
4071 return -1;
4072 }
Michal Vaskocf024702015-10-08 15:01:42 +02004073 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004074 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4075 if (!unres->type) {
4076 LOGMEM;
4077 return -1;
4078 }
Michal Vaskocf024702015-10-08 15:01:42 +02004079 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004080#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004081 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4082 if (!unres->line) {
4083 LOGMEM;
4084 return -1;
4085 }
Michal Vaskocf024702015-10-08 15:01:42 +02004086 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004087#endif
4088
4089 return EXIT_SUCCESS;
4090}
4091
4092/**
4093 * @brief Resolve every unres data item in the structure. Logs directly.
4094 *
4095 * @param[in] unres Unres data structure to use.
4096 *
4097 * @return EXIT_SUCCESS on success, -1 on error.
4098 */
4099int
4100resolve_unres_data(struct unres_data *unres)
4101{
4102 uint32_t i;
4103 int rc;
4104
4105 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004106 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004107 if (rc) {
4108 LOGVAL(LYE_SPEC, 0, "There are unresolved data items left.");
4109 return -1;
4110 }
4111 }
4112
4113 return EXIT_SUCCESS;
4114}