blob: 18975c8d53888410c7599e543d207fe73079f08b [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Michal Vasko88c29542015-11-27 14:57:53 +010028#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020029#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020030#include "tree_internal.h"
31
Michal Vasko730dfdf2015-08-11 14:48:05 +020032/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020033 * @brief Parse an identifier.
34 *
35 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
36 * identifier = (ALPHA / "_")
37 * *(ALPHA / DIGIT / "_" / "-" / ".")
38 *
Michal Vaskobb211122015-08-19 14:03:11 +020039 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020040 *
41 * @return Number of characters successfully parsed.
42 */
Michal Vasko249e6b52015-08-19 11:08:52 +020043int
Radek Krejci6dc53a22015-08-17 13:27:59 +020044parse_identifier(const char *id)
45{
46 int parsed = 0;
47
Michal Vasko1ab90bc2016-03-15 10:40:22 +010048 assert(id);
49
Radek Krejci6dc53a22015-08-17 13:27:59 +020050 if (((id[0] == 'x') || (id[0] == 'X'))
Michal Vasko1ab90bc2016-03-15 10:40:22 +010051 && (id[0] && ((id[1] == 'm') || (id[0] == 'M')))
52 && (id[1] && ((id[2] == 'l') || (id[2] == 'L')))) {
Radek Krejci6dc53a22015-08-17 13:27:59 +020053 return -parsed;
54 }
55
56 if (!isalpha(id[0]) && (id[0] != '_')) {
57 return -parsed;
58 }
59
60 ++parsed;
61 ++id;
62
63 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
64 ++parsed;
65 ++id;
66 }
67
68 return parsed;
69}
70
71/**
72 * @brief Parse a node-identifier.
73 *
Michal Vasko723e50c2015-10-20 15:20:29 +020074 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020075 *
Michal Vaskobb211122015-08-19 14:03:11 +020076 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020077 * @param[out] mod_name Points to the module name, NULL if there is not any.
78 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020079 * @param[out] name Points to the node name.
80 * @param[out] nam_len Length of the node name.
81 *
82 * @return Number of characters successfully parsed,
83 * positive on success, negative on failure.
84 */
85static int
Michal Vasko723e50c2015-10-20 15:20:29 +020086parse_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 +020087{
88 int parsed = 0, ret;
89
90 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020091 if (mod_name) {
92 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020093 }
Michal Vasko723e50c2015-10-20 15:20:29 +020094 if (mod_name_len) {
95 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020096 }
97 if (name) {
98 *name = NULL;
99 }
100 if (nam_len) {
101 *nam_len = 0;
102 }
103
104 if ((ret = parse_identifier(id)) < 1) {
105 return ret;
106 }
107
Michal Vasko723e50c2015-10-20 15:20:29 +0200108 if (mod_name) {
109 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200110 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200111 if (mod_name_len) {
112 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200113 }
114
115 parsed += ret;
116 id += ret;
117
118 /* there is prefix */
119 if (id[0] == ':') {
120 ++parsed;
121 ++id;
122
123 /* there isn't */
124 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200125 if (name && mod_name) {
126 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200127 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200128 if (mod_name) {
129 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200130 }
131
Michal Vasko723e50c2015-10-20 15:20:29 +0200132 if (nam_len && mod_name_len) {
133 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200134 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200135 if (mod_name_len) {
136 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200137 }
138
139 return parsed;
140 }
141
142 /* identifier (node name) */
143 if ((ret = parse_identifier(id)) < 1) {
144 return -parsed+ret;
145 }
146
147 if (name) {
148 *name = id;
149 }
150 if (nam_len) {
151 *nam_len = ret;
152 }
153
154 return parsed+ret;
155}
156
157/**
158 * @brief Parse a path-predicate (leafref).
159 *
160 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
161 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
162 *
Michal Vaskobb211122015-08-19 14:03:11 +0200163 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200164 * @param[out] prefix Points to the prefix, NULL if there is not any.
165 * @param[out] pref_len Length of the prefix, 0 if there is not any.
166 * @param[out] name Points to the node name.
167 * @param[out] nam_len Length of the node name.
168 * @param[out] path_key_expr Points to the path-key-expr.
169 * @param[out] pke_len Length of the path-key-expr.
170 * @param[out] has_predicate Flag to mark whether there is another predicate following.
171 *
172 * @return Number of characters successfully parsed,
173 * positive on success, negative on failure.
174 */
175static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200176parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
177 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200178{
179 const char *ptr;
180 int parsed = 0, ret;
181
182 assert(id);
183 if (prefix) {
184 *prefix = NULL;
185 }
186 if (pref_len) {
187 *pref_len = 0;
188 }
189 if (name) {
190 *name = NULL;
191 }
192 if (nam_len) {
193 *nam_len = 0;
194 }
195 if (path_key_expr) {
196 *path_key_expr = NULL;
197 }
198 if (pke_len) {
199 *pke_len = 0;
200 }
201 if (has_predicate) {
202 *has_predicate = 0;
203 }
204
205 if (id[0] != '[') {
206 return -parsed;
207 }
208
209 ++parsed;
210 ++id;
211
212 while (isspace(id[0])) {
213 ++parsed;
214 ++id;
215 }
216
217 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
218 return -parsed+ret;
219 }
220
221 parsed += ret;
222 id += ret;
223
224 while (isspace(id[0])) {
225 ++parsed;
226 ++id;
227 }
228
229 if (id[0] != '=') {
230 return -parsed;
231 }
232
233 ++parsed;
234 ++id;
235
236 while (isspace(id[0])) {
237 ++parsed;
238 ++id;
239 }
240
241 if ((ptr = strchr(id, ']')) == NULL) {
242 return -parsed;
243 }
244
245 --ptr;
246 while (isspace(ptr[0])) {
247 --ptr;
248 }
249 ++ptr;
250
251 ret = ptr-id;
252 if (path_key_expr) {
253 *path_key_expr = id;
254 }
255 if (pke_len) {
256 *pke_len = ret;
257 }
258
259 parsed += ret;
260 id += ret;
261
262 while (isspace(id[0])) {
263 ++parsed;
264 ++id;
265 }
266
267 assert(id[0] == ']');
268
269 if (id[1] == '[') {
270 *has_predicate = 1;
271 }
272
273 return parsed+1;
274}
275
276/**
277 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
278 * the ".." and the first node-identifier, other calls parse a single
279 * node-identifier each.
280 *
281 * path-key-expr = current-function-invocation *WSP "/" *WSP
282 * rel-path-keyexpr
283 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
284 * *(node-identifier *WSP "/" *WSP)
285 * node-identifier
286 *
Michal Vaskobb211122015-08-19 14:03:11 +0200287 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200288 * @param[out] prefix Points to the prefix, NULL if there is not any.
289 * @param[out] pref_len Length of the prefix, 0 if there is not any.
290 * @param[out] name Points to the node name.
291 * @param[out] nam_len Length of the node name.
292 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
293 * must not be changed between consecutive calls.
294 * @return Number of characters successfully parsed,
295 * positive on success, negative on failure.
296 */
297static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200298parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
299 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200300{
301 int parsed = 0, ret, par_times = 0;
302
303 assert(id);
304 assert(parent_times);
305 if (prefix) {
306 *prefix = NULL;
307 }
308 if (pref_len) {
309 *pref_len = 0;
310 }
311 if (name) {
312 *name = NULL;
313 }
314 if (nam_len) {
315 *nam_len = 0;
316 }
317
318 if (!*parent_times) {
319 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
320 if (strncmp(id, "current()", 9)) {
321 return -parsed;
322 }
323
324 parsed += 9;
325 id += 9;
326
327 while (isspace(id[0])) {
328 ++parsed;
329 ++id;
330 }
331
332 if (id[0] != '/') {
333 return -parsed;
334 }
335
336 ++parsed;
337 ++id;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 /* rel-path-keyexpr */
345 if (strncmp(id, "..", 2)) {
346 return -parsed;
347 }
348 ++par_times;
349
350 parsed += 2;
351 id += 2;
352
353 while (isspace(id[0])) {
354 ++parsed;
355 ++id;
356 }
357 }
358
359 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
360 *
361 * first parent reference with whitespaces already parsed
362 */
363 if (id[0] != '/') {
364 return -parsed;
365 }
366
367 ++parsed;
368 ++id;
369
370 while (isspace(id[0])) {
371 ++parsed;
372 ++id;
373 }
374
375 while (!strncmp(id, "..", 2) && !*parent_times) {
376 ++par_times;
377
378 parsed += 2;
379 id += 2;
380
381 while (isspace(id[0])) {
382 ++parsed;
383 ++id;
384 }
385
386 if (id[0] != '/') {
387 return -parsed;
388 }
389
390 ++parsed;
391 ++id;
392
393 while (isspace(id[0])) {
394 ++parsed;
395 ++id;
396 }
397 }
398
399 if (!*parent_times) {
400 *parent_times = par_times;
401 }
402
403 /* all parent references must be parsed at this point */
404 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
405 return -parsed+ret;
406 }
407
408 parsed += ret;
409 id += ret;
410
411 return parsed;
412}
413
414/**
415 * @brief Parse path-arg (leafref).
416 *
417 * path-arg = absolute-path / relative-path
418 * absolute-path = 1*("/" (node-identifier *path-predicate))
419 * relative-path = 1*(".." "/") descendant-path
420 *
Michal Vaskobb211122015-08-19 14:03:11 +0200421 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200422 * @param[out] prefix Points to the prefix, NULL if there is not any.
423 * @param[out] pref_len Length of the prefix, 0 if there is not any.
424 * @param[out] name Points to the node name.
425 * @param[out] nam_len Length of the node name.
426 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
427 * must not be changed between consecutive calls. -1 if the
428 * path is relative.
429 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
430 *
431 * @return Number of characters successfully parsed,
432 * positive on success, negative on failure.
433 */
434static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200435parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
436 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200437{
438 int parsed = 0, ret, par_times = 0;
439
440 assert(id);
441 assert(parent_times);
442 if (prefix) {
443 *prefix = NULL;
444 }
445 if (pref_len) {
446 *pref_len = 0;
447 }
448 if (name) {
449 *name = NULL;
450 }
451 if (nam_len) {
452 *nam_len = 0;
453 }
454 if (has_predicate) {
455 *has_predicate = 0;
456 }
457
458 if (!*parent_times && !strncmp(id, "..", 2)) {
459 ++par_times;
460
461 parsed += 2;
462 id += 2;
463
464 while (!strncmp(id, "/..", 3)) {
465 ++par_times;
466
467 parsed += 3;
468 id += 3;
469 }
470 }
471
472 if (!*parent_times) {
473 if (par_times) {
474 *parent_times = par_times;
475 } else {
476 *parent_times = -1;
477 }
478 }
479
480 if (id[0] != '/') {
481 return -parsed;
482 }
483
484 /* skip '/' */
485 ++parsed;
486 ++id;
487
488 /* node-identifier ([prefix:]identifier) */
489 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
490 return -parsed-ret;
491 }
492
493 parsed += ret;
494 id += ret;
495
496 /* there is no predicate */
497 if ((id[0] == '/') || !id[0]) {
498 return parsed;
499 } else if (id[0] != '[') {
500 return -parsed;
501 }
502
503 if (has_predicate) {
504 *has_predicate = 1;
505 }
506
507 return parsed;
508}
509
510/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200511 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200512 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200513 *
514 * instance-identifier = 1*("/" (node-identifier *predicate))
515 *
Michal Vaskobb211122015-08-19 14:03:11 +0200516 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200517 * @param[out] model Points to the model name.
518 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200519 * @param[out] name Points to the node name.
520 * @param[out] nam_len Length of the node name.
521 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
522 *
523 * @return Number of characters successfully parsed,
524 * positive on success, negative on failure.
525 */
526static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200527parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
528 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200529{
530 int parsed = 0, ret;
531
532 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200533 if (model) {
534 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200535 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200536 if (mod_len) {
537 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200538 }
539 if (name) {
540 *name = NULL;
541 }
542 if (nam_len) {
543 *nam_len = 0;
544 }
545 if (has_predicate) {
546 *has_predicate = 0;
547 }
548
549 if (id[0] != '/') {
550 return -parsed;
551 }
552
553 ++parsed;
554 ++id;
555
Michal Vasko1f2cc332015-08-19 11:18:32 +0200556 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200557 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200558 } else if (model && !*model) {
559 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200560 }
561
562 parsed += ret;
563 id += ret;
564
565 if ((id[0] == '[') && has_predicate) {
566 *has_predicate = 1;
567 }
568
569 return parsed;
570}
571
572/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200573 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200574 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575 *
576 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
577 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
578 * ((DQUOTE string DQUOTE) /
579 * (SQUOTE string SQUOTE))
580 * pos = non-negative-integer-value
581 *
Michal Vaskobb211122015-08-19 14:03:11 +0200582 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200583 * @param[out] model Points to the model name.
584 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200585 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
586 * @param[out] nam_len Length of the node name.
587 * @param[out] value Value the node-identifier must have (string from the grammar),
588 * NULL if there is not any.
589 * @param[out] val_len Length of the value, 0 if there is not any.
590 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
591 *
592 * @return Number of characters successfully parsed,
593 * positive on success, negative on failure.
594 */
595static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200596parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
597 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200598{
599 const char *ptr;
600 int parsed = 0, ret;
601 char quote;
602
603 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200604 if (model) {
605 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200606 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200607 if (mod_len) {
608 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609 }
610 if (name) {
611 *name = NULL;
612 }
613 if (nam_len) {
614 *nam_len = 0;
615 }
616 if (value) {
617 *value = NULL;
618 }
619 if (val_len) {
620 *val_len = 0;
621 }
622 if (has_predicate) {
623 *has_predicate = 0;
624 }
625
626 if (id[0] != '[') {
627 return -parsed;
628 }
629
630 ++parsed;
631 ++id;
632
633 while (isspace(id[0])) {
634 ++parsed;
635 ++id;
636 }
637
638 /* pos */
639 if (isdigit(id[0])) {
640 if (name) {
641 *name = id;
642 }
643
644 if (id[0] == '0') {
645 ++parsed;
646 ++id;
647
648 if (isdigit(id[0])) {
649 return -parsed;
650 }
651 }
652
653 while (isdigit(id[0])) {
654 ++parsed;
655 ++id;
656 }
657
658 if (nam_len) {
659 *nam_len = id-(*name);
660 }
661
662 /* "." */
663 } else if (id[0] == '.') {
664 if (name) {
665 *name = id;
666 }
667 if (nam_len) {
668 *nam_len = 1;
669 }
670
671 ++parsed;
672 ++id;
673
674 /* node-identifier */
675 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200676 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200677 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200678 } else if (model && !*model) {
679 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200680 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200681
682 parsed += ret;
683 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 }
685
686 while (isspace(id[0])) {
687 ++parsed;
688 ++id;
689 }
690
691 if (id[0] != '=') {
692 return -parsed;
693 }
694
695 ++parsed;
696 ++id;
697
698 while (isspace(id[0])) {
699 ++parsed;
700 ++id;
701 }
702
703 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
704 if ((id[0] == '\"') || (id[0] == '\'')) {
705 quote = id[0];
706
707 ++parsed;
708 ++id;
709
710 if ((ptr = strchr(id, quote)) == NULL) {
711 return -parsed;
712 }
713 ret = ptr-id;
714
715 if (value) {
716 *value = id;
717 }
718 if (val_len) {
719 *val_len = ret;
720 }
721
722 parsed += ret+1;
723 id += ret+1;
724 } else {
725 return -parsed;
726 }
727
728 while (isspace(id[0])) {
729 ++parsed;
730 ++id;
731 }
732
733 if (id[0] != ']') {
734 return -parsed;
735 }
736
737 ++parsed;
738 ++id;
739
740 if ((id[0] == '[') && has_predicate) {
741 *has_predicate = 1;
742 }
743
744 return parsed;
745}
746
747/**
748 * @brief Parse schema-nodeid.
749 *
750 * schema-nodeid = absolute-schema-nodeid /
751 * descendant-schema-nodeid
752 * absolute-schema-nodeid = 1*("/" node-identifier)
753 * descendant-schema-nodeid =
754 * node-identifier
755 * absolute-schema-nodeid
756 *
Michal Vaskobb211122015-08-19 14:03:11 +0200757 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200758 * @param[out] mod_name Points to the module name, NULL if there is not any.
759 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
761 * @param[out] nam_len Length of the node name.
762 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
763 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100764 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
765 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200766 *
767 * @return Number of characters successfully parsed,
768 * positive on success, negative on failure.
769 */
770static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200771parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100772 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200773{
774 int parsed = 0, ret;
775
776 assert(id);
777 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200778 if (mod_name) {
779 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200780 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200781 if (mod_name_len) {
782 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200783 }
784 if (name) {
785 *name = NULL;
786 }
787 if (nam_len) {
788 *nam_len = 0;
789 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100790 if (has_predicate) {
791 *has_predicate = 0;
792 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200793
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
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100812 parsed += ret;
813 id += ret;
814
815 if ((id[0] == '[') && has_predicate) {
816 *has_predicate = 1;
817 }
818
819 return parsed;
820}
821
822/**
823 * @brief Parse schema predicate (special format internally used).
824 *
825 * predicate = "[" *WSP predicate-expr *WSP "]"
826 * predicate-expr = identifier / key-with-value
827 * key-with-value = identifier *WSP "=" *WSP
828 * ((DQUOTE string DQUOTE) /
829 * (SQUOTE string SQUOTE))
830 *
831 * @param[in] id Identifier to use.
832 * @param[out] name Points to the list key name.
833 * @param[out] nam_len Length of \p name.
834 * @param[out] value Points to the key value.
835 * @param[out] val_len Length of \p value.
836 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
837 */
838static int
Michal Vasko3547c532016-03-14 09:40:50 +0100839parse_schema_list_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
840 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100841{
842 const char *ptr;
843 int parsed = 0, ret;
844 char quote;
845
846 assert(id);
847 if (name) {
848 *name = NULL;
849 }
850 if (nam_len) {
851 *nam_len = 0;
852 }
853 if (value) {
854 *value = NULL;
855 }
856 if (val_len) {
857 *val_len = 0;
858 }
859 if (has_predicate) {
860 *has_predicate = 0;
861 }
862
863 if (id[0] != '[') {
864 return -parsed;
865 }
866
867 ++parsed;
868 ++id;
869
870 while (isspace(id[0])) {
871 ++parsed;
872 ++id;
873 }
874
875 /* node-identifier */
876 if ((ret = parse_identifier(id)) < 1) {
877 return -parsed + ret;
878 }
879 if (name) {
880 *name = id;
881 }
882 if (nam_len) {
883 *nam_len = ret;
884 }
885
886 parsed += ret;
887 id += ret;
888
889 while (isspace(id[0])) {
890 ++parsed;
891 ++id;
892 }
893
894 /* there is value as well */
895 if (id[0] == '=') {
896 ++parsed;
897 ++id;
898
899 while (isspace(id[0])) {
900 ++parsed;
901 ++id;
902 }
903
904 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
905 if ((id[0] == '\"') || (id[0] == '\'')) {
906 quote = id[0];
907
908 ++parsed;
909 ++id;
910
911 if ((ptr = strchr(id, quote)) == NULL) {
912 return -parsed;
913 }
914 ret = ptr - id;
915
916 if (value) {
917 *value = id;
918 }
919 if (val_len) {
920 *val_len = ret;
921 }
922
923 parsed += ret + 1;
924 id += ret + 1;
925 } else {
926 return -parsed;
927 }
928
929 while (isspace(id[0])) {
930 ++parsed;
931 ++id;
932 }
933 }
934
935 if (id[0] != ']') {
936 return -parsed;
937 }
938
939 ++parsed;
940 ++id;
941
942 if ((id[0] == '[') && has_predicate) {
943 *has_predicate = 1;
944 }
945
946 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200947}
948
949/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100950 * @brief Resolve (find) a data node based on a schema-nodeid.
951 *
952 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
953 * module).
954 *
955 */
956struct lyd_node *
957resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
958{
959 char *str, *token, *p;
960 struct lyd_node *result = start, *iter;
961 const struct lys_node *schema = NULL;
962
963 assert(nodeid && start);
964
965 if (nodeid[0] == '/') {
966 return NULL;
967 }
968
969 str = p = strdup(nodeid);
970 if (!str) {
971 LOGMEM;
972 return NULL;
973 }
974 while (p) {
975 token = p;
976 p = strchr(p, '/');
977 if (p) {
978 *p = '\0';
979 p++;
980 }
981
982 schema = NULL;
983 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
984 free(str);
985 return NULL;
986 }
987
988 LY_TREE_FOR(result, iter) {
989 if (iter->schema == schema) {
990 break;
991 }
992 }
993
994 if (!p) {
995 /* final result */
996 result = iter;
997 } else {
998 result = iter->child;
999 }
1000 }
1001 free(str);
1002
1003 return result;
1004}
1005
1006/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1007int
1008resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1009 const struct lys_node **ret)
1010{
1011 const char *name, *mod_name, *id;
1012 const struct lys_node *sibling;
1013 int r, nam_len, mod_name_len, is_relative = -1;
1014 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001015 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001016
1017 assert(nodeid && (start || module) && !(start && module) && ret);
1018
1019 id = nodeid;
1020
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001021 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001022 return ((id - nodeid) - r) + 1;
1023 }
1024 id += r;
1025
1026 if ((is_relative && !start) || (!is_relative && !module)) {
1027 return -1;
1028 }
1029
1030 /* descendant-schema-nodeid */
1031 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001032 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001033
1034 /* absolute-schema-nodeid */
1035 } else {
1036 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001037 if (!start_mod) {
1038 return -1;
1039 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001040 start = start_mod->data;
1041 }
1042
1043 while (1) {
1044 sibling = NULL;
1045 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1046 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1047 /* name match */
1048 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1049 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
1050 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
1051
1052 /* module check */
1053 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1054 if (!prefix_mod) {
1055 return -1;
1056 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001057 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001058 continue;
1059 }
1060
1061 /* the result node? */
1062 if (!id[0]) {
1063 *ret = sibling;
1064 return EXIT_SUCCESS;
1065 }
1066
1067 /* check for shorthand cases - then 'start' does not change */
1068 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1069 || (sibling->nodetype == LYS_CASE)) {
1070 start = sibling->child;
1071 }
1072 break;
1073 }
1074 }
1075
1076 /* no match */
1077 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001078 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001079 return EXIT_SUCCESS;
1080 }
1081
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001082 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001083 return ((id - nodeid) - r) + 1;
1084 }
1085 id += r;
1086 }
1087
1088 /* cannot get here */
1089 LOGINT;
1090 return -1;
1091}
1092
1093/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1094int
1095resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
1096 const struct lys_node **ret)
1097{
1098 const char *name, *mod_name, *id;
1099 const struct lys_node *sibling;
1100 int r, nam_len, mod_name_len, is_relative = -1;
1101 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001102 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001103
1104 assert(nodeid && start && ret);
1105 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1106
1107 id = nodeid;
1108 module = start->module;
1109
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001110 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001111 return ((id - nodeid) - r) + 1;
1112 }
1113 id += r;
1114
1115 if (!is_relative) {
1116 return -1;
1117 }
1118
1119 while (1) {
1120 sibling = NULL;
1121 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1122 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1123 /* name match */
1124 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1125
1126 /* module check */
1127 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1128 if (!prefix_mod) {
1129 return -1;
1130 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001131 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001132 continue;
1133 }
1134
1135 /* the result node? */
1136 if (!id[0]) {
1137 if (!(sibling->nodetype & ret_nodetype)) {
1138 /* wrong node type, too bad */
1139 continue;
1140 }
1141 *ret = sibling;
1142 return EXIT_SUCCESS;
1143 }
1144
1145 /* check for shorthand cases - then 'start' does not change */
1146 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1147 || (sibling->nodetype == LYS_CASE)) {
1148 start = sibling->child;
1149 }
1150 break;
1151 }
1152 }
1153
1154 /* no match */
1155 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001156 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001157 return EXIT_SUCCESS;
1158 }
1159
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001160 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001161 return ((id - nodeid) - r) + 1;
1162 }
1163 id += r;
1164 }
1165
1166 /* cannot get here */
1167 LOGINT;
1168 return -1;
1169}
1170
1171/* choice default */
1172int
1173resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1174{
1175 /* cannot actually be a path */
1176 if (strchr(nodeid, '/')) {
1177 return -1;
1178 }
1179
1180 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1181}
1182
1183/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1184static int
1185resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1186{
1187 const struct lys_module *module;
1188 const char *mod_prefix, *name;
1189 int i, mod_prefix_len, nam_len;
1190
1191 /* parse the identifier, it must be parsed on one call */
1192 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1193 return -i + 1;
1194 }
1195
1196 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1197 if (!module) {
1198 return -1;
1199 }
1200 if (module != start->module) {
1201 start = module->data;
1202 }
1203
1204 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1205
1206 return EXIT_SUCCESS;
1207}
1208
1209int
1210resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1211 const struct lys_node **ret)
1212{
1213 const char *name, *mod_name, *id;
1214 const struct lys_node *sibling, *start;
1215 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko4f0dad02016-02-15 14:08:23 +01001216 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001217
1218 assert(nodeid && module && ret);
1219 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1220
1221 id = nodeid;
1222 start = module->data;
1223
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001224 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001225 return ((id - nodeid) - r) + 1;
1226 }
1227 id += r;
1228
1229 if (is_relative) {
1230 return -1;
1231 }
1232
1233 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001234 if (!abs_start_mod) {
1235 return -1;
1236 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001237
1238 while (1) {
1239 sibling = NULL;
1240 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1241 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1242 /* name match */
1243 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1244
1245 /* module check */
1246 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1247 if (!prefix_mod) {
1248 return -1;
1249 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001250 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001251 continue;
1252 }
1253
1254 /* the result node? */
1255 if (!id[0]) {
1256 if (!(sibling->nodetype & ret_nodetype)) {
1257 /* wrong node type, too bad */
1258 continue;
1259 }
1260 *ret = sibling;
1261 return EXIT_SUCCESS;
1262 }
1263
1264 /* check for shorthand cases - then 'start' does not change */
1265 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1266 || (sibling->nodetype == LYS_CASE)) {
1267 start = sibling->child;
1268 }
1269 break;
1270 }
1271 }
1272
1273 /* no match */
1274 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001275 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001276 return EXIT_SUCCESS;
1277 }
1278
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001279 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001280 return ((id - nodeid) - r) + 1;
1281 }
1282 id += r;
1283 }
1284
1285 /* cannot get here */
1286 LOGINT;
1287 return -1;
1288}
1289
Michal Vaskoe733d682016-03-14 09:08:27 +01001290static int
Michal Vasko3547c532016-03-14 09:40:50 +01001291resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001292{
1293 const char *name;
1294 int nam_len, has_predicate, i;
1295
Michal Vasko3547c532016-03-14 09:40:50 +01001296 if ((i = parse_schema_list_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001297 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
1298 return -1;
1299 }
1300
1301 predicate += i;
1302 *parsed += i;
1303
1304 for (i = 0; i < list->keys_size; ++i) {
1305 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1306 break;
1307 }
1308 }
1309
1310 if (i == list->keys_size) {
1311 LOGVAL(LYE_PATH_INKEY, 0, LY_VLOG_NONE, NULL, name);
1312 return -1;
1313 }
1314
1315 /* more predicates? */
1316 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001317 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001318 }
1319
1320 return 0;
1321}
1322
1323/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
1324const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001325resolve_json_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001326{
1327 char *str;
1328 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001329 const struct lys_node *sibling;
Michal Vaskoe733d682016-03-14 09:08:27 +01001330 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001331 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001332 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001333
Michal Vasko3547c532016-03-14 09:40:50 +01001334 assert(nodeid && (ctx || start));
1335 if (!ctx) {
1336 ctx = start->module->ctx;
1337 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001338
1339 id = nodeid;
1340
Michal Vaskoe733d682016-03-14 09:08:27 +01001341 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
1342 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1343 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001344 }
1345 id += r;
1346
1347 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001348 assert(start);
1349 start = start->child;
1350 if (!start) {
1351 /* no descendants, fail for sure */
1352 LOGVAL(LYE_PATH_INNODE, 0, LY_VLOG_NONE, NULL, name);
1353 return NULL;
1354 }
1355 module = start->module;
1356 } else {
1357 if (!mod_name) {
1358 LOGVAL(LYE_PATH_MISSMOD, 0, LY_VLOG_NONE, NULL, name);
1359 return NULL;
1360 }
1361
1362 str = strndup(mod_name, mod_name_len);
1363 module = ly_ctx_get_module(ctx, str, NULL);
1364 free(str);
1365 if (!module) {
1366 LOGVAL(LYE_PATH_INMOD, 0, LY_VLOG_NONE, NULL, mod_name);
1367 return NULL;
1368 }
1369 start = module->data;
1370
1371 /* now it's as if there was no module name */
1372 mod_name = NULL;
1373 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001374 }
1375
Michal Vaskoe733d682016-03-14 09:08:27 +01001376 prev_mod = module;
1377
Michal Vasko3edeaf72016-02-11 13:17:43 +01001378 while (1) {
1379 sibling = NULL;
1380 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1381 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1382 /* name match */
1383 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1384
1385 /* module check */
1386 if (mod_name) {
1387 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1388 if (!prefix_mod) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001389 LOGVAL(LYE_PATH_INMOD, 0, LY_VLOG_NONE, NULL, mod_name);
1390 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001391 }
1392 } else {
1393 prefix_mod = prev_mod;
1394 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001395 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001396 continue;
1397 }
1398
Michal Vaskoe733d682016-03-14 09:08:27 +01001399 /* do we have some predicates on it? */
1400 if (has_predicate) {
1401 r = 0;
1402 if (sibling->nodetype != LYS_LIST) {
1403 LOGVAL(LYE_PATH_NLIST, 0, LY_VLOG_NONE, NULL, name);
1404 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001405 } else if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001406 return NULL;
1407 }
1408 id += r;
1409 }
1410
Michal Vasko3edeaf72016-02-11 13:17:43 +01001411 /* the result node? */
1412 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001413 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001414 }
1415
1416 /* check for shorthand cases - then 'start' does not change */
1417 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1418 || (sibling->nodetype == LYS_CASE)) {
1419 start = sibling->child;
1420 }
1421
1422 /* update prev mod */
1423 prev_mod = start->module;
1424 break;
1425 }
1426 }
1427
1428 /* no match */
1429 if (!sibling) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001430 LOGVAL(LYE_PATH_INNODE, 0, LY_VLOG_NONE, NULL, name);
1431 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001432 }
1433
Michal Vaskoe733d682016-03-14 09:08:27 +01001434 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
1435 LOGVAL(LYE_PATH_INCHAR, 0, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1436 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001437 }
1438 id += r;
1439 }
1440
1441 /* cannot get here */
1442 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001443 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001444}
1445
1446/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001447 * @brief Resolves length or range intervals. Does not log.
1448 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1449 *
1450 * @param[in] str_restr The restriction as a string.
1451 * @param[in] type The type of the restriction.
1452 * @param[in] superior_restr Flag whether to check superior
1453 * types.
1454 * @param[out] local_intv The final interval structure.
1455 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001456 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001457 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001458int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001459resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1460 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001461{
1462 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001463 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001464 int64_t local_smin, local_smax;
1465 uint64_t local_umin, local_umax;
1466 long double local_fmin, local_fmax;
1467 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001468 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001469
1470 switch (type->base) {
1471 case LY_TYPE_BINARY:
1472 kind = 0;
1473 local_umin = 0;
1474 local_umax = 18446744073709551615UL;
1475
1476 if (!str_restr && type->info.binary.length) {
1477 str_restr = type->info.binary.length->expr;
1478 }
1479 break;
1480 case LY_TYPE_DEC64:
1481 kind = 2;
1482 local_fmin = -9223372036854775808.0;
1483 local_fmin /= 1 << type->info.dec64.dig;
1484 local_fmax = 9223372036854775807.0;
1485 local_fmax /= 1 << type->info.dec64.dig;
1486
1487 if (!str_restr && type->info.dec64.range) {
1488 str_restr = type->info.dec64.range->expr;
1489 }
1490 break;
1491 case LY_TYPE_INT8:
1492 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001493 local_smin = __INT64_C(-128);
1494 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001495
1496 if (!str_restr && type->info.num.range) {
1497 str_restr = type->info.num.range->expr;
1498 }
1499 break;
1500 case LY_TYPE_INT16:
1501 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001502 local_smin = __INT64_C(-32768);
1503 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001504
1505 if (!str_restr && type->info.num.range) {
1506 str_restr = type->info.num.range->expr;
1507 }
1508 break;
1509 case LY_TYPE_INT32:
1510 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001511 local_smin = __INT64_C(-2147483648);
1512 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001513
1514 if (!str_restr && type->info.num.range) {
1515 str_restr = type->info.num.range->expr;
1516 }
1517 break;
1518 case LY_TYPE_INT64:
1519 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001520 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1521 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001522
1523 if (!str_restr && type->info.num.range) {
1524 str_restr = type->info.num.range->expr;
1525 }
1526 break;
1527 case LY_TYPE_UINT8:
1528 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001529 local_umin = __UINT64_C(0);
1530 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001531
1532 if (!str_restr && type->info.num.range) {
1533 str_restr = type->info.num.range->expr;
1534 }
1535 break;
1536 case LY_TYPE_UINT16:
1537 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001538 local_umin = __UINT64_C(0);
1539 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001540
1541 if (!str_restr && type->info.num.range) {
1542 str_restr = type->info.num.range->expr;
1543 }
1544 break;
1545 case LY_TYPE_UINT32:
1546 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001547 local_umin = __UINT64_C(0);
1548 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001549
1550 if (!str_restr && type->info.num.range) {
1551 str_restr = type->info.num.range->expr;
1552 }
1553 break;
1554 case LY_TYPE_UINT64:
1555 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001556 local_umin = __UINT64_C(0);
1557 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001558
1559 if (!str_restr && type->info.num.range) {
1560 str_restr = type->info.num.range->expr;
1561 }
1562 break;
1563 case LY_TYPE_STRING:
1564 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001565 local_umin = __UINT64_C(0);
1566 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001567
1568 if (!str_restr && type->info.str.length) {
1569 str_restr = type->info.str.length->expr;
1570 }
1571 break;
1572 default:
1573 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001574 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001575 }
1576
1577 /* process superior types */
1578 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001579 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1580 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001581 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001582 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001583 assert(!intv || (intv->kind == kind));
1584 }
1585
1586 if (!str_restr) {
1587 /* we are validating data and not have any restriction, but a superior type might have */
1588 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001589 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1590 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001591 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001592 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001593 assert(!intv || (intv->kind == kind));
1594 }
1595 *local_intv = intv;
1596 return EXIT_SUCCESS;
1597 }
1598
1599 /* adjust local min and max */
1600 if (intv) {
1601 tmp_intv = intv;
1602
1603 if (kind == 0) {
1604 local_umin = tmp_intv->value.uval.min;
1605 } else if (kind == 1) {
1606 local_smin = tmp_intv->value.sval.min;
1607 } else if (kind == 2) {
1608 local_fmin = tmp_intv->value.fval.min;
1609 }
1610
1611 while (tmp_intv->next) {
1612 tmp_intv = tmp_intv->next;
1613 }
1614
1615 if (kind == 0) {
1616 local_umax = tmp_intv->value.uval.max;
1617 } else if (kind == 1) {
1618 local_smax = tmp_intv->value.sval.max;
1619 } else if (kind == 2) {
1620 local_fmax = tmp_intv->value.fval.max;
1621 }
1622 }
1623
1624 /* finally parse our restriction */
1625 seg_ptr = str_restr;
1626 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001627 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001628 *local_intv = malloc(sizeof **local_intv);
1629 tmp_local_intv = *local_intv;
1630 } else {
1631 tmp_local_intv->next = malloc(sizeof **local_intv);
1632 tmp_local_intv = tmp_local_intv->next;
1633 }
Michal Vasko253035f2015-12-17 16:58:13 +01001634 if (!tmp_local_intv) {
1635 LOGMEM;
1636 return -1;
1637 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001638
1639 tmp_local_intv->kind = kind;
1640 tmp_local_intv->next = NULL;
1641
1642 /* min */
1643 ptr = seg_ptr;
1644 while (isspace(ptr[0])) {
1645 ++ptr;
1646 }
1647 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1648 if (kind == 0) {
1649 tmp_local_intv->value.uval.min = atoll(ptr);
1650 } else if (kind == 1) {
1651 tmp_local_intv->value.sval.min = atoll(ptr);
1652 } else if (kind == 2) {
1653 tmp_local_intv->value.fval.min = atoll(ptr);
1654 }
1655
1656 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1657 ++ptr;
1658 }
1659 while (isdigit(ptr[0])) {
1660 ++ptr;
1661 }
1662 } else if (!strncmp(ptr, "min", 3)) {
1663 if (kind == 0) {
1664 tmp_local_intv->value.uval.min = local_umin;
1665 } else if (kind == 1) {
1666 tmp_local_intv->value.sval.min = local_smin;
1667 } else if (kind == 2) {
1668 tmp_local_intv->value.fval.min = local_fmin;
1669 }
1670
1671 ptr += 3;
1672 } else if (!strncmp(ptr, "max", 3)) {
1673 if (kind == 0) {
1674 tmp_local_intv->value.uval.min = local_umax;
1675 } else if (kind == 1) {
1676 tmp_local_intv->value.sval.min = local_smax;
1677 } else if (kind == 2) {
1678 tmp_local_intv->value.fval.min = local_fmax;
1679 }
1680
1681 ptr += 3;
1682 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001683 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001684 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001685 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001686 }
1687
1688 while (isspace(ptr[0])) {
1689 ptr++;
1690 }
1691
1692 /* no interval or interval */
1693 if ((ptr[0] == '|') || !ptr[0]) {
1694 if (kind == 0) {
1695 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1696 } else if (kind == 1) {
1697 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1698 } else if (kind == 2) {
1699 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1700 }
1701 } else if (!strncmp(ptr, "..", 2)) {
1702 /* skip ".." */
1703 ptr += 2;
1704 while (isspace(ptr[0])) {
1705 ++ptr;
1706 }
1707
1708 /* max */
1709 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1710 if (kind == 0) {
1711 tmp_local_intv->value.uval.max = atoll(ptr);
1712 } else if (kind == 1) {
1713 tmp_local_intv->value.sval.max = atoll(ptr);
1714 } else if (kind == 2) {
1715 tmp_local_intv->value.fval.max = atoll(ptr);
1716 }
1717 } else if (!strncmp(ptr, "max", 3)) {
1718 if (kind == 0) {
1719 tmp_local_intv->value.uval.max = local_umax;
1720 } else if (kind == 1) {
1721 tmp_local_intv->value.sval.max = local_smax;
1722 } else if (kind == 2) {
1723 tmp_local_intv->value.fval.max = local_fmax;
1724 }
1725 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001726 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001727 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001728 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001729 }
1730 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001731 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001732 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001733 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001734 }
1735
1736 /* next segment (next OR) */
1737 seg_ptr = strchr(seg_ptr, '|');
1738 if (!seg_ptr) {
1739 break;
1740 }
1741 seg_ptr++;
1742 }
1743
1744 /* check local restrictions against superior ones */
1745 if (intv) {
1746 tmp_intv = intv;
1747 tmp_local_intv = *local_intv;
1748
1749 while (tmp_local_intv && tmp_intv) {
1750 /* reuse local variables */
1751 if (kind == 0) {
1752 local_umin = tmp_local_intv->value.uval.min;
1753 local_umax = tmp_local_intv->value.uval.max;
1754
1755 /* it must be in this interval */
1756 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1757 /* this interval is covered, next one */
1758 if (local_umax <= tmp_intv->value.uval.max) {
1759 tmp_local_intv = tmp_local_intv->next;
1760 continue;
1761 /* ascending order of restrictions -> fail */
1762 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001763 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001764 goto cleanup;
1765 }
1766 }
1767 } else if (kind == 1) {
1768 local_smin = tmp_local_intv->value.sval.min;
1769 local_smax = tmp_local_intv->value.sval.max;
1770
1771 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1772 if (local_smax <= tmp_intv->value.sval.max) {
1773 tmp_local_intv = tmp_local_intv->next;
1774 continue;
1775 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001776 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001777 goto cleanup;
1778 }
1779 }
1780 } else if (kind == 2) {
1781 local_fmin = tmp_local_intv->value.fval.min;
1782 local_fmax = tmp_local_intv->value.fval.max;
1783
1784 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1785 if (local_fmax <= tmp_intv->value.fval.max) {
1786 tmp_local_intv = tmp_local_intv->next;
1787 continue;
1788 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001789 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001790 goto cleanup;
1791 }
1792 }
1793 }
1794
1795 tmp_intv = tmp_intv->next;
1796 }
1797
1798 /* some interval left uncovered -> fail */
1799 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001800 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001801 }
1802
1803 }
1804
1805cleanup:
1806 while (intv) {
1807 tmp_intv = intv->next;
1808 free(intv);
1809 intv = tmp_intv;
1810 }
1811
1812 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001813 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001814 while (*local_intv) {
1815 tmp_local_intv = (*local_intv)->next;
1816 free(*local_intv);
1817 *local_intv = tmp_local_intv;
1818 }
1819 }
1820
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001821 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001822}
1823
Michal Vasko730dfdf2015-08-11 14:48:05 +02001824/**
Michal Vasko88c29542015-11-27 14:57:53 +01001825 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001826 *
1827 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001828 * @param[in] mod_name Typedef name module name.
1829 * @param[in] module Main module.
1830 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001831 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001832 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001833 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001834 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001835int
Michal Vasko1e62a092015-12-01 12:27:20 +01001836resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
1837 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001838{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001839 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001840 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841 int tpdf_size;
1842
Michal Vasko1dca6882015-10-22 14:29:42 +02001843 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001844 /* no prefix, try built-in types */
1845 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1846 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001847 if (ret) {
1848 *ret = ly_types[i].def;
1849 }
1850 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001851 }
1852 }
1853 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001854 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001855 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001856 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001857 }
1858 }
1859
Michal Vasko1dca6882015-10-22 14:29:42 +02001860 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001861 /* search in local typedefs */
1862 while (parent) {
1863 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001864 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001865 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1866 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001867 break;
1868
Radek Krejci76512572015-08-04 09:47:08 +02001869 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001870 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1871 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001872 break;
1873
Radek Krejci76512572015-08-04 09:47:08 +02001874 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001875 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1876 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001877 break;
1878
Radek Krejci76512572015-08-04 09:47:08 +02001879 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001880 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1881 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001882 break;
1883
Radek Krejci76512572015-08-04 09:47:08 +02001884 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001885 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1886 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001887 break;
1888
Radek Krejci76512572015-08-04 09:47:08 +02001889 case LYS_INPUT:
1890 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001891 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1892 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001893 break;
1894
1895 default:
1896 parent = parent->parent;
1897 continue;
1898 }
1899
1900 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001901 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001902 if (ret) {
1903 *ret = &tpdf[i];
1904 }
1905 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001906 }
1907 }
1908
1909 parent = parent->parent;
1910 }
Radek Krejcic071c542016-01-27 14:57:51 +01001911 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001912 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001913 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001914 if (!module) {
1915 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001916 }
1917 }
1918
1919 /* search in top level typedefs */
1920 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001921 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001922 if (ret) {
1923 *ret = &module->tpdf[i];
1924 }
1925 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001926 }
1927 }
1928
1929 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01001930 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001931 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001932 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 +02001933 if (ret) {
1934 *ret = &module->inc[i].submodule->tpdf[j];
1935 }
1936 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001937 }
1938 }
1939 }
1940
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001941 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001942}
1943
Michal Vasko1dca6882015-10-22 14:29:42 +02001944/**
1945 * @brief Check the default \p value of the \p type. Logs directly.
1946 *
1947 * @param[in] type Type definition to use.
1948 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01001949 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02001950 * @param[in] first Whether this is the first resolution try. Affects logging.
1951 * @param[in] line Line in the input file.
1952 *
1953 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1954 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001955static int
Michal Vasko56826402016-03-02 11:11:37 +01001956check_default(struct lys_type *type, const char *value, struct lys_module *module, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001957{
Michal Vasko1dca6882015-10-22 14:29:42 +02001958 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01001959 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02001960
1961 /* dummy leaf */
1962 node.value_str = value;
1963 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01001964 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01001965 if (!node.schema) {
1966 LOGMEM;
1967 return -1;
1968 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001969 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01001970 if (!node.schema->name) {
1971 LOGMEM;
1972 return -1;
1973 }
Michal Vasko56826402016-03-02 11:11:37 +01001974 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01001975 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02001976
Radek Krejci37b756f2016-01-18 10:15:03 +01001977 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02001978 if (!type->info.lref.target) {
1979 ret = EXIT_FAILURE;
1980 goto finish;
1981 }
Michal Vasko56826402016-03-02 11:11:37 +01001982 ret = check_default(&type->info.lref.target->type, value, module, first, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001983
1984 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1985 /* it was converted to JSON format before, nothing else sensible we can do */
1986
1987 } else {
Radek Krejci37b756f2016-01-18 10:15:03 +01001988 ret = lyp_parse_value(&node, NULL, 1, NULL, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001989 }
1990
1991finish:
1992 if (node.value_type == LY_TYPE_BITS) {
1993 free(node.value.bit);
1994 }
1995 free((char *)node.schema->name);
1996 free(node.schema);
1997
1998 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001999}
2000
Michal Vasko730dfdf2015-08-11 14:48:05 +02002001/**
2002 * @brief Check a key for mandatory attributes. Logs directly.
2003 *
2004 * @param[in] key The key to check.
2005 * @param[in] flags What flags to check.
2006 * @param[in] list The list of all the keys.
2007 * @param[in] index Index of the key in the key list.
2008 * @param[in] name The name of the keys.
2009 * @param[in] len The name length.
2010 * @param[in] line The line in the input file.
2011 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002012 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002013 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002014static int
Radek Krejciadb57612016-02-16 13:34:34 +01002015check_key(struct lys_node_list *list, int index, const char *name, int len, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002016{
Radek Krejciadb57612016-02-16 13:34:34 +01002017 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002018 char *dup = NULL;
2019 int j;
2020
2021 /* existence */
2022 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002023 if (name[len] != '\0') {
2024 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002025 if (!dup) {
2026 LOGMEM;
2027 return -1;
2028 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002029 dup[len] = '\0';
2030 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002031 }
Radek Krejciadb57612016-02-16 13:34:34 +01002032 LOGVAL(LYE_KEY_MISS, line, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002033 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002034 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002035 }
2036
2037 /* uniqueness */
2038 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002039 if (key == list->keys[j]) {
2040 LOGVAL(LYE_KEY_DUP, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002041 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002042 }
2043 }
2044
2045 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002046 if (key->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002047 LOGVAL(LYE_KEY_NLEAF, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002048 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002049 }
2050
2051 /* type of the leaf is not built-in empty */
2052 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejciadb57612016-02-16 13:34:34 +01002053 LOGVAL(LYE_KEY_TYPE, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002054 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002055 }
2056
2057 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002058 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
2059 LOGVAL(LYE_KEY_CONFIG, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002060 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002061 }
2062
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002063 /* key is not placed from augment */
2064 if (key->parent->nodetype == LYS_AUGMENT) {
2065 LOGVAL(LYE_KEY_MISS, line, 0, NULL, key->name);
2066 LOGVAL(LYE_SPEC, 0, LY_VLOG_LYS, key, "Key inserted from augment.");
2067 return -1;
2068 }
2069
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002070 return EXIT_SUCCESS;
2071}
2072
Michal Vasko730dfdf2015-08-11 14:48:05 +02002073/**
Radek Krejci581ce772015-11-10 17:22:40 +01002074 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002075 *
2076 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002077 * @param[in] uniq_str_path One path from the unique string.
Michal Vasko184521f2015-09-24 13:14:26 +02002078 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002079 * @param[in] line The line in the input file.
2080 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002081 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002082 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002083int
Michal Vasko0b85aa82016-03-07 14:37:43 +01002084resolve_unique(struct lys_node *parent, const char *uniq_str_path, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002085{
Radek Krejci581ce772015-11-10 17:22:40 +01002086 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002087 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002088
Michal Vasko0b85aa82016-03-07 14:37:43 +01002089 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002090 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002091 if (rc) {
2092 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2093 if (rc > 0) {
2094 LOGVAL(LYE_INCHAR, 0, 0, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejci581ce772015-11-10 17:22:40 +01002095 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002096 rc = -1;
2097 } else if (!first) {
2098 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2099 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target leaf not found.");
2100 rc = -1;
2101 } else {
2102 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002103 }
Radek Krejci581ce772015-11-10 17:22:40 +01002104 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002105 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002106 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002107 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Radek Krejciadb57612016-02-16 13:34:34 +01002108 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002109 rc = -1;
2110 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002111 }
2112
Radek Krejcicf509982015-12-15 09:22:44 +01002113 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002114 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name,
2115 line, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002116 return -1;
2117 }
2118
Radek Krejcica7efb72016-01-18 13:06:01 +01002119 /* set leaf's unique flag */
2120 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2121
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002122 return EXIT_SUCCESS;
2123
2124error:
2125
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002126 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002127}
2128
Michal Vasko730dfdf2015-08-11 14:48:05 +02002129/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002130 * @brief Resolve (find) a feature definition. Logs directly.
2131 *
2132 * @param[in] name Feature name.
2133 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02002134 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002135 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002136 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002137 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002138 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002139 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002140static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002141resolve_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 +02002142{
Michal Vasko2d851a92015-10-20 16:16:36 +02002143 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002144 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002145 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002146
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002147 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002148 assert(module);
2149
2150 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002151 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002152 LOGVAL(LYE_INCHAR, line, 0, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002153 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002154 }
2155
Radek Krejcic071c542016-01-27 14:57:51 +01002156 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2157 if (!module) {
2158 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01002159 LOGVAL(LYE_INMOD_LEN, line, 0, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002160 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002161 }
2162
Radek Krejcic071c542016-01-27 14:57:51 +01002163 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002164 for (j = 0; j < module->features_size; j++) {
2165 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002166 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002167 /* check status */
2168 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002169 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejciadb57612016-02-16 13:34:34 +01002170 module->features[j].module, module->features[j].name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002171 return -1;
2172 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002173 *ret = &module->features[j];
2174 }
2175 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002176 }
2177 }
Radek Krejcic071c542016-01-27 14:57:51 +01002178 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002179 for (i = 0; i < module->inc_size; i++) {
2180 if (!module->inc[i].submodule) {
2181 /* not yet resolved */
2182 continue;
2183 }
Radek Krejcic071c542016-01-27 14:57:51 +01002184 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2185 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2186 if (ret) {
2187 /* check status */
2188 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002189 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002190 module->inc[i].submodule->features[j].flags,
2191 module->inc[i].submodule->features[j].module,
Radek Krejciadb57612016-02-16 13:34:34 +01002192 module->inc[i].submodule->features[j].name, line, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002193 return -1;
2194 }
2195 *ret = &(module->inc[i].submodule->features[j]);
2196 }
2197 return EXIT_SUCCESS;
2198 }
2199 }
2200 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201
2202 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02002203 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002204 LOGVAL(LYE_INRESOLV, line, 0, NULL, "feature", id);
Michal Vasko184521f2015-09-24 13:14:26 +02002205 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002206 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002207}
2208
Michal Vasko23b61ec2015-08-19 11:19:50 +02002209/* ignores line */
2210static void
2211unres_data_del(struct unres_data *unres, uint32_t i)
2212{
2213 /* there are items after the one deleted */
2214 if (i+1 < unres->count) {
2215 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002216 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002217
2218 /* deleting the last item */
2219 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002220 free(unres->node);
2221 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002222 }
2223
2224 /* if there are no items after and it is not the last one, just move the counter */
2225 --unres->count;
2226}
2227
Michal Vasko0491ab32015-08-19 14:28:29 +02002228/**
2229 * @brief Resolve (find) a data node from a specific module. Does not log.
2230 *
2231 * @param[in] mod Module to search in.
2232 * @param[in] name Name of the data node.
2233 * @param[in] nam_len Length of the name.
2234 * @param[in] start Data node to start the search from.
2235 * @param[in,out] parents Resolved nodes. If there are some parents,
2236 * they are replaced (!!) with the resolvents.
2237 *
2238 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2239 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002240static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002241resolve_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 +02002242{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002243 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002244 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002245 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002246
Michal Vasko23b61ec2015-08-19 11:19:50 +02002247 if (!parents->count) {
2248 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002249 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002250 if (!parents->node) {
2251 LOGMEM;
2252 return EXIT_FAILURE;
2253 }
Michal Vaskocf024702015-10-08 15:01:42 +02002254 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002255 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002256 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002257 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002258 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002259 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002260 continue;
2261 }
2262 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002263 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002264 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2265 && node->schema->name[nam_len] == '\0') {
2266 /* matching target */
2267 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002268 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002269 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002270 flag = 1;
2271 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002272 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002273 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002274 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2275 if (!parents->node) {
2276 return EXIT_FAILURE;
2277 }
Michal Vaskocf024702015-10-08 15:01:42 +02002278 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002279 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002280 }
2281 }
2282 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002283
2284 if (!flag) {
2285 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002286 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002287 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002288 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002289 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002290 }
2291
Michal Vasko0491ab32015-08-19 14:28:29 +02002292 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002293}
2294
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002295/**
2296 * @brief Resolve (find) a data node. Does not log.
2297 *
Radek Krejci581ce772015-11-10 17:22:40 +01002298 * @param[in] mod_name Module name of the data node.
2299 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002300 * @param[in] name Name of the data node.
2301 * @param[in] nam_len Length of the name.
2302 * @param[in] start Data node to start the search from.
2303 * @param[in,out] parents Resolved nodes. If there are some parents,
2304 * they are replaced (!!) with the resolvents.
2305 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002306 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002307 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002308static int
Radek Krejci581ce772015-11-10 17:22:40 +01002309resolve_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 +02002310 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002311{
Michal Vasko1e62a092015-12-01 12:27:20 +01002312 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002313 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002314
Michal Vasko23b61ec2015-08-19 11:19:50 +02002315 assert(start);
2316
Michal Vasko31fc3672015-10-21 12:08:13 +02002317 if (mod_name) {
2318 /* we have mod_name, find appropriate module */
2319 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002320 if (!str) {
2321 LOGMEM;
2322 return -1;
2323 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002324 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2325 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002326 if (!mod) {
2327 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002328 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002329 }
2330 } else {
2331 /* no prefix, module is the same as of current node */
2332 mod = start->schema->module;
2333 }
2334
2335 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002336}
2337
Michal Vasko730dfdf2015-08-11 14:48:05 +02002338/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002339 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02002340 * only specific errors, general no-resolvent error is left to the caller,
2341 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002342 *
Michal Vaskobb211122015-08-19 14:03:11 +02002343 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02002344 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02002345 * @param[in] line Line in the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01002346 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002347 * @param[in,out] node_match Nodes satisfying the restriction
2348 * without the predicate. Nodes not
2349 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002350 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002351 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002352 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002353 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002354static int
Radek Krejciadb57612016-02-16 13:34:34 +01002355resolve_path_predicate_data(const char *pred, int first, uint32_t line,struct lyd_node *node,
2356 struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002357{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002358 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002359 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002360 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002361 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2362 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002363 uint32_t j;
2364
2365 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002366 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002367 if (!source_match.node) {
2368 LOGMEM;
2369 return -1;
2370 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002371 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002372 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002373 if (!dest_match.node) {
2374 LOGMEM;
2375 return -1;
2376 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002377
2378 do {
2379 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2380 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002381 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002382 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002383 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002384 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002385 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002386 pred += i;
2387
Michal Vasko23b61ec2015-08-19 11:19:50 +02002388 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002389 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002390 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002391
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002392 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002393 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002394 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002395 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002396 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002397 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002398 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002399 i = 0;
2400 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002401 }
2402
2403 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002404 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002405 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002406 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2407 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002408 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002409 rc = -1;
2410 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002411 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002412 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002413 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002414 dest_match.node[0] = dest_match.node[0]->parent;
2415 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002416 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002417 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002418 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002419 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002420 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002421 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002422 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002423 }
2424 }
2425 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002426 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002427 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002428 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002429 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002430 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002431 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002432 i = 0;
2433 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002434 }
2435
2436 if (pke_len == pke_parsed) {
2437 break;
2438 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002439 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 +02002440 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002441 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002442 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002443 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002444 }
2445 pke_parsed += i;
2446 }
2447
2448 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002449 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2450 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002451 goto remove_leafref;
2452 }
2453
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002454 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002455 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456 goto remove_leafref;
2457 }
2458
2459 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002460 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002461 continue;
2462
2463remove_leafref:
2464 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002465 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002466 }
2467 } while (has_predicate);
2468
Michal Vaskocf024702015-10-08 15:01:42 +02002469 free(source_match.node);
2470 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002471 if (parsed) {
2472 *parsed = parsed_loc;
2473 }
2474 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002475
2476error:
2477
2478 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002479 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002480 }
2481 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002482 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002483 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002484 if (parsed) {
2485 *parsed = -parsed_loc+i;
2486 }
2487 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002488}
2489
Michal Vasko730dfdf2015-08-11 14:48:05 +02002490/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002491 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002492 *
Michal Vaskocf024702015-10-08 15:01:42 +02002493 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002494 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002495 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002496 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002497 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002498 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002499 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002500 */
Michal Vasko184521f2015-09-24 13:14:26 +02002501static int
Michal Vaskocf024702015-10-08 15:01:42 +02002502resolve_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 +02002503{
Radek Krejci71b795b2015-08-10 16:20:39 +02002504 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002505 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002506 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002507 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002508
Michal Vaskocf024702015-10-08 15:01:42 +02002509 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002510
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002511 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002512 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002513
2514 /* searching for nodeset */
2515 do {
2516 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002517 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002518 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002519 goto error;
2520 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002521 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002522 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523
Michal Vasko23b61ec2015-08-19 11:19:50 +02002524 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002525 if (parent_times != -1) {
2526 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002527 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002528 if (!ret->node) {
2529 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002530 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002531 goto error;
2532 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002533 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002534 for (i = 0; i < parent_times; ++i) {
2535 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002536 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002537 /* error, too many .. */
Radek Krejciadb57612016-02-16 13:34:34 +01002538 LOGVAL(LYE_INVAL, line, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002539 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002540 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002541 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002542 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002543 data = ret->node[0] = node->parent;
2544 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002545 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002546 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002547 free(ret->node);
2548 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002549 } else {
2550 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002551 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002552 }
2553 }
2554
2555 /* absolute path */
2556 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002557 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002558 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002559 if (data->prev) {
2560 for (; data->prev->next; data = data->prev);
2561 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002562 }
2563 }
2564
2565 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002566 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002567 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002568 LOGVAL(LYE_INELEM_LEN, line, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002569 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002570 goto error;
2571 }
2572
2573 if (has_predicate) {
2574 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002575 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002576 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2577 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002578 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002579 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002580 continue;
2581 }
2582
2583 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002584 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002585 }
Radek Krejciadb57612016-02-16 13:34:34 +01002586 if ((rc = resolve_path_predicate_data(path, first, line, node, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002587 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002588 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002589 LOGVAL(LYE_NORESOLV, 0, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002590 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002591 goto error;
2592 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002594 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002595
Michal Vasko23b61ec2015-08-19 11:19:50 +02002596 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002597 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002598 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, node, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002599 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002600 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002601 goto error;
2602 }
2603 }
2604 } while (path[0] != '\0');
2605
Michal Vaskof02e3742015-08-05 16:27:02 +02002606 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002607
2608error:
2609
Michal Vaskocf024702015-10-08 15:01:42 +02002610 free(ret->node);
2611 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002612 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002613
Michal Vasko0491ab32015-08-19 14:28:29 +02002614 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002615}
2616
Michal Vasko730dfdf2015-08-11 14:48:05 +02002617/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002618 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002619 *
Michal Vaskobb211122015-08-19 14:03:11 +02002620 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002621 * @param[in] context_node Predicate context node (where the predicate is placed).
2622 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko184521f2015-09-24 13:14:26 +02002623 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002624 * @param[in] line Line in the input file.
2625 *
Michal Vasko184521f2015-09-24 13:14:26 +02002626 * @return 0 on forward reference, otherwise the number
2627 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002628 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002629 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002630static int
Radek Krejciadb57612016-02-16 13:34:34 +01002631resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
2632 struct lys_node *parent, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002633{
Michal Vasko1e62a092015-12-01 12:27:20 +01002634 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002635 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2636 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 +02002637 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002638
2639 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002640 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002641 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002642 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002643 return -parsed+i;
2644 }
2645 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002646 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002647
Michal Vasko58090902015-08-13 14:04:15 +02002648 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002649 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002650 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002651 }
Radek Krejciadb57612016-02-16 13:34:34 +01002652 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002653 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002654 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002655 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002656 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002657 }
2658 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002659 }
2660
2661 /* destination */
2662 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2663 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002664 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002665 return -parsed;
2666 }
2667 pke_parsed += i;
2668
Radek Krejciadb57612016-02-16 13:34:34 +01002669 /* parent is actually the parent of this leaf, so skip the first ".." */
2670 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002671 if (!dst_node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002672 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002673 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002674 }
Radek Krejciadb57612016-02-16 13:34:34 +01002675 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002676 }
2677 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002678 if (!dest_pref) {
2679 dest_pref = dst_node->module->name;
2680 }
2681 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002682 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002683 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002684 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002685 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002686 }
2687 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002688 }
2689
2690 if (pke_len == pke_parsed) {
2691 break;
2692 }
2693
2694 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2695 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002696 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent,
2697 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002698 return -parsed;
2699 }
2700 pke_parsed += i;
2701 }
2702
2703 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002704 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002705 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
2706 LOGVAL(LYE_SPEC, 0, 0, NULL, "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02002707 return -parsed;
2708 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002709 } while (has_predicate);
2710
2711 return parsed;
2712}
2713
Michal Vasko730dfdf2015-08-11 14:48:05 +02002714/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002715 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002716 *
Michal Vaskobb211122015-08-19 14:03:11 +02002717 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002718 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002719 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2720 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002721 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002722 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002723 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002724 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002725 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002726 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002727static int
Radek Krejciadb57612016-02-16 13:34:34 +01002728resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf, int first, uint32_t line,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002729 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002730{
Michal Vasko1e62a092015-12-01 12:27:20 +01002731 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002732 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002733 const char *id, *prefix, *name;
2734 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002735 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002736
Michal Vasko184521f2015-09-24 13:14:26 +02002737 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002738 parent_times = 0;
2739 id = path;
2740
2741 do {
2742 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002743 LOGVAL(LYE_INCHAR, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002744 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002745 }
2746 id += i;
2747
Michal Vasko184521f2015-09-24 13:14:26 +02002748 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002749 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002750 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002751 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002752 /* get start node */
2753 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002754 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002755 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002756 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002757 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002758 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002759 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002760 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002761 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002762 if (parent_tpdf) {
2763 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejciadb57612016-02-16 13:34:34 +01002764 LOGVAL(LYE_NORESOLV, line, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002765 return -1;
2766 }
2767
Radek Krejciadb57612016-02-16 13:34:34 +01002768 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002769 i = 0;
2770 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002771 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002772 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002773 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002774 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002775 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002776 }
Michal Vasko58090902015-08-13 14:04:15 +02002777
2778 /* this node is a wrong node, we actually need the augment target */
2779 if (node->nodetype == LYS_AUGMENT) {
2780 node = ((struct lys_node_augment *)node)->target;
2781 if (!node) {
2782 continue;
2783 }
2784 }
2785
2786 ++i;
2787 if (i == parent_times) {
2788 break;
2789 }
2790 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002791 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002792
Michal Vasko1f76a282015-08-04 16:16:53 +02002793 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002794 } else {
2795 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002796 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002797 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002798
Michal Vasko184521f2015-09-24 13:14:26 +02002799 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002800 } else {
2801 node = node->child;
2802 }
2803
Michal Vasko4f0dad02016-02-15 14:08:23 +01002804 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002805 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01002806 }
2807
Michal Vasko36cbaa42015-12-14 13:15:48 +01002808 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 +02002809 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002810 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002811 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002812 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002813 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002814 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002815
2816 if (has_predicate) {
2817 /* we have predicate, so the current result must be list */
2818 if (node->nodetype != LYS_LIST) {
Radek Krejciadb57612016-02-16 13:34:34 +01002819 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002820 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002821 }
2822
Radek Krejciadb57612016-02-16 13:34:34 +01002823 i = resolve_path_predicate_schema(id, node, parent, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002824 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002825 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002826 } else if (i < 0) {
2827 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002828 }
2829 id += i;
2830 }
2831 } while (id[0]);
2832
Radek Krejcib1c12512015-08-11 11:22:04 +02002833 /* the target must be leaf or leaf-list */
2834 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejciadb57612016-02-16 13:34:34 +01002835 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002836 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002837 }
2838
Radek Krejcicf509982015-12-15 09:22:44 +01002839 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002840 if (lyp_check_status(parent->flags, parent->module, parent->name,
2841 node->flags, node->module, node->name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002842 return -1;
2843 }
2844
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002845 if (ret) {
2846 *ret = node;
2847 }
2848 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002849}
2850
Michal Vasko730dfdf2015-08-11 14:48:05 +02002851/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002852 * @brief Resolve instance-identifier predicate in JSON data format.
2853 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002854 *
Michal Vaskobb211122015-08-19 14:03:11 +02002855 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002856 * @param[in,out] node_match Nodes matching the restriction without
2857 * the predicate. Nodes not satisfying
2858 * the predicate are removed.
2859 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002860 * @return Number of characters successfully parsed,
2861 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002862 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002864resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002866 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002867 struct unres_data target_match;
2868 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002869 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002870 const char *model, *name, *value;
2871 char *str;
2872 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2873 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002874
Michal Vasko1f2cc332015-08-19 11:18:32 +02002875 assert(pred && node_match->count);
2876
Michal Vaskocf024702015-10-08 15:01:42 +02002877 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878 idx = -1;
2879 parsed = 0;
2880
2881 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002882 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 return -parsed+i;
2884 }
2885 parsed += i;
2886 pred += i;
2887
Michal Vasko1f2cc332015-08-19 11:18:32 +02002888 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 if (isdigit(name[0])) {
2890 idx = atoi(name);
2891 }
2892
Michal Vasko1f2cc332015-08-19 11:18:32 +02002893 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002894 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002895 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002897 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002898 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002899 if (!target_match.node) {
2900 LOGMEM;
2901 return -1;
2902 }
Michal Vaskocf024702015-10-08 15:01:42 +02002903 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002904 } else {
2905 str = strndup(model, mod_len);
2906 mod = ly_ctx_get_module(ctx, str, NULL);
2907 free(str);
2908
Radek Krejci804836a2016-02-03 10:39:55 +01002909 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002910 goto remove_instid;
2911 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002912 }
2913
2914 /* check that we have the correct type */
2915 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002916 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 goto remove_instid;
2918 }
2919 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002920 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002921 goto remove_instid;
2922 }
2923 }
2924
Michal Vasko83a6c462015-10-08 16:43:53 +02002925 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2926 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002927 || (!value && (idx != cur_idx))) {
2928 goto remove_instid;
2929 }
2930
Michal Vaskocf024702015-10-08 15:01:42 +02002931 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932
2933 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002934 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 continue;
2936
2937remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002938 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939
2940 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002941 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002942 }
2943 } while (has_predicate);
2944
2945 return parsed;
2946}
2947
Michal Vasko730dfdf2015-08-11 14:48:05 +02002948/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002949 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002950 *
Radek Krejciadb57612016-02-16 13:34:34 +01002951 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02002952 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002953 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002954 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002955 * @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 +02002956 */
Michal Vasko184521f2015-09-24 13:14:26 +02002957static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002958resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002959{
Radek Krejcic5090c32015-08-12 09:46:19 +02002960 int i = 0, j;
2961 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002962 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002963 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002964 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002965 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002966 int mod_len, name_len, has_predicate;
2967 struct unres_data node_match;
2968 uint32_t k;
2969
2970 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002971
Radek Krejcic5090c32015-08-12 09:46:19 +02002972 /* we need root to resolve absolute path */
2973 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002974 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002975 if (data->prev) {
2976 for (; data->prev->next; data = data->prev);
2977 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002978
Radek Krejcic5090c32015-08-12 09:46:19 +02002979 /* search for the instance node */
2980 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002981 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002982 if (j <= 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002983 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002984 goto error;
2985 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002986 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002987
Michal Vasko1f2cc332015-08-19 11:18:32 +02002988 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002989 if (!str) {
2990 LOGMEM;
2991 goto error;
2992 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002993 mod = ly_ctx_get_module(ctx, str, NULL);
2994 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002995
Radek Krejcic5090c32015-08-12 09:46:19 +02002996 if (!mod) {
2997 /* no instance exists */
2998 return NULL;
2999 }
3000
Michal Vasko1f2cc332015-08-19 11:18:32 +02003001 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003002 /* no instance exists */
3003 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003004 }
3005
3006 if (has_predicate) {
3007 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003008 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003009 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3010 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3011 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003012 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003013 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014 continue;
3015 }
3016
3017 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003018 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003019 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003020
Michal Vaskof39142b2015-10-21 11:40:05 +02003021 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003022 if (j < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003023 LOGVAL(LYE_INPRED, line, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003024 goto error;
3025 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003026 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003027
Michal Vasko1f2cc332015-08-19 11:18:32 +02003028 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003029 /* no instance exists */
3030 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003031 }
3032 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003033 }
3034
Michal Vasko1f2cc332015-08-19 11:18:32 +02003035 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003036 /* no instance exists */
3037 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003038 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003039 /* instance identifier must resolve to a single node */
Radek Krejciadb57612016-02-16 13:34:34 +01003040 LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003041
3042 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003043 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003044
3045 return NULL;
3046 } else {
3047 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003048 result = node_match.node[0];
3049 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003050
3051 return result;
3052 }
3053
3054error:
3055
3056 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003057 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003058
3059 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003060}
3061
Michal Vasko730dfdf2015-08-11 14:48:05 +02003062/**
3063 * @brief Passes config flag down to children. Does not log.
3064 *
3065 * @param[in] node Parent node.
3066 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003067static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003068inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003069{
Radek Krejci1d82ef62015-08-07 14:44:40 +02003070 LY_TREE_FOR(node, node) {
3071 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
3072 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073 }
3074}
3075
Michal Vasko730dfdf2015-08-11 14:48:05 +02003076/**
Michal Vasko7178e692016-02-12 15:58:05 +01003077 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003078 *
Michal Vaskobb211122015-08-19 14:03:11 +02003079 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003080 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko7178e692016-02-12 15:58:05 +01003081 * @param[in] first Whether this is the first resolution try.
3082 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003083 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003084 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003085 */
Michal Vasko7178e692016-02-12 15:58:05 +01003086static int
3087resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003088{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003089 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003090 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003091
Michal Vasko1d87a922015-08-21 12:57:16 +02003092 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003093
3094 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003095 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), (const struct lys_node **)&aug->target);
Michal Vasko7178e692016-02-12 15:58:05 +01003096 if (rc == -1) {
3097 return -1;
3098 }
3099 if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003100 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003101 return -1;
3102 }
3103 if (!aug->target) {
Michal Vasko7178e692016-02-12 15:58:05 +01003104 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003105 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01003106 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003107 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003108 }
3109
3110 if (!aug->child) {
3111 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003112 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113 return EXIT_SUCCESS;
3114 }
3115
Michal Vaskod58d5962016-03-02 14:29:41 +01003116 /* check for mandatory nodes - if the target node is in another module
3117 * the added nodes cannot be mandatory
3118 */
3119 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3120 && lyp_check_mandatory((struct lys_node *)aug)) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003121 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, "mandatory", "augment node");
3122 LOGVAL(LYE_SPEC, 0, 0, NULL, "When augmenting data in another module, mandatory nodes are not allowed.");
Michal Vaskod58d5962016-03-02 14:29:41 +01003123 return -1;
3124 }
3125
Michal Vasko07e89ef2016-03-03 13:28:57 +01003126 /* check augment target type and then augment nodes type */
3127 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3128 LY_TREE_FOR(aug->child, sub) {
3129 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003130 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3131 LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003132 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3133 return -1;
3134 }
3135 }
3136 } else if (aug->target->nodetype == LYS_CHOICE) {
3137 LY_TREE_FOR(aug->child, sub) {
3138 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003139 LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3140 LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003141 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3142 return -1;
3143 }
3144 }
3145 } else {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003146 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3147 LOGVAL(LYE_SPEC, 0, 0, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003148 return -1;
3149 }
3150
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151 /* inherit config information from parent, augment does not have
3152 * config property, but we need to keep the information for subelements
3153 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003154 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 inherit_config_flag(sub);
3157 }
3158
Radek Krejcic071c542016-01-27 14:57:51 +01003159 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003160 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01003161 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003162 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003163 }
3164 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003165 /* reconnect augmenting data into the target - add them to the target child list */
3166 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003167 sub = aug->target->child->prev; /* remember current target's last node */
3168 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003169 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003170 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003171 } else {
3172 aug->target->child = aug->child;
3173 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174
3175 return EXIT_SUCCESS;
3176}
3177
Michal Vasko730dfdf2015-08-11 14:48:05 +02003178/**
3179 * @brief Resolve uses, apply augments, refines. Logs directly.
3180 *
Michal Vaskobb211122015-08-19 14:03:11 +02003181 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003182 * @param[in,out] unres List of unresolved items.
3183 * @param[in] line Line in the input file.
3184 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003185 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003186 */
Michal Vasko184521f2015-09-24 13:14:26 +02003187static int
Michal Vaskodef0db12015-10-07 13:22:48 +02003188resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003189{
3190 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003191 struct lys_node *node = NULL;
3192 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003193 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003194 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003195 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003196 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197
Michal Vasko71e1aa82015-08-12 12:17:51 +02003198 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003199 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003200 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003201
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003203 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01003204 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003205 if (!node) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003206 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3207 LOGVAL(LYE_SPEC, 0, 0, NULL, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210 }
3211 ctx = uses->module->ctx;
3212
Michal Vaskodef0db12015-10-07 13:22:48 +02003213 /* we managed to copy the grouping, the rest must be possible to resolve */
3214
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003215 /* apply refines */
3216 for (i = 0; i < uses->refine_size; i++) {
3217 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003218 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
3219 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003220 if (rc || !node) {
Radek Krejciadb57612016-02-16 13:34:34 +01003221 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003222 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003223 }
3224
Radek Krejci1d82ef62015-08-07 14:44:40 +02003225 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003226 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3227 LOGVAL(LYE_SPEC, 0, 0, NULL, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003228 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 }
3230
3231 /* description on any nodetype */
3232 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003233 lydict_remove(ctx, node->dsc);
3234 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003235 }
3236
3237 /* reference on any nodetype */
3238 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003239 lydict_remove(ctx, node->ref);
3240 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 }
3242
3243 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003244 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003245 node->flags &= ~LYS_CONFIG_MASK;
3246 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003247 }
3248
3249 /* default value ... */
3250 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003251 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003253 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3254 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3255 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003257 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3258 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003259 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejciadb57612016-02-16 13:34:34 +01003260 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003261 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 }
3263 }
3264 }
3265
3266 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003267 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003268 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003270 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271
3272 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003273 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003274 }
3275 }
3276
3277 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003278 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3279 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3280 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003281 }
3282
3283 /* min/max-elements on list or leaf-list */
3284 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003285 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003287 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003288 }
3289 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003290 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003292 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003294 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003295 }
3296 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003297 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298 }
3299 }
3300
3301 /* must in leaf, leaf-list, list, container or anyxml */
3302 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003303 switch (node->nodetype) {
3304 case LYS_LEAF:
3305 old_size = &((struct lys_node_leaf *)node)->must_size;
3306 old_must = &((struct lys_node_leaf *)node)->must;
3307 break;
3308 case LYS_LEAFLIST:
3309 old_size = &((struct lys_node_leaflist *)node)->must_size;
3310 old_must = &((struct lys_node_leaflist *)node)->must;
3311 break;
3312 case LYS_LIST:
3313 old_size = &((struct lys_node_list *)node)->must_size;
3314 old_must = &((struct lys_node_list *)node)->must;
3315 break;
3316 case LYS_CONTAINER:
3317 old_size = &((struct lys_node_container *)node)->must_size;
3318 old_must = &((struct lys_node_container *)node)->must;
3319 break;
3320 case LYS_ANYXML:
3321 old_size = &((struct lys_node_anyxml *)node)->must_size;
3322 old_must = &((struct lys_node_anyxml *)node)->must;
3323 break;
3324 default:
3325 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003326 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003327 }
3328
3329 size = *old_size + rfn->must_size;
3330 must = realloc(*old_must, size * sizeof *rfn->must);
3331 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003332 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003333 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003334 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003335 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3336 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3337 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3338 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3339 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3340 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003341 }
3342
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003343 *old_must = must;
3344 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 }
3346 }
3347
3348 /* apply augments */
3349 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko7178e692016-02-12 15:58:05 +01003350 rc = resolve_augment(&uses->augment[i], uses->child, 0, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003351 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003352 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003353 }
3354 }
3355
3356 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003357}
3358
Michal Vasko730dfdf2015-08-11 14:48:05 +02003359/**
3360 * @brief Resolve base identity recursively. Does not log.
3361 *
3362 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003363 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003364 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003365 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003366 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003367 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003368 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003369static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003370resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003371 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372{
Michal Vaskof02e3742015-08-05 16:27:02 +02003373 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003374 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003375 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003376
Radek Krejcicf509982015-12-15 09:22:44 +01003377 assert(ret);
3378
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 /* search module */
3380 for (i = 0; i < module->ident_size; i++) {
3381 if (!strcmp(basename, module->ident[i].name)) {
3382
3383 if (!ident) {
3384 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003385 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003386 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003387 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 }
3389
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003390 base = &module->ident[i];
3391 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 }
3393 }
3394
3395 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003396 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3397 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3398 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003400 if (!ident) {
3401 *ret = &module->inc[j].submodule->ident[i];
3402 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003403 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003404
3405 base = &module->inc[j].submodule->ident[i];
3406 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407 }
3408 }
3409 }
3410
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003411matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003413 if (base) {
3414 /* check for circular reference */
3415 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3416 if (ident == base_iter) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01003417 LOGVAL(LYE_INARG, 0, LY_VLOG_NONE, NULL, base_iter->name, "base");
3418 LOGVAL(LYE_SPEC, 0, 0, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003419 return EXIT_FAILURE;
3420 }
3421 }
3422 /* checks done, store the result */
3423 ident->base = base;
3424
3425 /* maintain backlinks to the derived identitise */
3426 while (base) {
3427 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003428 if (der) {
3429 der->next = malloc(sizeof *der);
3430 der = der->next;
3431 } else {
3432 ident->base->der = der = malloc(sizeof *der);
3433 }
Michal Vasko253035f2015-12-17 16:58:13 +01003434 if (!der) {
3435 LOGMEM;
3436 return EXIT_FAILURE;
3437 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438 der->next = NULL;
3439 der->ident = ident;
3440
Radek Krejcibabbff82016-02-19 13:31:37 +01003441 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003442 }
Radek Krejcicf509982015-12-15 09:22:44 +01003443 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003444 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445 }
3446
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003447 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003448}
3449
Michal Vasko730dfdf2015-08-11 14:48:05 +02003450/**
3451 * @brief Resolve base identity. Logs directly.
3452 *
3453 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003454 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003455 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003456 * @param[in] parent Either "type" or "identity".
Michal Vasko184521f2015-09-24 13:14:26 +02003457 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003459 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003460 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003461 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003462 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003463static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003464resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003465 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003466{
3467 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003468 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003469 struct lys_ident *target, **ret;
3470 uint8_t flags;
3471 struct lys_module *mod;
3472
3473 assert((ident && !type) || (!ident && type));
3474
3475 if (!type) {
3476 /* have ident to resolve */
3477 ret = &target;
3478 flags = ident->flags;
3479 mod = ident->module;
3480 } else {
3481 /* have type to fill */
3482 ret = &type->info.ident.ref;
3483 flags = type->parent->flags;
3484 mod = type->parent->module;
3485 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486
3487 /* search for the base identity */
3488 name = strchr(basename, ':');
3489 if (name) {
3490 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003491 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003492 name++;
3493
Michal Vasko2d851a92015-10-20 16:16:36 +02003494 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003496 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003497 }
3498 } else {
3499 name = basename;
3500 }
3501
Radek Krejcic071c542016-01-27 14:57:51 +01003502 /* get module where to search */
3503 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3504 if (!module) {
3505 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01003506 LOGVAL(LYE_INMOD, line, 0, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003507 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508 }
3509
Radek Krejcic071c542016-01-27 14:57:51 +01003510 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003511 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003512 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003513 } else if (ly_errno) {
3514 LOGVAL(LYE_LINE, line, 0, NULL);
3515 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 }
Radek Krejcic071c542016-01-27 14:57:51 +01003517 /* and all its submodules */
3518 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3519 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3520 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003521 } else if (ly_errno) {
3522 LOGVAL(LYE_LINE, line, 0, NULL);
3523 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003524 }
3525 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003526
Michal Vasko184521f2015-09-24 13:14:26 +02003527 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003528 LOGVAL(LYE_INARG, line, 0, NULL, basename, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003529 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003530 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003531
3532success:
3533 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003534 if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name,
3535 line, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003536 return -1;
3537 }
3538
3539 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003540}
3541
Michal Vasko730dfdf2015-08-11 14:48:05 +02003542/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003543 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003544 *
3545 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003546 * @param[in] ident_name Identityref name.
3547 * @param[in] line Line from the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01003548 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003549 *
3550 * @return Pointer to the identity resolvent, NULL on error.
3551 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003552struct lys_ident *
Radek Krejciadb57612016-02-16 13:34:34 +01003553resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003555 const char *mod_name, *name;
3556 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003557 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558
Michal Vaskofb0873c2015-08-21 09:00:07 +02003559 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003560 return NULL;
3561 }
3562
Michal Vaskoc633ca02015-08-21 14:03:51 +02003563 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003564 if (rc < (signed)strlen(ident_name)) {
Radek Krejciadb57612016-02-16 13:34:34 +01003565 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003566 return NULL;
3567 }
3568
Michal Vaskoc633ca02015-08-21 14:03:51 +02003569 if (!strcmp(base->name, name) && (!mod_name
3570 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003571 return base;
3572 }
3573
3574 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003575 if (!strcmp(der->ident->name, name) && (!mod_name
3576 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3577 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578 /* we have match */
3579 return der->ident;
3580 }
3581 }
3582
Radek Krejciadb57612016-02-16 13:34:34 +01003583 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003584 return NULL;
3585}
3586
Michal Vasko730dfdf2015-08-11 14:48:05 +02003587/**
Michal Vasko7955b362015-09-04 14:18:15 +02003588 * @brief Resolve (find) choice default case. Does not log.
3589 *
3590 * @param[in] choic Choice to use.
3591 * @param[in] dflt Name of the default case.
3592 *
3593 * @return Pointer to the default node or NULL.
3594 */
3595static struct lys_node *
3596resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3597{
3598 struct lys_node *child, *ret;
3599
3600 LY_TREE_FOR(choic->child, child) {
3601 if (child->nodetype == LYS_USES) {
3602 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3603 if (ret) {
3604 return ret;
3605 }
3606 }
3607
Radek Krejci749190d2016-02-18 16:26:25 +01003608 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003609 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3610 return child;
3611 }
3612 }
3613
3614 return NULL;
3615}
3616
3617/**
Michal Vaskobb211122015-08-19 14:03:11 +02003618 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003619 *
Michal Vaskobb211122015-08-19 14:03:11 +02003620 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003621 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003622 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003623 * @param[in] line Line in the input file.
3624 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003625 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003626 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003628resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003629{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003630 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003631 struct lys_node *parent;
3632
3633 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3634 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3635
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003636 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003637 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3638 if (rc == -1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003639 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003640 return -1;
3641 } else if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003642 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003643 return -1;
3644 } else if (!uses->grp) {
3645 if (parent && first) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003646 ++parent->nacm;
3647 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003648 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003649 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003650 }
3651
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003652 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003653 if (parent && first) {
3654 ++parent->nacm;
3655 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003656 return EXIT_FAILURE;
3657 }
3658
Michal Vaskodef0db12015-10-07 13:22:48 +02003659 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003660 if (!rc) {
3661 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003662 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003663 if (!parent->nacm) {
3664 LOGINT;
3665 return -1;
3666 }
3667 --parent->nacm;
3668 }
Radek Krejcicf509982015-12-15 09:22:44 +01003669
3670 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003671 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003672 uses->grp->flags, uses->grp->module, uses->grp->name,
3673 line, (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003674 return -1;
3675 }
3676
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003677 return EXIT_SUCCESS;
3678 }
3679
Michal Vasko407f1bb2015-09-23 15:51:07 +02003680 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003681 ++parent->nacm;
3682 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003683 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684}
3685
Michal Vasko730dfdf2015-08-11 14:48:05 +02003686/**
Michal Vasko9957e592015-08-17 15:04:09 +02003687 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003688 *
Michal Vaskobb211122015-08-19 14:03:11 +02003689 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003690 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003691 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003692 * @param[in] line Line in the input file.
3693 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003694 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003695 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003696static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003697resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003698{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003699 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003700 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003701
3702 for (i = 0; i < list->keys_size; ++i) {
3703 /* get the key name */
3704 if ((value = strpbrk(keys_str, " \t\n"))) {
3705 len = value - keys_str;
3706 while (isspace(value[0])) {
3707 value++;
3708 }
3709 } else {
3710 len = strlen(keys_str);
3711 }
3712
Michal Vasko4f0dad02016-02-15 14:08:23 +01003713 rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003714 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003715 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003716 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003717 }
3718 return rc;
3719 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003720
Radek Krejciadb57612016-02-16 13:34:34 +01003721 if (check_key(list, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003722 /* check_key logs */
3723 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003724 }
3725
Radek Krejcicf509982015-12-15 09:22:44 +01003726 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003727 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejciadb57612016-02-16 13:34:34 +01003728 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3729 line, (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003730 return -1;
3731 }
3732
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003733 /* prepare for next iteration */
3734 while (value && isspace(value[0])) {
3735 value++;
3736 }
3737 keys_str = value;
3738 }
3739
Michal Vaskof02e3742015-08-05 16:27:02 +02003740 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003741}
3742
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003743/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003744 * @brief Resolve (check) all must conditions of \p node.
3745 * Logs directly.
3746 *
3747 * @param[in] node Data node with optional must statements.
3748 * @param[in] first Whether this is the first resolution to try.
3749 * @param[in] line Line in the input file.
3750 *
3751 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3752 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003753static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003754resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003755{
Michal Vaskobf19d252015-10-08 15:39:17 +02003756 uint8_t i, must_size;
3757 struct lys_restr *must;
3758 struct lyxp_set set;
3759
3760 assert(node);
3761 memset(&set, 0, sizeof set);
3762
3763 switch (node->schema->nodetype) {
3764 case LYS_CONTAINER:
3765 must_size = ((struct lys_node_container *)node->schema)->must_size;
3766 must = ((struct lys_node_container *)node->schema)->must;
3767 break;
3768 case LYS_LEAF:
3769 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3770 must = ((struct lys_node_leaf *)node->schema)->must;
3771 break;
3772 case LYS_LEAFLIST:
3773 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3774 must = ((struct lys_node_leaflist *)node->schema)->must;
3775 break;
3776 case LYS_LIST:
3777 must_size = ((struct lys_node_list *)node->schema)->must_size;
3778 must = ((struct lys_node_list *)node->schema)->must;
3779 break;
3780 case LYS_ANYXML:
3781 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3782 must = ((struct lys_node_anyxml *)node->schema)->must;
3783 break;
3784 default:
3785 must_size = 0;
3786 break;
3787 }
3788
3789 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003790 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003791 return -1;
3792 }
3793
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003794 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003795
3796 if (!set.value.bool) {
3797 if (!first) {
Michal Vasko7d3ec592016-02-17 12:06:44 +01003798 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003799 }
3800 return 1;
3801 }
3802 }
3803
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003804 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003805}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003806
Michal Vaskobf19d252015-10-08 15:39:17 +02003807/**
Michal Vaskocf024702015-10-08 15:01:42 +02003808 * @brief Resolve (find) when condition context node. Does not log.
3809 *
3810 * @param[in] node Data node, whose conditional definition is being decided.
3811 * @param[in] schema Schema node with a when condition.
3812 *
3813 * @return Context node.
3814 */
3815static struct lyd_node *
3816resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003817{
Michal Vaskocf024702015-10-08 15:01:42 +02003818 struct lyd_node *parent;
3819 struct lys_node *sparent;
3820 uint16_t i, data_depth, schema_depth;
3821
3822 /* find a not schema-only node */
3823 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3824 schema = lys_parent(schema);
3825 if (!schema) {
3826 return NULL;
3827 }
3828 }
3829
3830 /* get node depths */
3831 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3832 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3833 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3834 ++schema_depth;
3835 }
3836 }
3837 if (data_depth < schema_depth) {
3838 return NULL;
3839 }
3840
3841 /* find the corresponding data node */
3842 for (i = 0; i < data_depth - schema_depth; ++i) {
3843 node = node->parent;
3844 }
3845 if (node->schema != schema) {
3846 return NULL;
3847 }
3848
3849 return node;
3850}
3851
3852/**
3853 * @brief Resolve (check) all when conditions relevant for \p node.
3854 * Logs directly.
3855 *
3856 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3857 * @param[in] first Whether this is the first resolution to try.
3858 * @param[in] line Line in the input file.
3859 *
3860 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3861 */
3862static int
3863resolve_when(struct lyd_node *node, int first, uint32_t line)
3864{
3865 struct lyd_node *ctx_node = NULL;
3866 struct lys_node *parent;
3867 struct lyxp_set set;
3868
3869 assert(node);
3870 memset(&set, 0, sizeof set);
3871
3872 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003873 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003874 return -1;
3875 }
3876
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003877 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003878
3879 if (!set.value.bool) {
3880 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003881 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003882 }
3883 return 1;
3884 }
3885 }
3886
3887 parent = node->schema;
3888 goto check_augment;
3889
3890 /* check when in every schema node that affects node */
3891 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3892 if (((struct lys_node_uses *)parent)->when) {
3893 if (!ctx_node) {
3894 ctx_node = resolve_when_ctx_node(node, parent);
3895 if (!ctx_node) {
3896 LOGINT;
3897 return -1;
3898 }
3899 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003900 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003901 return -1;
3902 }
3903
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003904 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003905
3906 if (!set.value.bool) {
3907 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003908 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003909 }
3910 return 1;
3911 }
3912 }
3913
3914check_augment:
3915 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3916 if (!ctx_node) {
3917 ctx_node = resolve_when_ctx_node(node, parent->parent);
3918 if (!ctx_node) {
3919 LOGINT;
3920 return -1;
3921 }
3922 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003923 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003924 return -1;
3925 }
3926
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003927 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003928
3929 if (!set.value.bool) {
3930 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003931 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003932 }
3933 return 1;
3934 }
3935 }
3936
3937 parent = lys_parent(parent);
3938 }
3939
3940 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003941}
3942
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003943/**
Michal Vaskobb211122015-08-19 14:03:11 +02003944 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003945 *
3946 * @param[in] mod Main module.
3947 * @param[in] item Item to resolve. Type determined by \p type.
3948 * @param[in] type Type of the unresolved item.
3949 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003950 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003951 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003952 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003953 *
3954 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3955 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003956static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003957resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003958 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003959{
Radek Krejci4f78b532016-02-17 13:43:00 +01003960 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003961 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003962 const char *base_name;
3963
3964 struct lys_ident *ident;
3965 struct lys_type *stype;
3966 struct lys_feature **feat_ptr;
3967 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003968 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003969
3970 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003971 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003972 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003973 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003974 ident = item;
3975
Radek Krejcibabbff82016-02-19 13:31:37 +01003976 rc = resolve_base_ident(mod, ident, base_name, "identity", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003977 break;
3978 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003979 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003980 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003981 stype = item;
3982
Radek Krejcicf509982015-12-15 09:22:44 +01003983 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003984 break;
3985 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003986 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003987 stype = item;
3988
Radek Krejci2f12f852016-01-08 12:59:57 +01003989 /* HACK - when there is no parent, we are in top level typedef and in that
3990 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3991 * know it via tpdf_flag */
3992 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01003993 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01003994 node = (struct lys_node *)stype->parent;
3995 }
3996
3997 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003998 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01003999 if (stype->info.lref.target) {
4000 /* store the backlink from leafref target */
4001 if (!stype->info.lref.target->child) {
4002 stype->info.lref.target->child = (void*)ly_set_new();
4003 if (!stype->info.lref.target->child) {
4004 LOGMEM;
4005 return -1;
4006 }
4007 }
4008 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
4009 }
4010
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004011 break;
4012 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004013 /* parent */
4014 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004015 stype = item;
4016
Michal Vasko88c29542015-11-27 14:57:53 +01004017 /* HACK type->der is temporarily unparsed type statement */
4018 yin = (struct lyxml_elem *)stype->der;
4019 stype->der = NULL;
4020
4021 rc = fill_yin_type(mod, node, yin, stype, unres);
4022 if (!rc) {
4023 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01004024 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01004025 } else {
4026 /* may try again later, put all back how it was */
4027 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004028 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004029 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004030 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004031 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004032 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004033 feat_ptr = item;
4034
Michal Vasko184521f2015-09-24 13:14:26 +02004035 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036 break;
4037 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02004038 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004039 break;
4040 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004041 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004042 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004043 stype = item;
4044
Michal Vasko56826402016-03-02 11:11:37 +01004045 rc = check_default(stype, base_name, mod, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004046 break;
4047 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004048 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004049 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004050 choic = item;
4051
Michal Vasko7955b362015-09-04 14:18:15 +02004052 choic->dflt = resolve_choice_dflt(choic, base_name);
4053 if (choic->dflt) {
4054 rc = EXIT_SUCCESS;
4055 } else {
4056 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004057 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058 break;
4059 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004060 has_str = 1;
Michal Vasko36cbaa42015-12-14 13:15:48 +01004061 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004062 break;
4063 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004064 has_str = 1;
Radek Krejci581ce772015-11-10 17:22:40 +01004065 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004067 case UNRES_AUGMENT:
4068 rc = resolve_augment(item, NULL, first, line);
Michal Vasko7178e692016-02-12 15:58:05 +01004069 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004070 default:
4071 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004072 break;
4073 }
4074
Radek Krejci4f78b532016-02-17 13:43:00 +01004075 if (has_str && !rc) {
4076 lydict_remove(mod->ctx, str_snode);
4077 }
4078
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004079 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080}
4081
Michal Vaskof02e3742015-08-05 16:27:02 +02004082/* logs directly */
4083static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02004084print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085{
Michal Vaskof02e3742015-08-05 16:27:02 +02004086 char line_str[18];
4087
4088 if (line) {
4089 sprintf(line_str, " (line %u)", line);
4090 } else {
4091 line_str[0] = '\0';
4092 }
4093
4094 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004095 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004096 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004097 break;
4098 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004099 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004100 break;
4101 case UNRES_TYPE_LEAFREF:
4102 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
4103 break;
4104 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004105 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
4106 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02004107 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004108 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004109 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 +02004110 break;
4111 case UNRES_USES:
4112 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
4113 break;
4114 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004115 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 +02004116 break;
4117 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004118 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 +02004119 break;
4120 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004121 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 +02004122 break;
4123 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02004124 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 +02004125 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004126 case UNRES_AUGMENT:
Michal Vasko729d2912016-02-12 16:01:43 +01004127 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "augment target", ((struct lys_node_augment *)item)->target_name, line_str);
Michal Vasko7178e692016-02-12 15:58:05 +01004128 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004129 default:
4130 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004131 break;
4132 }
4133}
4134
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004135/**
Michal Vaskobb211122015-08-19 14:03:11 +02004136 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004137 *
4138 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004139 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004140 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004141 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004142 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004143int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004144resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004145{
Michal Vasko88c29542015-11-27 14:57:53 +01004146 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004147 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004148
4149 assert(unres);
4150
Michal Vasko51054ca2015-08-12 12:20:00 +02004151 resolved = 0;
4152
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004153 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004154 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004155 unres_count = 0;
4156 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004157
4158 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01004159 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
4160 * we need every type's base only */
4161 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004162 continue;
4163 }
4164
Michal Vasko88c29542015-11-27 14:57:53 +01004165 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004166 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
4167 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004168 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004169 unres->type[i] = UNRES_RESOLVED;
4170 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004171 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004172 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004173 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004174 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004175 }
Michal Vasko88c29542015-11-27 14:57:53 +01004176 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004177
Michal Vasko88c29542015-11-27 14:57:53 +01004178 if (res_count < unres_count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004179 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004180 }
4181
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004182 /* the rest */
4183 for (i = 0; i < unres->count; ++i) {
4184 if (unres->type[i] == UNRES_RESOLVED) {
4185 continue;
4186 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004187
Michal Vasko407f1bb2015-09-23 15:51:07 +02004188 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
4189 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02004190 if (rc) {
4191 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004192 }
Michal Vasko184521f2015-09-24 13:14:26 +02004193
4194 unres->type[i] = UNRES_RESOLVED;
4195 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004196 }
4197
4198 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004199 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004200 }
4201
Radek Krejcic071c542016-01-27 14:57:51 +01004202 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004203 return EXIT_SUCCESS;
4204}
4205
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004206/**
Michal Vaskobb211122015-08-19 14:03:11 +02004207 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004208 *
4209 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004210 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004211 * @param[in] item Item to resolve. Type determined by \p type.
4212 * @param[in] type Type of the unresolved item.
4213 * @param[in] str String argument.
4214 * @param[in] line Line in the input file.
4215 *
4216 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4217 */
4218int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004219unres_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 +02004220 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221{
Radek Krejci4f78b532016-02-17 13:43:00 +01004222 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)lydict_insert(mod->ctx, str, 0), line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004223}
4224
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004225/**
Michal Vaskobb211122015-08-19 14:03:11 +02004226 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004227 *
4228 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004229 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004230 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004231 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004232 * @param[in] snode Schema node argument.
4233 * @param[in] line Line in the input file.
4234 *
4235 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4236 */
4237int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004238unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02004239 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004240{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004241 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004242 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004243
Michal Vasko9bf425b2015-10-22 11:42:03 +02004244 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4245 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004246
Michal Vasko184521f2015-09-24 13:14:26 +02004247 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004248 if (rc != EXIT_FAILURE) {
4249 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004250 }
4251
Michal Vasko0bd29d12015-08-19 11:45:49 +02004252 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02004253
Michal Vasko88c29542015-11-27 14:57:53 +01004254 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4255 if (type == UNRES_TYPE_DER) {
4256 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
4257 lyxml_unlink_elem(mod->ctx, yin, 1);
4258 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4259 }
4260
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004261 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004262 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4263 if (!unres->item) {
4264 LOGMEM;
4265 return -1;
4266 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004267 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004268 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4269 if (!unres->type) {
4270 LOGMEM;
4271 return -1;
4272 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004273 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004274 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4275 if (!unres->str_snode) {
4276 LOGMEM;
4277 return -1;
4278 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004279 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004280 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4281 if (!unres->module) {
4282 LOGMEM;
4283 return -1;
4284 }
4285 unres->module[unres->count-1] = mod;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004286#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004287 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
4288 if (!unres->line) {
4289 LOGMEM;
4290 return -1;
4291 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004292 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004293#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004294
4295 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004296}
4297
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004298/**
Michal Vaskobb211122015-08-19 14:03:11 +02004299 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004300 *
4301 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004302 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004303 * @param[in] item Old item to be resolved.
4304 * @param[in] type Type of the old unresolved item.
4305 * @param[in] new_item New item to use in the duplicate.
4306 *
4307 * @return EXIT_SUCCESS on success, -1 on error.
4308 */
Michal Vaskodad19402015-08-06 09:51:53 +02004309int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004310unres_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 +02004311{
4312 int i;
4313
Michal Vaskocf024702015-10-08 15:01:42 +02004314 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004315
Michal Vasko0bd29d12015-08-19 11:45:49 +02004316 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004317
4318 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004319 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004320 }
4321
Michal Vasko0d204592015-10-07 09:50:04 +02004322 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004323 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004324 LOGINT;
4325 return -1;
4326 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004327 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004328 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004329 LOGINT;
4330 return -1;
4331 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004332 }
Michal Vaskodad19402015-08-06 09:51:53 +02004333
4334 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004335}
4336
Michal Vaskof02e3742015-08-05 16:27:02 +02004337/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004338int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004339unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004340{
4341 uint32_t ret = -1, i;
4342
4343 for (i = 0; i < unres->count; ++i) {
4344 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4345 ret = i;
4346 break;
4347 }
4348 }
4349
4350 return ret;
4351}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004352
Michal Vasko88c29542015-11-27 14:57:53 +01004353void
Radek Krejcic071c542016-01-27 14:57:51 +01004354unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004355{
4356 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004357 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01004358
Radek Krejcic071c542016-01-27 14:57:51 +01004359 if (!unres || !(*unres)) {
4360 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004361 }
4362
Radek Krejcic071c542016-01-27 14:57:51 +01004363 assert(module || (*unres)->count == 0);
4364
4365 for (i = 0; i < (*unres)->count; ++i) {
4366 if ((*unres)->module[i] != module) {
4367 if ((*unres)->type[i] != UNRES_RESOLVED) {
4368 unresolved++;
4369 }
4370 continue;
4371 }
4372 if ((*unres)->type[i] == UNRES_TYPE_DER) {
4373 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
4374 }
4375 (*unres)->type[i] = UNRES_RESOLVED;
4376 }
4377
4378 if (!module || (!unresolved && !module->type)) {
4379 free((*unres)->item);
4380 free((*unres)->type);
4381 free((*unres)->str_snode);
4382 free((*unres)->module);
Michal Vasko88c29542015-11-27 14:57:53 +01004383#ifndef NDEBUG
Radek Krejcic071c542016-01-27 14:57:51 +01004384 free((*unres)->line);
Michal Vasko88c29542015-11-27 14:57:53 +01004385#endif
Radek Krejcic071c542016-01-27 14:57:51 +01004386 free((*unres));
4387 (*unres) = NULL;
4388 }
Michal Vasko88c29542015-11-27 14:57:53 +01004389}
4390
Michal Vasko8bcdf292015-08-19 14:04:43 +02004391/* logs directly */
4392static void
Michal Vaskocf024702015-10-08 15:01:42 +02004393print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004394{
4395 struct lys_node_leaf *sleaf;
4396 char line_str[18];
4397
4398 if (line) {
4399 sprintf(line_str, " (line %u)", line);
4400 } else {
4401 line_str[0] = '\0';
4402 }
4403
Michal Vaskocf024702015-10-08 15:01:42 +02004404 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004405
Michal Vaskocf024702015-10-08 15:01:42 +02004406 switch (type) {
4407 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004408 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
4409 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004410 break;
4411 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004412 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02004413 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004414 break;
4415 case UNRES_WHEN:
4416 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
4417 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02004418 case UNRES_MUST:
4419 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
4420 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004421 default:
4422 LOGINT;
4423 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004424 }
4425}
4426
4427/**
4428 * @brief Resolve a single unres data item. Logs directly.
4429 *
Michal Vaskocf024702015-10-08 15:01:42 +02004430 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02004431 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02004432 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02004433 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004434 *
4435 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4436 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004437int
Michal Vaskocf024702015-10-08 15:01:42 +02004438resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004439{
4440 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004441 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004442 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004443 struct lys_node_leaf *sleaf;
4444 struct unres_data matches;
4445
4446 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004447 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004448 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004449
Michal Vaskocf024702015-10-08 15:01:42 +02004450 switch (type) {
4451 case UNRES_LEAFREF:
4452 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02004453 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004454 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004455 }
4456
4457 /* check that value matches */
4458 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004459 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004460 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004461 break;
4462 }
4463 }
4464
Michal Vaskocf024702015-10-08 15:01:42 +02004465 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004466 memset(&matches, 0, sizeof matches);
4467
Michal Vaskocf024702015-10-08 15:01:42 +02004468 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004469 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02004470 if (!first) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01004471 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
4472 LOGVAL(LYE_SPEC, 0, 0, NULL, "Leafref value \"%s\" did not match any node value.", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004473 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004474 return EXIT_FAILURE;
4475 }
Michal Vaskocf024702015-10-08 15:01:42 +02004476 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004477
Michal Vaskocf024702015-10-08 15:01:42 +02004478 case UNRES_INSTID:
4479 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004480 ly_errno = 0;
Radek Krejci40f17b92016-02-03 14:30:43 +01004481 leaf->value.instance = resolve_instid(node, leaf->value_str, line);
4482 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004483 if (ly_errno) {
4484 return -1;
4485 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004486 if (!first) {
Michal Vasko6ea3e362016-03-11 10:25:36 +01004487 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004488 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004489 return EXIT_FAILURE;
4490 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004491 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004492 }
4493 }
Michal Vaskocf024702015-10-08 15:01:42 +02004494 break;
4495
4496 case UNRES_WHEN:
4497 if ((rc = resolve_when(node, first, line))) {
4498 return rc;
4499 }
4500 break;
4501
Michal Vaskobf19d252015-10-08 15:39:17 +02004502 case UNRES_MUST:
4503 if ((rc = resolve_must(node, first, line))) {
4504 return rc;
4505 }
4506 break;
4507
Michal Vaskocf024702015-10-08 15:01:42 +02004508 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004509 LOGINT;
4510 return -1;
4511 }
4512
4513 return EXIT_SUCCESS;
4514}
4515
4516/**
4517 * @brief Try to resolve an unres data item. Logs indirectly.
4518 *
4519 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004520 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004521 * @param[in] line Line in the input file.
4522 *
4523 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4524 */
4525int
Michal Vaskocf024702015-10-08 15:01:42 +02004526unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004527{
4528 int rc;
4529
Michal Vaskobf19d252015-10-08 15:39:17 +02004530 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004531
Michal Vaskocf024702015-10-08 15:01:42 +02004532 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004533 if (rc != EXIT_FAILURE) {
4534 return rc;
4535 }
4536
Michal Vaskocf024702015-10-08 15:01:42 +02004537 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004538
4539 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004540 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4541 if (!unres->node) {
4542 LOGMEM;
4543 return -1;
4544 }
Michal Vaskocf024702015-10-08 15:01:42 +02004545 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004546 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4547 if (!unres->type) {
4548 LOGMEM;
4549 return -1;
4550 }
Michal Vaskocf024702015-10-08 15:01:42 +02004551 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004552#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004553 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4554 if (!unres->line) {
4555 LOGMEM;
4556 return -1;
4557 }
Michal Vaskocf024702015-10-08 15:01:42 +02004558 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004559#endif
4560
4561 return EXIT_SUCCESS;
4562}
4563
4564/**
4565 * @brief Resolve every unres data item in the structure. Logs directly.
4566 *
4567 * @param[in] unres Unres data structure to use.
4568 *
4569 * @return EXIT_SUCCESS on success, -1 on error.
4570 */
4571int
4572resolve_unres_data(struct unres_data *unres)
4573{
4574 uint32_t i;
4575 int rc;
4576
4577 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004578 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004579 if (rc) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004580 return -1;
4581 }
4582 }
4583
4584 return EXIT_SUCCESS;
4585}